Commit afe6613aed80af844046e3c03b4bad1322996e0a

Authored by zichun
1 parent a0e6eabb

chore(prototype): add erp.html UI prototype

Static HTML mockup used as design reference for the frontend
scaffold (layout, color tokens, table/form patterns).
Showing 1 changed file with 850 additions and 0 deletions
prototype/erp.html 0 → 100644
  1 +<!doctype html>
  2 +<html lang="zh-CN">
  3 +<head>
  4 +<meta charset="utf-8" />
  5 +<title>ERP - 企业业务能力平台</title>
  6 +<meta name="viewport" content="width=device-width, initial-scale=1" />
  7 +<style>
  8 + :root {
  9 + --bg: #f3f4f6;
  10 + --panel: #ffffff;
  11 + --topbar: #1f1f23;
  12 + --topbar-text: #ffffff;
  13 + --primary: #2f7adf;
  14 + --primary-strong: #1f6ed4;
  15 + --link: #1e84e6;
  16 + --text: #333333;
  17 + --text-soft: #555;
  18 + --text-mute: #888;
  19 + --border: #e3e6eb;
  20 + --row-alt: #f7f8fa;
  21 + --header-bg: #f4f5f7;
  22 + --danger: #e34d4d;
  23 + --tab-active: #1e84e6;
  24 + --toolbar-bg: #2c2f36;
  25 + --toolbar-text: #ffffff;
  26 + --label: #f04848;
  27 + --field-bg: #eaf3fe;
  28 + --field-bg-readonly: #f1f3f5;
  29 + }
  30 + *{box-sizing:border-box}
  31 + html,body{margin:0;padding:0;background:var(--bg);color:var(--text);font-family:"Microsoft YaHei","PingFang SC","Helvetica Neue",Helvetica,Arial,"Segoe UI",sans-serif;font-size:13px;}
  32 + button{font-family:inherit;cursor:pointer}
  33 + a{color:inherit;text-decoration:none}
  34 + input,select,textarea{font-family:inherit;font-size:13px}
  35 +
  36 + /* ======= TOP BAR ======= */
  37 + .topbar{display:flex;align-items:stretch;height:44px;background:var(--topbar);color:var(--topbar-text);position:relative;z-index:30;}
  38 + .topbar .logo{width:54px;display:flex;align-items:center;justify-content:center;}
  39 + .topbar .logo svg{width:30px;height:30px}
  40 + .topbar .nav-btn{display:flex;align-items:center;gap:6px;padding:0 18px;color:#fff;cursor:pointer;font-size:14px;border:none;background:transparent;height:100%;}
  41 + .topbar .nav-btn.active{background:var(--primary);}
  42 + .topbar .nav-btn:hover{background:#33363d}
  43 + .topbar .nav-btn.active:hover{background:var(--primary-strong)}
  44 + .topbar .tabs{display:flex;align-items:stretch;flex:1;}
  45 + .topbar .tab{display:flex;align-items:center;gap:8px;padding:0 18px;cursor:pointer;color:#cfd2d8;font-size:14px;height:100%;}
  46 + .topbar .tab .ic{opacity:.85}
  47 + .topbar .tab.active{color:var(--link)}
  48 + .topbar .tab .close{margin-left:6px;width:14px;height:14px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;font-size:11px;color:#9aa0a8}
  49 + .topbar .tab .close:hover{background:#3a3d44;color:#fff}
  50 + .topbar .right{display:flex;align-items:center;gap:18px;padding-right:14px;}
  51 + .topbar .right .ic{width:18px;height:18px;opacity:.9;cursor:pointer}
  52 + .topbar .user{display:flex;align-items:center;gap:6px;font-size:14px}
  53 + .topbar .more{font-size:18px;letter-spacing:2px;cursor:pointer;padding:0 4px}
  54 +
  55 + /* ======= APP LAYOUT ======= */
  56 + .app{height:100vh;display:flex;flex-direction:column;overflow:hidden}
  57 + .stage{flex:1;position:relative;overflow:hidden;background:var(--bg)}
  58 + .screen{position:absolute;inset:0;display:none;overflow:auto}
  59 + .screen.active{display:block}
  60 +
  61 + /* ======= MAIN / DASHBOARD ======= */
  62 + .main-wrap{display:grid;grid-template-columns:1fr 280px;gap:10px;padding:10px;min-height:100%;}
  63 + .panel{background:var(--panel);border:1px solid var(--border);border-radius:2px}
  64 + .kpi-head{padding:14px 18px;display:flex;align-items:center;gap:24px;flex-wrap:wrap;}
  65 + .kpi-head .title{font-size:15px;color:#222;font-weight:500;margin-right:6px}
  66 + .kpi-head .stat{color:var(--text-soft)}
  67 + .kpi-head .stat b{color:var(--danger);font-weight:500;margin-left:6px;font-size:14px}
  68 + .kpi-head .stat.blue b{color:var(--link)}
  69 + .kpi-head .sep{color:#cdd0d6}
  70 + .kpi-head .ai-btn{margin-left:auto;background:var(--primary);color:#fff;border:none;padding:7px 14px;border-radius:2px;display:inline-flex;align-items:center;gap:6px;font-size:13px;}
  71 + .kpi-head .ai-btn:hover{background:var(--primary-strong)}
  72 +
  73 + .kpi-body{display:grid;grid-template-columns:200px 90px 1fr 1fr 90px 90px 130px;border-top:1px solid var(--border)}
  74 + .kpi-body > div{border-right:1px solid var(--border);border-bottom:1px solid var(--border);padding:10px 12px;font-size:13px;min-height:38px;display:flex;align-items:center}
  75 + .kpi-body > div:nth-last-child(-n+7){border-bottom:none}
  76 + .kpi-body > div:last-child{border-right:none}
  77 + .kpi-body .h{background:var(--header-bg);font-weight:500;color:#222;padding:9px 12px}
  78 + .kpi-body .row-alt{background:var(--row-alt)}
  79 + .kpi-body .link{color:var(--link);cursor:pointer}
  80 + .kpi-body .link:hover{text-decoration:underline}
  81 + .kpi-body .num-red{color:var(--danger);font-weight:600;justify-content:center}
  82 + .kpi-body .num-zero{color:var(--danger);font-weight:600;justify-content:center}
  83 + .kpi-body .num{justify-content:center}
  84 + .kpi-body .center{justify-content:center}
  85 +
  86 + .nav-tree{padding:6px 0}
  87 + .nav-tree .group{padding:8px 14px;color:#444;font-size:13px;display:flex;align-items:center;gap:6px;cursor:pointer}
  88 + .nav-tree .group .arrow{display:inline-block;width:0;height:0;border-left:4px solid #888;border-top:4px solid transparent;border-bottom:4px solid transparent;transform:rotate(90deg);margin-right:2px}
  89 + .nav-tree .group .ico{color:#e0b96a}
  90 + .nav-tree .item{padding:6px 14px 6px 36px;display:flex;align-items:center;gap:8px;color:#3a3a3a;cursor:pointer;font-size:13px}
  91 + .nav-tree .item:hover{background:#eef3fb}
  92 + .nav-tree .item.active{background:#d8eaff;color:#1166cc}
  93 + .nav-tree .item .ico{color:#e0b96a}
  94 +
  95 + .three-col{display:grid;grid-template-columns:280px 1fr;height:100%;}
  96 + .three-col .left-nav{background:var(--panel);border:1px solid var(--border);overflow:auto}
  97 + .three-col .center{display:flex;flex-direction:column;gap:10px;min-width:0}
  98 +
  99 + .common-ops{padding:14px 18px}
  100 + .common-ops .h{font-size:14px;color:#222;margin-bottom:14px;font-weight:500}
  101 + .common-ops a{display:block;color:var(--link);padding:8px 0;font-size:13px;border-bottom:1px dashed transparent}
  102 + .common-ops a:hover{text-decoration:underline}
  103 +
  104 + /* table sub-process column */
  105 + .subproc{writing-mode:vertical-rl;text-orientation:upright;color:#222;font-weight:500;justify-content:center;min-width:24px;}
  106 + .subproc.estimate{ background:transparent }
  107 +
  108 + footer.foot{
  109 + background:#f3f4f6;border-top:1px solid var(--border);padding:10px 14px;text-align:center;color:#666;font-size:12px;
  110 + }
  111 + footer.foot .pipe{margin:0 8px;color:#bbb}
  112 + footer.foot .police{display:inline-flex;align-items:center;gap:4px;margin-left:6px}
  113 + footer.foot .police svg{width:14px;height:14px}
  114 +
  115 + /* ======= NAV OVERLAY ======= */
  116 + #nav-overlay{position:absolute;inset:0;background:#2b3137;display:none;z-index:20;color:#cfd3da;}
  117 + #nav-overlay.show{display:flex}
  118 + #nav-overlay .side{width:200px;background:#2b3137;padding:8px 0;border-right:1px solid #1e2226}
  119 + #nav-overlay .side .si{display:flex;align-items:center;gap:10px;padding:11px 18px;font-size:14px;color:#d3d6db;cursor:pointer}
  120 + #nav-overlay .side .si:hover{background:#34393f}
  121 + #nav-overlay .side .si.active{color:var(--link);background:#34393f}
  122 + #nav-overlay .side .si svg{width:16px;height:16px;opacity:.85}
  123 + #nav-overlay .grid{flex:1;padding:30px 40px;display:grid;grid-template-columns:repeat(7,1fr);gap:30px 40px;align-content:start}
  124 + #nav-overlay .col h3{font-size:15px;color:#e8eaee;font-weight:500;margin:0 0 18px;border-bottom:1px solid #4a4f57;padding-bottom:10px}
  125 + #nav-overlay .col a{display:flex;align-items:center;gap:6px;padding:7px 0;color:#cfd3da;font-size:14px;cursor:pointer}
  126 + #nav-overlay .col a:hover{color:#fff}
  127 + #nav-overlay .col a .star{color:#f3b526}
  128 +
  129 + /* ======= USER LIST ======= */
  130 + .toolbar{background:var(--toolbar-bg);color:#fff;display:flex;align-items:center;gap:6px;padding:0 8px;height:38px}
  131 + .toolbar .tb-btn{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;color:#e6e7ea;cursor:pointer;font-size:13px;border-radius:2px}
  132 + .toolbar .tb-btn:hover{background:#3a3d44}
  133 + .toolbar .tb-btn .ic{opacity:.9}
  134 + .toolbar .spacer{flex:1}
  135 + .toolbar .gear{padding:6px 8px;cursor:pointer;color:#cfd2d8}
  136 +
  137 + .filterbar{display:flex;align-items:center;gap:8px;padding:10px 12px;background:var(--panel);border-bottom:1px solid var(--border)}
  138 + .filterbar select, .filterbar input{height:30px;border:1px solid #d5d8de;border-radius:2px;padding:0 28px 0 10px;background:#fff;min-width:140px;appearance:none;
  139 + background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path d='M2 3l3 4 3-4z' fill='%23888'/></svg>");
  140 + background-repeat:no-repeat;background-position:right 8px center}
  141 + .filterbar input{background-image:none;padding-right:10px}
  142 + .filterbar .down{width:34px;height:30px;background:#dfe5ee;border:1px solid #d5d8de;display:flex;align-items:center;justify-content:center;border-radius:2px;cursor:pointer;color:#3776c8}
  143 + .filterbar .btn{height:30px;padding:0 14px;border-radius:2px;border:1px solid var(--primary);background:var(--primary);color:#fff;display:inline-flex;align-items:center;gap:5px;font-size:13px;cursor:pointer}
  144 + .filterbar .btn.ghost{background:#fff;color:#444;border-color:#cfd3da}
  145 + .filterbar .btn:hover{filter:brightness(1.05)}
  146 +
  147 + .grid-table{width:100%;border-collapse:collapse;background:#fff;font-size:13px;}
  148 + .grid-table th, .grid-table td{border:1px solid var(--border);padding:7px 10px;text-align:left;white-space:nowrap}
  149 + .grid-table thead th{background:var(--header-bg);font-weight:500;color:#333;position:sticky;top:0;z-index:1}
  150 + .grid-table thead th .h-flex{display:flex;align-items:center;gap:6px;justify-content:space-between}
  151 + .grid-table thead th .h-flex .ic{display:flex;gap:2px;color:#aaa}
  152 + .grid-table tbody tr:nth-child(even){background:var(--row-alt)}
  153 + .grid-table tbody tr:hover{background:#eaf3fe}
  154 + .grid-table .radio-cell{width:32px;text-align:center}
  155 + .radio-dot{width:14px;height:14px;border:1px solid #b8bcc3;border-radius:50%;display:inline-block;vertical-align:middle;background:#fff}
  156 + .grid-table input.cb{margin:0}
  157 +
  158 + .pager{display:flex;align-items:center;gap:8px;padding:10px 14px;background:#fff;border-top:1px solid var(--border);justify-content:flex-end;font-size:13px;color:#555}
  159 + .pager .pgbtn{width:28px;height:28px;border:1px solid #d5d8de;background:#fff;border-radius:2px;display:inline-flex;align-items:center;justify-content:center;cursor:pointer;color:#666}
  160 + .pager .pgcur{width:28px;height:28px;border:1px solid var(--primary);color:var(--primary);display:inline-flex;align-items:center;justify-content:center;border-radius:2px}
  161 + .pager select{height:28px;border:1px solid #d5d8de;border-radius:2px;padding:0 8px;background:#fff}
  162 +
  163 + /* ======= USER DETAIL ======= */
  164 + .form-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:0;background:#fff;padding:10px 14px;border-bottom:1px solid var(--border)}
  165 + .form-cell{display:flex;align-items:center;gap:6px;padding:8px 10px;}
  166 + .form-cell .lbl{min-width:88px;color:#333;font-size:13px;text-align:right}
  167 + .form-cell .lbl.req::before{content:"*";color:var(--label);margin-right:3px}
  168 + .form-cell .lbl.req{color:var(--label)}
  169 + .form-cell input[type=text], .form-cell .field{
  170 + flex:1;height:28px;border:1px solid #d5d8de;border-radius:2px;padding:0 24px 0 10px;background:var(--field-bg);
  171 + appearance:none; min-width:0;
  172 + }
  173 + .form-cell .field.readonly{background:var(--field-bg-readonly);color:#444;display:flex;align-items:center}
  174 + .form-cell .field.with-caret{background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path d='M2 3l3 4 3-4z' fill='%23888'/></svg>");background-repeat:no-repeat;background-position:right 8px center;background-color:var(--field-bg)}
  175 + .form-cell .field.with-cal{background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none' stroke='%23888' stroke-width='1.4'><rect x='2' y='3' width='12' height='11' rx='1'/><path d='M2 6h12M5 1v3M11 1v3'/></svg>");background-repeat:no-repeat;background-position:right 8px center;background-color:var(--field-bg-readonly)}
  176 + .form-cell .cb{width:14px;height:14px;border:1px solid #b8bcc3;background:#fff;display:inline-block}
  177 +
  178 + .tabs-row{display:flex;background:#fff;border-bottom:1px solid var(--border);padding:0 6px}
  179 + .tabs-row .tb{padding:11px 18px;font-size:14px;color:#444;cursor:pointer;border-bottom:2px solid transparent;margin-right:4px}
  180 + .tabs-row .tb.active{color:var(--tab-active);border-bottom-color:var(--tab-active)}
  181 +
  182 + .perm-list{background:#fff}
  183 + .perm-row{display:flex;align-items:center;gap:14px;padding:10px 14px;border-bottom:1px solid var(--border);font-size:13px;color:#333}
  184 + .perm-row.head{background:var(--header-bg);font-weight:500;color:#222}
  185 + .perm-row .cb{width:14px;height:14px;border:1px solid #b8bcc3;background:#fff;display:inline-block;flex-shrink:0}
  186 + .perm-row.head .ic{margin-left:auto;color:#aaa}
  187 +
  188 + /* ======= LOGIN ======= */
  189 + .login-wrap{position:absolute;inset:0;background:#eaedf2;display:flex;flex-direction:column}
  190 + .login-head{display:flex;align-items:center;gap:12px;padding:18px 36px;background:#eaedf2}
  191 + .login-head .lg{width:42px;height:42px;display:flex;align-items:center;justify-content:center}
  192 + .login-head .name{font-size:24px;font-weight:700;color:#e0a020;letter-spacing:2px}
  193 + .login-head .sub{color:#444;font-size:14px;margin-left:6px}
  194 + .login-hero{flex:1;position:relative;background:
  195 + radial-gradient(ellipse at center, #1a4ea0 0%, #0a1d44 60%, #050d20 100%);
  196 + overflow:hidden}
  197 + .login-hero::before{
  198 + content:"";position:absolute;inset:0;
  199 + background-image:
  200 + linear-gradient(rgba(80,160,255,.18) 1px, transparent 1px),
  201 + linear-gradient(90deg, rgba(80,160,255,.18) 1px, transparent 1px);
  202 + background-size:80px 80px;
  203 + transform:perspective(800px) rotateX(55deg) translateY(20%);
  204 + transform-origin:center;
  205 + opacity:.55;
  206 + }
  207 + .login-hero::after{
  208 + content:"";position:absolute;inset:0;
  209 + background:
  210 + radial-gradient(ellipse 800px 300px at 50% 50%, rgba(140,200,255,.35), transparent 60%),
  211 + radial-gradient(circle 200px at 30% 40%, rgba(255,255,255,.15), transparent 70%),
  212 + radial-gradient(circle 160px at 70% 60%, rgba(255,255,255,.12), transparent 70%);
  213 + }
  214 + .login-text{position:absolute;left:8%;top:35%;color:#fff;z-index:2}
  215 + .login-text .en{font-size:30px;font-weight:300;letter-spacing:1px;color:#cfe1ff;margin-bottom:6px}
  216 + .login-text .zh{font-size:54px;font-weight:700;color:#fff;letter-spacing:4px;margin-bottom:4px}
  217 + .login-text .erp{font-size:90px;font-weight:800;color:#fff;letter-spacing:8px;line-height:.9}
  218 + .login-card{position:absolute;right:8%;top:50%;transform:translateY(-50%);background:#fff;width:380px;padding:36px 32px;border-radius:2px;box-shadow:0 12px 40px rgba(0,0,0,.3);z-index:3}
  219 + .login-card h3{margin:0 0 22px;font-size:18px;color:#333;font-weight:500}
  220 + .login-card .lf{display:flex;align-items:center;border:1px solid #e1e4e8;border-radius:2px;height:42px;margin-bottom:14px;background:#fff;}
  221 + .login-card .lf .ic{width:42px;display:flex;align-items:center;justify-content:center;color:#888}
  222 + .login-card .lf .div{width:1px;height:20px;background:#e1e4e8}
  223 + .login-card .lf input{flex:1;border:none;outline:none;height:100%;padding:0 12px;background:transparent}
  224 + .login-card .lf select{flex:1;border:none;outline:none;height:100%;padding:0 12px;background:transparent;appearance:none}
  225 + .login-card .lf.dropdown{position:relative}
  226 + .login-card .lf.dropdown::after{content:"";position:absolute;right:14px;top:50%;width:0;height:0;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #888;transform:translateY(-50%)}
  227 + .login-card .lf.dropdown.open .opt{display:block}
  228 + .login-card .lf .opt{display:none;position:absolute;left:-1px;right:-1px;top:42px;background:#fff;border:1px solid #e1e4e8;border-top:none;z-index:5}
  229 + .login-card .lf .opt .o{padding:10px 14px;color:#333;cursor:pointer;background:#eef5ff}
  230 + .login-card .lf .opt .o:hover{background:#dde9fb}
  231 + .login-card .submit{width:100%;height:42px;background:var(--primary);color:#fff;border:none;border-radius:2px;font-size:15px;letter-spacing:8px;cursor:pointer;margin-top:6px}
  232 + .login-card .submit:hover{background:var(--primary-strong)}
  233 + .login-foot{background:#eaedf2;text-align:center;padding:14px 8px;color:#666;font-size:12px;border-top:1px solid #d8dce2}
  234 +
  235 + /* misc */
  236 + .ic{display:inline-flex;align-items:center;justify-content:center}
  237 + .star{color:#f3b526}
  238 + .scrollable-y{overflow-y:auto}
  239 + .table-shell{background:#fff;flex:1;overflow:auto;border:1px solid var(--border);border-top:none}
  240 +
  241 + /* Antler logo color */
  242 + .lg-antler{color:#0e1216}
  243 +</style>
  244 +</head>
  245 +<body>
  246 +<div class="app">
  247 +
  248 + <!-- ======= TOP BAR ======= -->
  249 + <div class="topbar" id="topbar">
  250 + <div class="logo" data-go="main" title="主页">
  251 + <!-- antler/deer logo -->
  252 + <svg viewBox="0 0 64 64" fill="currentColor" class="lg-antler">
  253 + <path d="M14 10c2 4 1 8-1 11 3-1 7 0 10 3 1-4 4-7 8-7-3 3-4 7-3 11l4 1c-1 3 0 6 3 8-3 0-6 1-8 4-1-3-4-5-8-5 2-3 2-7 0-10-3 1-7 0-10-3 3 0 5-2 6-5l-1-8z"/>
  254 + <path d="M48 14c-2 3-2 6-1 9-2-2-5-2-8-1 1 3 1 6-1 9 3 0 5 2 6 5 1-3 4-5 7-5-2-3-2-6 0-9 2 1 5 1 7-1-2 0-4-1-5-3-1-2-3-4-5-4z"/>
  255 + <path d="M28 38c2 3 5 5 9 5 1 4 4 7 8 8-3 2-5 5-5 9-3-2-7-3-11-2 1-3 1-7-1-10-3 0-6-1-8-4 3-1 6-3 8-6z"/>
  256 + </svg>
  257 + </div>
  258 +
  259 + <div class="tabs" id="tabs">
  260 + <button class="nav-btn" id="nav-toggle">
  261 + <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="4" y1="7" x2="20" y2="7"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="17" x2="20" y2="17"/></svg>
  262 + 全部导航
  263 + </button>
  264 + <div class="tab" data-go="main">
  265 + <span class="ic"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 11l9-8 9 8"/><path d="M5 10v10h14V10"/></svg></span>
  266 + 主页
  267 + </div>
  268 + <div class="tab" id="tab-userlist" data-go="userlist" style="display:none">
  269 + 用户列表 <span class="close" data-close="userlist">✕</span>
  270 + </div>
  271 + <div class="tab" id="tab-userdetail" data-go="userdetail" style="display:none">
  272 + 用户信息单据 <span class="close" data-close="userdetail">✕</span>
  273 + </div>
  274 + </div>
  275 +
  276 + <div class="right">
  277 + <span class="ic" title="搜索">
  278 + <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.5" y2="16.5"/></svg>
  279 + </span>
  280 + <span class="ic" title="通知">
  281 + <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 8a6 6 0 0 1 12 0v5l1.5 3h-15L6 13z"/><path d="M10 19a2 2 0 0 0 4 0"/></svg>
  282 + </span>
  283 + <div class="user">
  284 + <span class="ic"><svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="5" width="18" height="14" rx="1"/><path d="M3 9h18"/></svg></span>
  285 + 朱子纯(超级管理员) <span style="font-size:10px">▾</span>
  286 + </div>
  287 + <span class="more">⋯</span>
  288 + </div>
  289 + </div>
  290 +
  291 + <!-- ======= STAGE ======= -->
  292 + <div class="stage" id="stage">
  293 +
  294 + <!-- NAV OVERLAY -->
  295 + <div id="nav-overlay">
  296 + <div class="side" id="nav-side"></div>
  297 + <div class="grid" id="nav-grid"></div>
  298 + </div>
  299 +
  300 + <!-- ===== MAIN ===== -->
  301 + <section class="screen active" id="screen-main">
  302 + <div class="main-wrap">
  303 + <div style="display:flex;flex-direction:column;gap:10px;min-height:0">
  304 + <!-- KPI head bar -->
  305 + <div class="panel kpi-head">
  306 + <span class="title">KPI监控</span>
  307 + <span class="stat">今日未处理:<b>37428</b></span>
  308 + <span class="sep">|</span>
  309 + <span class="stat blue">未清总数:<b>56433</b></span>
  310 + <button class="ai-btn">
  311 + <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2l2 5 5 2-5 2-2 5-2-5-5-2 5-2z"/></svg>
  312 + 小ai同学,请帮我安排今日工作
  313 + </button>
  314 + </div>
  315 +
  316 + <!-- KPI body grid -->
  317 + <div class="three-col">
  318 + <!-- Left tree -->
  319 + <div class="left-nav nav-tree">
  320 + <div class="group"><span class="arrow"></span><span class="ico">📁</span>按角色</div>
  321 + <div class="item active"><span class="ico">📄</span>所有部门 (37428)</div>
  322 + <div class="item"><span class="ico">📄</span>核价人员 (17)</div>
  323 + <div class="item"><span class="ico">📄</span>销售人员 (0)</div>
  324 + <div class="item"><span class="ico">📄</span>印前 (11)</div>
  325 + <div class="item"><span class="ico">📄</span>客服部 (30127)</div>
  326 + <div class="item"><span class="ico">📄</span>技术研发部 (47)</div>
  327 + <div class="item"><span class="ico">📄</span>车间主管 (316)</div>
  328 + <div class="item"><span class="ico">📄</span>工艺部 (6)</div>
  329 + <div class="item"><span class="ico">📄</span>物控部 (728)</div>
  330 + <div class="item"><span class="ico">📄</span>生产计划部 (225)</div>
  331 + <div class="item"><span class="ico">📄</span>版房 (120)</div>
  332 + <div class="item"><span class="ico">📄</span>生产车间 (596)</div>
  333 + <div class="item"><span class="ico">📄</span>工艺技术部 (0)</div>
  334 + <div class="item"><span class="ico">📄</span>品质管理部 (589)</div>
  335 + <div class="item"><span class="ico">📄</span>储运部 (3496)</div>
  336 + <div class="item"><span class="ico">📄</span>通用 (0)</div>
  337 + <div class="item"><span class="ico">📄</span>外发组 (867)</div>
  338 + <div class="item"><span class="ico">📄</span>材料仓管 (0)</div>
  339 + <div class="item"><span class="ico">📄</span>机修组 (42)</div>
  340 + <div class="item"><span class="ico">📄</span>应收 (30)</div>
  341 + <div class="item"><span class="ico">📄</span>出纳 (211)</div>
  342 + <div class="item"><span class="ico">📄</span>应付 (0)</div>
  343 + <div class="item"><span class="ico">📄</span>客服 (0)</div>
  344 + <div class="group"><span class="arrow"></span><span class="ico">📁</span>按流程</div>
  345 + <div class="item"><span class="ico">📄</span>估价管理流程 (17)</div>
  346 + <div class="item"><span class="ico">📄</span>设计制作流程 (11)</div>
  347 + <div class="item"><span class="ico">📄</span>新品研发流程 (11)</div>
  348 + <div class="item"><span class="ico">📄</span>材料测试流程 (51)</div>
  349 + <div class="item"><span class="ico">📄</span>订单下达流程 (30118)</div>
  350 + </div>
  351 + <div class="center">
  352 + <div class="panel" style="overflow:auto">
  353 + <div class="kpi-body" id="kpi-body"></div>
  354 + </div>
  355 + </div>
  356 + </div>
  357 + </div>
  358 +
  359 + <!-- right side common ops -->
  360 + <div class="panel common-ops" style="height:fit-content">
  361 + <div class="h">常用操作</div>
  362 + <a data-go="userlist">用户列表</a>
  363 + <a>系统功能模块设置</a>
  364 + </div>
  365 + </div>
  366 +
  367 + <footer class="foot">
  368 + <span style="vertical-align:middle">🛠</span>
  369 + ©Copyright Antler Software <span class="pipe">|</span> 印刷智慧工厂 <span class="pipe">|</span> 印刷MES <span class="pipe">|</span> 印刷ERP <span class="pipe">|</span> 印刷电商平台 <span class="pipe">|</span> 文件智能处理 <span class="pipe">|</span> 印前自动化 <span class="pipe">|</span> 400-880-6237
  370 + <span class="police">
  371 + <svg viewBox="0 0 24 24" fill="#3a6cb6"><path d="M12 2l9 4v6c0 5-4 9-9 10-5-1-9-5-9-10V6z"/></svg>
  372 + 沪ICP备14034791号-1
  373 + </span>
  374 + </footer>
  375 + </section>
  376 +
  377 + <!-- ===== USER LIST ===== -->
  378 + <section class="screen" id="screen-userlist">
  379 + <div class="toolbar">
  380 + <span class="tb-btn"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12a9 9 0 1 1-3-6.7"/><path d="M21 4v5h-5"/></svg>刷新</span>
  381 + <span class="tb-btn" id="btn-add" data-add-user="1"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M12 8v8M8 12h8"/></svg>新增</span>
  382 + <span class="tb-btn"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 4h12l4 4v12H4z"/><path d="M16 4v4h4"/><path d="M8 12h8M8 16h8"/></svg>导出Excel</span>
  383 + <span class="spacer"></span>
  384 + <span class="gear">⚙</span>
  385 + </div>
  386 + <div class="filterbar">
  387 + <select><option>全部用户</option></select>
  388 + <select><option>用户名</option></select>
  389 + <select><option>包含</option></select>
  390 + <input type="text" />
  391 + <span class="down">▾</span>
  392 + <button class="btn"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><line x1="21" y1="21" x2="16.5" y2="16.5"/></svg>搜索</button>
  393 + <button class="btn ghost">⊗ 清空</button>
  394 + </div>
  395 + <div class="table-shell">
  396 + <table class="grid-table" id="user-table">
  397 + <thead>
  398 + <tr>
  399 + <th style="width:36px"></th>
  400 + <th style="width:60px">序号</th>
  401 + <th>用户名 <span style="color:#aaa">⇅ ⌕</span></th>
  402 + <th>员工名 <span style="color:#aaa">⇅ ⌕</span></th>
  403 + <th>用户号 <span style="color:#aaa">⇅ ⌕</span></th>
  404 + <th>部门 <span style="color:#aaa">⇅ ⌕</span></th>
  405 + <th>用户类型 <span style="color:#aaa">⇅ ⌕</span></th>
  406 + <th>语言 <span style="color:#aaa">⇅ ⌕</span></th>
  407 + <th>作 <span style="color:#aaa">⇅ ⌕</span></th>
  408 + <th>登录日期</th>
  409 + <th>制单人 <span style="color:#aaa">⇅ ⌕</span></th>
  410 + <th>制单日期</th>
  411 + </tr>
  412 + </thead>
  413 + <tbody id="user-tbody"></tbody>
  414 + </table>
  415 + </div>
  416 + <div class="pager">
  417 + <span>当前显示 共37个单据 共37条记录</span>
  418 + <span class="pgbtn">‹</span>
  419 + <span class="pgcur">1</span>
  420 + <span class="pgbtn">›</span>
  421 + <select><option>10000 条/页</option></select>
  422 + </div>
  423 + </section>
  424 +
  425 + <!-- ===== USER DETAIL ===== -->
  426 + <section class="screen" id="screen-userdetail">
  427 + <div class="toolbar">
  428 + <span class="tb-btn"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M12 8v8M8 12h8"/></svg>新增</span>
  429 + <span class="tb-btn"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 3l7 7-11 11H3v-7z"/></svg>修改</span>
  430 + <span class="tb-btn"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M8 8l8 8M16 8l-8 8"/></svg>删除</span>
  431 + <span class="tb-btn"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M5 4h11l3 3v13H5z"/><rect x="8" y="4" width="8" height="5"/></svg>保存</span>
  432 + <span class="tb-btn"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="9"/><path d="M9 9l6 6M15 9l-6 6"/></svg>取消</span>
  433 + <span class="tb-btn"><svg class="ic" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>功能</span>
  434 + <span class="tb-btn">作废</span>
  435 + <span class="tb-btn">重置密码</span>
  436 + <span class="tb-btn">取消作废</span>
  437 + <span class="spacer"></span>
  438 + <span class="gear">⚙</span>
  439 + </div>
  440 +
  441 + <div class="form-grid">
  442 + <div class="form-cell"><span class="lbl">创建时间:</span><div class="field with-cal readonly" id="f-ctime">2023-10-26 17:02:01</div></div>
  443 + <div class="form-cell"><span class="lbl">制单人:</span><div class="field readonly" id="f-creator">超级管理员</div></div>
  444 + <div class="form-cell"><span class="lbl req">员工名:</span><div class="field with-caret" id="f-empname">管广飞</div></div>
  445 +
  446 + <div class="form-cell"><span class="lbl req">用户名:</span><input type="text" id="f-username" value="管广飞"/></div>
  447 + <div class="form-cell"><span class="lbl req">类型:</span><div class="field with-caret" id="f-type">超级管理员</div></div>
  448 + <div class="form-cell"><span class="lbl req">语言:</span><div class="field with-caret" id="f-lang">英文</div></div>
  449 +
  450 + <div class="form-cell"><span class="lbl req">用户号:</span><input type="text" id="f-userno" value="ggf"/></div>
  451 + <div class="form-cell"></div>
  452 + <div class="form-cell"><span class="lbl">单据修改权限:</span><span class="cb"></span></div>
  453 + </div>
  454 +
  455 + <div class="tabs-row">
  456 + <div class="tb active">权限组</div>
  457 + <div class="tb">客户查看权限</div>
  458 + <div class="tb">供应商查看权限</div>
  459 + <div class="tb">人员查看权限</div>
  460 + <div class="tb">工序查看权限</div>
  461 + <div class="tb">司机查看权限</div>
  462 + </div>
  463 +
  464 + <div class="perm-list" id="perm-list">
  465 + <div class="perm-row head"><span class="cb"></span><span>权限分类</span><span class="ic" style="margin-left:auto;color:#aaa">⇅</span></div>
  466 + </div>
  467 + </section>
  468 +
  469 + <!-- ===== LOGIN ===== -->
  470 + <section class="screen" id="screen-login">
  471 + <div class="login-wrap">
  472 + <div class="login-head">
  473 + <span class="lg">
  474 + <svg viewBox="0 0 64 64" width="42" height="42" fill="#0e1216">
  475 + <path d="M14 10c2 4 1 8-1 11 3-1 7 0 10 3 1-4 4-7 8-7-3 3-4 7-3 11l4 1c-1 3 0 6 3 8-3 0-6 1-8 4-1-3-4-5-8-5 2-3 2-7 0-10-3 1-7 0-10-3 3 0 5-2 6-5l-1-8z"/>
  476 + <path d="M48 14c-2 3-2 6-1 9-2-2-5-2-8-1 1 3 1 6-1 9 3 0 5 2 6 5 1-3 4-5 7-5-2-3-2-6 0-9 2 1 5 1 7-1-2 0-4-1-5-3-1-2-3-4-5-4z"/>
  477 + <path d="M28 38c2 3 5 5 9 5 1 4 4 7 8 8-3 2-5 5-5 9-3-2-7-3-11-2 1-3 1-7-1-10-3 0-6-1-8-4 3-1 6-3 8-6z"/>
  478 + </svg>
  479 + </span>
  480 + <span class="name">Antler ERP</span>
  481 + <span class="sub">欢迎登录EBC平台</span>
  482 + </div>
  483 + <div class="login-hero">
  484 + <div class="login-text">
  485 + <div class="en">Enterprise Business Capability</div>
  486 + <div class="zh">企业业务能力平台</div>
  487 + <div class="erp">ERP</div>
  488 + </div>
  489 + <div class="login-card">
  490 + <h3>用户登录</h3>
  491 + <div class="lf">
  492 + <span class="ic"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="8" r="4"/><path d="M4 21c0-4 4-7 8-7s8 3 8 7"/></svg></span>
  493 + <span class="div"></span>
  494 + <input type="text" placeholder="请输入你的用户名" />
  495 + </div>
  496 + <div class="lf">
  497 + <span class="ic"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="4" y="11" width="16" height="10" rx="1"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/></svg></span>
  498 + <span class="div"></span>
  499 + <input type="password" placeholder="请输入你的密码" />
  500 + </div>
  501 + <div class="lf dropdown" id="ver-drop">
  502 + <input type="text" value="标准版" readonly style="cursor:pointer"/>
  503 + <div class="opt">
  504 + <div class="o">标准版</div>
  505 + </div>
  506 + <div class="opt">
  507 + <div class="o">标准版1</div>
  508 + </div>
  509 + </div>
  510 + <button class="submit" data-go="main">登 录</button>
  511 + </div>
  512 + </div>
  513 + <div class="login-foot">
  514 + 🛠 ©Copyright Antler Software | 印刷智慧工厂 | 印刷MES | 印刷ERP | 印刷电商平台 | 文件智能处理 | 印前自动化 | 400-880-6237
  515 + <span style="display:inline-flex;align-items:center;gap:4px;margin-left:6px">
  516 + <svg width="14" height="14" viewBox="0 0 24 24" fill="#3a6cb6"><path d="M12 2l9 4v6c0 5-4 9-9 10-5-1-9-5-9-10V6z"/></svg>
  517 + 沪ICP备14034791号-1
  518 + </span>
  519 + </div>
  520 + </div>
  521 + </section>
  522 +
  523 + </div>
  524 +</div>
  525 +
  526 +<script>
  527 +/* ============ KPI ROWS ============ */
  528 +const kpiHeader = ['导航类型','角色','KPI待处理事项(当前行双击进入)','KPI内容描述及处理结果(点击蓝色查看明细)','今日未处理','未清总数','子流程'];
  529 +const kpiRows = [
  530 + // [role, item, desc, today, total, sub, navType?, rowSpanRole?, rowSpanSub?]
  531 + // group 1: 估价管理流程 — 5 rows, role 核价人员 spans 4, 销售人员 1
  532 + {role:'核价人员', item:'01/04【新增】新报价单', desc:'报价单明细', today:'-', total:'-', sub:'估价管理流程', navTypeFirst:true, roleSpan:4, subSpan:5},
  533 + {role:null, item:'02/04 审核后报价单->客户确认价格', desc:'报价单明细', today:'16', total:'16', red:true},
  534 + {role:null, item:'03/04 客户不认可->二次确认', desc:'报价单明细', today:'-', total:'-'},
  535 + {role:null, item:'04/04 报价单->销售订单', desc:'销售订单明细', today:'1', total:'1', red:true},
  536 + {role:'销售人员', item:'04/04 报价单->销售订单(标签)', desc:'销售订单明细(标签)', today:'0', total:'0', red:true},
  537 + // group 2: 设计制作流程 — 印前 (2 rows), span 2
  538 + {role:'印前', item:'1/2 新增设计申请单', desc:'设计申请明细', today:'-', total:'-', sub:'设计制作流程', roleSpan:2, subSpan:2},
  539 + {role:null, item:'2/2 设计申请->设计制作', desc:'根据设计申请单进行设计制作,当日16:00前审核的为今日任务,16:00后(含)顺延至次日', today:'11', total:'11', red:true},
  540 + // group 3: 新品研发流程 — 客服部, 技术研发部, 客服部, 技术研发部
  541 + {role:'客服部', item:'1/1 研发申请->文件制作', desc:'根据研发申请单,制作电子文件,当日16:00前下达的为今日任务,16:00后(含)顺延至次日', today:'0', total:'12', red:true, sub:'新品研发流程', subSpan:5},
  542 + {role:'客服部', item:'1/5 新增研发申请单', desc:'研发申请明细', today:'-', total:'-'},
  543 + {role:'技术研发部', item:'2/5 研发申请>>研发工单', desc:'及时开立研发工单,当日16:00前审核的为今日任务,16:00后(含)顺延至次日', today:'4', total:'4', red:true, roleSpan:2},
  544 + {role:null, item:'3/5 研发工单>>完工处理', desc:'计划人员在交货日期前确认工单完工', today:'7', total:'7', red:true},
  545 + {role:'客服部', item:'4/5 研发工单->客户确认', desc:'工单完工后需在7天内和客户确认样品', today:'-', total:'2703'},
  546 + // 5/5 技术研发部
  547 + {role:'技术研发部', item:'5/5 客户确认->工艺卡', desc:'根据客户已经确认的研发工单,生成产品工艺卡。当日16:00前确认的为今日任务,16:00后(含)顺延至次日', today:'0', total:'1632', red:true, sub:'', subSpan:0},
  548 + // group 4: 材料测试流程 — 车间主管, 技术研发部, 技术研发部
  549 + {role:'车间主管', item:'1/3 工单(测试部门数)->车间反馈', desc:'车间主管在工单完工前对测试材料进行数据反馈', today:'10', total:'115', red:true, sub:'材料测试流程', subSpan:3},
  550 + {role:null, item:'2/3 车间反馈->车间补充(多部门)', desc:'补充新材料测试信息,车间反馈次日16:00前的为当日任务,16:00后(含)顺延一日', today:'8', total:'8', red:true, roleSpan:2},
  551 + {role:'技术研发部', item:'2/3 车间反馈->工程部反馈(单部门)', desc:'工程部对新材料的测试结果进行反馈,车间反馈次日16:00前的为当日任务,16:00后(含)顺延一日', today:'23', total:'23', red:true},
  552 +];
  553 +
  554 +/* Render KPI grid via spans simulated with empty cells (CSS grid) */
  555 +(function renderKpi(){
  556 + const host = document.getElementById('kpi-body');
  557 + const heads = ['导航类型','角色','KPI待处理事项(当前行双击进入)','KPI内容描述及处理结果(点击蓝色查看明细)','今日未处理','未清总数','子流程'];
  558 + heads.forEach(h => { const d = document.createElement('div'); d.className='h'; d.textContent=h; host.appendChild(d); });
  559 +
  560 + // We'll render 7 columns per row.
  561 + // Track active rowspans for col 0(navType), 1(role), 6(sub).
  562 + // We model by emitting blank cells for spanned positions (visually merge by removing borders).
  563 + // Simpler: emit single tall cells via grid-row span.
  564 + let r = 2; // CSS row index (1-based) but auto rows after header row = 1
  565 + // Use explicit grid placement
  566 + let line = 2;
  567 + // First, emit a single big "按角色" cell for col1 spanning all data rows? Original shows rows have nav type only at start.
  568 + // We'll emit "按角色" merged across all rows (24 rows in screenshot share 按角色). Use full span.
  569 + // Emit nav cell once
  570 + const total = kpiRows.length;
  571 + const navCell = document.createElement('div');
  572 + navCell.style.gridColumn = '1';
  573 + navCell.style.gridRow = `2 / span ${total}`;
  574 + navCell.className = 'center';
  575 + navCell.textContent = '按角色';
  576 + host.appendChild(navCell);
  577 +
  578 + let curRow = 2;
  579 + let i = 0;
  580 + while (i < kpiRows.length) {
  581 + const row = kpiRows[i];
  582 + const altClass = (i%2===1)?'row-alt':'';
  583 + // role
  584 + if (row.role) {
  585 + const span = row.roleSpan || 1;
  586 + const c = document.createElement('div');
  587 + c.style.gridColumn = '2';
  588 + c.style.gridRow = `${curRow} / span ${span}`;
  589 + c.className = 'center ' + altClass;
  590 + c.textContent = row.role;
  591 + host.appendChild(c);
  592 + }
  593 + // item
  594 + const item = document.createElement('div');
  595 + item.style.gridColumn = '3';
  596 + item.style.gridRow = `${curRow}`;
  597 + item.className = 'link ' + altClass;
  598 + item.textContent = row.item;
  599 + host.appendChild(item);
  600 + // desc
  601 + const desc = document.createElement('div');
  602 + desc.style.gridColumn = '4';
  603 + desc.style.gridRow = `${curRow}`;
  604 + desc.className = 'link ' + altClass;
  605 + desc.textContent = row.desc;
  606 + host.appendChild(desc);
  607 + // today
  608 + const today = document.createElement('div');
  609 + today.style.gridColumn = '5';
  610 + today.style.gridRow = `${curRow}`;
  611 + today.className = 'num ' + (row.red?'num-red':'') + ' ' + altClass;
  612 + today.textContent = row.today;
  613 + host.appendChild(today);
  614 + // total
  615 + const tot = document.createElement('div');
  616 + tot.style.gridColumn = '6';
  617 + tot.style.gridRow = `${curRow}`;
  618 + tot.className = 'num ' + (row.red?'num-red':'') + ' ' + altClass;
  619 + tot.textContent = row.total;
  620 + host.appendChild(tot);
  621 + // sub
  622 + if (row.sub && row.subSpan) {
  623 + const c = document.createElement('div');
  624 + c.style.gridColumn = '7';
  625 + c.style.gridRow = `${curRow} / span ${row.subSpan}`;
  626 + c.className = 'subproc';
  627 + c.textContent = row.sub;
  628 + host.appendChild(c);
  629 + }
  630 + curRow++;
  631 + i++;
  632 + }
  633 + host.style.gridTemplateRows = `38px repeat(${total}, minmax(38px, auto))`;
  634 +})();
  635 +
  636 +/* ============ USER TABLE ============ */
  637 +const users = [
  638 + ['管广飞','管广飞','ggf','工艺技术','超级管理员','英文','','2026-02-27 17:48:11','超级管理员','2023-10-26 17:02:01'],
  639 + ['李斌','李斌','lib','印前制作','超级管理员','中文','','2026-01-28 16:53:32','超级管理员','2023-10-26 17:02:58'],
  640 + ['系统管理员','','admin','','超级管理员','中文','','2026-05-06 12:28:49','超级管理员','2023-10-26 17:05:58'],
  641 + ['朱财喜','朱财喜','zhucx','印刷车间','超级管理员','中文','','2026-03-23 10:08:29','超级管理员','2023-11-20 10:29:09'],
  642 + ['ljh','ljh','ljh','机修','超级管理员','中文','','2026-05-06 11:14:04','YFZ','2024-10-08 13:48:59'],
  643 + ['wx','汪鑫','wx','工艺技术','超级管理员','中文','','2026-03-23 11:57:13','超级管理员','2023-11-22 13:22:35'],
  644 + ['钱豹','钱豹','qianb','物控部','超级管理员','中文','','2026-04-28 16:49:04','超级管理员','2023-11-27 15:30:11'],
  645 + ['zyf','张寅飞','zyf','印前制作','超级管理员','中文','','2025-09-11 11:42:12','LJH','2024-11-11 15:59:52'],
  646 + ['孟威','孟威','mengw','工艺技术','超级管理员','中文','','2026-05-06 13:56:22','系统管理员','2025-06-03 21:26:07'],
  647 + ['杭仁萍','杭仁萍','hangrp','跟单','超级管理员','中文','','2026-04-30 14:18:28','孟威','2025-06-05 11:11:56'],
  648 + ['李丹','','李丹','','超级管理员','中文','','2026-04-27 13:47:58','杭仁萍','2025-06-11 10:34:29'],
  649 + ['王宽明','王宽明','王宽明','印刷车间','超级管理员','中文','','2026-04-25 16:07:38','李丹','2025-06-11 10:40:22'],
  650 + ['潘茹','潘茹','潘茹','工艺技术','超级管理员','中文','','2025-06-17 09:04:46','李丹','2025-06-11 10:41:07'],
  651 + ['耿广东','耿广东','耿广东','工艺技术','超级管理员','中文','','2025-07-04 14:40:02','李丹','2025-06-11 10:41:37'],
  652 + ['yut','余涛','yut','印刷车间','超级管理员','中文','','2026-04-03 18:39:34','杭仁萍','2025-06-17 14:32:49'],
  653 + ['lzj','廖赵军','lzj','财务部','超级管理员','中文','','','杭仁萍','2025-06-26 10:57:28'],
  654 + ['caojy','caojy','caojy','物控部','超级管理员','中文','','2026-02-02 13:58:14','李明青','2025-07-28 13:59:21'],
  655 + ['陈淑贤','陈淑贤','csx','品质管理部','超级管理员','中文','','2026-04-24 15:05:52','csx','2025-07-29 13:26:58'],
  656 + ['张红英','张红英','zhy','模烫车间','超级管理员','中文','','2025-12-24 16:24:52','系统管理员','2025-08-18 09:34:47'],
  657 + ['lzy','吕政彦','吕政彦','总经理办公室','超级管理员','中文','','2026-04-16 08:54:24','杭仁萍','2025-08-21 11:16:12'],
  658 + ['陈鑫涛','陈鑫涛','cxt','品质管理部','超级管理员','中文','','2026-03-23 10:12:47','陈淑贤','2025-09-01 11:22:00'],
  659 + ['陆鑫','陆鑫','luxin','工艺技术','超级管理员','中文','','2026-05-05 17:56:03','张震','2025-09-04 11:48:44'],
  660 + ['陆鑫-储运部…','陆鑫','ZY0006','工艺技术','普通用户','中文','','2025-11-19 09:11:27','陆鑫','2025-09-05 11:28:37'],
  661 + ['朱咸兵','朱咸兵','zhuxb','工艺技术','超级管理员','中文','','2026-04-27 13:40:15','钱豹','2025-09-08 15:00:29'],
  662 + ['孟臻晟','孟臻晟','mengzs','装订车间','超级管理员','中文','','2026-05-07 09:17:57','系统管理员','2025-09-12 16:24:07'],
  663 + ['pengm','彭敏','pengm','计划管理','超级管理员','中文','','2026-05-06 11:28:33','彭敏','2025-10-16 13:30:32'],
  664 + ['张伟','张伟','zhangw','印刷车间','超级管理员','中文','','2026-03-15 09:22:14','张伟','2025-10-22 10:12:00'],
  665 + ['李娜','李娜','lin','质检部','普通用户','中文','','2026-04-02 14:50:33','李丹','2025-11-04 16:08:21'],
  666 + ['王军','王军','wangj','装订车间','超级管理员','中文','','2026-04-15 17:10:55','系统管理员','2025-11-15 09:30:11'],
  667 + ['赵敏','赵敏','zhaom','财务部','超级管理员','中文','','2026-05-01 08:45:00','赵敏','2025-12-01 11:00:00'],
  668 + ['周强','周强','zhouq','物控部','普通用户','中文','','2026-04-20 10:30:21','钱豹','2025-12-08 14:22:33'],
  669 + ['吴丽','吴丽','wul','人事部','超级管理员','中文','','2026-04-25 15:18:09','吴丽','2026-01-05 09:15:42'],
  670 + ['郑涛','郑涛','zhengt','工艺技术','超级管理员','中文','','2026-05-02 11:40:58','郑涛','2026-01-18 13:55:27'],
  671 + ['冯静','冯静','fengj','客服部','超级管理员','中文','','2026-05-04 16:25:17','冯静','2026-02-02 10:08:14'],
  672 + ['孙磊','孙磊','sunl','装订车间','普通用户','中文','','2026-05-05 09:55:36','系统管理员','2026-02-20 15:32:48'],
  673 + ['马超','马超','mac','机修','超级管理员','中文','','2026-05-06 14:12:25','LJH','2026-03-08 11:48:09'],
  674 + ['朱子纯','朱子纯','zhuzc','总经理办公室','超级管理员','中文','','2026-05-07 13:00:00','超级管理员','2026-03-22 09:00:00'],
  675 +];
  676 +
  677 +(function renderUsers(){
  678 + const tb = document.getElementById('user-tbody');
  679 + users.forEach((u,i)=>{
  680 + const tr = document.createElement('tr');
  681 + tr.innerHTML = `
  682 + <td class="radio-cell"><span class="radio-dot"></span></td>
  683 + <td>${i+1}</td>
  684 + <td>${u[0]}</td>
  685 + <td>${u[1]}</td>
  686 + <td>${u[2]}</td>
  687 + <td>${u[3]}</td>
  688 + <td>${u[4]}</td>
  689 + <td>${u[5]}</td>
  690 + <td><input class="cb" type="checkbox"></td>
  691 + <td>${u[7]}</td>
  692 + <td>${u[8]}</td>
  693 + <td>${u[9]}</td>
  694 + `;
  695 + tr.addEventListener('dblclick', ()=> goTo('userdetail'));
  696 + tb.appendChild(tr);
  697 + });
  698 +})();
  699 +
  700 +/* ============ PERM LIST ============ */
  701 +const perms = ['默认显示(必选)','禁止查看价格','客服跟单','报价组员工','物控部员工','供应链PMC','允许查看订单价格','储运部员工','外部供应商','品质部员工','技术中心员工','机修组员工','生产部计划员工','外发组员工','模烫车间','装订车间','后加工车间','品质部管理','精品车间','人事组','统计组','机修主管','样品开发部员工','设计开发','总经办','审核组','结算组','打样车间','制版组','文控组','行政组','成本组','采购组','OA管理员','开发组','API对接','MES管理员','报表组'];
  702 +(function(){
  703 + const host = document.getElementById('perm-list');
  704 + perms.forEach(p=>{
  705 + const r = document.createElement('div');
  706 + r.className = 'perm-row';
  707 + r.innerHTML = `<span class="cb"></span><span>${p}</span>`;
  708 + host.appendChild(r);
  709 + });
  710 +})();
  711 +
  712 +/* ============ NAV OVERLAY ============ */
  713 +const navSide = [
  714 + {ico:'sales', label:'销售管理'}, {ico:'dcs', label:'DCS系统'}, {ico:'prod', label:'产品管理'},
  715 + {ico:'ops', label:'生产运营'}, {ico:'exec', label:'生产执行'}, {ico:'mold', label:'模具管理'},
  716 + {ico:'cart', label:'采购管理'}, {ico:'mat', label:'材料库存'}, {ico:'fg', label:'成品库存'},
  717 + {ico:'out', label:'外协管理'}, {ico:'logi', label:'物流管理'}, {ico:'qa', label:'质量管理'},
  718 + {ico:'fin', label:'财务管理'}, {ico:'cost1', label:'成本管理(专)'}, {ico:'cost2', label:'成本管理'},
  719 + {ico:'eq', label:'设备管理'}, {ico:'hr', label:'人事行政'}, {ico:'oa', label:'OA系统'},
  720 + {ico:'base', label:'基础设置'}, {ico:'sys', label:'系统设置', active:true},
  721 +];
  722 +const sideIco = {
  723 + sales:'M3 7l3 10h12l3-10M5 7l1-3h12l1 3M9 21a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm8 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z',
  724 + dcs:'M12 2l9 5-9 5-9-5z M3 12l9 5 9-5 M3 17l9 5 9-5',
  725 + prod:'M3 7l9-5 9 5v10l-9 5-9-5z',
  726 + ops:'M4 4h6v6H4zM14 4h6v6h-6zM4 14h6v6H4zM14 14h6v6h-6z',
  727 + exec:'M5 4h14v16H5z M5 9h14 M9 4v5',
  728 + mold:'M4 7h16v10H4z M8 7v10 M16 7v10',
  729 + cart:'M5 5h2l3 11h10l2-8H8 M9 20a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm9 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z',
  730 + mat:'M4 21V8l8-5 8 5v13z M9 21v-7h6v7',
  731 + fg:'M3 21V9l9-6 9 6v12z',
  732 + out:'M12 12c2 0 4-1 4-4s-2-4-4-4-4 1-4 4 2 4 4 4z M4 21c0-4 4-7 8-7s8 3 8 7',
  733 + logi:'M3 7h11v9H3z M14 10h5l3 3v3h-8z M7 19a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm10 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2z',
  734 + qa:'M12 2l8 4v6c0 5-4 8-8 10-4-2-8-5-8-10V6z M9 12l2 2 4-4',
  735 + fin:'M12 2v20 M7 6h10 M7 10h10',
  736 + cost1:'M4 20V8 M9 20V4 M14 20v-8 M19 20v-6 M2 20h20',
  737 + cost2:'M4 20V8 M9 20V4 M14 20v-8 M19 20v-6 M2 20h20',
  738 + eq:'M12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8z M19 12a7 7 0 0 0-.5-2.5l1.5-1.5-2-2-1.5 1.5A7 7 0 0 0 14 7l-.5-2h-3l-.5 2A7 7 0 0 0 7.5 7.5L6 6 4 8l1.5 1.5A7 7 0 0 0 5 12',
  739 + hr:'M9 11a4 4 0 1 0 0-8 4 4 0 0 0 0 8z M2 21c0-4 3-7 7-7s7 3 7 7 M17 11a3 3 0 1 0 0-6 3 3 0 0 0 0 6z M22 21c0-3-2-5-5-5',
  740 + oa:'M3 7h18v12H3z M3 11h18 M8 7V4h8v3',
  741 + base:'M4 6h16 M4 12h16 M4 18h16 M8 6v12 M14 6v12',
  742 + sys:'M12 8a4 4 0 1 1 0 8 4 4 0 0 1 0-8z M19 12a7 7 0 0 0-.5-2.5l1.5-1.5-2-2-1.5 1.5A7 7 0 0 0 14 7l-.5-2h-3l-.5 2A7 7 0 0 0 7.5 7.5L6 6 4 8l1.5 1.5A7 7 0 0 0 5 12',
  743 +};
  744 +const navSideHost = document.getElementById('nav-side');
  745 +navSide.forEach(s=>{
  746 + const d = document.createElement('div');
  747 + d.className = 'si' + (s.active?' active':'');
  748 + d.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="${sideIco[s.ico]||''}"/></svg>${s.label}`;
  749 + navSideHost.appendChild(d);
  750 +});
  751 +
  752 +const navCols = [
  753 + {title:'期初设置', items:['客户期初','供应商期初','材料期初','产品期初','数据导入','离线导出下载']},
  754 + {title:'用户管理', items:[{label:'用户列表',star:true,go:'userlist'},'系统权限','系统权限稽查表','权限组']},
  755 + {title:'系统参数', items:['系统参数','财务结账','系统常量配置']},
  756 + {title:'计算方案', items:['方案列表','计算参数']},
  757 + {title:'日志', items:['个性化模块','操作日志','异常清除KPI任务表','MYSQL监听器']},
  758 + {title:'开发平台', items:['自定义开发范例',{label:'系统功能模块设置',star:true},'EBC流程清单','功能模块界面设置','增删改存业务处理']},
  759 + {title:'API对接管理', items:['调用第三方接口(TOKEN配置)','调用第三方接口(接口定义)','被第三方调用(生成token)','数据同步','被第三方调用(API定义)']},
  760 +];
  761 +const navGridHost = document.getElementById('nav-grid');
  762 +navCols.forEach(c=>{
  763 + const col = document.createElement('div');
  764 + col.className = 'col';
  765 + let html = `<h3>${c.title}</h3>`;
  766 + c.items.forEach(it=>{
  767 + if (typeof it === 'string') html += `<a>${it}</a>`;
  768 + else html += `<a data-go="${it.go||''}">${it.label}${it.star?' <span class="star">★</span>':''}</a>`;
  769 + });
  770 + col.innerHTML = html;
  771 + navGridHost.appendChild(col);
  772 +});
  773 +
  774 +/* ============ NAV / TABS ============ */
  775 +const screens = ['main','userlist','userdetail','login'];
  776 +function goTo(name){
  777 + screens.forEach(s=>document.getElementById('screen-'+s).classList.toggle('active', s===name));
  778 + // hide top bar on login
  779 + document.getElementById('topbar').style.display = (name==='login') ? 'none' : 'flex';
  780 + // tabs visibility
  781 + document.getElementById('tab-userlist').style.display = (['userlist','userdetail'].includes(name) || tabsOpen.userlist) ? 'flex' : 'none';
  782 + document.getElementById('tab-userdetail').style.display = (name==='userdetail' || tabsOpen.userdetail) ? 'flex' : 'none';
  783 + // tab active states
  784 + document.querySelectorAll('.topbar .tab').forEach(t=>t.classList.remove('active'));
  785 + if (name==='main') document.querySelectorAll('.topbar .tab')[0]?.classList.add('active');
  786 + if (name==='userlist') document.getElementById('tab-userlist').classList.add('active');
  787 + if (name==='userdetail') document.getElementById('tab-userdetail').classList.add('active');
  788 + // nav button active when on main with overlay; clear otherwise
  789 + document.getElementById('nav-overlay').classList.remove('show');
  790 + document.getElementById('nav-toggle').classList.remove('active');
  791 + // close login overlay if leaving
  792 +}
  793 +const tabsOpen = {userlist:false, userdetail:false};
  794 +function openTab(name){
  795 + if (name==='userlist'){ tabsOpen.userlist = true; }
  796 + if (name==='userdetail'){ tabsOpen.userlist = true; tabsOpen.userdetail = true; }
  797 + goTo(name);
  798 +}
  799 +
  800 +document.body.addEventListener('click', (e)=>{
  801 + const go = e.target.closest('[data-go]');
  802 + if (go){
  803 + const name = go.dataset.go;
  804 + if (!name) return;
  805 + if (name==='userlist' || name==='userdetail') openTab(name);
  806 + else goTo(name);
  807 + return;
  808 + }
  809 + const close = e.target.closest('[data-close]');
  810 + if (close){
  811 + e.stopPropagation();
  812 + const which = close.dataset.close;
  813 + tabsOpen[which] = false;
  814 + if (which==='userdetail') goTo('userlist');
  815 + else goTo('main');
  816 + if (which==='userlist'){ tabsOpen.userdetail=false; }
  817 + return;
  818 + }
  819 +});
  820 +
  821 +document.getElementById('nav-toggle').addEventListener('click', ()=>{
  822 + const ov = document.getElementById('nav-overlay');
  823 + ov.classList.toggle('show');
  824 + document.getElementById('nav-toggle').classList.toggle('active', ov.classList.contains('show'));
  825 +});
  826 +
  827 +// new-user mode
  828 +function setUserDetailMode(mode){
  829 + const isNew = mode === 'new';
  830 + document.getElementById('f-ctime').textContent = isNew ? '' : '2023-10-26 17:02:01';
  831 + document.getElementById('f-creator').textContent = isNew ? '保存后自动生成' : '超级管理员';
  832 + document.getElementById('f-empname').textContent = isNew ? '' : '管广飞';
  833 + document.getElementById('f-type').textContent = isNew ? '' : '超级管理员';
  834 + document.getElementById('f-lang').textContent = isNew ? '' : '英文';
  835 + document.getElementById('f-username').value = isNew ? '' : '管广飞';
  836 + document.getElementById('f-userno').value = isNew ? '' : 'ggf';
  837 + document.querySelectorAll('#perm-list .perm-row:not(.head) .cb').forEach(cb=>{cb.classList.remove('checked')});
  838 +}
  839 +document.querySelector('[data-add-user]')?.addEventListener('click', ()=>{ setUserDetailMode('new'); openTab('userdetail'); });
  840 +
  841 +// Default initial screen: login
  842 +goTo('login');
  843 +
  844 +// version dropdown demo
  845 +document.getElementById('ver-drop').addEventListener('click', e=>{
  846 + e.currentTarget.classList.toggle('open');
  847 +});
  848 +</script>
  849 +</body>
  850 +</html>