feat: align Bell prototype with go-admin-ui (#31)
This commit is contained in:
@@ -16,8 +16,8 @@ python -m http.server 4173 --directory prototypes
|
||||
|
||||
- `sense/index.html`:设备接入、ONVIF/RTSP、MediaMTX、实时监看和区域配置;直接映射 go-admin-ui 与 Element Plus 的通用管理端组件。
|
||||
- `brain/index.html`:合成输入到项目内匿名事件的内部流水线;Brain 无客户管理 UI。
|
||||
- `bell/index.html`:合成事件、不可变 Event、规则/Alert、ack/close 和审计时间线。
|
||||
- `assets/`:三套原型复用的样式和交互脚本。
|
||||
- `bell/index.html`:合成事件、不可变 Event、规则/Alert、ack/close 和审计时间线;直接映射 go-admin-ui 与 Element Plus 的通用管理端组件。
|
||||
- `assets/`:三套原型复用的基础样式和交互脚本;Sense/Bell 共同复用 go-admin-ui 原型外壳适配器。
|
||||
- `design-system/yovision/MASTER.md`:由 UI/UX Pro Max 生成的设计系统基线。
|
||||
|
||||
## 交互提示
|
||||
@@ -28,13 +28,16 @@ python -m http.server 4173 --directory prototypes
|
||||
- Bell 可注入合成事件,并演示 Alert 的 ack 和 close。
|
||||
- 所有弹窗支持 `Esc` 关闭,交互元素支持键盘焦点。
|
||||
|
||||
## Sense 的 go-admin-ui 对齐基线
|
||||
## Sense / Bell 的 go-admin-ui 对齐基线
|
||||
|
||||
- 只读参考仓库:`D:\github\goadmin\go-admin-ui`。
|
||||
- 参考 commit:`67d393d713877572fab0b897296a4c1d525fc81d`。
|
||||
- 应用外壳映射:`Sidebar`、`Navbar`、`TagsView`、`AppMain` 和 `BasicLayout` / 页面容器。
|
||||
- 通用组件映射:Element Plus 的 Button、Form、Input/Select、Table、Pagination、Dialog 和 Tag,以及 go-admin-ui 的搜索区与 `v-permisaction` 权限按钮模式。
|
||||
- Sense 专用组件:视频舞台 `SenseVideoStage` 与区域画布 `SenseZoneCanvas`;正式实现前先确认 go-admin-ui 内没有等价组件。
|
||||
- 共用原型适配器:`assets/go-admin-ui.css` 与 `assets/go-admin-shell.js`;两套产品不复制应用外壳和通用组件原型代码。
|
||||
- Sense 专用组件:视频舞台 `SenseVideoStage` 与区域画布 `SenseZoneCanvas`。
|
||||
- Bell 专用组件:值班处置工作台 `AlertWorkbench` 与审计时间线 `AlertAuditTimeline`。
|
||||
- 新增专用组件前必须先确认 go-admin-ui / Element Plus 中没有等价组件。
|
||||
- 原型仍是无构建依赖的 HTML/CSS/JavaScript,并未嵌入或复制 go-admin-ui / Element Plus 源码;这些名称用于约束正式 Vue 实现的组件落点。
|
||||
|
||||
## 事实来源边界
|
||||
|
||||
Vendored
+17
-13
@@ -148,14 +148,16 @@
|
||||
});
|
||||
|
||||
qs("[data-action='inject-event']")?.addEventListener("click", (event) => {
|
||||
event.currentTarget.disabled = true;
|
||||
event.currentTarget.textContent = "注入中…";
|
||||
const button = event.currentTarget;
|
||||
const idleText = button.textContent;
|
||||
button.disabled = true;
|
||||
button.textContent = "注入中…";
|
||||
window.setTimeout(() => {
|
||||
const count = qs("[data-alert-count]");
|
||||
if (count) count.textContent = String(Number(count.textContent) + 1);
|
||||
event.currentTarget.disabled = false;
|
||||
event.currentTarget.textContent = "注入合成事件";
|
||||
closeModal(event.currentTarget.closest(".modal-backdrop"));
|
||||
button.disabled = false;
|
||||
button.textContent = idleText;
|
||||
closeModal(button.closest(".modal-backdrop"));
|
||||
toast("合成事件已校验并生成新的 Alert");
|
||||
}, 520);
|
||||
});
|
||||
@@ -165,7 +167,7 @@
|
||||
const closeButton = qs("[data-action='close-alert']");
|
||||
ackButton?.addEventListener("click", () => {
|
||||
alertState.textContent = "已确认";
|
||||
alertState.className = "status status-warning";
|
||||
alertState.className = "status status-warning el-tag";
|
||||
ackButton.disabled = true;
|
||||
closeButton.disabled = false;
|
||||
const timeline = qs("[data-alert-timeline]");
|
||||
@@ -174,7 +176,7 @@
|
||||
});
|
||||
closeButton?.addEventListener("click", () => {
|
||||
alertState.textContent = "已关闭";
|
||||
alertState.className = "status status-success";
|
||||
alertState.className = "status status-success el-tag";
|
||||
closeButton.disabled = true;
|
||||
qs("[data-alert-timeline]")?.insertAdjacentHTML("beforeend", `<div class="timeline-item"><div class="timeline-title">处置完成并关闭</div><div class="timeline-meta">刚刚 · 原始 Event 保持不变</div></div>`);
|
||||
toast("Alert 已关闭,原始 Event 未修改");
|
||||
@@ -186,12 +188,14 @@
|
||||
toast(`已选择:${row.dataset.selectAlert}`);
|
||||
};
|
||||
row.addEventListener("click", select);
|
||||
row.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
select();
|
||||
}
|
||||
});
|
||||
if (row.tagName !== "BUTTON") {
|
||||
row.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
select();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const initial = qs("[data-view-target].active")?.dataset.viewTarget || qs("[data-view]")?.dataset.view;
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
const shell = document.querySelector("[data-go-admin-shell]");
|
||||
const collapse = document.querySelector("[data-collapse-sidebar]");
|
||||
const queryForm = document.querySelector("[data-device-query]");
|
||||
const queryInput = document.querySelector("#device-filter");
|
||||
|
||||
function syncTags(viewName) {
|
||||
document.querySelectorAll(".tags-view-item").forEach((tag) => {
|
||||
@@ -27,17 +25,17 @@
|
||||
});
|
||||
}
|
||||
|
||||
if (queryForm) {
|
||||
queryForm.addEventListener("submit", (event) => {
|
||||
document.querySelectorAll("[data-go-admin-query]").forEach((form) => {
|
||||
const input = document.querySelector(form.dataset.queryInput || "");
|
||||
form.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
if (queryInput) queryInput.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
input?.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
});
|
||||
queryForm.addEventListener("reset", () => {
|
||||
window.setTimeout(() => {
|
||||
if (queryInput) queryInput.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
}, 0);
|
||||
form.addEventListener("reset", () => {
|
||||
window.setTimeout(() => input?.dispatchEvent(new Event("input", { bubbles: true })), 0);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
syncTags("overview");
|
||||
const initialView = document.querySelector("[data-view-target].active")?.dataset.viewTarget;
|
||||
if (initialView) syncTags(initialView);
|
||||
})();
|
||||
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Shared prototype adapter for go-admin-ui commit 67d393d713877572fab0b897296a4c1d525fc81d.
|
||||
* This is an offline visual/interaction mapping, not copied framework CSS and not an Element Plus runtime.
|
||||
*/
|
||||
.go-admin-prototype {
|
||||
--ga-primary: #1677ff;
|
||||
--ga-primary-hover: #409eff;
|
||||
--ga-sidebar: #001529;
|
||||
--ga-sidebar-hover: #000c17;
|
||||
--ga-app-bg: #f0f2f5;
|
||||
--ga-border: #e4e7ed;
|
||||
--ga-text: #303133;
|
||||
--ga-muted: #606266;
|
||||
--ga-sidebar-width: 210px;
|
||||
color: var(--ga-text);
|
||||
background: var(--ga-app-bg);
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.go-admin-prototype .go-admin-shell { grid-template-columns: var(--ga-sidebar-width) minmax(0, 1fr); }
|
||||
.go-admin-prototype .sidebar-container { width: var(--ga-sidebar-width); padding: 0; background: var(--ga-sidebar); box-shadow: 2px 0 6px rgba(0, 21, 41, .35); transition: width .28s ease, transform .28s ease; }
|
||||
.go-admin-prototype .sidebar-logo { height: 64px; min-height: 64px; padding: 0 16px; gap: 12px; color: #fff; text-decoration: none; background: #001529; }
|
||||
.go-admin-prototype .brand-mark { width: 34px; height: 34px; flex: 0 0 34px; border-radius: 5px; background: var(--ga-primary); }
|
||||
.go-admin-prototype .brand-copy { min-width: 0; }
|
||||
.go-admin-prototype .brand-name { white-space: nowrap; }
|
||||
.go-admin-prototype .brand-subtitle { color: rgba(255,255,255,.56); white-space: nowrap; }
|
||||
.go-admin-prototype .el-menu { gap: 0; padding: 8px 0; }
|
||||
.go-admin-prototype .menu-group,
|
||||
.go-admin-prototype .el-menu-item { min-height: 50px; height: 50px; padding: 0 18px; border-radius: 0; gap: 14px; color: rgba(255,255,255,.82); }
|
||||
.go-admin-prototype .menu-group { display: flex; align-items: center; font-size: 14px; font-weight: 500; }
|
||||
.go-admin-prototype .menu-group .menu-arrow { width: 14px; margin-left: auto; transform: rotate(90deg); }
|
||||
.go-admin-prototype .el-menu-item:hover { color: #fff; background: var(--ga-sidebar-hover); }
|
||||
.go-admin-prototype .el-menu-item.active { color: var(--ga-primary); background: var(--ga-sidebar-hover); box-shadow: inset 3px 0 0 var(--ga-primary); }
|
||||
.go-admin-prototype .side-note { margin: 12px; padding: 11px 12px; border-radius: 4px; color: rgba(255,255,255,.72); }
|
||||
|
||||
.go-admin-prototype .main-container { min-width: 0; background: var(--ga-app-bg); }
|
||||
.go-admin-prototype .fixed-header { position: sticky; top: 0; z-index: 30; }
|
||||
.go-admin-prototype .navbar { position: relative; min-height: 50px; height: 50px; padding: 0 16px 0 0; border-bottom: 1px solid #eef0f6; background: #fff; box-shadow: 0 1px 8px rgba(79,70,229,.06); backdrop-filter: none; }
|
||||
.go-admin-prototype .navbar::after { content: ""; position: absolute; right: 0; bottom: 0; left: 0; height: 2px; background: linear-gradient(90deg, #1677ff, #40a9ff); opacity: .7; }
|
||||
.go-admin-prototype .navbar-action,
|
||||
.go-admin-prototype .avatar-button { min-width: 46px; height: 48px; padding: 0 12px; border: 0; display: inline-flex; align-items: center; justify-content: center; gap: 7px; background: transparent; color: #64748b; }
|
||||
.go-admin-prototype .navbar-action:hover,
|
||||
.go-admin-prototype .avatar-button:hover { color: var(--ga-primary); background: rgba(22,119,255,.06); }
|
||||
.go-admin-prototype .navbar-action svg { width: 19px; height: 19px; }
|
||||
.go-admin-prototype .mobile-menu { display: none; }
|
||||
.go-admin-prototype .breadcrumb { display: flex; align-items: center; gap: 9px; color: #97a8be; font-size: 13px; white-space: nowrap; }
|
||||
.go-admin-prototype .breadcrumb a { color: #606266; text-decoration: none; }
|
||||
.go-admin-prototype .breadcrumb strong { color: #303133; font-weight: 500; }
|
||||
.go-admin-prototype .avatar-button { min-width: auto; }
|
||||
.go-admin-prototype .avatar { width: 32px; height: 32px; display: grid; place-items: center; border: 2px solid rgba(22,119,255,.2); border-radius: 50%; color: var(--ga-primary); }
|
||||
.go-admin-prototype .prototype-pill { min-height: 25px; border-radius: 4px; }
|
||||
|
||||
.go-admin-prototype .tags-view-container { height: 40px; padding: 8px 8px 0; display: flex; align-items: flex-end; gap: 3px; overflow-x: auto; border-bottom: 1px solid #e8eaec; background: #fff; box-shadow: 0 1px 4px rgba(0,21,41,.08); }
|
||||
.go-admin-prototype .tags-view-item { height: 32px; padding: 0 10px; border: 1px solid #e0e0e6; border-radius: 3px 3px 0 0; flex: 0 0 auto; background: #f8f9fa; color: #606266; font-size: 12px; }
|
||||
.go-admin-prototype .tags-view-item:hover { color: var(--ga-primary); background: #e6f4ff; }
|
||||
.go-admin-prototype .tags-view-item.active { color: var(--ga-primary); border-color: #91caff; border-bottom-color: #fff; background: #fff; font-weight: 500; }
|
||||
.go-admin-prototype .tags-view-item span { margin-left: 4px; color: #909399; }
|
||||
|
||||
.go-admin-prototype .app-main { width: 100%; min-height: calc(100vh - 90px); padding: 16px; background: var(--ga-app-bg); }
|
||||
.go-admin-prototype .compact-header { margin-bottom: 14px; }
|
||||
.go-admin-prototype .compact-header h1 { font-size: 20px; font-weight: 500; letter-spacing: 0; }
|
||||
.go-admin-prototype .compact-header p { font-size: 13px; }
|
||||
.go-admin-prototype .el-card { border-color: var(--ga-border); border-radius: 4px; box-shadow: 0 1px 2px rgba(0,0,0,.03); }
|
||||
.go-admin-prototype .card-header { min-height: 48px; padding: 10px 14px; }
|
||||
.go-admin-prototype .card-body { padding: 14px; }
|
||||
.go-admin-prototype .metric { padding: 14px; }
|
||||
|
||||
.go-admin-prototype .el-button { min-height: 32px; height: 32px; padding: 5px 12px; border-color: #dcdfe6; border-radius: 4px; background: #fff; color: #606266; font-size: 12px; font-weight: 400; }
|
||||
.go-admin-prototype .el-button svg { width: 15px; height: 15px; }
|
||||
.go-admin-prototype .el-button:hover { color: var(--ga-primary); border-color: #a0cfff; background: #ecf5ff; }
|
||||
.go-admin-prototype .el-button-primary { color: #fff; border-color: var(--ga-primary); background: var(--ga-primary); }
|
||||
.go-admin-prototype .el-button-primary:hover { color: #fff; border-color: var(--ga-primary-hover); background: var(--ga-primary-hover); }
|
||||
.go-admin-prototype .el-button-link { min-height: 30px; height: 30px; padding: 3px 4px; border: 0; color: var(--ga-primary); background: transparent; }
|
||||
.go-admin-prototype .el-button:disabled { color: #a8abb2; border-color: #e4e7ed; background: #f5f7fa; }
|
||||
|
||||
.go-admin-prototype .el-form { color: var(--ga-text); }
|
||||
.go-admin-prototype .el-form-inline { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 18px; padding-bottom: 14px; border-bottom: 1px solid #ebeef5; }
|
||||
.go-admin-prototype .form-item { min-width: 180px; display: grid; grid-template-columns: auto minmax(150px, 220px); align-items: center; gap: 8px; }
|
||||
.go-admin-prototype .form-item label { color: #606266; font-size: 13px; white-space: nowrap; }
|
||||
.go-admin-prototype .form-actions { display: flex; gap: 8px; }
|
||||
.go-admin-prototype .el-input,
|
||||
.go-admin-prototype .el-select { min-height: 32px; height: 32px; padding: 4px 10px; border-color: #dcdfe6; border-radius: 4px; color: #606266; font-size: 13px; }
|
||||
.go-admin-prototype .el-input:focus,
|
||||
.go-admin-prototype .el-select:focus { border-color: var(--ga-primary); outline: 2px solid rgba(22,119,255,.16); }
|
||||
.go-admin-prototype .vertical-form { display: grid; gap: 16px; }
|
||||
.go-admin-prototype .vertical-form .form-item { grid-template-columns: 92px minmax(0,1fr); }
|
||||
.go-admin-prototype .vertical-form .help { margin: -8px 0 0 100px; }
|
||||
.go-admin-prototype .form-footer { display: flex; justify-content: flex-end; }
|
||||
|
||||
.go-admin-prototype .operation-bar { min-height: 48px; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
||||
.go-admin-prototype .operation-actions { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.go-admin-prototype .permission-hint { display: inline-flex; align-items: center; gap: 5px; color: #909399; font-size: 12px; }
|
||||
.go-admin-prototype .permission-hint svg { width: 14px; height: 14px; }
|
||||
.go-admin-prototype .el-table { min-width: 760px; border: 1px solid #ebeef5; }
|
||||
.go-admin-prototype .el-table th,
|
||||
.go-admin-prototype .el-table td { padding: 9px 10px; border-right: 1px solid #ebeef5; border-bottom-color: #ebeef5; }
|
||||
.go-admin-prototype .el-table th { background: #f5f7fa; color: #909399; font-weight: 500; }
|
||||
.go-admin-prototype .el-table tbody tr:nth-child(even) { background: #fafafa; }
|
||||
.go-admin-prototype .el-table tbody tr:hover { background: #f5f7fa; }
|
||||
.go-admin-prototype .checkbox-faux { width: 14px; height: 14px; display: inline-block; border: 1px solid #dcdfe6; border-radius: 2px; background: #fff; }
|
||||
.go-admin-prototype .action-divider { height: 14px; margin: 0 3px; display: inline-block; border-left: 1px solid #dcdfe6; vertical-align: middle; }
|
||||
.go-admin-prototype .el-tag { min-height: 24px; padding: 2px 8px; border: 1px solid currentColor; border-radius: 4px; font-weight: 400; }
|
||||
.go-admin-prototype .el-tag::before { display: none; }
|
||||
|
||||
.go-admin-prototype .pagination-container { min-height: 48px; display: flex; align-items: center; justify-content: flex-end; gap: 6px; color: #606266; font-size: 12px; }
|
||||
.go-admin-prototype .pagination-container button { min-width: 30px; height: 28px; border: 0; border-radius: 3px; background: #f4f4f5; color: #606266; }
|
||||
.go-admin-prototype .pagination-container button.active { color: #fff; background: var(--ga-primary); }
|
||||
.go-admin-prototype .pagination-container button:disabled { color: #c0c4cc; cursor: not-allowed; }
|
||||
.go-admin-prototype .pagination-size { height: 28px; border: 1px solid #dcdfe6; border-radius: 4px; color: #606266; }
|
||||
.go-admin-prototype .pagination-total { margin-right: 4px; }
|
||||
|
||||
.go-admin-prototype .description-list { display: grid; }
|
||||
.go-admin-prototype .description-row { min-height: 43px; padding: 8px 0; display: grid; grid-template-columns: minmax(90px,.7fr) minmax(0,1.5fr) auto; align-items: center; gap: 10px; border-bottom: 1px solid #ebeef5; }
|
||||
.go-admin-prototype .description-row:last-child { border-bottom: 0; }
|
||||
.go-admin-prototype .description-row > span:first-child { color: #909399; font-size: 12px; }
|
||||
.go-admin-prototype .description-row strong { font-size: 13px; font-weight: 500; }
|
||||
|
||||
.go-admin-prototype .sense-video-stage,
|
||||
.go-admin-prototype .sense-zone-canvas { border-radius: 4px; }
|
||||
.go-admin-prototype .el-overlay { background: rgba(0,0,0,.5); }
|
||||
.go-admin-prototype .el-dialog { width: min(600px,100%); border-radius: 4px; }
|
||||
.go-admin-prototype .el-dialog-header,
|
||||
.go-admin-prototype .el-dialog-footer { padding: 16px 20px; }
|
||||
.go-admin-prototype .el-dialog-body { padding: 20px; }
|
||||
.go-admin-prototype .dialog-close { min-height: 32px; height: 32px; color: #909399; }
|
||||
|
||||
.go-admin-prototype .go-admin-shell.compact { grid-template-columns: 54px minmax(0,1fr); }
|
||||
.go-admin-prototype .go-admin-shell.compact .sidebar-container { width: 54px; }
|
||||
.go-admin-prototype .go-admin-shell.compact .brand-copy,
|
||||
.go-admin-prototype .go-admin-shell.compact .el-menu-item span,
|
||||
.go-admin-prototype .go-admin-shell.compact .menu-group span,
|
||||
.go-admin-prototype .go-admin-shell.compact .menu-arrow,
|
||||
.go-admin-prototype .go-admin-shell.compact .side-note { display: none; }
|
||||
.go-admin-prototype .go-admin-shell.compact .sidebar-logo,
|
||||
.go-admin-prototype .go-admin-shell.compact .menu-group,
|
||||
.go-admin-prototype .go-admin-shell.compact .el-menu-item { padding-right: 0; padding-left: 0; justify-content: center; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.go-admin-prototype .go-admin-shell,
|
||||
.go-admin-prototype .go-admin-shell.compact { display: block; }
|
||||
.go-admin-prototype .sidebar-container,
|
||||
.go-admin-prototype .go-admin-shell.compact .sidebar-container { position: fixed; top: 0; left: 0; z-index: 40; width: min(300px,88vw); height: 100vh; transform: translateX(-102%); }
|
||||
.go-admin-prototype .sidebar-container.open,
|
||||
.go-admin-prototype .go-admin-shell.compact .sidebar-container.open { transform: translateX(0); }
|
||||
.go-admin-prototype .go-admin-shell.compact .brand-copy,
|
||||
.go-admin-prototype .go-admin-shell.compact .el-menu-item span,
|
||||
.go-admin-prototype .go-admin-shell.compact .menu-group span,
|
||||
.go-admin-prototype .go-admin-shell.compact .menu-arrow,
|
||||
.go-admin-prototype .go-admin-shell.compact .side-note { display: initial; }
|
||||
.go-admin-prototype .go-admin-shell.compact .sidebar-logo,
|
||||
.go-admin-prototype .go-admin-shell.compact .menu-group,
|
||||
.go-admin-prototype .go-admin-shell.compact .el-menu-item { padding: 0 18px; justify-content: flex-start; }
|
||||
.go-admin-prototype .desktop-collapse { display: none; }
|
||||
.go-admin-prototype .mobile-menu { display: inline-flex; }
|
||||
.go-admin-prototype .breadcrumb { max-width: 46vw; overflow: hidden; }
|
||||
.go-admin-prototype .breadcrumb a,
|
||||
.go-admin-prototype .breadcrumb span { display: none; }
|
||||
.go-admin-prototype .app-main { padding: 12px; }
|
||||
.go-admin-prototype .tags-view-container { height: 48px; padding-top: 8px; }
|
||||
.go-admin-prototype .tags-view-item { height: 40px; }
|
||||
.go-admin-prototype .el-button { min-height: 44px; height: 44px; }
|
||||
.go-admin-prototype .el-input,
|
||||
.go-admin-prototype .el-select { min-height: 44px; height: 44px; font-size: 16px; }
|
||||
.go-admin-prototype .el-form-inline { align-items: stretch; }
|
||||
.go-admin-prototype .el-form-inline .form-item { width: 100%; grid-template-columns: 82px minmax(0,1fr); }
|
||||
.go-admin-prototype .el-form-inline .form-actions { margin-left: 90px; }
|
||||
.go-admin-prototype .operation-bar { align-items: flex-start; flex-direction: column; padding: 9px 0; }
|
||||
.go-admin-prototype .pagination-container button,
|
||||
.go-admin-prototype .pagination-size { min-width: 40px; height: 40px; }
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.go-admin-prototype .desktop-only,
|
||||
.go-admin-prototype .prototype-pill { display: none; }
|
||||
.go-admin-prototype .topbar-actions { gap: 0; }
|
||||
.go-admin-prototype .navbar-action,
|
||||
.go-admin-prototype .avatar-button { min-width: 42px; padding: 0 8px; }
|
||||
.go-admin-prototype .vertical-form .form-item { grid-template-columns: 1fr; gap: 5px; }
|
||||
.go-admin-prototype .vertical-form .help { margin-left: 0; }
|
||||
.go-admin-prototype .pagination-container { justify-content: flex-start; overflow-x: auto; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/* Bell-only components layered on the shared go-admin-ui prototype adapter. */
|
||||
.bell-go-admin .brand-mark { background: #1677ff; }
|
||||
.bell-go-admin .bell-workbench { grid-template-columns: minmax(340px,.95fr) minmax(460px,1.35fr); }
|
||||
.bell-go-admin .alert-list { display: grid; gap: 8px; }
|
||||
.bell-go-admin .alert-row { width: 100%; min-height: 72px; grid-template-columns: 4px minmax(0,1fr) auto; padding: 11px 12px; border-color: #e4e7ed; border-radius: 4px; text-align: left; color: #303133; }
|
||||
.bell-go-admin .alert-row:hover { border-color: #91caff; background: #f5f9ff; }
|
||||
.bell-go-admin .alert-row.selected { border-color: #69b1ff; background: #e6f4ff; box-shadow: inset 0 0 0 1px #91caff; }
|
||||
.bell-go-admin .severity-bar { background: #f56c6c; }
|
||||
.bell-go-admin .severity-bar.medium { background: #e6a23c; }
|
||||
.bell-go-admin .alert-title { display: block; font-size: 14px; font-weight: 500; }
|
||||
.bell-go-admin .alert-meta { margin-top: 5px; }
|
||||
.bell-go-admin .alert-actions { margin-top: 14px; display: flex; justify-content: flex-end; gap: 8px; }
|
||||
.bell-go-admin .el-tabs { margin-bottom: 14px; }
|
||||
.bell-go-admin .el-tabs button { height: 36px; padding: 0 16px; color: #606266; font-size: 13px; }
|
||||
.bell-go-admin .el-tabs button[aria-selected="true"] { color: #1677ff; border-bottom-color: #1677ff; }
|
||||
.bell-go-admin .timeline { padding-left: 2px; }
|
||||
.bell-go-admin .timeline-item::before { background: #1677ff; box-shadow: 0 0 0 4px #e6f4ff; }
|
||||
.bell-go-admin .dev-only-note { margin: 0 0 18px; border-left-color: #e6a23c; border-radius: 4px; }
|
||||
|
||||
@media (max-width: 1080px) {
|
||||
.bell-go-admin .bell-workbench { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.bell-go-admin .alert-row { min-height: 76px; }
|
||||
.bell-go-admin .alert-actions { flex-wrap: wrap; }
|
||||
.bell-go-admin .alert-actions .el-button { flex: 1 1 150px; }
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.bell-go-admin .alert-row { grid-template-columns: 4px minmax(0,1fr); }
|
||||
.bell-go-admin .alert-row .activity-time { grid-column: 2; }
|
||||
}
|
||||
+98
-32
@@ -3,60 +3,126 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="description" content="YoVision Bell 当前 MVP 交互原型">
|
||||
<title>YoVision Bell · 当前 MVP 原型</title>
|
||||
<meta name="description" content="YoVision Bell 当前 MVP 交互原型,直接对齐 go-admin-ui 与 Element Plus">
|
||||
<title>YoVision Bell · go-admin-ui 对齐原型</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<link rel="stylesheet" href="../assets/styles.css">
|
||||
<link rel="stylesheet" href="../assets/go-admin-ui.css">
|
||||
<link rel="stylesheet" href="./bell.css">
|
||||
</head>
|
||||
<body>
|
||||
<body class="go-admin-prototype bell-go-admin">
|
||||
<svg class="sr-only" aria-hidden="true">
|
||||
<symbol id="icon-menu" viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h16"/></symbol>
|
||||
<symbol id="icon-bell" viewBox="0 0 24 24"><path d="M18 8a6 6 0 00-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9M10 21h4"/></symbol>
|
||||
<symbol id="icon-bell" viewBox="0 0 24 24"><path d="M18 8a6 6 0 0 0-12 0c0 7-3 7-3 9h18c0-2-3-2-3-9M10 21h4"/></symbol>
|
||||
<symbol id="icon-file" viewBox="0 0 24 24"><path d="M6 2h8l4 4v16H6zM14 2v5h5M9 13h6m-6 4h6"/></symbol>
|
||||
<symbol id="icon-rule" viewBox="0 0 24 24"><path d="M4 6h10m4 0h2M4 12h3m4 0h9M4 18h7m4 0h5"/><circle cx="16" cy="6" r="2"/><circle cx="9" cy="12" r="2"/><circle cx="13" cy="18" r="2"/></symbol>
|
||||
<symbol id="icon-plus" viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></symbol>
|
||||
<symbol id="icon-activity" viewBox="0 0 24 24"><path d="M3 12h4l2-7 4 14 2-7h6"/></symbol>
|
||||
<symbol id="icon-search" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/></symbol>
|
||||
<symbol id="icon-refresh" viewBox="0 0 24 24"><path d="M20 6v5h-5M4 18v-5h5M18 9a7 7 0 0 0-12-2L4 11m16 2-2 4a7 7 0 0 1-12-2"/></symbol>
|
||||
<symbol id="icon-fullscreen" viewBox="0 0 24 24"><path d="M8 3H3v5M16 3h5v5M8 21H3v-5M16 21h5v-5"/></symbol>
|
||||
<symbol id="icon-user" viewBox="0 0 24 24"><circle cx="12" cy="8" r="4"/><path d="M4 21a8 8 0 0 1 16 0"/></symbol>
|
||||
<symbol id="icon-lock" viewBox="0 0 24 24"><rect x="5" y="10" width="14" height="11" rx="2"/><path d="M8 10V7a4 4 0 0 1 8 0v3"/></symbol>
|
||||
<symbol id="icon-arrow" viewBox="0 0 24 24"><path d="M9 18l6-6-6-6"/></symbol>
|
||||
</svg>
|
||||
|
||||
<a class="skip-link" href="#main-content">跳到主要内容</a>
|
||||
<div class="app-shell">
|
||||
<aside class="sidebar" data-sidebar aria-label="Bell 主导航">
|
||||
<a class="brand" href="../index.html" style="text-decoration:none"><span class="brand-mark">B</span><span><span class="brand-name">YoVision Bell</span><span class="brand-subtitle">事件预警与处置</span></span></a>
|
||||
<div class="side-label">值班工作区</div>
|
||||
<nav class="side-nav">
|
||||
<button class="active" data-view-target="duty" data-title="实时值班台"><svg aria-hidden="true"><use href="#icon-bell"></use></svg>实时值班台</button>
|
||||
<button data-view-target="events" data-title="事件中心"><svg aria-hidden="true"><use href="#icon-file"></use></svg>事件中心</button>
|
||||
<button data-view-target="rules" data-title="规则策略"><svg aria-hidden="true"><use href="#icon-rule"></use></svg>规则策略</button>
|
||||
<div class="app-shell go-admin-shell" data-go-admin-shell>
|
||||
<aside class="sidebar sidebar-container" data-sidebar aria-label="Bell 主导航">
|
||||
<a class="brand sidebar-logo" href="../index.html">
|
||||
<span class="brand-mark">B</span>
|
||||
<span class="brand-copy"><span class="brand-name">YoVision Bell</span><span class="brand-subtitle">事件预警与处置</span></span>
|
||||
</a>
|
||||
<nav class="side-nav el-menu" aria-label="预警处置菜单">
|
||||
<div class="menu-group"><svg aria-hidden="true"><use href="#icon-bell"></use></svg><span>预警处置</span><svg class="menu-arrow" aria-hidden="true"><use href="#icon-arrow"></use></svg></div>
|
||||
<button class="active el-menu-item" data-view-target="duty" data-title="实时值班台"><svg aria-hidden="true"><use href="#icon-bell"></use></svg><span>实时值班台</span></button>
|
||||
<button class="el-menu-item" data-view-target="events" data-title="事件中心"><svg aria-hidden="true"><use href="#icon-file"></use></svg><span>事件中心</span></button>
|
||||
<button class="el-menu-item" data-view-target="rules" data-title="规则策略"><svg aria-hidden="true"><use href="#icon-rule"></use></svg><span>规则策略</span></button>
|
||||
</nav>
|
||||
<div class="side-note"><strong>独立产品边界</strong>Bell 使用自己的账户、会话和数据库。当前通过合成事件验收,不接受 Sense 用户 token。</div>
|
||||
<div class="side-note"><strong>独立产品边界</strong><span>Bell 使用独立账户、会话和数据库;当前以合成事件验收,不接受 Sense 用户 token。</span></div>
|
||||
</aside>
|
||||
<div class="main-column">
|
||||
<header class="topbar"><div class="topbar-left"><button class="btn btn-icon mobile-menu" data-mobile-menu aria-label="打开主导航" aria-expanded="false"><svg aria-hidden="true"><use href="#icon-menu"></use></svg></button><div><div class="page-eyebrow">青藤学校 · Bell 值班账号</div><h2 class="page-name" data-page-name>实时值班台</h2></div></div><div class="topbar-actions"><span class="prototype-pill">交互原型 · 非生产数据</span><a class="btn" href="../index.html">返回原型入口</a></div></header>
|
||||
<main id="main-content" class="content" tabindex="-1">
|
||||
|
||||
<div class="main-column main-container">
|
||||
<div class="fixed-header">
|
||||
<header class="topbar navbar">
|
||||
<div class="topbar-left">
|
||||
<button class="navbar-action mobile-menu" type="button" data-mobile-menu aria-label="打开主导航" aria-expanded="false"><svg aria-hidden="true"><use href="#icon-menu"></use></svg></button>
|
||||
<button class="navbar-action desktop-collapse" type="button" data-collapse-sidebar aria-label="折叠主导航" aria-expanded="true"><svg aria-hidden="true"><use href="#icon-menu"></use></svg></button>
|
||||
<nav class="breadcrumb" aria-label="面包屑"><a href="../index.html">YoVision</a><span>/</span><span>Bell</span><span>/</span><strong data-page-name>实时值班台</strong></nav>
|
||||
</div>
|
||||
<div class="topbar-actions right-menu">
|
||||
<button class="navbar-action" type="button" data-toast="原型搜索仅演示入口,不发送请求" aria-label="全局搜索"><svg aria-hidden="true"><use href="#icon-search"></use></svg></button>
|
||||
<button class="navbar-action desktop-only" type="button" data-toast="原型不切换浏览器全屏" aria-label="全屏"><svg aria-hidden="true"><use href="#icon-fullscreen"></use></svg></button>
|
||||
<span class="prototype-pill">交互原型 · 非生产数据</span>
|
||||
<button class="avatar-button" type="button" data-toast="当前原型用户:王值班员" aria-label="打开用户菜单"><span class="avatar"><svg aria-hidden="true"><use href="#icon-user"></use></svg></span><span class="desktop-only">王值班员</span></button>
|
||||
</div>
|
||||
</header>
|
||||
<nav class="tags-view-container" aria-label="已访问页面">
|
||||
<button class="tags-view-item active" data-view-target="duty" data-title="实时值班台" aria-current="page">实时值班台</button>
|
||||
<button class="tags-view-item" data-view-target="events" data-title="事件中心">事件中心 <span aria-hidden="true">×</span></button>
|
||||
<button class="tags-view-item" data-view-target="rules" data-title="规则策略">规则策略 <span aria-hidden="true">×</span></button>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<main id="main-content" class="content app-main" tabindex="-1">
|
||||
<section class="view active" data-view="duty">
|
||||
<div class="page-header"><div><h1>实时值班台</h1><p>使用合成事件完成 Event → Rule → Alert → ack → close;原始 Event 始终保持不可变。</p></div><div class="page-actions"><button class="btn btn-primary" data-open-modal="inject-event"><svg aria-hidden="true"><use href="#icon-plus"></use></svg>注入合成事件</button></div></div>
|
||||
<div class="metric-grid"><article class="metric"><div class="metric-label">待确认 Alert</div><div class="metric-value" data-alert-count>3</div><div class="metric-foot"><span class="status status-danger">1 高危</span></div></article><article class="metric"><div class="metric-label">处理中</div><div class="metric-value">2</div><div class="metric-foot"><span>已明确处置人</span></div></article><article class="metric"><div class="metric-label">今日关闭</div><div class="metric-value">18</div><div class="metric-foot"><strong>中位 3m 42s</strong></div></article><article class="metric"><div class="metric-label">重复收据</div><div class="metric-value">6</div><div class="metric-foot"><span>均未重复建 Alert</span></div></article></div>
|
||||
<div class="grid grid-2">
|
||||
<div class="stack" aria-label="待处置预警列表">
|
||||
<article class="alert-row selected" role="button" tabindex="0" data-select-alert="危险区域闯入"><span class="severity-bar"></span><div><div class="alert-title">危险区域闯入</div><div class="alert-meta"><span>北围墙 01</span><span>2 个关联 Event</span><span>未确认</span></div></div><span class="activity-time">10:24</span></article>
|
||||
<article class="alert-row" role="button" tabindex="0" data-select-alert="方向越线"><span class="severity-bar medium"></span><div><div class="alert-title">反向越过警戒线</div><div class="alert-meta"><span>宿舍东门 02</span><span>1 个 Event</span><span>处理中</span></div></div><span class="activity-time">10:19</span></article>
|
||||
<article class="alert-row" role="button" tabindex="0" data-select-alert="区域停留"><span class="severity-bar medium"></span><div><div class="alert-title">危险区域持续停留</div><div class="alert-meta"><span>食堂后门 01</span><span>3 个关联 Event</span><span>未确认</span></div></div><span class="activity-time">10:11</span></article>
|
||||
</div>
|
||||
<article class="card"><header class="card-header"><div><h2>危险区域闯入</h2><p class="card-subtitle">Alert BEL-A-20260812-0031</p></div><span class="status status-danger" data-alert-state>未确认</span></header><div class="card-body">
|
||||
<div class="tabs" role="tablist" data-tabs aria-label="预警详情"><button role="tab" aria-selected="true" data-tab-target="alert-summary">处置摘要</button><button role="tab" aria-selected="false" tabindex="-1" data-tab-target="alert-events">关联 Event</button></div>
|
||||
<div id="alert-summary" class="tab-panel active"><div class="stack"><div><span class="metric-label">规则</span><div class="table-title">校园高危区域 · v4</div></div><div><span class="metric-label">处置建议</span><div>确认现场情况;如无法确认,联系校内保安巡查。</div></div><div class="inline"><button class="btn btn-primary" data-action="ack-alert">确认预警</button><button class="btn" data-action="close-alert" disabled>完成并关闭</button></div></div></div>
|
||||
<div class="page-header compact-header"><div><h1>实时值班台</h1><p>使用合成事件完成 Event → Rule → Alert → ack → close;原始 Event 始终保持不可变。</p></div><div class="page-actions"><button class="btn el-button el-button-primary" data-open-modal="inject-event" title="权限:bell:event:inject;仅开发测试"><svg aria-hidden="true"><use href="#icon-plus"></use></svg>注入合成事件</button></div></div>
|
||||
<div class="metric-grid">
|
||||
<article class="metric el-card"><div class="metric-label">待确认 Alert</div><div class="metric-value" data-alert-count>3</div><div class="metric-foot"><span class="status status-danger el-tag">1 高危</span></div></article>
|
||||
<article class="metric el-card"><div class="metric-label">处理中</div><div class="metric-value">2</div><div class="metric-foot"><span>已明确处置人</span></div></article>
|
||||
<article class="metric el-card"><div class="metric-label">今日关闭</div><div class="metric-value">18</div><div class="metric-foot"><strong>中位 3m 42s</strong></div></article>
|
||||
<article class="metric el-card"><div class="metric-label">重复收据</div><div class="metric-value">6</div><div class="metric-foot"><span>均未重复建 Alert</span></div></article>
|
||||
</div>
|
||||
<div class="grid grid-2 bell-workbench">
|
||||
<article class="card el-card alert-workbench"><header class="card-header"><div><h2>待处置预警</h2><p class="card-subtitle">AlertWorkbench · Bell 业务专用组件</p></div><span class="status status-danger el-tag">3 待处理</span></header><div class="card-body alert-list" aria-label="待处置预警列表">
|
||||
<button class="alert-row selected" type="button" data-select-alert="危险区域闯入"><span class="severity-bar"></span><span><strong class="alert-title">危险区域闯入</strong><span class="alert-meta"><span>北围墙 01</span><span>2 个 Event</span><span>未确认</span></span></span><time class="activity-time">10:24</time></button>
|
||||
<button class="alert-row" type="button" data-select-alert="方向越线"><span class="severity-bar medium"></span><span><strong class="alert-title">反向越过警戒线</strong><span class="alert-meta"><span>宿舍东门 02</span><span>1 个 Event</span><span>处理中</span></span></span><time class="activity-time">10:19</time></button>
|
||||
<button class="alert-row" type="button" data-select-alert="区域停留"><span class="severity-bar medium"></span><span><strong class="alert-title">危险区域持续停留</strong><span class="alert-meta"><span>食堂后门 01</span><span>3 个 Event</span><span>未确认</span></span></span><time class="activity-time">10:11</time></button>
|
||||
</div></article>
|
||||
<article class="card el-card alert-detail"><header class="card-header"><div><h2>危险区域闯入</h2><p class="card-subtitle">Alert BEL-A-20260812-0031</p></div><span class="status status-danger el-tag" data-alert-state>未确认</span></header><div class="card-body">
|
||||
<div class="tabs el-tabs" role="tablist" data-tabs aria-label="预警详情"><button role="tab" aria-selected="true" data-tab-target="alert-summary">处置摘要</button><button role="tab" aria-selected="false" tabindex="-1" data-tab-target="alert-events">关联 Event</button></div>
|
||||
<div id="alert-summary" class="tab-panel active"><div class="description-list"><div class="description-row"><span>规则</span><strong>校园高危区域 · v4</strong></div><div class="description-row"><span>处置建议</span><strong>确认现场情况;如无法确认,联系校内保安巡查。</strong></div></div><div class="alert-actions"><button class="btn el-button el-button-primary" data-action="ack-alert" title="权限:bell:alert:ack">确认预警</button><button class="btn el-button" data-action="close-alert" title="权限:bell:alert:close" disabled>完成并关闭</button></div></div>
|
||||
<div id="alert-events" class="tab-panel" hidden><div class="activity-list"><div class="activity-item"><div class="activity-icon"><svg aria-hidden="true"><use href="#icon-file"></use></svg></div><div><div class="activity-title">producer-lab / evt-000041</div><div class="activity-meta">不可变 Event · 10:23:48 · 证据引用可用</div></div></div><div class="activity-item"><div class="activity-icon"><svg aria-hidden="true"><use href="#icon-file"></use></svg></div><div><div class="activity-title">producer-lab / evt-000042</div><div class="activity-meta">不可变 Event · 10:23:55 · 同一 Alert 聚合</div></div></div></div></div>
|
||||
</div><header class="card-header"><h3>审计时间线</h3></header><div class="card-body timeline" data-alert-timeline><div class="timeline-item"><div class="timeline-title">规则命中并创建 Alert</div><div class="timeline-meta">10:23:56 · system · 规则 v4</div></div><div class="timeline-item"><div class="timeline-title">值班台已显示</div><div class="timeline-meta">10:23:57 · sent/seen 与 ack 分离</div></div></div></article>
|
||||
</div><header class="card-header"><div><h3>审计时间线</h3><p class="card-subtitle">AlertAuditTimeline · Bell 业务专用组件</p></div></header><div class="card-body timeline" data-alert-timeline><div class="timeline-item"><div class="timeline-title">规则命中并创建 Alert</div><div class="timeline-meta">10:23:56 · system · 规则 v4</div></div><div class="timeline-item"><div class="timeline-title">值班台已显示</div><div class="timeline-meta">10:23:57 · sent/seen 与 ack 分离</div></div></div></article>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="view" data-view="events" hidden><div class="page-header"><div><h1>事件中心</h1><p>结构化 Event 校验后不可修改;误报和处置结果记录在 Alert/审计事实中。</p></div><div class="page-actions"><button class="btn btn-primary" data-open-modal="inject-event">注入合成事件</button></div></div><article class="card"><div class="card-body"><div class="toolbar"><div class="field grow"><label for="event-filter">搜索事件</label><input id="event-filter" class="input" data-filter-input="#event-table" placeholder="producer、source event ID 或规则"></div><div class="field"><label for="receipt-status">收据状态</label><select id="receipt-status" class="input"><option>全部</option><option>首次接收</option><option>重复收据</option></select></div></div><div class="table-wrap"><table id="event-table"><thead><tr><th>Event</th><th>Producer / Source ID</th><th>接收时间</th><th>收据</th><th>Alert</th></tr></thead><tbody><tr><td><span class="table-title">危险区域进入</span><span class="table-subtitle">结构化事实已冻结</span></td><td>producer-lab / evt-000042</td><td>10:23:55</td><td><span class="status status-success">首次接收</span></td><td>BEL-A-0031</td></tr><tr><td><span class="table-title">危险区域进入</span><span class="table-subtitle">正文与首次一致</span></td><td>producer-lab / evt-000042</td><td>10:24:03</td><td><span class="status status-neutral">重复收据</span></td><td>未重复创建</td></tr><tr><td><span class="table-title">方向越线</span><span class="table-subtitle">结构化事实已冻结</span></td><td>producer-lab / evt-000039</td><td>10:19:12</td><td><span class="status status-success">首次接收</span></td><td>BEL-A-0029</td></tr></tbody></table></div></div></article></section>
|
||||
<section class="view" data-view="events" hidden>
|
||||
<div class="page-header compact-header"><div><h1>事件中心</h1><p>结构化 Event 校验后不可修改;误报和处置结果记录在 Alert/审计事实中。</p></div></div>
|
||||
<article class="card el-card box-card"><div class="card-body">
|
||||
<form class="search-form el-form el-form-inline" data-go-admin-query data-query-input="#event-filter">
|
||||
<div class="form-item"><label for="event-filter">事件关键字</label><input id="event-filter" class="input el-input" data-filter-input="#event-table" placeholder="Producer、Source ID 或规则"></div>
|
||||
<div class="form-item"><label for="receipt-status">收据状态</label><select id="receipt-status" class="input el-select"><option>全部状态</option><option>首次接收</option><option>重复收据</option></select></div>
|
||||
<div class="form-actions"><button class="btn el-button el-button-primary" type="submit"><svg aria-hidden="true"><use href="#icon-search"></use></svg>搜索</button><button class="btn el-button" type="reset"><svg aria-hidden="true"><use href="#icon-refresh"></use></svg>重置</button></div>
|
||||
</form>
|
||||
<div class="operation-bar"><div class="operation-actions"><button class="btn el-button el-button-primary" data-open-modal="inject-event" title="权限:bell:event:inject;仅开发测试"><svg aria-hidden="true"><use href="#icon-plus"></use></svg>注入合成事件</button><button class="btn el-button" disabled title="权限:bell:event:export;MVP 暂不开放"><svg aria-hidden="true"><use href="#icon-lock"></use></svg>导出</button></div><span class="permission-hint"><svg aria-hidden="true"><use href="#icon-lock"></use></svg>操作按钮受 RBAC 与环境开关双重控制</span></div>
|
||||
<div class="table-wrap"><table id="event-table" class="el-table"><thead><tr><th>Event</th><th>Producer / Source ID</th><th>接收时间</th><th>收据</th><th>Alert</th><th>操作</th></tr></thead><tbody>
|
||||
<tr><td><span class="table-title">危险区域进入</span><span class="table-subtitle">结构化事实已冻结</span></td><td>producer-lab / evt-000042</td><td>10:23:55</td><td><span class="status status-success el-tag">首次接收</span></td><td>BEL-A-0031</td><td><button class="btn btn-quiet el-button-link" data-toast="已打开 Event 与 Alert 导航链路">查看链路</button></td></tr>
|
||||
<tr><td><span class="table-title">危险区域进入</span><span class="table-subtitle">正文与首次一致</span></td><td>producer-lab / evt-000042</td><td>10:24:03</td><td><span class="status status-neutral el-tag">重复收据</span></td><td>未重复创建</td><td><button class="btn btn-quiet el-button-link" data-toast="已打开永久幂等收据">查看收据</button></td></tr>
|
||||
<tr><td><span class="table-title">方向越线</span><span class="table-subtitle">结构化事实已冻结</span></td><td>producer-lab / evt-000039</td><td>10:19:12</td><td><span class="status status-success el-tag">首次接收</span></td><td>BEL-A-0029</td><td><button class="btn btn-quiet el-button-link" data-toast="已打开 Event 与 Alert 导航链路">查看链路</button></td></tr>
|
||||
</tbody></table></div>
|
||||
<nav class="pagination-container el-pagination" aria-label="事件列表分页"><span class="pagination-total">共 3 条</span><button type="button" disabled aria-label="上一页">‹</button><button type="button" class="active" aria-current="page">1</button><button type="button" disabled aria-label="下一页">›</button><select class="pagination-size" aria-label="每页条数"><option>10 条/页</option><option>20 条/页</option></select></nav>
|
||||
</div></article>
|
||||
</section>
|
||||
|
||||
<section class="view" data-view="rules" hidden><div class="page-header"><div><h1>规则策略</h1><p>MVP 仅展示事件到 Alert 的基本匹配;自动升级、通知和排班属于后续阶段。</p></div><div class="page-actions"><button class="btn btn-primary" data-toast="已创建规则草稿,不影响当前发布版本">新建规则草稿</button></div></div><div class="grid grid-even"><article class="card"><header class="card-header"><div><h2>校园高危区域</h2><p class="card-subtitle">发布版本 v4</p></div><span class="status status-success">生效</span></header><div class="card-body stack"><div><span class="metric-label">匹配条件</span><div class="table-title">event.type = zone_intrusion</div></div><div><span class="metric-label">Alert 严重度</span><div class="table-title">高危</div></div><button class="btn" data-toast="已进入校园高危区域规则草稿">编辑草稿</button></div></article><article class="card"><header class="card-header"><div><h2>方向越线</h2><p class="card-subtitle">发布版本 v2</p></div><span class="status status-success">生效</span></header><div class="card-body stack"><div><span class="metric-label">匹配条件</span><div class="table-title">event.type = line_crossing</div></div><div><span class="metric-label">Alert 严重度</span><div class="table-title">中危</div></div><button class="btn" data-toast="已进入方向越线规则草稿">编辑草稿</button></div></article></div></section>
|
||||
<section class="view" data-view="rules" hidden>
|
||||
<div class="page-header compact-header"><div><h1>规则策略</h1><p>MVP 仅展示事件到 Alert 的基本匹配;自动升级、通知和排班属于后续阶段。</p></div></div>
|
||||
<article class="card el-card box-card"><div class="card-body"><div class="operation-bar"><div class="operation-actions"><button class="btn el-button el-button-primary" data-toast="已创建规则草稿,不影响当前发布版本" title="权限:bell:rule:add"><svg aria-hidden="true"><use href="#icon-plus"></use></svg>新建规则草稿</button><button class="btn el-button" disabled title="请先选择规则">批量停用</button></div><span class="permission-hint"><svg aria-hidden="true"><use href="#icon-lock"></use></svg>发布版本不可直接修改</span></div>
|
||||
<div class="table-wrap"><table class="el-table"><thead><tr><th>规则名称</th><th>发布版本</th><th>匹配条件</th><th>Alert 严重度</th><th>状态</th><th>操作</th></tr></thead><tbody><tr><td><span class="table-title">校园高危区域</span></td><td>v4</td><td>event.type = zone_intrusion</td><td><span class="status status-danger el-tag">高危</span></td><td><span class="status status-success el-tag">生效</span></td><td><button class="btn btn-quiet el-button-link" data-toast="已进入校园高危区域规则草稿">编辑草稿</button></td></tr><tr><td><span class="table-title">方向越线</span></td><td>v2</td><td>event.type = line_crossing</td><td><span class="status status-warning el-tag">中危</span></td><td><span class="status status-success el-tag">生效</span></td><td><button class="btn btn-quiet el-button-link" data-toast="已进入方向越线规则草稿">编辑草稿</button></td></tr></tbody></table></div>
|
||||
</div></article>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-backdrop" id="inject-event" aria-hidden="true"><section class="modal" role="dialog" aria-modal="true" aria-labelledby="inject-title"><header class="modal-header"><h2 id="inject-title">注入合成事件</h2><button class="btn btn-icon btn-quiet" data-close-modal aria-label="关闭合成事件窗口">×</button></header><div class="modal-body stack"><div class="boundary-note" style="margin:0">该入口仅用于开发测试,生产环境必须禁用。</div><div class="field"><label for="synthetic-type">事件类型</label><select id="synthetic-type" class="input"><option>危险区域进入</option><option>方向越线</option></select></div><div class="field"><label for="synthetic-producer">Producer identity</label><input id="synthetic-producer" class="input" value="producer-lab" readonly></div><div class="field"><label for="synthetic-source">Source event ID</label><input id="synthetic-source" class="input" value="evt-demo-0001"></div></div><footer class="modal-footer"><button class="btn" data-close-modal>取消</button><button class="btn btn-primary" data-action="inject-event">注入合成事件</button></footer></section></div>
|
||||
<div class="modal-backdrop el-overlay" id="inject-event" aria-hidden="true">
|
||||
<section class="modal el-dialog" role="dialog" aria-modal="true" aria-labelledby="inject-title">
|
||||
<header class="modal-header el-dialog-header"><h2 id="inject-title">注入合成事件</h2><button class="btn btn-icon btn-quiet dialog-close" data-close-modal aria-label="关闭合成事件窗口">×</button></header>
|
||||
<div class="modal-body el-dialog-body"><div class="boundary-note dev-only-note">该入口仅用于开发测试;生产构建必须通过环境开关移除。</div><form class="el-form vertical-form"><div class="form-item"><label for="synthetic-type">事件类型</label><select id="synthetic-type" class="input el-select"><option>危险区域进入</option><option>方向越线</option></select></div><div class="form-item"><label for="synthetic-producer">Producer identity</label><input id="synthetic-producer" class="input el-input" value="producer-lab" readonly></div><div class="form-item"><label for="synthetic-source">Source event ID</label><input id="synthetic-source" class="input el-input" value="evt-demo-0001"></div></form></div>
|
||||
<footer class="modal-footer el-dialog-footer"><button class="btn el-button" data-close-modal>取消</button><button class="btn el-button el-button-primary" data-action="inject-event">确定注入</button></footer>
|
||||
</section>
|
||||
</div>
|
||||
<div class="toast-region" data-toast-region aria-live="polite"></div>
|
||||
<script src="../assets/app.js"></script>
|
||||
<script src="../assets/go-admin-shell.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
/*
|
||||
* Sense prototype adapter for go-admin-ui commit 67d393d713877572fab0b897296a4c1d525fc81d.
|
||||
* This is an offline visual/interaction mapping, not copied framework CSS and not an Element Plus runtime.
|
||||
*/
|
||||
.sense-go-admin {
|
||||
--ga-primary: #1677ff;
|
||||
--ga-primary-hover: #409eff;
|
||||
--ga-sidebar: #001529;
|
||||
--ga-sidebar-hover: #000c17;
|
||||
--ga-app-bg: #f0f2f5;
|
||||
--ga-border: #e4e7ed;
|
||||
--ga-text: #303133;
|
||||
--ga-muted: #606266;
|
||||
--ga-sidebar-width: 210px;
|
||||
color: var(--ga-text);
|
||||
background: var(--ga-app-bg);
|
||||
font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
|
||||
}
|
||||
|
||||
.sense-go-admin .go-admin-shell { grid-template-columns: var(--ga-sidebar-width) minmax(0, 1fr); }
|
||||
.sense-go-admin .sidebar-container { width: var(--ga-sidebar-width); padding: 0; background: var(--ga-sidebar); box-shadow: 2px 0 6px rgba(0, 21, 41, .35); transition: width .28s ease, transform .28s ease; }
|
||||
.sense-go-admin .sidebar-logo { height: 64px; min-height: 64px; padding: 0 16px; gap: 12px; color: #fff; text-decoration: none; background: #001529; }
|
||||
.sense-go-admin .brand-mark { width: 34px; height: 34px; flex: 0 0 34px; border-radius: 5px; background: var(--ga-primary); }
|
||||
.sense-go-admin .brand-copy { min-width: 0; }
|
||||
.sense-go-admin .brand-name { white-space: nowrap; }
|
||||
.sense-go-admin .brand-subtitle { color: rgba(255,255,255,.56); white-space: nowrap; }
|
||||
.sense-go-admin .el-menu { gap: 0; padding: 8px 0; }
|
||||
.sense-go-admin .menu-group,
|
||||
.sense-go-admin .el-menu-item { min-height: 50px; height: 50px; padding: 0 18px; border-radius: 0; gap: 14px; color: rgba(255,255,255,.82); }
|
||||
.sense-go-admin .menu-group { display: flex; align-items: center; font-size: 14px; font-weight: 500; }
|
||||
.sense-go-admin .menu-group .menu-arrow { width: 14px; margin-left: auto; transform: rotate(90deg); }
|
||||
.sense-go-admin .el-menu-item:hover { color: #fff; background: var(--ga-sidebar-hover); }
|
||||
.sense-go-admin .el-menu-item.active { color: var(--ga-primary); background: var(--ga-sidebar-hover); box-shadow: inset 3px 0 0 var(--ga-primary); }
|
||||
.sense-go-admin .side-note { margin: 12px; padding: 11px 12px; border-radius: 4px; color: rgba(255,255,255,.72); }
|
||||
|
||||
.sense-go-admin .main-container { min-width: 0; background: var(--ga-app-bg); }
|
||||
.sense-go-admin .fixed-header { position: sticky; top: 0; z-index: 30; }
|
||||
.sense-go-admin .navbar { position: relative; min-height: 50px; height: 50px; padding: 0 16px 0 0; border-bottom: 1px solid #eef0f6; background: #fff; box-shadow: 0 1px 8px rgba(79,70,229,.06); backdrop-filter: none; }
|
||||
.sense-go-admin .navbar::after { content: ""; position: absolute; right: 0; bottom: 0; left: 0; height: 2px; background: linear-gradient(90deg, #1677ff, #40a9ff); opacity: .7; }
|
||||
.sense-go-admin .navbar-action,
|
||||
.sense-go-admin .avatar-button { min-width: 46px; height: 48px; padding: 0 12px; border: 0; display: inline-flex; align-items: center; justify-content: center; gap: 7px; background: transparent; color: #64748b; }
|
||||
.sense-go-admin .navbar-action:hover,
|
||||
.sense-go-admin .avatar-button:hover { color: var(--ga-primary); background: rgba(22,119,255,.06); }
|
||||
.sense-go-admin .navbar-action svg { width: 19px; height: 19px; }
|
||||
.sense-go-admin .mobile-menu { display: none; }
|
||||
.sense-go-admin .breadcrumb { display: flex; align-items: center; gap: 9px; color: #97a8be; font-size: 13px; white-space: nowrap; }
|
||||
.sense-go-admin .breadcrumb a { color: #606266; text-decoration: none; }
|
||||
.sense-go-admin .breadcrumb strong { color: #303133; font-weight: 500; }
|
||||
.sense-go-admin .avatar-button { min-width: auto; }
|
||||
.sense-go-admin .avatar { width: 32px; height: 32px; display: grid; place-items: center; border: 2px solid rgba(22,119,255,.2); border-radius: 50%; color: var(--ga-primary); }
|
||||
.sense-go-admin .prototype-pill { min-height: 25px; border-radius: 4px; }
|
||||
|
||||
.sense-go-admin .tags-view-container { height: 40px; padding: 8px 8px 0; display: flex; align-items: flex-end; gap: 3px; overflow-x: auto; border-bottom: 1px solid #e8eaec; background: #fff; box-shadow: 0 1px 4px rgba(0,21,41,.08); }
|
||||
.sense-go-admin .tags-view-item { height: 32px; padding: 0 10px; border: 1px solid #e0e0e6; border-radius: 3px 3px 0 0; flex: 0 0 auto; background: #f8f9fa; color: #606266; font-size: 12px; }
|
||||
.sense-go-admin .tags-view-item:hover { color: var(--ga-primary); background: #e6f4ff; }
|
||||
.sense-go-admin .tags-view-item.active { color: var(--ga-primary); border-color: #91caff; border-bottom-color: #fff; background: #fff; font-weight: 500; }
|
||||
.sense-go-admin .tags-view-item span { margin-left: 4px; color: #909399; }
|
||||
|
||||
.sense-go-admin .app-main { width: 100%; min-height: calc(100vh - 90px); padding: 16px; background: var(--ga-app-bg); }
|
||||
.sense-go-admin .compact-header { margin-bottom: 14px; }
|
||||
.sense-go-admin .compact-header h1 { font-size: 20px; font-weight: 500; letter-spacing: 0; }
|
||||
.sense-go-admin .compact-header p { font-size: 13px; }
|
||||
.sense-go-admin .el-card { border-color: var(--ga-border); border-radius: 4px; box-shadow: 0 1px 2px rgba(0,0,0,.03); }
|
||||
.sense-go-admin .card-header { min-height: 48px; padding: 10px 14px; }
|
||||
.sense-go-admin .card-body { padding: 14px; }
|
||||
.sense-go-admin .metric { padding: 14px; }
|
||||
|
||||
.sense-go-admin .el-button { min-height: 32px; height: 32px; padding: 5px 12px; border-color: #dcdfe6; border-radius: 4px; background: #fff; color: #606266; font-size: 12px; font-weight: 400; }
|
||||
.sense-go-admin .el-button svg { width: 15px; height: 15px; }
|
||||
.sense-go-admin .el-button:hover { color: var(--ga-primary); border-color: #a0cfff; background: #ecf5ff; }
|
||||
.sense-go-admin .el-button-primary { color: #fff; border-color: var(--ga-primary); background: var(--ga-primary); }
|
||||
.sense-go-admin .el-button-primary:hover { color: #fff; border-color: var(--ga-primary-hover); background: var(--ga-primary-hover); }
|
||||
.sense-go-admin .el-button-link { min-height: 30px; height: 30px; padding: 3px 4px; border: 0; color: var(--ga-primary); background: transparent; }
|
||||
.sense-go-admin .el-button:disabled { color: #a8abb2; border-color: #e4e7ed; background: #f5f7fa; }
|
||||
|
||||
.sense-go-admin .el-form { color: var(--ga-text); }
|
||||
.sense-go-admin .el-form-inline { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 18px; padding-bottom: 14px; border-bottom: 1px solid #ebeef5; }
|
||||
.sense-go-admin .form-item { min-width: 180px; display: grid; grid-template-columns: auto minmax(150px, 220px); align-items: center; gap: 8px; }
|
||||
.sense-go-admin .form-item label { color: #606266; font-size: 13px; white-space: nowrap; }
|
||||
.sense-go-admin .form-actions { display: flex; gap: 8px; }
|
||||
.sense-go-admin .el-input,
|
||||
.sense-go-admin .el-select { min-height: 32px; height: 32px; padding: 4px 10px; border-color: #dcdfe6; border-radius: 4px; color: #606266; font-size: 13px; }
|
||||
.sense-go-admin .el-input:focus,
|
||||
.sense-go-admin .el-select:focus { border-color: var(--ga-primary); outline: 2px solid rgba(22,119,255,.16); }
|
||||
.sense-go-admin .vertical-form { display: grid; gap: 16px; }
|
||||
.sense-go-admin .vertical-form .form-item { grid-template-columns: 92px minmax(0,1fr); }
|
||||
.sense-go-admin .vertical-form .help { margin: -8px 0 0 100px; }
|
||||
.sense-go-admin .form-footer { display: flex; justify-content: flex-end; }
|
||||
|
||||
.sense-go-admin .operation-bar { min-height: 48px; display: flex; align-items: center; justify-content: space-between; gap: 12px; }
|
||||
.sense-go-admin .operation-actions { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.sense-go-admin .permission-hint { display: inline-flex; align-items: center; gap: 5px; color: #909399; font-size: 12px; }
|
||||
.sense-go-admin .permission-hint svg { width: 14px; height: 14px; }
|
||||
.sense-go-admin .el-table { min-width: 760px; border: 1px solid #ebeef5; }
|
||||
.sense-go-admin .el-table th,
|
||||
.sense-go-admin .el-table td { padding: 9px 10px; border-right: 1px solid #ebeef5; border-bottom-color: #ebeef5; }
|
||||
.sense-go-admin .el-table th { background: #f5f7fa; color: #909399; font-weight: 500; }
|
||||
.sense-go-admin .el-table tbody tr:nth-child(even) { background: #fafafa; }
|
||||
.sense-go-admin .el-table tbody tr:hover { background: #f5f7fa; }
|
||||
.sense-go-admin .checkbox-faux { width: 14px; height: 14px; display: inline-block; border: 1px solid #dcdfe6; border-radius: 2px; background: #fff; }
|
||||
.sense-go-admin .action-divider { height: 14px; margin: 0 3px; display: inline-block; border-left: 1px solid #dcdfe6; vertical-align: middle; }
|
||||
.sense-go-admin .el-tag { min-height: 24px; padding: 2px 8px; border: 1px solid currentColor; border-radius: 4px; font-weight: 400; }
|
||||
.sense-go-admin .el-tag::before { display: none; }
|
||||
|
||||
.sense-go-admin .pagination-container { min-height: 48px; display: flex; align-items: center; justify-content: flex-end; gap: 6px; color: #606266; font-size: 12px; }
|
||||
.sense-go-admin .pagination-container button { min-width: 30px; height: 28px; border: 0; border-radius: 3px; background: #f4f4f5; color: #606266; }
|
||||
.sense-go-admin .pagination-container button.active { color: #fff; background: var(--ga-primary); }
|
||||
.sense-go-admin .pagination-container button:disabled { color: #c0c4cc; cursor: not-allowed; }
|
||||
.sense-go-admin .pagination-size { height: 28px; border: 1px solid #dcdfe6; border-radius: 4px; color: #606266; }
|
||||
.sense-go-admin .pagination-total { margin-right: 4px; }
|
||||
|
||||
.sense-go-admin .description-list { display: grid; }
|
||||
.sense-go-admin .description-row { min-height: 43px; padding: 8px 0; display: grid; grid-template-columns: minmax(90px,.7fr) minmax(0,1.5fr) auto; align-items: center; gap: 10px; border-bottom: 1px solid #ebeef5; }
|
||||
.sense-go-admin .description-row:last-child { border-bottom: 0; }
|
||||
.sense-go-admin .description-row > span:first-child { color: #909399; font-size: 12px; }
|
||||
.sense-go-admin .description-row strong { font-size: 13px; font-weight: 500; }
|
||||
|
||||
.sense-go-admin .sense-video-stage,
|
||||
.sense-go-admin .sense-zone-canvas { border-radius: 4px; }
|
||||
.sense-go-admin .el-overlay { background: rgba(0,0,0,.5); }
|
||||
.sense-go-admin .el-dialog { width: min(600px,100%); border-radius: 4px; }
|
||||
.sense-go-admin .el-dialog-header,
|
||||
.sense-go-admin .el-dialog-footer { padding: 16px 20px; }
|
||||
.sense-go-admin .el-dialog-body { padding: 20px; }
|
||||
.sense-go-admin .dialog-close { min-height: 32px; height: 32px; color: #909399; }
|
||||
|
||||
.sense-go-admin .go-admin-shell.compact { grid-template-columns: 54px minmax(0,1fr); }
|
||||
.sense-go-admin .go-admin-shell.compact .sidebar-container { width: 54px; }
|
||||
.sense-go-admin .go-admin-shell.compact .brand-copy,
|
||||
.sense-go-admin .go-admin-shell.compact .el-menu-item span,
|
||||
.sense-go-admin .go-admin-shell.compact .menu-group span,
|
||||
.sense-go-admin .go-admin-shell.compact .menu-arrow,
|
||||
.sense-go-admin .go-admin-shell.compact .side-note { display: none; }
|
||||
.sense-go-admin .go-admin-shell.compact .sidebar-logo,
|
||||
.sense-go-admin .go-admin-shell.compact .menu-group,
|
||||
.sense-go-admin .go-admin-shell.compact .el-menu-item { padding-right: 0; padding-left: 0; justify-content: center; }
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.sense-go-admin .go-admin-shell,
|
||||
.sense-go-admin .go-admin-shell.compact { display: block; }
|
||||
.sense-go-admin .sidebar-container,
|
||||
.sense-go-admin .go-admin-shell.compact .sidebar-container { position: fixed; top: 0; left: 0; z-index: 40; width: min(300px,88vw); height: 100vh; transform: translateX(-102%); }
|
||||
.sense-go-admin .sidebar-container.open,
|
||||
.sense-go-admin .go-admin-shell.compact .sidebar-container.open { transform: translateX(0); }
|
||||
.sense-go-admin .go-admin-shell.compact .brand-copy,
|
||||
.sense-go-admin .go-admin-shell.compact .el-menu-item span,
|
||||
.sense-go-admin .go-admin-shell.compact .menu-group span,
|
||||
.sense-go-admin .go-admin-shell.compact .menu-arrow,
|
||||
.sense-go-admin .go-admin-shell.compact .side-note { display: initial; }
|
||||
.sense-go-admin .go-admin-shell.compact .sidebar-logo,
|
||||
.sense-go-admin .go-admin-shell.compact .menu-group,
|
||||
.sense-go-admin .go-admin-shell.compact .el-menu-item { padding: 0 18px; justify-content: flex-start; }
|
||||
.sense-go-admin .desktop-collapse { display: none; }
|
||||
.sense-go-admin .mobile-menu { display: inline-flex; }
|
||||
.sense-go-admin .breadcrumb { max-width: 46vw; overflow: hidden; }
|
||||
.sense-go-admin .breadcrumb a,
|
||||
.sense-go-admin .breadcrumb span { display: none; }
|
||||
.sense-go-admin .app-main { padding: 12px; }
|
||||
.sense-go-admin .tags-view-container { height: 48px; padding-top: 8px; }
|
||||
.sense-go-admin .tags-view-item { height: 40px; }
|
||||
.sense-go-admin .el-button { min-height: 44px; height: 44px; }
|
||||
.sense-go-admin .el-input,
|
||||
.sense-go-admin .el-select { min-height: 44px; height: 44px; font-size: 16px; }
|
||||
.sense-go-admin .el-form-inline { align-items: stretch; }
|
||||
.sense-go-admin .el-form-inline .form-item { width: 100%; grid-template-columns: 82px minmax(0,1fr); }
|
||||
.sense-go-admin .el-form-inline .form-actions { margin-left: 90px; }
|
||||
.sense-go-admin .operation-bar { align-items: flex-start; flex-direction: column; padding: 9px 0; }
|
||||
.sense-go-admin .pagination-container button,
|
||||
.sense-go-admin .pagination-size { min-width: 40px; height: 40px; }
|
||||
}
|
||||
|
||||
@media (max-width: 430px) {
|
||||
.sense-go-admin .desktop-only,
|
||||
.sense-go-admin .prototype-pill { display: none; }
|
||||
.sense-go-admin .topbar-actions { gap: 0; }
|
||||
.sense-go-admin .navbar-action,
|
||||
.sense-go-admin .avatar-button { min-width: 42px; padding: 0 8px; }
|
||||
.sense-go-admin .vertical-form .form-item { grid-template-columns: 1fr; gap: 5px; }
|
||||
.sense-go-admin .vertical-form .help { margin-left: 0; }
|
||||
.sense-go-admin .pagination-container { justify-content: flex-start; overflow-x: auto; }
|
||||
}
|
||||
@@ -7,9 +7,9 @@
|
||||
<title>YoVision Sense · go-admin-ui 对齐原型</title>
|
||||
<link rel="icon" href="data:,">
|
||||
<link rel="stylesheet" href="../assets/styles.css">
|
||||
<link rel="stylesheet" href="./go-admin-ui.css">
|
||||
<link rel="stylesheet" href="../assets/go-admin-ui.css">
|
||||
</head>
|
||||
<body class="sense-go-admin">
|
||||
<body class="go-admin-prototype sense-go-admin">
|
||||
<svg class="sr-only" aria-hidden="true">
|
||||
<symbol id="icon-menu" viewBox="0 0 24 24"><path d="M4 7h16M4 12h16M4 17h16"/></symbol>
|
||||
<symbol id="icon-grid" viewBox="0 0 24 24"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></symbol>
|
||||
@@ -93,7 +93,7 @@
|
||||
<section class="view" data-view="devices" hidden>
|
||||
<div class="page-header compact-header"><div><h1>设备接入</h1><p>从发现、验证到激活的单设备闭环;凭据更新后只显示脱敏结果。</p></div></div>
|
||||
<article class="card el-card box-card"><div class="card-body">
|
||||
<form class="search-form el-form el-form-inline" data-device-query>
|
||||
<form class="search-form el-form el-form-inline" data-go-admin-query data-query-input="#device-filter">
|
||||
<div class="form-item"><label for="device-filter">设备关键字</label><input id="device-filter" class="input el-input" data-filter-input="#device-table" placeholder="名称、地址或状态"></div>
|
||||
<div class="form-item"><label for="device-status">接入状态</label><select id="device-status" class="input el-select"><option>全部状态</option><option>在线</option><option>需处理</option><option>待激活</option></select></div>
|
||||
<div class="form-actions"><button class="btn el-button el-button-primary" type="submit"><svg aria-hidden="true"><use href="#icon-search"></use></svg>搜索</button><button class="btn el-button" type="reset" data-reset-device-query><svg aria-hidden="true"><use href="#icon-refresh"></use></svg>重置</button></div>
|
||||
@@ -133,6 +133,6 @@
|
||||
</div>
|
||||
<div class="toast-region" data-toast-region aria-live="polite"></div>
|
||||
<script src="../assets/app.js"></script>
|
||||
<script src="./sense.js"></script>
|
||||
<script src="../assets/go-admin-shell.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user