1569 lines
116 KiB
HTML
1569 lines
116 KiB
HTML
<!doctype html>
|
||
<html lang="zh-CN">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<title>USER ERP 0-1需求重构 · 可点击参考原型 v1</title>
|
||
<style>
|
||
:root {
|
||
--bg: #f5f7fb;
|
||
--panel: #ffffff;
|
||
--panel-2: #f8fafc;
|
||
--text: #142033;
|
||
--muted: #66758a;
|
||
--line: #dfe5ee;
|
||
--line-strong: #cbd5e1;
|
||
--blue: #2563eb;
|
||
--blue-soft: #e8f0ff;
|
||
--green: #15803d;
|
||
--green-soft: #e8f7ee;
|
||
--amber: #b45309;
|
||
--amber-soft: #fff4df;
|
||
--red: #b91c1c;
|
||
--red-soft: #fdecec;
|
||
--purple: #6d28d9;
|
||
--purple-soft: #f2ecff;
|
||
--nav: #111827;
|
||
--nav-soft: #1f2937;
|
||
--radius: 8px;
|
||
--shadow: 0 16px 36px rgba(15, 23, 42, 0.10);
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
|
||
body {
|
||
margin: 0;
|
||
min-height: 100vh;
|
||
background: var(--bg);
|
||
color: var(--text);
|
||
font-family: "Microsoft YaHei", "Segoe UI", Arial, sans-serif;
|
||
letter-spacing: 0;
|
||
}
|
||
|
||
button, input, select { font: inherit; }
|
||
button { cursor: pointer; }
|
||
|
||
.app {
|
||
min-height: 100vh;
|
||
display: grid;
|
||
grid-template-columns: 330px minmax(0, 1fr);
|
||
}
|
||
|
||
.sidebar {
|
||
height: 100vh;
|
||
position: sticky;
|
||
top: 0;
|
||
display: grid;
|
||
grid-template-columns: 92px 238px;
|
||
border-right: 1px solid var(--line);
|
||
background: var(--panel);
|
||
z-index: 10;
|
||
}
|
||
|
||
.rail {
|
||
background: var(--nav);
|
||
color: #e5edf7;
|
||
display: grid;
|
||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||
gap: 12px;
|
||
padding: 16px 12px;
|
||
min-height: 0;
|
||
}
|
||
|
||
.brand {
|
||
display: grid;
|
||
gap: 4px;
|
||
justify-items: center;
|
||
padding-bottom: 14px;
|
||
border-bottom: 1px solid rgba(255,255,255,.12);
|
||
text-align: center;
|
||
}
|
||
|
||
.brand strong { font-size: 14px; color: #fff; }
|
||
.brand span { color: #aebbc9; font-size: 12px; }
|
||
|
||
.rail-nav {
|
||
display: grid;
|
||
gap: 8px;
|
||
align-content: start;
|
||
overflow: auto;
|
||
min-height: 0;
|
||
}
|
||
|
||
.rail-btn {
|
||
min-height: 66px;
|
||
border: 0;
|
||
border-radius: var(--radius);
|
||
background: transparent;
|
||
color: #dbe7f5;
|
||
display: grid;
|
||
justify-items: center;
|
||
align-content: center;
|
||
gap: 5px;
|
||
padding: 8px 4px;
|
||
position: relative;
|
||
}
|
||
|
||
.rail-btn:hover, .rail-btn.active { background: var(--nav-soft); color: #fff; }
|
||
.rail-btn.active::before {
|
||
content: "";
|
||
position: absolute;
|
||
left: -12px;
|
||
top: 12px;
|
||
bottom: 12px;
|
||
width: 4px;
|
||
background: var(--blue);
|
||
border-radius: 999px;
|
||
}
|
||
|
||
.rail-icon {
|
||
width: 28px;
|
||
height: 28px;
|
||
border: 1px solid rgba(255,255,255,.25);
|
||
border-radius: 7px;
|
||
display: grid;
|
||
place-items: center;
|
||
font-size: 12px;
|
||
font-weight: 800;
|
||
}
|
||
|
||
.rail-label { font-size: 12px; line-height: 1.2; text-align: center; }
|
||
|
||
.rail-foot {
|
||
border: 1px solid rgba(255,255,255,.14);
|
||
border-radius: var(--radius);
|
||
padding: 10px 6px;
|
||
display: grid;
|
||
gap: 4px;
|
||
text-align: center;
|
||
color: #cbd5e1;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.panel-nav {
|
||
display: grid;
|
||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||
min-height: 0;
|
||
padding: 18px 14px;
|
||
gap: 14px;
|
||
}
|
||
|
||
.module-head {
|
||
padding-bottom: 14px;
|
||
border-bottom: 1px solid var(--line);
|
||
display: grid;
|
||
gap: 4px;
|
||
}
|
||
|
||
.eyebrow {
|
||
margin: 0;
|
||
color: var(--muted);
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.module-head h1 {
|
||
margin: 0;
|
||
font-size: 22px;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.module-head span { color: var(--muted); font-size: 12px; line-height: 1.5; }
|
||
|
||
.page-nav {
|
||
overflow: auto;
|
||
min-height: 0;
|
||
display: grid;
|
||
gap: 7px;
|
||
align-content: start;
|
||
}
|
||
|
||
.page-btn, .todo-btn {
|
||
border: 1px solid transparent;
|
||
background: transparent;
|
||
color: var(--text);
|
||
border-radius: var(--radius);
|
||
min-height: 42px;
|
||
padding: 9px 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
text-align: left;
|
||
}
|
||
|
||
.page-btn:hover, .todo-btn:hover, .page-btn.active {
|
||
background: var(--blue-soft);
|
||
border-color: #bcd0ff;
|
||
color: #123f9f;
|
||
}
|
||
|
||
.page-btn small {
|
||
color: var(--muted);
|
||
font-size: 11px;
|
||
flex: none;
|
||
}
|
||
|
||
.quick {
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--radius);
|
||
padding: 12px;
|
||
background: var(--panel-2);
|
||
display: grid;
|
||
gap: 8px;
|
||
}
|
||
|
||
.quick-head {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
color: var(--muted);
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.main {
|
||
min-width: 0;
|
||
display: grid;
|
||
grid-template-rows: auto minmax(0, 1fr);
|
||
}
|
||
|
||
.topbar {
|
||
min-height: 76px;
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 8;
|
||
background: rgba(245, 247, 251, 0.92);
|
||
backdrop-filter: blur(12px);
|
||
border-bottom: 1px solid var(--line);
|
||
padding: 14px 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
}
|
||
|
||
.top-title { display: grid; gap: 4px; }
|
||
.top-title strong { font-size: 18px; }
|
||
.top-title span { color: var(--muted); font-size: 12px; }
|
||
|
||
.top-actions {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
}
|
||
|
||
.search {
|
||
height: 38px;
|
||
width: 260px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--radius);
|
||
padding: 0 10px;
|
||
background: #fff;
|
||
color: var(--muted);
|
||
font-size: 12px;
|
||
}
|
||
|
||
.search input {
|
||
border: 0;
|
||
outline: none;
|
||
width: 100%;
|
||
min-width: 0;
|
||
color: var(--text);
|
||
background: transparent;
|
||
font-size: 13px;
|
||
}
|
||
|
||
select, input[type="date"] {
|
||
height: 38px;
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--radius);
|
||
background: #fff;
|
||
color: var(--text);
|
||
padding: 0 10px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.period {
|
||
height: 38px;
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--radius);
|
||
background: #fff;
|
||
display: flex;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.period button {
|
||
border: 0;
|
||
background: transparent;
|
||
padding: 0 12px;
|
||
color: var(--muted);
|
||
}
|
||
|
||
.period button.active { background: var(--blue); color: #fff; }
|
||
|
||
.content {
|
||
padding: 24px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.page-head {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) auto;
|
||
gap: 16px;
|
||
align-items: start;
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
.page-title {
|
||
margin: 0;
|
||
font-size: 26px;
|
||
line-height: 1.2;
|
||
}
|
||
|
||
.page-desc {
|
||
margin: 8px 0 0;
|
||
max-width: 900px;
|
||
color: var(--muted);
|
||
line-height: 1.7;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.head-actions { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
|
||
|
||
.grid {
|
||
display: grid;
|
||
gap: 14px;
|
||
}
|
||
|
||
.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||
.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
|
||
.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
|
||
|
||
.panel {
|
||
background: var(--panel);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--radius);
|
||
box-shadow: 0 8px 20px rgba(15,23,42,.04);
|
||
min-width: 0;
|
||
}
|
||
|
||
.panel-head {
|
||
min-height: 58px;
|
||
border-bottom: 1px solid var(--line);
|
||
padding: 14px 16px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
}
|
||
|
||
.panel-head h2 {
|
||
margin: 0;
|
||
font-size: 16px;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.panel-head p, .panel-note {
|
||
margin: 4px 0 0;
|
||
color: var(--muted);
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.panel-body { padding: 16px; }
|
||
|
||
.metric {
|
||
padding: 16px;
|
||
display: grid;
|
||
gap: 8px;
|
||
min-height: 116px;
|
||
}
|
||
|
||
.metric span { color: var(--muted); font-size: 12px; }
|
||
.metric strong { font-size: 28px; line-height: 1; }
|
||
.metric p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.5; }
|
||
|
||
.pill, .stage {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 24px;
|
||
padding: 3px 8px;
|
||
border-radius: 999px;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.pill.blue, .stage.v1 { color: #1d4ed8; background: var(--blue-soft); }
|
||
.pill.green { color: var(--green); background: var(--green-soft); }
|
||
.pill.amber, .stage.reserve { color: var(--amber); background: var(--amber-soft); }
|
||
.pill.red { color: var(--red); background: var(--red-soft); }
|
||
.pill.purple, .stage.v2 { color: var(--purple); background: var(--purple-soft); }
|
||
.pill.gray { color: var(--muted); background: #eef2f7; }
|
||
|
||
.list {
|
||
display: grid;
|
||
gap: 10px;
|
||
margin: 0;
|
||
padding: 0;
|
||
list-style: none;
|
||
}
|
||
|
||
.list li, .task-row, .issue-row {
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--radius);
|
||
background: #fff;
|
||
padding: 11px 12px;
|
||
display: grid;
|
||
gap: 5px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.task-row {
|
||
grid-template-columns: minmax(0, 1fr) auto;
|
||
align-items: center;
|
||
}
|
||
|
||
.task-row strong, .issue-row strong { font-size: 14px; }
|
||
.task-row span, .issue-row span, .list li span { color: var(--muted); font-size: 12px; line-height: 1.55; }
|
||
|
||
.flow {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
align-items: center;
|
||
}
|
||
|
||
.flow-step {
|
||
border: 1px solid var(--line);
|
||
background: #fff;
|
||
border-radius: var(--radius);
|
||
min-height: 38px;
|
||
padding: 8px 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
color: var(--text);
|
||
font-size: 13px;
|
||
}
|
||
|
||
.flow-step::after {
|
||
content: "";
|
||
width: 18px;
|
||
height: 1px;
|
||
background: var(--line-strong);
|
||
display: inline-block;
|
||
}
|
||
|
||
.flow-step:last-child::after { display: none; }
|
||
|
||
.btn {
|
||
min-height: 36px;
|
||
border: 1px solid var(--line-strong);
|
||
border-radius: var(--radius);
|
||
background: #fff;
|
||
color: var(--text);
|
||
padding: 0 12px;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
font-size: 13px;
|
||
font-weight: 700;
|
||
text-decoration: none;
|
||
}
|
||
|
||
.btn:hover { border-color: #9db7ec; color: #1d4ed8; background: #f8fbff; }
|
||
.btn.primary { border-color: var(--blue); background: var(--blue); color: #fff; }
|
||
.btn.danger { border-color: #f0b3b3; color: var(--red); background: var(--red-soft); }
|
||
.btn.ghost { border-color: transparent; background: transparent; color: var(--muted); }
|
||
.btn.small { min-height: 30px; padding: 0 9px; font-size: 12px; }
|
||
|
||
table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
font-size: 13px;
|
||
}
|
||
|
||
th, td {
|
||
padding: 11px 10px;
|
||
border-bottom: 1px solid var(--line);
|
||
vertical-align: top;
|
||
text-align: left;
|
||
}
|
||
|
||
th {
|
||
color: var(--muted);
|
||
font-size: 12px;
|
||
font-weight: 800;
|
||
background: #f8fafc;
|
||
}
|
||
|
||
td.actions-cell {
|
||
min-width: 150px;
|
||
display: flex;
|
||
gap: 7px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.table-wrap { overflow: auto; }
|
||
|
||
.role-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||
gap: 10px;
|
||
}
|
||
|
||
.role-card {
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--radius);
|
||
background: #fff;
|
||
padding: 12px;
|
||
display: grid;
|
||
gap: 8px;
|
||
min-height: 128px;
|
||
}
|
||
|
||
.role-card.active {
|
||
border-color: #94b5ff;
|
||
box-shadow: inset 0 0 0 1px #94b5ff;
|
||
background: #fbfdff;
|
||
}
|
||
|
||
.role-card strong { font-size: 14px; }
|
||
.role-card span { color: var(--muted); font-size: 12px; line-height: 1.55; }
|
||
|
||
.source-bar {
|
||
border: 1px solid #bfd2ff;
|
||
background: #f4f8ff;
|
||
color: #21406d;
|
||
border-radius: var(--radius);
|
||
padding: 10px 12px;
|
||
display: flex;
|
||
gap: 8px;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.drawer-mask, .modal-mask {
|
||
position: fixed;
|
||
inset: 0;
|
||
background: rgba(15,23,42,.32);
|
||
z-index: 30;
|
||
display: none;
|
||
}
|
||
|
||
.drawer-mask.open, .modal-mask.open { display: block; }
|
||
|
||
.drawer {
|
||
position: fixed;
|
||
top: 0;
|
||
right: 0;
|
||
width: min(640px, 100vw);
|
||
height: 100vh;
|
||
background: #fff;
|
||
z-index: 31;
|
||
transform: translateX(100%);
|
||
transition: transform .18s ease;
|
||
display: grid;
|
||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||
border-left: 1px solid var(--line);
|
||
}
|
||
|
||
.drawer.open { transform: translateX(0); }
|
||
|
||
.drawer-head, .drawer-foot {
|
||
padding: 16px;
|
||
border-bottom: 1px solid var(--line);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
}
|
||
|
||
.drawer-foot { border-top: 1px solid var(--line); border-bottom: 0; justify-content: flex-end; }
|
||
.drawer-body { padding: 16px; overflow: auto; display: grid; gap: 12px; }
|
||
.drawer h2 { margin: 0; font-size: 18px; }
|
||
|
||
.toast {
|
||
position: fixed;
|
||
left: 50%;
|
||
bottom: 24px;
|
||
transform: translateX(-50%) translateY(18px);
|
||
background: #111827;
|
||
color: #fff;
|
||
border-radius: var(--radius);
|
||
padding: 10px 14px;
|
||
font-size: 13px;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
transition: .18s ease;
|
||
z-index: 50;
|
||
}
|
||
|
||
.toast.open { opacity: 1; transform: translateX(-50%) translateY(0); }
|
||
|
||
.spacer { height: 14px; }
|
||
|
||
@media (max-width: 1120px) {
|
||
.app { grid-template-columns: 1fr; }
|
||
.sidebar { position: static; height: auto; grid-template-columns: 1fr; }
|
||
.rail { grid-template-rows: auto auto auto; }
|
||
.rail-nav { grid-auto-flow: column; grid-auto-columns: 86px; overflow-x: auto; }
|
||
.panel-nav { display: block; }
|
||
.page-nav { grid-template-columns: repeat(2, minmax(0,1fr)); margin-top: 12px; max-height: 280px; }
|
||
.quick { display: none; }
|
||
.topbar { position: static; align-items: flex-start; flex-direction: column; }
|
||
.top-actions { justify-content: flex-start; }
|
||
.search { width: min(100%, 420px); }
|
||
.cols-4, .cols-3, .cols-2, .role-grid { grid-template-columns: 1fr; }
|
||
.page-head { grid-template-columns: 1fr; }
|
||
.head-actions { justify-content: flex-start; }
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="app">
|
||
<aside class="sidebar">
|
||
<section class="rail" aria-label="一级模块导航">
|
||
<div class="brand">
|
||
<strong>USER ERP</strong>
|
||
<span>Stage 1 Prototype</span>
|
||
</div>
|
||
<nav class="rail-nav" id="moduleRail"></nav>
|
||
<div class="rail-foot">
|
||
<strong>模拟数据</strong>
|
||
<span>仅用于流程验证</span>
|
||
</div>
|
||
</section>
|
||
<section class="panel-nav">
|
||
<div class="module-head">
|
||
<p class="eyebrow">当前模块</p>
|
||
<h1 id="moduleTitle">今日作战</h1>
|
||
<span id="moduleNote">从异常、资源和今日动作进入业务闭环。</span>
|
||
</div>
|
||
<nav class="page-nav" id="pageNav"></nav>
|
||
<section class="quick">
|
||
<div class="quick-head"><span>高频跳转</span><strong>6</strong></div>
|
||
<button class="todo-btn" data-route="exceptions"><span>P0/P1异常</span><strong>37</strong></button>
|
||
<button class="todo-btn" data-route="demand"><span>需求待评估</span><strong>12</strong></button>
|
||
<button class="todo-btn" data-route="branch-cs"><span>客服超时</span><strong>9</strong></button>
|
||
<button class="todo-btn" data-route="branch-free"><span>免评缺口</span><strong>4</strong></button>
|
||
<button class="todo-btn" data-route="people"><span>额度预警</span><strong>18</strong></button>
|
||
<button class="todo-btn" data-route="retro"><span>复盘待写</span><strong>7</strong></button>
|
||
</section>
|
||
</section>
|
||
</aside>
|
||
|
||
<main class="main">
|
||
<header class="topbar">
|
||
<div class="top-title">
|
||
<strong id="topPageTitle">今日作战台</strong>
|
||
<span id="topPageSubtitle">高级主管 / USER运营 / 客服 / 渠道 / KOC-KOL / 财务 / 风险</span>
|
||
</div>
|
||
<div class="top-actions">
|
||
<label class="search">
|
||
<span>搜索</span>
|
||
<input id="globalSearch" placeholder="需求 / ASIN / 真实人 / 工单 / 风险" />
|
||
</label>
|
||
<div class="period" id="period">
|
||
<button class="active" data-period="day">日</button>
|
||
<button data-period="week">周</button>
|
||
<button data-period="month">月</button>
|
||
</div>
|
||
<input type="date" value="2026-05-28" />
|
||
<select id="roleSelect">
|
||
<option value="owner">高级主管</option>
|
||
<option value="ops">USER运营</option>
|
||
<option value="channel">渠道运营</option>
|
||
<option value="csLead">客服主管</option>
|
||
<option value="cs">一线客服</option>
|
||
<option value="koc">KOC/KOL运营</option>
|
||
<option value="finance">财务/返款</option>
|
||
<option value="risk">风险/审核</option>
|
||
</select>
|
||
<button class="btn" data-action="drawer" data-kind="source">来源 7</button>
|
||
</div>
|
||
</header>
|
||
<section class="content" id="content"></section>
|
||
</main>
|
||
</div>
|
||
|
||
<div class="drawer-mask" id="drawerMask"></div>
|
||
<aside class="drawer" id="drawer">
|
||
<div class="drawer-head">
|
||
<div>
|
||
<h2 id="drawerTitle">详情</h2>
|
||
<p class="panel-note" id="drawerNote">模拟数据,敏感字段默认脱敏。</p>
|
||
</div>
|
||
<button class="btn" data-action="closeDrawer">关闭</button>
|
||
</div>
|
||
<div class="drawer-body" id="drawerBody"></div>
|
||
<div class="drawer-foot" id="drawerFoot"></div>
|
||
</aside>
|
||
<div class="toast" id="toast"></div>
|
||
|
||
<script>
|
||
const sourceDocs = [
|
||
"00_项目入口分级",
|
||
"01_主流程说明",
|
||
"02_日常操作页面结构",
|
||
"03_功能页面按钮盘点表",
|
||
"04_分支流程_完整需求域",
|
||
"05_异常流程_完整需求域",
|
||
"06_VibeCoding页面验证记录",
|
||
"参考:20260528_USER_ERP_完整参考原型_v1.html"
|
||
];
|
||
|
||
const modules = [
|
||
{ id: "overview", label: "作战", icon: "DB", title: "今日作战", note: "异常、目标、资源和复盘入口。", pages: ["dashboard", "role-workflow"] },
|
||
{ id: "dispatch", label: "调度", icon: "PL", title: "需求调度", note: "需求进入、计划生成、资源匹配。", pages: ["demand", "action-matrix"] },
|
||
{ id: "branches", label: "分支", icon: "WF", title: "分支流程", note: "IM、EDM、Phone、客服、订单、免评、财务、KOC/KOL、风险。", pages: ["branch-im", "branch-edm", "branch-phone", "branch-cs", "branch-order", "branch-free", "branch-finance", "branch-koc", "branch-risk"] },
|
||
{ id: "ops", label: "运营", icon: "OP", title: "运营中心", note: "客服、渠道、真实人、KOC/KOL和风险日常页面。", pages: ["orders", "cs-exec", "cs-mgmt", "channel", "people", "koc-center", "risk-center"] },
|
||
{ id: "data", label: "复盘", icon: "BI", title: "复盘验证", note: "异常总表、数据复盘、Vibe Coding验证。", pages: ["exceptions", "retro", "validation"] }
|
||
];
|
||
|
||
const pages = {
|
||
"dashboard": { module: "overview", title: "今日作战台", short: "作战台", subtitle: "所有角色每天打开后的第一屏:先看异常、目标缺口、资源压力和今日必须推进的动作。", owner: "高级主管 / USER运营负责人", source: "00/01/02" },
|
||
"role-workflow": { module: "overview", title: "角色每日工作流", short: "角色工作流", subtitle: "明确每个岗位每天该看什么、不该先看什么、必须判断什么、复盘什么。", owner: "各岗位负责人", source: "00/02/04" },
|
||
"demand": { module: "dispatch", title: "需求与计划调度中心", short: "需求调度", subtitle: "把OA、销售、运营、ASIN异常、客服反馈、KOC/KOL合作请求转成可执行计划。", owner: "USER运营", source: "01/02/03/04", kind: "workflow" },
|
||
"action-matrix": { module: "dispatch", title: "按钮行为矩阵", short: "按钮矩阵", subtitle: "覆盖03按钮盘点表中的全部核心按钮。每个按钮均可执行演示或跳转到对应页面。", owner: "产品 / 前端观察员", source: "03" },
|
||
"branch-im": { module: "branches", title: "分支二:IM推送看板", short: "IM推送", subtitle: "按真实人累计提交评价、额度、风险、未完成单和卡片有效性决定推送策略。", owner: "渠道运营", source: "04/05", kind: "workflow" },
|
||
"branch-edm": { module: "branches", title: "分支三:EDM每日运营", short: "EDM", subtitle: "先看域名、邮箱、IP信誉、UID/KV人群、H5、AB Test与转化异常。", owner: "EDM运营", source: "04/05", kind: "workflow" },
|
||
"branch-phone": { module: "branches", title: "分支四:Phone工作流", short: "Phone", subtitle: "处理未接、待回拨、国家/时段/语言匹配和客服承接容量。", owner: "Phone / 客服主管", source: "04/05", kind: "workflow" },
|
||
"branch-cs": { module: "branches", title: "分支五:客服承接", short: "客服承接", subtitle: "用户回复、信息缺失、订单登记、催评、售后、投诉和风险升级的执行闭环。", owner: "客服主管", source: "02/04/05", kind: "workflow" },
|
||
"branch-order": { module: "branches", title: "分支六A:评价型订单", short: "评价订单", subtitle: "测评/回评从订单核验、评价提交、展示确认到返款;提交即计12,展示才计完成。", owner: "USER运营 / 客服", source: "01/04/05", kind: "workflow" },
|
||
"branch-free": { module: "branches", title: "分支六B:免评执行", short: "免评执行", subtitle: "KOC/KOL为主,IM/EDM/APP协同,终点是内容、Code、点击、订单和权重结果。", owner: "KOC/KOL运营 / 渠道运营", source: "04", kind: "workflow" },
|
||
"branch-finance": { module: "branches", title: "分支七:财务返款与佣金", short: "返款佣金", subtitle: "用户返款V1必做,KOC/KOL佣金V1预留/V2实现;双重退款必须进风险。", owner: "财务 / 风险", source: "03/04/05", kind: "workflow" },
|
||
"branch-koc": { module: "branches", title: "分支八:KOC/KOL协作", short: "KOC/KOL", subtitle: "线索、分层、任务、内容、带货、佣金、风险完整进入需求域。", owner: "KOC/KOL运营", source: "00/01/04/06", kind: "workflow" },
|
||
"branch-risk": { module: "branches", title: "分支九:风险与黑名单", short: "风险分支", subtitle: "每次有效互动都复检身份、额度、风险、订单和未关闭承诺。", owner: "风险/审核", source: "01/04/05", kind: "workflow" },
|
||
"orders": { module: "ops", title: "评价计划与订单中心", short: "计划订单", subtitle: "测评、回评、免评计划和订单履约的综合页面。", owner: "USER运营", source: "02/03", kind: "workflow" },
|
||
"cs-exec": { module: "ops", title: "客服执行中心", short: "客服执行", subtitle: "工单池、聊天、答应配合、催评、订单登记和售后详情。", owner: "一线客服 / 客服主管", source: "02/03/04", kind: "workflow" },
|
||
"cs-mgmt": { module: "ops", title: "客服管理中心", short: "客服管理", subtitle: "在线、排班、出勤、目标、绩效、服务质量和工单分配管理。", owner: "客服主管", source: "02/03/04", kind: "workflow" },
|
||
"channel": { module: "ops", title: "渠道运营中心", short: "渠道中心", subtitle: "IM、EDM、Phone、APP/H5/卡片、推送配置和渠道漏斗。", owner: "渠道负责人", source: "02/03/04", kind: "workflow" },
|
||
"people": { module: "ops", title: "测评人/真实人中心", short: "真实人", subtitle: "自动归并真实人、额度台账、4/4/12、风险历史和人工合并/拆分入口。", owner: "USER运营 / 风险", source: "02/03", kind: "workflow" },
|
||
"koc-center": { module: "ops", title: "KOC/KOL协作中心", short: "KOC中心", subtitle: "线索池、达人档案、合作任务、内容记录、带货归因、佣金结算和风险。", owner: "KOC/KOL运营", source: "02/03/04/06", kind: "workflow" },
|
||
"risk-center": { module: "ops", title: "风险与黑名单中心", short: "风险中心", subtitle: "风险事件、黑名单、退款比对、关联风险、内容/佣金风险。", owner: "风险/审核", source: "02/03/05", kind: "workflow" },
|
||
"exceptions": { module: "data", title: "异常流程总表", short: "异常总表", subtitle: "覆盖需求计划、评价订单、客服、渠道、KOC/KOL、返款、风险异常。", owner: "风险 / 测试", source: "05" },
|
||
"retro": { module: "data", title: "数据复盘看板", short: "复盘看板", subtitle: "计划、ASIN、渠道、客服、测评人、KOC/KOL、财务复盘指标。", owner: "业务负责人", source: "01/02/06", kind: "workflow" },
|
||
"validation": { module: "data", title: "Vibe Coding页面验证记录", short: "验证记录", subtitle: "现有原型只作为需求验证材料,不作为正式开发底座。", owner: "产品 / 前端观察员", source: "06" }
|
||
};
|
||
|
||
const referencePages = [
|
||
{ id: "ref-demand-pool", short: "需求池", title: "需求池 · 完整参考细化", owner: "USER运营", ref: "完整参考原型:demand-pool", intent: "承接 OA、销售、运营、ASIN异常、客服反馈和KOC/KOL合作请求,统一进入需求评估。", metrics: [["待评估", "12", "含测评/回评/免评/客服"], ["可转计划", "8", "信息已补齐"], ["被退回", "3", "缺ASIN或素材"], ["P0需求", "2", "当天处理"]], steps: ["新增/导入需求", "补齐ASIN/站点/目标", "设置优先级", "进入需求评估", "转计划或退回"], buttons: ["新增需求", "导入OA需求", "评估", "转计划", "补充信息"], retro: ["需求来源转化率", "退回原因", "需求评估耗时", "P0处理时效"] },
|
||
{ id: "ref-demand-review", short: "需求评估", title: "需求评估 · ASIN与资源校验", owner: "USER运营", ref: "完整参考原型:demand-review", intent: "在生成计划前校验产品状态、库存、评分、近7天掉评、H5/卡片、资源和客服容量。", metrics: [["库存紧张", "1", "需限制节奏"], ["H5缺失", "2", "不可直接推送"], ["掉评触发", "2", "可转回评"], ["资源不足", "5", "需补量"]], steps: ["读取需求", "校验产品/ASIN", "预估人群/客服/渠道", "评估通过或退回", "生成执行计划"], buttons: ["评估通过", "退回补充", "暂缓", "驳回", "生成计划"], retro: ["评估通过率", "产品阻断项", "资源缺口", "退回次数"] },
|
||
{ id: "ref-plan-builder", short: "计划生成", title: "从需求生成计划", owner: "USER运营", ref: "完整参考原型:plan-builder", intent: "把需求转成测评、回评、免评或客服跟进计划,并设置周期、每日节奏、渠道策略和目标人群。", metrics: [["今日新计划", "9", "含免评2个"], ["待生成", "8", "已评估"], ["冲突计划", "2", "同ASIN/同人群"], ["客服跟进", "4", "独立计划"]], steps: ["选择关联需求", "选择计划类型", "设置目标与周期", "设置渠道策略", "设置真实人额度规则", "生成计划"], buttons: ["生成计划", "进入执行匹配", "保存草稿", "查看现有计划"], retro: ["计划生成耗时", "计划类型占比", "计划取消原因", "目标调整次数"], note: "目标人群必须按真实人判断:同一真实人累计提交评价 < 12 才可进入普通测评/回评;累计提交评价 >= 12 应进入免评或KOC/KOL路径。" },
|
||
{ id: "ref-exec-match", short: "执行匹配", title: "执行匹配 · 人群/额度/客服", owner: "USER运营", ref: "完整参考原型:exec-match", intent: "生成 audience_snapshot,预占 quota_reservations,并按容量、语言和工单量分配客服。", metrics: [["候选人群", "1,280", "已排除风险23人"], ["预占额度", "30", "7天有效"], ["可用客服", "5", "按班次分配"], ["KOC入口", "1", "免评补单"]], steps: ["匹配人群", "复检真实人额度", "预占额度", "分配客服", "生成IM/EDM/Phone任务", "记录匹配日志"], buttons: ["匹配人群", "预占额度", "释放预占", "分配客服", "匹配KOC/KOL"], retro: ["预占释放率", "匹配失败原因", "客服容量缺口", "候选人排除原因"] },
|
||
{ id: "ref-plan-adjust", short: "计划调整", title: "计划调整 · 补量/暂停/转免评", owner: "USER运营主管", ref: "完整参考原型:plan-adjust", intent: "处理完成率不足、库存紧张、产品禁用、渠道失败等计划级异常。", metrics: [["缺口计划", "5", "需补量"], ["暂停计划", "2", "产品/风险"], ["转免评", "1", "测评不可继续"], ["待关闭", "3", "完成或失败"]], steps: ["发现执行偏差", "判断原因", "调整名额或补量", "暂停/恢复/转免评", "写回需求状态"], buttons: ["调整名额", "补量", "暂停", "恢复", "转免评", "关闭计划"], retro: ["补量成功率", "暂停原因", "转免评次数", "目标变更记录"] },
|
||
{ id: "ref-review-plan", short: "测评计划", title: "测评计划管理", owner: "USER运营", ref: "完整参考原型:review-plan", intent: "查看测评计划目标、周期、完成进度、优先级、风险状态,并进入订单或推送。", metrics: [["进行中", "18", "测评/回评"], ["完成率低", "4", "低于50%"], ["风险计划", "3", "需审核"], ["待复盘", "7", "昨日关闭"]], steps: ["查看计划列表", "筛选站点/状态", "进入订单", "进入推送", "调整计划"], buttons: ["新建测评计划", "订单", "推送", "调整", "复盘"], retro: ["计划完成率", "评价展示率", "掉评率", "计划ROI"] },
|
||
{ id: "ref-review-order", short: "评价订单", title: "评价型订单 · 测评/回评", owner: "USER运营 / 客服", ref: "完整参考原型:review-order", intent: "跟踪订单校验、评价提交、Amazon展示确认和返款请款,不把提交等同于展示完成。", metrics: [["待登记", "31", "客服/用户提交"], ["待展示确认", "22", "未计完成"], ["掉评/差评", "9", "触发回评"], ["待请款", "48", "需财务审核"]], steps: ["订单登记", "订单校验", "提交评价", "计入真实人累计12", "展示确认", "请款返款", "完成或异常关闭"], buttons: ["登记订单", "校验订单", "上传评价", "确认展示", "发起请款", "异常关闭"], retro: ["提交到展示耗时", "展示失败原因", "返款耗时", "评价质量"] },
|
||
{ id: "ref-free-review", short: "免评计划", title: "免评执行 · KOC/KOL与站外流量", owner: "KOC/KOL运营", ref: "完整参考原型:free-review", intent: "免评不以用户提交评价为终点,而以内容发布、Code/点击/订单和权重结果为终点。", metrics: [["免评计划", "6", "进行中"], ["KOC任务", "15", "内容交付"], ["Code订单", "56", "模拟"], ["权重结果", "70%", "目标进度"]], steps: ["创建免评计划", "匹配KOC/KOL或渠道", "发布内容/投放Code", "跟踪点击和订单", "回收权重结果", "复盘"], buttons: ["关联KOC任务", "管理KOC任务", "记录Code", "查看订单", "关闭计划"], retro: ["内容发布率", "Code使用率", "点击转化", "权重变化"] },
|
||
{ id: "ref-reply-plan", short: "回评计划", title: "回评计划 · 掉评/差评补救", owner: "USER运营 / 客服", ref: "完整参考原型:reply-plan", intent: "针对掉评、差评、未展示或客服反馈触发回评计划,独立跟踪补救口径。", metrics: [["待回评", "22", "掉评/差评"], ["已触达", "15", "IM/客服"], ["待展示", "7", "Amazon确认"], ["关闭异常", "3", "不可继续"]], steps: ["识别掉评/差评", "生成回评计划", "匹配人群", "触达/客服跟进", "展示确认", "关闭"], buttons: ["生成回评", "催评", "转人工", "确认展示", "关闭异常"], retro: ["回评成功率", "掉评补回率", "差评处理耗时", "客服介入效果"] },
|
||
{ id: "ref-ticket-pool", short: "工单池", title: "客服执行中心 · 工单池", owner: "客服主管", ref: "完整参考原型:ticket-pool", intent: "主管每天优先看未分配、超时、投诉和可转化工单,按班次和能力分配。", metrics: [["待处理", "89", "今日"], ["超时未分配", "3", "P1"], ["在线客服", "12", "可承接"], ["首次回复", "4.2min", "平均"]], steps: ["工单进入", "识别优先级", "自动/手动分配", "转移或升级", "跟踪关闭"], buttons: ["自动分配", "手动分配", "转移", "升级", "关闭"], retro: ["首次回复", "分配耗时", "工单解决率", "投诉率"] },
|
||
{ id: "ref-my-tickets", short: "我的工单", title: "一线客服 · 我的工单", owner: "一线客服", ref: "完整参考原型:my-tickets", intent: "客服每天只先看自己的待回复、待登记、待催评、待升级工单。", metrics: [["我的待回", "14", "含P1 2个"], ["待登记订单", "6", "RSO/RDO"], ["待催评", "9", "用户答应"], ["待升级", "2", "财务/风险"]], steps: ["打开我的工单", "查看用户上下文", "回复/补信息", "登记订单或催评", "升级/关闭"], buttons: ["回复用户", "登记订单", "催评", "升级", "标记解决"], retro: ["客服处理数", "RSO/RDO", "催评成功", "升级原因"] },
|
||
{ id: "ref-user-conversation", short: "用户会话", title: "用户会话与上下文卡", owner: "一线客服", ref: "完整参考原型:user-conversation", intent: "在聊天前展示真实人额度、历史订单、风险和承诺,避免客服误导或重复触达。", metrics: [["真实人额度", "5/12", "累计提交评价"], ["月测评", "2/4", "可继续"], ["未关闭承诺", "1", "需跟进"], ["风险提示", "0", "当前正常"]], steps: ["打开会话", "读取上下文卡", "确认额度/风险", "回复用户", "登记结果"], buttons: ["回复", "补信息", "登记订单", "创建承诺", "升级"], retro: ["会话到订单转化", "补信息次数", "承诺完成率", "风险触发次数"] },
|
||
{ id: "ref-promise-track", short: "承诺跟踪", title: "用户答应配合跟踪", owner: "客服 / USER运营", ref: "完整参考原型:promise-track", intent: "跟踪用户答应下单、答应评价、答应补截图等承诺,超过时限自动提醒。", metrics: [["未完成承诺", "26", "需催办"], ["今日到期", "9", "优先处理"], ["已过期", "4", "需升级"], ["完成率", "68%", "本周"]], steps: ["创建承诺", "设置截止时间", "自动提醒", "客服跟进", "完成/过期/升级"], buttons: ["确认答应", "催办", "标记完成", "标记过期", "升级"], retro: ["承诺完成率", "过期原因", "催办次数", "转化结果"] },
|
||
{ id: "ref-review-reminder", short: "催评", title: "待催评列表", owner: "一线客服", ref: "完整参考原型:review-reminder", intent: "管理答应评价但未提交/未展示的用户,区分催评、转人工和关闭。", metrics: [["待催评", "33", "今日"], ["已催办", "12", "待反馈"], ["转人工", "5", "复杂问题"], ["关闭", "7", "不可继续"]], steps: ["筛选待催评", "确认订单和承诺", "发送提醒", "用户反馈", "提交/转人工/关闭"], buttons: ["催评", "转人工", "确认提交", "关闭", "查看订单"], retro: ["催评成功率", "催办次数", "转人工原因", "展示确认率"] },
|
||
{ id: "ref-cs-dashboard", short: "客服看板", title: "客服管理中心 · Dashboard", owner: "客服主管", ref: "完整参考原型:cs-dashboard", intent: "主管实时查看在线、排班、工单趋势、服务质量和转化目标。", metrics: [["在线客服", "12", "当前"], ["今日工单", "89", "模拟"], ["待处理", "23", "需分配"], ["转化率", "67%", "今日"]], steps: ["查看在线状态", "查看趋势", "识别排班缺口", "调整工单分配", "查看绩效"], buttons: ["刷新状态", "调整分配", "查看排班", "查看绩效"], retro: ["客服目标完成", "首次回复", "解决率", "满意度"] },
|
||
{ id: "ref-attendance", short: "出勤", title: "客服出勤管理", owner: "客服主管", ref: "完整参考原型:attendance", intent: "导入出勤数据,识别迟到、缺勤、早退与班次缺口。", metrics: [["应出勤", "14", "今日"], ["实际出勤", "12", "当前"], ["缺口", "2", "需补班"], ["异常", "3", "迟到/早退"]], steps: ["导入出勤", "匹配排班", "识别异常", "补班或调班", "沉淀绩效"], buttons: ["导入出勤", "标记异常", "补班", "导出"], retro: ["出勤率", "缺口影响", "工单积压", "绩效扣分"] },
|
||
{ id: "ref-schedule", short: "排班", title: "客服排班", owner: "客服主管", ref: "完整参考原型:schedule", intent: "按国家、语言、时段和工单峰值安排班次与最大工单数。", metrics: [["本周班次", "42", "模拟"], ["晚班缺口", "2", "Phone/客服"], ["峰值时段", "16-20", "需覆盖"], ["最大工单", "15/人", "建议"]], steps: ["查看峰值", "设置班次", "批量排班", "限制最大工单", "发布排班"], buttons: ["设置班次", "批量排班", "调整容量", "发布"], retro: ["班次覆盖率", "峰值积压", "超时回复", "人效"] },
|
||
{ id: "ref-cs-performance", short: "客服绩效", title: "客服绩效与月目标", owner: "客服主管", ref: "完整参考原型:cs-performance", intent: "管理客服 RSO/RDO、处理工单、满意度、首次回复和月度目标。", metrics: [["RSO目标", "1,200", "月度"], ["RDO目标", "900", "月度"], ["满意度", "96%", "模拟"], ["首次回复", "4.2min", "平均"]], steps: ["设置月目标", "跟踪日完成", "识别低绩效", "复盘原因", "调整排班/训练"], buttons: ["设置月目标", "查看明细", "导出绩效", "复盘"], retro: ["目标达成", "RSO/RDO转化", "客服排名", "培训需求"] },
|
||
{ id: "ref-im-push", short: "IM推送", title: "IM推送任务", owner: "渠道运营", ref: "完整参考原型:im-push", intent: "基于真实人去重、额度复检、卡片/H5有效性和渠道频控生成IM推送任务。", metrics: [["今日任务", "16", "IM"], ["可推人群", "18,420", "去重后"], ["回复率", "4.8%", "模拟"], ["频控命中", "37", "需排除"]], steps: ["选择计划", "选择 audience_snapshot", "选择卡片/H5", "额度/风险复检", "发送/暂停", "回流结果"], buttons: ["新增推送", "上架", "下架", "批量分配", "配置去重"], retro: ["发送", "点击", "回复", "订单", "退订投诉"] },
|
||
{ id: "ref-edm-check", short: "EDM检查", title: "EDM每日检查", owner: "EDM运营", ref: "完整参考原型:edm-check", intent: "发信前先检查域名、邮箱、IP信誉、UID/KV人群、H5链接和退订投诉。", metrics: [["域名健康", "2/3", "1个预警"], ["UID人群", "9,880", "今日可发"], ["打开率", "19.4%", "模拟"], ["投诉率", "0.42%", "接近阈值"]], steps: ["基础设施检查", "同步OA计划", "检查UID/KV人群", "检查H5", "生成EDM任务", "AB Test"], buttons: ["检查基础设施", "创建AB Test", "生成任务", "暂停发送"], retro: ["送达", "打开", "点击", "退订", "投诉"] },
|
||
{ id: "ref-channel-funnel", short: "渠道漏斗", title: "渠道漏斗对比", owner: "渠道运营", ref: "完整参考原型:channel-funnel", intent: "对比IM、EDM、Phone、APP/H5各渠道从触达到订单/评价的漏斗。", metrics: [["IM回复", "4.8%", "模拟"], ["EDM打开", "19.4%", "模拟"], ["Phone接通", "62%", "模拟"], ["APP点击", "8.1%", "模拟"]], steps: ["查看渠道漏斗", "识别低效环节", "调整人群/素材/频控", "复盘转化"], buttons: ["查看IM", "查看EDM", "查看Phone", "配置去重"], retro: ["渠道ROI", "跨渠道重复触达", "转化贡献", "投诉率"] },
|
||
{ id: "ref-koc-leads", short: "KOC线索", title: "KOC/KOL线索池", owner: "KOC/KOL运营", ref: "完整参考原型:koc-leads", intent: "沉淀KOC/KOL线索来源、站点、垂类、标签、风险和合作状态。", metrics: [["新线索", "18", "本周"], ["待审核", "7", "需建档"], ["合作中", "12", "任务执行"], ["风险线索", "2", "需阻断"]], steps: ["导入/新增线索", "标签分层", "风险审核", "建档", "创建任务"], buttons: ["新增线索", "建档", "创建任务", "标记风险"], retro: ["线索转任务率", "达人质量", "风险命中", "垂类覆盖"] },
|
||
{ id: "ref-koc-profile", short: "达人档案", title: "KOC/KOL达人档案", owner: "KOC/KOL运营", ref: "完整参考原型:koc-profile", intent: "记录达人平台、账号、垂类、合作历史、佣金规则,并识别是否与测评人身份重叠。", metrics: [["关联测评人", "1", "同一真实人"], ["历史任务", "8", "模拟"], ["内容合格", "92%", "模拟"], ["佣金争议", "1", "待处理"]], steps: ["查看达人档案", "核验平台账号", "识别身份重叠", "查看任务历史", "设置合作规则"], buttons: ["编辑档案", "关联真实人", "创建任务", "暂停合作"], retro: ["内容质量", "带货效果", "身份冲突", "佣金争议"] },
|
||
{ id: "ref-koc-task", short: "合作任务", title: "KOC/KOL合作任务", owner: "KOC/KOL运营", ref: "完整参考原型:koc-task", intent: "跟踪任务创建、样品/Code、内容发布、链接回收、订单归因和佣金状态。", metrics: [["进行中", "15", "内容任务"], ["待发布", "6", "需催办"], ["待验收", "4", "内容链接"], ["佣金待算", "5", "订单归因"]], steps: ["创建任务", "分配达人", "发放Code/素材", "发布内容", "回收链接/订单", "验收结算"], buttons: ["创建任务", "催发布", "验收内容", "记录Code", "发起佣金"], retro: ["内容发布率", "订单归因", "佣金成本", "达人复用率"] },
|
||
{ id: "ref-reviewer-pool", short: "测评人池", title: "测评人/真实人池", owner: "USER运营 / 风险", ref: "完整参考原型:reviewer-pool", intent: "查看JOYHUB账号、Amazon账号、Profile、站点、标签和风险状态,但额度按真实人聚合。", metrics: [["真实人", "18,420", "模拟"], ["可参与", "12,880", "额度可用"], ["风险排除", "423", "黑名单/弱风险"], ["信息缺失", "306", "需补齐"]], steps: ["筛选测评人", "查看身份链路", "读取额度台账", "复检风险", "加入人群快照"], buttons: ["筛选", "加入快照", "查看额度", "标记风险"], retro: ["可用人群变化", "风险命中", "信息缺失", "转化率"] },
|
||
{ id: "ref-reviewer-quota", short: "额度台账", title: "测评人额度明细", owner: "USER运营 / 风险", ref: "完整参考原型:reviewer-quota", intent: "按 person_quota_ledgers 查看月度测评≤4、免评≤4、累计提交评价≤12和预占记录。", metrics: [["接近4次", "37", "月测评"], ["累计>=12", "1,204", "转免评"], ["预占超时", "9", "需释放"], ["冲突", "3", "待审核"]], steps: ["读取真实人额度", "查看预占", "提交评价计入累计12", "展示确认计计划完成", "释放/调整"], buttons: ["查看明细", "手动释放预占", "锁定额度", "导出"], retro: ["额度利用率", "预占超时", "归并冲突", "超限拦截"] },
|
||
{ id: "ref-identity-merge", short: "真实人归并", title: "真实人归并", owner: "风险 / USER运营", ref: "完整参考原型:identity-merge", intent: "V1必须自动归并真实人,人工确认/拆分可预留;否则4/4/12额度不可落地。", metrics: [["自动归并", "1,280", "今日"], ["高置信", "96%", "姓名/地址/设备"], ["冲突", "11", "需人工"], ["待拆分", "3", "预留"]], steps: ["收集身份线索", "标准化姓名/地址/设备", "自动归并", "写入identity_links", "更新额度台账"], buttons: ["查看归并", "人工确认", "手动合并", "手动拆分"], retro: ["归并准确率", "额度冲突", "人工处理量", "误合并率"] },
|
||
{ id: "ref-risk-event", short: "风险事件", title: "风险事件中心", owner: "风险/审核", ref: "完整参考原型:risk-event", intent: "统一管理订单、用户、测评人、返款、KOC/KOL相关风险信号和案件。", metrics: [["P0", "6", "强阻断"], ["P1", "31", "当天处理"], ["待复核", "18", "人工"], ["已关闭", "42", "本周"]], steps: ["创建/接收风险信号", "分级", "阻断或提示", "人工审核", "关闭并记录"], buttons: ["创建风险事件", "标记P0", "转案件", "关闭"], retro: ["风险命中率", "误杀率", "处理时效", "关闭原因"] },
|
||
{ id: "ref-blacklist", short: "黑名单", title: "黑名单管理", owner: "风险/审核", ref: "完整参考原型:blacklist", intent: "支持用户/测评人/KOC/KOL/设备/支付标识等强弱黑名单,并参与每次互动复检。", metrics: [["强风险", "84", "阻断"], ["弱风险", "212", "提示"], ["KOC风险", "7", "内容违规"], ["解除申请", "5", "待审"]], steps: ["新增黑名单", "选择对象类型", "设置强/弱风险", "写入原因", "参与复检"], buttons: ["新增黑名单", "解除", "升级强风险", "查看日志"], retro: ["黑名单命中", "解除率", "重复风险", "申诉结果"] },
|
||
{ id: "ref-refund-risk", short: "退款风险", title: "Amazon退款 vs OA返款比对", owner: "财务 / 风险", ref: "完整参考原型:refund-risk", intent: "识别Amazon退款、OA返款、非APP用户邮件退款和卡密返款之间的双重退款风险。", metrics: [["双重风险", "9", "需阻断"], ["非APP邮件", "6", "缺设备维度"], ["待补凭证", "12", "财务"], ["已阻断", "4", "今日"]], steps: ["导入退款/返款记录", "按真实人/订单/邮箱匹配", "识别双重退款", "阻断请款", "风险关闭"], buttons: ["比对退款", "阻断返款", "补凭证", "关闭风险"], retro: ["双重退款拦截", "非APP盲区", "凭证缺失", "返款争议"] },
|
||
{ id: "ref-refund-audit", short: "返款审核", title: "返款审核", owner: "财务", ref: "完整参考原型:refund-audit", intent: "审核用户返款请款、凭证、卡密、订单状态和风险信号。", metrics: [["待审核", "48", "今日"], ["缺凭证", "12", "需补"], ["风险阻断", "9", "退款比对"], ["已返款", "156,200", "月度"]], steps: ["接收请款", "核验订单/评价/展示", "风险比对", "审核通过或退回", "执行返款"], buttons: ["审核通过", "退回补充", "阻断", "执行返款"], retro: ["审核耗时", "返款成功率", "退回原因", "风险金额"] },
|
||
{ id: "ref-commission", short: "佣金", title: "KOC/KOL佣金", owner: "财务 / KOC运营", ref: "完整参考原型:commission", intent: "V1可预留完整佣金结算入口,免评补单相关的订单归因和佣金争议需记录。", metrics: [["待结算", "5", "任务"], ["归因争议", "1", "待审"], ["已结算", "23", "本月"], ["预留项", "V2", "完整实现"]], steps: ["读取KOC任务", "核验订单归因", "计算佣金", "审核争议", "结算"], buttons: ["计算佣金", "发起审核", "标记争议", "结算"], retro: ["佣金成本", "达人ROI", "争议率", "归因准确率"] },
|
||
{ id: "ref-report-plan", short: "计划复盘", title: "数据复盘 · 计划看板", owner: "业务负责人", ref: "完整参考原型:report-plan", intent: "按计划查看目标、完成、缺口、暂停、转免评、异常和负责人。", metrics: [["计划完成", "83%", "月度"], ["缺口", "253", "目标数"], ["异常关闭", "7", "本周"], ["转免评", "3", "本月"]], steps: ["选择时间", "查看计划趋势", "下钻异常", "生成复盘动作"], buttons: ["筛选", "下钻", "导出", "创建复盘"], retro: ["完成率", "异常率", "资源缺口", "动作闭环"] },
|
||
{ id: "ref-report-asin", short: "ASIN复盘", title: "数据复盘 · ASIN看板", owner: "业务负责人", ref: "完整参考原型:report-asin", intent: "按ASIN看评价、回评、免评、掉评、权重变化和渠道贡献。", metrics: [["ASIN数", "126", "本月"], ["掉评", "2.1%", "模拟"], ["权重提升", "70%", "免评"], ["库存阻断", "5", "影响计划"]], steps: ["选择ASIN", "查看评价/免评指标", "查看渠道贡献", "生成下一轮计划"], buttons: ["筛选ASIN", "查看趋势", "创建需求"], retro: ["评价质量", "掉评原因", "免评权重", "库存影响"] },
|
||
{ id: "ref-report-channel", short: "渠道复盘", title: "数据复盘 · 渠道看板", owner: "渠道负责人", ref: "完整参考原型:report-channel", intent: "对比IM、EDM、Phone、APP/H5触达、点击、回复、订单、投诉和ROI。", metrics: [["IM订单", "386", "模拟"], ["EDM订单", "142", "模拟"], ["Phone意向", "86", "模拟"], ["投诉", "0.42%", "EDM"]], steps: ["选择渠道", "查看漏斗", "对比计划", "识别低效原因", "调整策略"], buttons: ["对比渠道", "查看人群", "配置去重", "导出"], retro: ["渠道ROI", "触达疲劳", "重复触达", "投诉退订"] },
|
||
{ id: "ref-report-cs", short: "客服复盘", title: "数据复盘 · 客服看板", owner: "客服主管", ref: "完整参考原型:report-cs", intent: "复盘客服工单、解决率、满意度、RSO/RDO和目标完成。", metrics: [["工单解决率", "92%", "模拟"], ["满意度", "96%", "模拟"], ["RSO", "892", "月度"], ["RDO", "617", "月度"]], steps: ["查看客服表现", "识别目标缺口", "下钻工单类型", "调整排班和培训"], buttons: ["筛选客服", "查看明细", "设置目标", "导出"], retro: ["人效", "服务质量", "转化目标", "培训动作"] }
|
||
];
|
||
|
||
modules.push({
|
||
id: "reference",
|
||
label: "细化",
|
||
icon: "UX",
|
||
title: "完整参考原型细化页",
|
||
note: "参考 20260528_USER_ERP_完整参考原型_v1.html,把操作台页面拆成可跳转的执行入口。",
|
||
pages: referencePages.map(p => p.id)
|
||
});
|
||
|
||
referencePages.forEach(item => {
|
||
pages[item.id] = {
|
||
module: "reference",
|
||
title: item.title,
|
||
short: item.short,
|
||
subtitle: item.intent,
|
||
owner: item.owner,
|
||
source: "参考原型/02/03/04/05",
|
||
kind: "reference"
|
||
};
|
||
});
|
||
|
||
const roles = {
|
||
owner: { name: "高级主管", see: "OKR、资源压力、P0异常、跨部门阻塞、计划缺口", avoid: "不先看单条聊天、单条订单字段和普通P3观察项", judge: "是否暂停计划、是否补资源、是否升级跨部门", review: "目标缺口、TOP/BOTTOM任务、异常原因沉淀" },
|
||
ops: { name: "USER运营", see: "需求池、计划生成、执行匹配、今日缺口、待补量", avoid: "不把V1边界当需求边界,不只看订单页", judge: "需求是否可执行、资源是否匹配、是否转免评/客服/KOC", review: "计划完成、渠道表现、订单与评价口径" },
|
||
channel: { name: "渠道运营", see: "IM/EDM/Phone漏斗、人群、频控、卡片/H5、退订投诉", avoid: "不绕过真实人额度,不只按单渠道点击率决策", judge: "是否降频、换素材、换人群、暂停推送", review: "发送、点击、回复、订单、评价、投诉" },
|
||
csLead: { name: "客服主管", see: "在线、排班、待处理、首次回复、转化目标、投诉", avoid: "不先看已关闭低风险工单", judge: "是否自动分配、转移、调班、升级投诉", review: "RSO/RDO、首次回复、解决率、目标完成率" },
|
||
cs: { name: "一线客服", see: "我的工单、待回复、待催评、待登记订单、答应配合", avoid: "不看全局财务明细和他人敏感资料", judge: "回复、补信息、登记订单、催评、升级", review: "今日处理数、催评结果、用户承诺完成情况" },
|
||
koc: { name: "KOC/KOL运营", see: "新线索、标签、合作任务、内容/带货进度、身份冲突", avoid: "不把普通测评完成口径当内容任务完成口径", judge: "是否匹配达人、是否暂停合作、是否要求重提内容", review: "内容链接、Code、订单、佣金争议、风险" },
|
||
finance: { name: "财务/返款", see: "待请款、待审核、待返款、双重退款、凭证/卡密", avoid: "不看未到返款条件的普通工单", judge: "是否审核通过、是否阻断重复返款、是否补凭证", review: "返款成功率、异常返款、卡密缺失、争议" },
|
||
risk: { name: "风险/审核", see: "黑名单、强弱关联、退款取消、额度超限、敏感导出", avoid: "不只按账号判断,不用Profile累计Review替代真实人", judge: "弱风险提示、强风险阻断、拉黑/解除", review: "风险案件、复检记录、归并冲突、异常关闭" }
|
||
};
|
||
|
||
const workflowData = {
|
||
demand: {
|
||
metrics: [["待评估需求", "12", "OA/销售/客服/KOC入口"], ["资源匹配不足", "5", "人群或客服容量缺口"], ["今日待转计划", "8", "测评/回评/免评/客服"], ["冲突计划", "2", "需主管合并或暂停"]],
|
||
do: ["先看P0/P1需求和截止时间", "校验ASIN、库存、评分、产品状态", "确认需求类型:测评/回评/免评/客服/KOC", "检查人群、额度、渠道、客服容量是否能支撑"],
|
||
dont: ["不直接从需求跳到推送", "不在未核验产品/库存时生成计划", "不把KOC/KOL合作请求当普通测评单处理"],
|
||
steps: ["需求进入", "需求评估", "产品/ASIN校验", "计划生成", "执行匹配", "渠道/客服/KOC任务", "结果回流"],
|
||
issues: ["目标高于可用人群/额度", "产品禁用但计划仍执行", "计划有名额但渠道无人群", "渠道有响应但客服容量不足", "完成数口径不一致"],
|
||
actions: ["新增需求", "导入OA需求", "需求评估", "生成计划", "匹配人群", "预占额度", "分配客服", "生成推送任务", "调整名额", "暂停计划", "恢复计划", "转免评", "关闭需求"],
|
||
review: ["需求转计划耗时", "计划完成率", "资源匹配缺口", "客服容量压力", "被驳回/需补充原因"]
|
||
},
|
||
"branch-im": {
|
||
metrics: [["可推人群", "18,420", "按真实人去重"], ["长期测评人", "1,204", "累计提交评价>=12"], ["回复率", "4.8%", "低于目标需换素材"], ["额度预警", "37", "接近4/4/12"]],
|
||
do: ["先按真实人读取person_quota_ledgers", "检查黑名单、退款取消、未完成单", "确认卡片/H5和产品状态有效", "查看今日频控和渠道去重"],
|
||
dont: ["不按Profile累计Review分层", "不对累计>=12的真实人推普通测评/回评", "不绕过客服容量继续放量"],
|
||
steps: ["人群生成", "额度/风险复检", "选择卡片/H5", "推送", "用户响应", "核验信息", "订单/返款/客服"],
|
||
issues: ["IM点击低", "IM回复低于3%", "退订或不感兴趣升高", "卡片产品禁用未同步", "H5链接失效"],
|
||
actions: ["新增推送", "上架/下架", "批量分配", "新增卡片", "下架卡片", "配置去重规则"],
|
||
review: ["发送", "曝光", "点击", "回复", "订单", "评价", "退订/投诉"]
|
||
},
|
||
"branch-edm": {
|
||
metrics: [["域名健康", "2/3", "1个预警"], ["UID人群", "9,880", "今日可发"], ["打开率", "19.4%", "模拟数据"], ["投诉率", "0.42%", "接近阈值"]],
|
||
do: ["先看域名、邮箱、IP信誉", "核对OA计划变化", "检查KV/UID人群数量", "确认H5与产品禁用联动", "回收打开/点击/回复/退订/投诉"],
|
||
dont: ["不在信誉异常时继续发送", "不把EDM点击当评价完成", "不忽略菲律宾/国家问题清单"],
|
||
steps: ["基础设施检查", "同步OA计划", "检查UID人群", "检查产品/H5", "生成EDM任务", "发送与AB Test", "转化到订单/客服/风险"],
|
||
issues: ["EDM域名/IP信誉异常", "KV/UID人群导出失败", "H5链接失效", "退订或不感兴趣升高"],
|
||
actions: ["检查基础设施", "创建AB Test", "生成推送任务", "配置去重规则"],
|
||
review: ["送达", "打开", "点击", "回复", "退订", "投诉", "订单转化"]
|
||
},
|
||
"branch-phone": {
|
||
metrics: [["待回拨", "86", "含未接"], ["未接率", "38%", "需调整时段"], ["可用客服", "7", "晚班缺1"], ["转KOC线索", "4", "今日新增"]],
|
||
do: ["先看未接和待回拨", "按国家/语言/时段匹配客服", "查看问题类型分布", "确认高峰时段客服是否不足"],
|
||
dont: ["不在客服容量不足时批量外呼", "不把Phone售后问题直接记为评价转化"],
|
||
steps: ["生成电话名单", "匹配国家/语言/时段/排班", "拨打/记录", "转客服/订单/售后/KOC线索", "复盘未接率"],
|
||
issues: ["Phone未接率过高", "排班不足", "客服转移失败", "等待用户超时"],
|
||
actions: ["创建回拨任务", "设置班次", "批量排班", "转移工单"],
|
||
review: ["拨打数", "接通数", "未接率", "订单意向", "KOC意向", "售后问题"]
|
||
},
|
||
"branch-cs": {
|
||
metrics: [["待分配工单", "19", "含P1 6个"], ["首次回复超时", "7", "需主管处理"], ["今日登记订单", "43", "RSO/RDO"], ["答应配合待完成", "26", "需催评"]],
|
||
do: ["先看未分配和超时工单", "客服查看上下文卡后再回复", "缺订单/截图/返款信息时创建待补标签", "投诉、诈骗、退款异常立即升级"],
|
||
dont: ["不把客服降级成聊天窗口", "不绕过订单核验直接请款", "不查看无关敏感字段"],
|
||
steps: ["消息进入", "生成工单", "分配客服", "查看上下文卡", "回复/补信息", "登记订单/催评/上传结果", "关闭或升级"],
|
||
issues: ["无客服在线", "工单未分配", "首次回复超时", "客服误登记订单", "用户投诉客服"],
|
||
actions: ["自动分配", "手动分配", "转移工单", "回复用户", "登记订单", "催评", "标记解决", "关闭工单", "重开工单", "确认答应", "拒绝", "标记过期"],
|
||
review: ["处理工单", "首次回复", "解决率", "RSO/RDO转化", "投诉", "客服目标完成率"]
|
||
},
|
||
"branch-order": {
|
||
metrics: [["待登记订单", "31", "客服/用户提交"], ["待确认评价", "22", "展示未确认"], ["掉评/差评", "9", "触发回评"], ["待请款", "48", "需财务审核"]],
|
||
do: ["先核验订单号、店铺、ASIN、订单状态", "用户提交评价立即计入真实人累计12", "Amazon展示确认才计计划完成", "更换/更改/撤销必须留日志"],
|
||
dont: ["不把用户提交等同于展示完成", "不对已退款/已取消订单继续返款", "不把免评结果混进评价型完成数"],
|
||
steps: ["计划分配人群", "生成/提交订单", "核验订单号", "绑定ASIN/店铺/站点", "上传评价", "展示核验", "返款/请款", "完成/异常关闭"],
|
||
issues: ["订单号格式错误", "非公司产品", "店铺下错", "订单已取消/退款", "评论重复绑定", "评论未展示", "掉评/差评"],
|
||
actions: ["新建测评计划", "编辑计划", "查看关联订单", "新增订单", "上传订单", "上传回评", "提交排队", "请款", "更换订单", "更改订单", "撤销", "批量导出", "回评确认"],
|
||
review: ["订单完成", "评价提交", "展示确认", "返款成功", "掉评率", "异常关闭原因"]
|
||
},
|
||
"branch-free": {
|
||
metrics: [["免评计划", "6", "今日执行"], ["KOC内容待提交", "14", "含超时3"], ["Code订单", "126", "模拟归因"], ["权重结果", "3 ASIN", "待复盘"]],
|
||
do: ["先看免评计划目标和协同资源", "拆解KOC/KOL任务、Code、内容协同", "回收点击、Code使用、订单和权重结果", "免评结果单独形成快照"],
|
||
dont: ["不以用户提交评价为终点", "不以Amazon展示评价作为完成口径", "不混入测评/回评订单完成数"],
|
||
steps: ["免评计划批准", "拆解KOC/KOL/Code/内容任务", "匹配资源", "发布内容/分发Code", "同步IM/EDM/APP", "回收结果", "形成免评结果快照"],
|
||
issues: ["KOC/KOL与C类测评人身份重叠", "样品发出未产出内容", "内容链接无效", "带货订单归因失败", "佣金争议"],
|
||
actions: ["新建免评计划", "匹配KOC/KOL", "创建合作任务", "分配样品/免评名额", "上传内容链接", "审核内容", "同步订单"],
|
||
review: ["内容链接", "Code使用", "点击", "订单", "权重结果", "达人表现", "佣金争议"]
|
||
},
|
||
"branch-finance": {
|
||
metrics: [["待审核请款", "48", "含P0 3"], ["双重退款", "5", "需风险确认"], ["卡密缺失", "6", "V1预留"], ["佣金争议", "3", "V2实现"]],
|
||
do: ["先看待审核和P0资金风险", "比对Amazon退款和OA返款", "非APP邮件退款补齐识别线索", "返款成功后回写订单和工单"],
|
||
dont: ["不审核未满足条件的请款", "不跳过双重退款比对", "不暴露完整返款账号和卡密"],
|
||
steps: ["返款条件满足", "发起请款", "财务审核", "付款/礼品卡", "凭证/卡密通知", "状态回写", "风险复盘"],
|
||
issues: ["缺返款账号", "返款账号格式异常", "重复请款", "双重退款", "非APP用户邮件退款", "返款超额", "卡密/凭证缺失"],
|
||
actions: ["请款", "审核请款", "确认返款", "标记双重退款", "创建风险事件"],
|
||
review: ["待请款", "待审核", "返款成功", "异常返款", "双重退款", "凭证缺失"]
|
||
},
|
||
"branch-koc": {
|
||
metrics: [["新线索", "21", "今日新增"], ["合作任务", "38", "免评/内容/带货"], ["内容待审核", "12", "V2"], ["身份冲突", "4", "需复核"]],
|
||
do: ["先看新线索、任务超时、身份冲突", "区分KOC/KOL身份和普通测评人身份", "标签、带货、测评、免评不能混", "内容任务与订单任务分开完成口径"],
|
||
dont: ["不因为V1不做完整商家平台就删除KOC/KOL需求", "不把KOC内容任务混成普通测评订单"],
|
||
steps: ["新增线索", "身份/标签/风险检查", "自动打标与人工修正", "分层", "匹配任务", "接受/拒绝", "样品/内容/带货执行", "复盘"],
|
||
issues: ["KOC标签混乱", "达人重复触达", "内容不合规", "带货订单归因失败", "高风险KOC继续推送"],
|
||
actions: ["新增线索", "打标分层", "创建合作任务", "分配样品/免评名额", "上传内容链接", "审核内容", "同步订单", "计算佣金", "暂停合作"],
|
||
review: ["线索", "任务", "内容", "带货", "佣金", "风险", "合作等级"]
|
||
},
|
||
"branch-risk": {
|
||
metrics: [["风险事件", "37", "待处理"], ["强关联命中", "8", "阻断"], ["额度超限", "18", "真实人维度"], ["敏感导出", "2", "需审批"]],
|
||
do: ["先看P0资金/合规/账号安全", "每次有效互动复检身份、额度、风险", "强风险阻断,弱风险提示人工", "确认风险后同步黑名单"],
|
||
dont: ["不只按账号判断风险", "不让黑名单用户继续触达/返款/合作", "不导出未脱敏敏感字段"],
|
||
steps: ["风险信号产生", "判断弱/强风险", "弱风险提醒", "强风险阻断", "人工复核", "解除/确认", "黑名单同步/恢复执行"],
|
||
issues: ["黑名单命中", "强关联命中", "弱关联命中", "额度超限", "多账号归并冲突", "频控超限", "敏感字段导出风险"],
|
||
actions: ["创建风险事件", "复核通过", "排除风险", "新增黑名单", "标记双重退款", "查看审计记录", "手动合并", "手动拆分"],
|
||
review: ["风险案件", "黑名单", "退款比对", "额度超限", "强弱关联", "复检记录"]
|
||
},
|
||
"orders": null,
|
||
"cs-exec": null,
|
||
"cs-mgmt": null,
|
||
"channel": null,
|
||
"people": null,
|
||
"koc-center": null,
|
||
"risk-center": null,
|
||
"retro": null
|
||
};
|
||
|
||
workflowData.orders = workflowData["branch-order"];
|
||
workflowData["cs-exec"] = workflowData["branch-cs"];
|
||
workflowData["cs-mgmt"] = {
|
||
metrics: [["在线客服", "17", "晚班缺1"], ["今日工单", "163", "待处理19"], ["首次回复", "8.6分", "目标<10分"], ["目标完成", "76%", "本月"]],
|
||
do: ["先看在线、排班、待处理和超时", "检查RSO/RDO目标完成", "处理工单分配压力", "导出回复/转化/目标完成"],
|
||
dont: ["不先看已关闭低风险工单", "不调整未确认班次规则", "不忽略投诉工单"],
|
||
steps: ["看客服Dashboard", "检查出勤", "调整排班", "分配工单", "跟踪回复统计", "看转化绩效", "设置目标"],
|
||
issues: ["无客服在线", "排班不足", "目标异常", "用户投诉客服"],
|
||
actions: ["导入出勤", "调整出勤状态", "设置班次", "批量排班", "设置月目标", "导出绩效"],
|
||
review: ["出勤", "排班", "处理工单", "首次回复", "转化率", "目标完成率"]
|
||
};
|
||
workflowData.channel = workflowData["branch-im"];
|
||
workflowData.people = {
|
||
metrics: [["真实人档案", "42,180", "模拟聚合"], ["额度预警", "18", "接近12"], ["自动归并", "96.3%", "姓名+地址/设备"], ["人工复核", "11", "合并/拆分"]],
|
||
do: ["先看额度预警和归并冲突", "确认自动归并是否覆盖姓名+地址、设备、邮箱、电话、Profile、收款信息", "查看真实人下多账号额度一致性", "风险记录与黑名单联动"],
|
||
dont: ["不以单JOYHUB ID或Profile替代真实人", "不在归并冲突未解决时继续推普通测评"],
|
||
steps: ["识别身份线索", "自动归并真实人", "读取额度台账", "生成候选人群", "预占/释放额度", "互动复检", "人工合并/拆分"],
|
||
issues: ["多账号归并冲突", "额度超限", "强关联命中", "弱关联命中"],
|
||
actions: ["手动合并", "手动拆分", "查看额度明细", "查看审计记录", "手动释放预占"],
|
||
review: ["4/4/12", "预占", "释放", "提交计数", "风险历史", "归并准确率"]
|
||
};
|
||
workflowData["koc-center"] = workflowData["branch-koc"];
|
||
workflowData["risk-center"] = workflowData["branch-risk"];
|
||
workflowData.retro = {
|
||
metrics: [["计划完成率", "84%", "核心指标"], ["ASIN风险", "9", "低评分/掉评"], ["客服转化", "76%", "RSO/RDO"], ["KOC内容", "31", "已发布/待审"]],
|
||
do: ["先看昨日TOP/BOTTOM任务", "看异常原因是否有沉淀动作", "核对计划/订单/评价/免评不同完成口径", "输出本周资源缺口"],
|
||
dont: ["不把提交评价和展示确认混成一个指标", "不把免评结果混入评价型计划完成", "不展示未脱敏敏感字段"],
|
||
steps: ["结果回流", "指标聚合", "异常归因", "复盘记录", "沉淀动作", "下一轮计划调整"],
|
||
issues: ["完成数口径不一致", "渠道响应但客服容量不足", "内容/佣金风险", "双重退款"],
|
||
actions: ["创建复盘", "批量导出", "导出绩效", "查看关联推送", "查看关联订单"],
|
||
review: ["计划", "ASIN", "渠道", "客服", "测评人", "KOC/KOL", "财务"]
|
||
};
|
||
|
||
const exceptionGroups = [
|
||
["需求与执行计划不匹配", [["需求目标高于可用人群/额度", "提醒运营降低目标、拆分周期、转免评或补充渠道", "V1必做"], ["产品禁用但计划仍在执行", "自动暂停计划和下架H5/卡片", "V1必做"], ["库存不足但继续推测评/免评", "限制节奏或暂停", "V1必做"], ["ASIN/店铺/关键词变化未同步", "阻断新推送,生成维护任务", "V1必做"], ["计划有名额但渠道无可推人群", "补充人群、换渠道、延长周期", "V1必做"], ["渠道有响应但客服容量不足", "暂停或降频推送,调整排班", "V1必做"], ["完成数口径不一致", "进入口径复核", "V1必做"]]],
|
||
["评价/订单异常", [["订单号格式错误", "提示重填或转客服", "V1必做"], ["非公司产品", "阻断登记,转客服说明", "V1必做"], ["店铺下错", "人工处理,可转免评", "V1必做"], ["订单已取消/退款", "阻断回评和返款,进入风险", "V1必做"], ["评论重复绑定", "阻断或例外审核", "V1必做"], ["评论未展示", "计划不计完成", "V1必做"], ["掉评/差评", "触发回评/紧急催评/风险", "V1必做"]]],
|
||
["返款/佣金异常", [["缺返款账号", "客服跟进补齐", "V1必做"], ["重复请款", "阻断并提醒财务", "V1必做"], ["双重退款", "生成风险事件", "V1必做"], ["非APP用户邮件退款", "补充邮箱、订单、地址、收款信息等识别线索", "V1必做"], ["KOC/KOL佣金争议", "进入佣金复核", "V2实现"]]],
|
||
["客服异常", [["无客服在线", "提醒主管,暂停部分推送", "V1必做"], ["工单未分配", "自动分配或主管手动分配", "V1必做"], ["首次回复超时", "提醒客服/主管", "V1必做"], ["排班不足", "调整排班或降频推送", "V1必做"], ["客服误登记订单", "更改订单并留痕", "V1必做"]]],
|
||
["渠道异常", [["IM点击低", "换素材/卡片/人群", "V1必做"], ["IM回复低于3%", "更换图片/话术", "V1必做"], ["EDM域名/IP信誉异常", "暂停发送、切换账号", "V1必做"], ["KV/UID人群导出失败", "重跑导出", "V1必做"], ["Phone未接率过高", "调整时段/排班/回拨", "V1预留"]]],
|
||
["KOC/KOL异常", [["KOC标签混乱", "人工复核标签", "V1预留"], ["KOC/KOL与C类测评人身份重叠", "阻断重复触达,进入冲突复核", "V1必做"], ["达人重复触达", "合并或暂停任务", "V1预留"], ["内容不合规", "驳回、下架、降权", "V2实现"], ["带货订单归因失败", "进入人工归因", "V2实现"]]],
|
||
["风险异常", [["黑名单命中", "阻断触达/返款/合作", "V1必做"], ["强关联命中", "阻断并复核", "V1必做"], ["额度超限", "阻断普通测评,转免评池", "V1必做"], ["多账号归并冲突", "按person_quota_ledgers重新汇总", "V1必做"], ["敏感字段导出风险", "强制脱敏/审批", "V1必做"]]]
|
||
];
|
||
|
||
const actionRows = [
|
||
["今日作战台","查看异常","进入昨日/今日异常详情","alert、plan、channel_event、ticket、risk_event","-","-","主管、运营","否","V1必做","exceptions"],
|
||
["今日作战台","指派处理人","把异常转成可执行任务","alert、staff、shift","task、notification","异常:待处理 -> 已指派","主管、运营","是","V1必做","exceptions"],
|
||
["今日作战台","升级异常","P0/P1问题升级主管或跨部门","alert、risk_event、ticket","escalation、notification","异常:待处理 -> 已升级","主管、风险","是","V1必做","exceptions"],
|
||
["今日作战台","调整计划","从作战台直接进入计划调整","demand、plan、progress","plan_change_log","计划:进行中 -> 调整中/暂停/补量","主管、运营","是","V1必做","demand"],
|
||
["今日作战台","创建复盘","对异常或任务形成复盘记录","plan、channel_event、ticket、order","retrospective","异常:已处理 -> 待复盘","主管、运营","是","V1预留","retro"],
|
||
["需求池","新增需求","手动录入销售/运营/KOC-KOL需求","product、asin、staff","demand","需求:草稿","运营、主管","是","V1必做","demand"],
|
||
["需求池","导入OA需求","从OA或表格批量导入需求","import_file","demand、import_log","需求:待评估","运营、管理员","是","V1必做","demand"],
|
||
["需求池","需求评估","判断需求是否可执行","demand、product、asin、inventory、risk","demand_review","待评估 -> 已通过/需补充/驳回","运营、主管","是","V1必做","demand"],
|
||
["需求池","退回补充","信息不足时退回需求人","demand","demand、notification","待评估 -> 需补充","运营","是","V1必做","demand"],
|
||
["需求池","生成计划","将需求转成测评/回评/免评/KOC-KOL/客服计划","demand、product、audience、quota、risk","plan、plan_log","已通过 -> 已转计划","运营、主管","是","V1必做","demand"],
|
||
["计划编排","拆分计划","一个需求拆成多个站点/渠道/周期计划","demand、plan","plan、plan_relation","计划:草稿/进行中","运营、主管","是","V1预留","demand"],
|
||
["计划编排","合并计划","合并同产品/同周期/同目标计划","plan","plan_relation、plan_log","计划:合并/关闭旧计划","主管","是","V1预留","demand"],
|
||
["执行匹配","匹配人群","生成候选用户/测评人/KOC-KOL名单","person、reviewer、koc_kol、quota、risk","audience_snapshot、exclusion","匹配:待匹配 -> 完成/不足","运营","是","V1必做","demand"],
|
||
["执行匹配","预占额度","锁定测评/免评/Review额度","audience_snapshot、quota_ledger","quota_reservation","额度:可用 -> 预占","运营","是","V1必做","people"],
|
||
["执行匹配","手动释放预占","预占超时、计划取消或人群撤出后释放额度","quota_reservation、quota_ledger、plan","quota_reservation_log、quota_ledger","额度:已预占 -> 已释放","主管、管理员","是","V1必做","people"],
|
||
["执行匹配","分配客服","按容量、语言、工单量分配承接客服","plan、ticket、shift、agent_capacity","task、ticket_assignment","待分配 -> 已分配","主管、客服主管","是","V1必做","branch-cs"],
|
||
["执行匹配","生成推送任务","从计划生成人群和渠道任务","plan、audience、card、h5、channel_config","push_task、channel_event","待发送","渠道运营","是","V1必做","branch-im"],
|
||
["执行匹配","匹配KOC/KOL","将需求匹配给合适创作者","koc_kol_profile、task、risk","koc_kol_task","待分配 -> 待接受","KOC/KOL运营","是","V1预留","branch-koc"],
|
||
["计划调整","调整名额","增减计划数量","plan、progress、resource","plan_change_log","计划目标变化","运营、主管","是","V1必做","demand"],
|
||
["计划调整","暂停计划","禁止继续执行但保留历史","plan、risk、product","plan_log、notification","进行中 -> 暂停","主管","是","V1必做","demand"],
|
||
["计划调整","恢复计划","恢复已暂停计划","plan、product、risk","plan_log","暂停 -> 进行中","主管","是","V1必做","demand"],
|
||
["计划调整","转免评","普通测评/回评因店铺/订单/用户问题转免评","plan、order、reviewer","plan、order_log","测评/回评 -> 免评","运营、主管","是","V1必做","branch-free"],
|
||
["计划调整","关闭需求","需求完成或取消","demand、plan、progress","demand_close_log","需求:已关闭","主管","是","V1必做","demand"],
|
||
["测评计划","新建测评计划","从需求或人工创建计划","demand、product、asin","review_plan","草稿/未开始","运营","是","V1必做","orders"],
|
||
["测评计划","编辑计划","修改目标、渠道、周期、负责人","review_plan","plan_log","计划字段变化","运营、主管","是","V1必做","orders"],
|
||
["测评计划","复制关键词链接","运营执行用","review_plan","copy_event","-","运营","否","V1必做","orders"],
|
||
["测评计划","查看关联推送","查看计划下发的渠道任务","plan、push_task","-","-","运营、渠道","否","V1必做","branch-im"],
|
||
["测评计划","查看关联订单","查看计划履约订单","plan、order","-","-","运营","否","V1必做","branch-order"],
|
||
["回评计划","新建回评计划","因掉评/差评/维稳生成回评计划","asin、review_stats","reply_plan","待开始","运营","是","V1必做","orders"],
|
||
["回评计划","调整今日目标","根据评分/掉评变化调整当天目标","reply_plan、asin_stats","plan_log","今日目标变化","运营、主管","是","V1必做","orders"],
|
||
["免评计划","新建免评计划","给长期测评人/KOC-KOL/补单池创建免评计划","demand、reviewer、koc_kol","free_plan","待审批/进行中","运营","是","V1必做","branch-free"],
|
||
["测评订单","新增订单","记录测评执行单","plan、person、product","review_order","待上传回评/待登记","运营、客服","是","V1必做","branch-order"],
|
||
["测评订单","上传订单","绑定Amazon订单号","review_order、amazon_order","review_order、audit_log","订单:待登记 -> 已登记","运营、客服","是","V1必做","branch-order"],
|
||
["测评订单","上传回评","绑定评论ID/链接/截图","review_order、comment","review_submission","待回评 -> 待确认/已提交","运营、客服","是","V1必做","branch-order"],
|
||
["测评订单","提交排队","评论暂不能绑定,进入排队","review_order、comment_query","review_queue","待确认","运营、客服","是","V1必做","branch-order"],
|
||
["测评订单","请款","发起用户返款","review_order、refund_account","refund_request","待请款 -> 待审核","运营、客服","是","V1必做","branch-finance"],
|
||
["测评订单","更换订单","用新订单替代原订单","review_order、amazon_order","order_change_log","订单号变化","运营、主管","是","V1必做","branch-order"],
|
||
["测评订单","更改订单","修正订单字段","review_order","order_change_log","订单字段变化","运营、主管","是","V1必做","branch-order"],
|
||
["测评订单","撤销","撤销错误/风险订单","review_order、risk","order_log、quota_release","进行中 -> 撤销","风险、主管","是","V1必做","branch-order"],
|
||
["测评订单","批量导出","导出当前筛选结果","order、permission","export_task","-","有导出权限","是","V1必做","retro"],
|
||
["回评订单","回评确认","核验回评是否有效","review_submission、comment","review_display_check","待确认 -> 已回评/未通过","运营、审核","是","V1必做","branch-order"],
|
||
["工单池","自动分配","按在线、工单量、排班分配客服","ticket、agent、shift","ticket_assignment","待分配 -> 待处理","客服主管","是","V1必做","branch-cs"],
|
||
["工单池","手动分配","指定处理人","ticket、agent","ticket_assignment","待分配 -> 待处理","客服主管","是","V1必做","branch-cs"],
|
||
["工单池","转移工单","换客服处理","ticket、agent","ticket_transfer_log","处理人变化","客服、主管","是","V1必做","branch-cs"],
|
||
["我的工单","回复用户","处理用户消息","ticket、chat、context_snapshot","chat_message、ticket_log","待处理 -> 处理中/等待用户","客服","是","V1必做","branch-cs"],
|
||
["我的工单","登记订单","客服拿到订单号后登记","ticket、amazon_order、person","review_order、ticket_log","工单推进","客服","是","V1必做","branch-cs"],
|
||
["我的工单","催评","提醒用户提交评价","ticket、order、followup","reminder_event、followup","催评次数+1","客服、运营","是","V1必做","branch-cs"],
|
||
["我的工单","标记解决","用户问题解决","ticket","ticket_log","处理中 -> 已解决","客服","是","V1必做","branch-cs"],
|
||
["我的工单","关闭工单","完成或无需继续","ticket","ticket_log","已解决/等待用户 -> 已关闭","客服、主管","是","V1必做","branch-cs"],
|
||
["我的工单","重开工单","用户再次反馈","ticket","ticket_log","已关闭 -> 已重开/处理中","客服、主管","是","V1必做","branch-cs"],
|
||
["答应配合","确认答应","用户答应评价/反馈","ticket、person","support_followup","待确认 -> 已确认","客服","是","V1必做","branch-cs"],
|
||
["答应配合","拒绝","用户拒绝配合","ticket","support_followup","待确认 -> 已拒绝","客服","是","V1必做","branch-cs"],
|
||
["答应配合","标记过期","超时未提交","followup","support_followup","已确认 -> 已过期","客服、系统","是","V1必做","branch-cs"],
|
||
["出勤管理","导入出勤","导入当天/本月出勤","attendance_file","attendance_record","出勤记录更新","客服主管、人事","是","V1预留","cs-mgmt"],
|
||
["出勤管理","调整出勤状态","修正迟到/请假/缺勤","attendance_record","attendance_log","状态变化","客服主管","是","V1必做","cs-mgmt"],
|
||
["排班管理","设置班次","给客服设置早/午/晚班","agent、date","shift_schedule","排班变化","客服主管","是","V1必做","cs-mgmt"],
|
||
["排班管理","批量排班","一次生成多天排班","agent、date_range","shift_schedule","排班批量变化","客服主管","是","V1必做","cs-mgmt"],
|
||
["目标管理","设置月目标","设置RSO/RDO登记和上评目标","agent、period","support_target","目标变化","客服主管","是","V1必做","cs-mgmt"],
|
||
["绩效看板","导出绩效","导出回复/转化/目标完成","performance_snapshot","export_task","-","客服主管","是","V1必做","cs-mgmt"],
|
||
["IM推送","新增推送","创建IM触达任务","plan、audience、card","im_push_task","草稿/待发送","渠道运营","是","V1必做","branch-im"],
|
||
["IM推送","上架/下架","控制任务是否可执行","im_push_task","channel_log","已上架/已下架","渠道运营","是","V1必做","branch-im"],
|
||
["IM推送","批量分配","将任务分配到账号/渠道","push_task、im_account","assignment","待分配 -> 已分配","渠道运营","是","V1预留","branch-im"],
|
||
["IM卡片","新增卡片","创建卡片素材","product、h5","im_card","已上架/草稿","渠道运营","是","V1必做","branch-im"],
|
||
["IM卡片","下架卡片","产品禁用/素材失效时下架","im_card、product","card_log","已上架 -> 已下架","渠道运营","是","V1必做","branch-im"],
|
||
["EDM","检查基础设施","确认域名/邮箱/IP信誉","edm_config、deliverability","daily_check","健康/异常","EDM运营","否","V1必做","branch-edm"],
|
||
["EDM","创建AB Test","测试标题/素材/按钮","edm_campaign","ab_test","运行中","EDM运营","是","V1预留","branch-edm"],
|
||
["Phone","创建回拨任务","对未接/待跟进用户安排电话","tel_pool、agent_shift","tel_task","待拨打","Phone/客服","是","V1预留","branch-phone"],
|
||
["渠道配置","配置去重规则","定义跨IM/EDM/APP/Phone/KOC触达的去重、例外和频控条件","channel_config、person、risk、quota","channel_dedup_rule、channel_log","规则生效/停用","渠道主管、管理员","是","V1预留","channel"],
|
||
["线索池","新增线索","新增KOC/KOL候选人","source、contact","creator_profile","待审核","KOC/KOL运营","是","V1预留","branch-koc"],
|
||
["线索池","打标分层","区分新手KOC、稳定测评者、垂直专家、带货型KOL","creator_profile、metrics","creator_tag、tier_log","分层变化","KOC/KOL运营","是","V1预留","branch-koc"],
|
||
["任务管理","创建合作任务","样品、免评、内容、带货任务","demand、product、creator","creator_task","待接受","KOC/KOL运营","是","V1预留","branch-koc"],
|
||
["任务管理","分配样品/免评名额","执行合作资源分配","creator_task、inventory、quota","sample_order/free_order","待寄样/待执行","KOC/KOL运营","是","V1预留","branch-free"],
|
||
["内容记录","上传内容链接","记录发布内容","creator_task","content_record","待审核/已发布","KOC/KOL运营","是","V2实现","branch-free"],
|
||
["内容记录","审核内容","判断内容合规和是否可分发","content_record、content_policy","content_audit","通过/驳回","审核、运营","是","V2实现","branch-free"],
|
||
["带货归因","同步订单","记录Code/链接带来的订单","attribution、order","creator_order","待结算","KOC/KOL运营","是","V2实现","branch-free"],
|
||
["佣金结算","计算佣金","根据规则生成佣金","creator_order、commission_rule","commission_record","待审核","财务、运营","是","V2实现","branch-finance"],
|
||
["风险处理","暂停合作","风险/投诉/作弊时暂停","creator_profile、risk","creator_status_log","可合作 -> 暂停","风险、主管","是","V1预留","branch-koc"],
|
||
["真实人归并","手动合并","修正自动归并不足,把多个账号/身份线索合并到同一真实人","person、identity、quota_ledger、risk","person_identity_link、merge_log、quota_ledger","多个身份 -> 同一真实人","主管、风险、管理员","是","V1预留","people"],
|
||
["真实人归并","手动拆分","纠正误合并,拆开不同真实人","person、identity、quota_ledger、risk","person_identity_link、split_log、quota_ledger","同一真实人 -> 多个真实人","主管、风险、管理员","是","V1预留","people"],
|
||
["额度台账","查看额度明细","查看4/4/12额度、预占、释放、提交计数来源","person、quota_ledger、quota_reservation、review_submission","-","-","运营、客服主管、风险","否","V1必做","people"],
|
||
["互动复检","查看审计记录","追溯每次有效互动为什么继续、拦截或转人工","interaction_recheck、person、quota_ledger、risk","-","-","运营、风险、客服主管","否","V1必做","people"],
|
||
["风险事件","创建风险事件","人工或系统发现风险","person、order、refund、creator","risk_case","待复核","风险、系统","是","V1必做","risk-center"],
|
||
["风险事件","复核通过","确认风险","risk_case","risk_case、blacklist","复核中 -> 确认风险","风险","是","V1必做","risk-center"],
|
||
["风险事件","排除风险","解除误报","risk_case","risk_case","复核中 -> 排除","风险","是","V1必做","risk-center"],
|
||
["黑名单","新增黑名单","阻断后续触达/返款/合作","person、creator、identity","blacklist_item","生效中","风险","是","V1必做","risk-center"],
|
||
["退款比对","标记双重退款","Amazon退款+OA返款命中","refund_records","risk_signal","疑似/确认双重退款","风险、财务","是","V1必做","branch-finance"],
|
||
["返款","审核请款","付款前审核","refund_request、order、risk","refund_record","待审核 -> 待返款/失败","财务","是","V1必做","branch-finance"],
|
||
["返款","确认返款","完成付款/卡密发送","refund_record","refund_record、notification","待返款 -> 成功","财务","是","V1必做","branch-finance"]
|
||
].map((r, i) => ({ id: `ACT-${String(i + 1).padStart(3, "0")}`, page: r[0], name: r[1], meaning: r[2], read: r[3], write: r[4], change: r[5], role: r[6], audit: r[7], stage: r[8], route: r[9] }));
|
||
|
||
const sampleRows = [
|
||
{ id: "REQ-0528-001", type: "回评", asin: "B0USER001 / US", status: "待评估", owner: "USER运营A", risk: "P1", note: "评分低于4.5,客服容量不足" },
|
||
{ id: "PLAN-0528-006", type: "免评", asin: "B0USER019 / DE", status: "执行中", owner: "KOC运营B", risk: "P0", note: "长期测评人和KOC任务身份冲突" },
|
||
{ id: "CS-0528-033", type: "客服", asin: "B0USER011 / JP", status: "首次回复超时", owner: "客服主管", risk: "P1", note: "待转移工单,用户缺返款信息" },
|
||
{ id: "RISK-0528-009", type: "风险", asin: "真实人 P-8842", status: "强关联命中", owner: "风险审核", risk: "P0", note: "多账号归并后累计提交评价达到12" }
|
||
];
|
||
|
||
const state = { route: "dashboard", module: "overview", role: "owner", period: "day" };
|
||
|
||
const byId = id => document.getElementById(id);
|
||
const esc = value => String(value ?? "").replace(/[&<>"']/g, ch => ({ "&": "&", "<": "<", ">": ">", "\"": """, "'": "'" }[ch]));
|
||
const stageClass = stage => stage.includes("V2") ? "v2" : stage.includes("预留") ? "reserve" : "v1";
|
||
|
||
function init() {
|
||
renderShell();
|
||
const hashRoute = location.hash.replace("#", "");
|
||
setRoute(pages[hashRoute] ? hashRoute : "dashboard", false);
|
||
bindGlobalEvents();
|
||
}
|
||
|
||
function renderShell() {
|
||
byId("moduleRail").innerHTML = modules.map(m => `
|
||
<button class="rail-btn" data-module="${m.id}" title="${esc(m.title)}">
|
||
<span class="rail-icon">${esc(m.icon)}</span>
|
||
<span class="rail-label">${esc(m.label)}</span>
|
||
</button>
|
||
`).join("");
|
||
}
|
||
|
||
function renderPageNav(moduleId) {
|
||
const module = modules.find(m => m.id === moduleId);
|
||
byId("moduleTitle").textContent = module.title;
|
||
byId("moduleNote").textContent = module.note;
|
||
byId("pageNav").innerHTML = module.pages.map(id => {
|
||
const p = pages[id];
|
||
return `<button class="page-btn" data-route="${id}"><span>${esc(p.short)}</span><small>${esc(p.source)}</small></button>`;
|
||
}).join("");
|
||
document.querySelectorAll(".rail-btn").forEach(btn => btn.classList.toggle("active", btn.dataset.module === moduleId));
|
||
}
|
||
|
||
function setRoute(route, push = true) {
|
||
if (!pages[route]) route = "dashboard";
|
||
state.route = route;
|
||
state.module = pages[route].module;
|
||
renderPageNav(state.module);
|
||
renderContent();
|
||
document.querySelectorAll(".page-btn").forEach(btn => btn.classList.toggle("active", btn.dataset.route === route));
|
||
byId("topPageTitle").textContent = pages[route].title;
|
||
byId("topPageSubtitle").textContent = `${pages[route].owner} · 来源 ${pages[route].source} · ${state.period === "day" ? "日视图" : state.period === "week" ? "周视图" : "月视图"}`;
|
||
if (push) location.hash = route;
|
||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||
}
|
||
|
||
function pageHeader(p, actions = "") {
|
||
return `
|
||
<div class="page-head">
|
||
<div>
|
||
<div class="source-bar"><strong>需求来源</strong>${sourceDocs.map(d => `<span class="pill gray">${esc(d)}</span>`).join("")}<span class="pill amber">页面数据均为模拟</span></div>
|
||
<div class="spacer"></div>
|
||
<h1 class="page-title">${esc(p.title)}</h1>
|
||
<p class="page-desc">${esc(p.subtitle)}</p>
|
||
</div>
|
||
<div class="head-actions">
|
||
${actions}
|
||
<button class="btn" data-action="drawer" data-kind="source">查看来源</button>
|
||
<button class="btn primary" data-route="action-matrix">按钮矩阵</button>
|
||
</div>
|
||
</div>
|
||
`;
|
||
}
|
||
|
||
function renderContent() {
|
||
const p = pages[state.route];
|
||
if (state.route === "dashboard") return renderDashboard();
|
||
if (state.route === "role-workflow") return renderRoleWorkflow();
|
||
if (state.route === "action-matrix") return renderActionMatrix();
|
||
if (state.route === "exceptions") return renderExceptions();
|
||
if (state.route === "validation") return renderValidation();
|
||
if (pages[state.route]?.kind === "reference") return renderReferencePage(state.route);
|
||
return renderWorkflowPage(state.route);
|
||
}
|
||
|
||
function renderDashboard() {
|
||
const role = roles[state.role];
|
||
const html = `
|
||
${pageHeader(pages.dashboard, `<button class="btn" data-route="ref-demand-pool">完整操作台细化</button><button class="btn primary" data-route="demand">进入需求调度</button>`)}
|
||
<section class="grid cols-4">
|
||
${metric("P0/P1异常", "37", "直接影响今日目标、资金、合规或账号安全")}
|
||
${metric("今日必跟进", "84", "需求、计划、催评、返款、内容审核")}
|
||
${metric("资源压力", "5类", "人群、额度、客服、KOC/KOL、返款队列")}
|
||
${metric("待复盘", "7", "昨日TOP/BOTTOM和异常原因")}
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="grid cols-2">
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>当前角色:${esc(role.name)}</h2><p>切换右上角角色后,本卡片会更新每日工作重点。</p></div><span class="pill blue">角色视图</span></div>
|
||
<div class="panel-body grid cols-2">
|
||
${infoBox("每天先看", role.see, "green")}
|
||
${infoBox("今天不该先看", role.avoid, "amber")}
|
||
${infoBox("必须判断", role.judge, "blue")}
|
||
${infoBox("复盘数据", role.review, "purple")}
|
||
</div>
|
||
</article>
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>主业务闭环</h2><p>需求不是从推送开始,必须从需求进入到复盘闭环。</p></div><button class="btn small" data-route="demand">去调度</button></div>
|
||
<div class="panel-body">${flow(["需求进入","需求评估","产品校验","计划生成","执行匹配","渠道/客服/KOC任务","用户/达人响应","履约","风险复检","结果回流","复盘"] )}</div>
|
||
</article>
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="grid cols-2">
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>今日必须处理</h2><p>点击操作可打开详情或跳转对应页面。</p></div><span class="pill red">模拟</span></div>
|
||
<div class="panel-body grid">
|
||
${sampleRows.map(row => taskRow(row)).join("")}
|
||
</div>
|
||
</article>
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>主看板确认项</h2><p>交付前用于确认页面是否照顾每日工作流。</p></div><span class="pill green">已覆盖</span></div>
|
||
<div class="panel-body">
|
||
<ul class="list">
|
||
<li><strong>主看板</strong><span>P0/P1异常、今日任务、目标进度、资源压力、复盘入口都在首屏。</span></li>
|
||
<li><strong>分支看板</strong><span>IM、EDM、Phone、客服、评价订单、免评、财务、KOC/KOL、风险均有独立页面。</span></li>
|
||
<li><strong>按钮跳转</strong><span>03按钮盘点表已进入按钮行为矩阵,每个动作均可点击。</span></li>
|
||
<li><strong>口径提醒</strong><span>真实人、4/4/12、提交即计12、展示才计完成、免评独立结果口径均显式展示。</span></li>
|
||
<li><strong>模拟数据</strong><span>所有数据均标注为模拟,只用于本地点击和需求验证。</span></li>
|
||
</ul>
|
||
</div>
|
||
</article>
|
||
</section>
|
||
`;
|
||
byId("content").innerHTML = html;
|
||
}
|
||
|
||
function renderRoleWorkflow() {
|
||
byId("content").innerHTML = `
|
||
${pageHeader(pages["role-workflow"])}
|
||
<section class="role-grid">
|
||
${Object.entries(roles).map(([id, r]) => `
|
||
<button class="role-card ${state.role === id ? "active" : ""}" data-role-card="${id}">
|
||
<strong>${esc(r.name)}</strong>
|
||
<span>先看:${esc(r.see)}</span>
|
||
<span>不先看:${esc(r.avoid)}</span>
|
||
</button>
|
||
`).join("")}
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="panel">
|
||
<div class="panel-head"><div><h2>角色工作流要求</h2><p>用于确认工作人员每天进入系统时的优先级。</p></div><span class="pill blue">Stage 1</span></div>
|
||
<div class="panel-body table-wrap">
|
||
<table>
|
||
<thead><tr><th>角色</th><th>每天先看</th><th>今天不该先看</th><th>必须判断</th><th>复盘数据</th><th>入口</th></tr></thead>
|
||
<tbody>
|
||
${Object.entries(roles).map(([id, r]) => `<tr><td><strong>${esc(r.name)}</strong></td><td>${esc(r.see)}</td><td>${esc(r.avoid)}</td><td>${esc(r.judge)}</td><td>${esc(r.review)}</td><td><button class="btn small" data-route="${id === "cs" ? "branch-cs" : id === "koc" ? "branch-koc" : id === "finance" ? "branch-finance" : id === "risk" ? "branch-risk" : id === "channel" ? "branch-im" : "dashboard"}">进入</button></td></tr>`).join("")}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
`;
|
||
}
|
||
|
||
function renderWorkflowPage(route) {
|
||
const p = pages[route];
|
||
const data = workflowData[route] || workflowData.demand;
|
||
byId("content").innerHTML = `
|
||
${pageHeader(p, `<button class="btn primary" data-route="exceptions">看异常</button>`)}
|
||
<section class="grid cols-4">${data.metrics.map(m => metric(m[0], m[1], m[2])).join("")}</section>
|
||
<div class="spacer"></div>
|
||
<section class="grid cols-2">
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>工作人员每天该看什么</h2><p>先看会影响今日目标或阻断流程的项。</p></div><span class="pill green">先看</span></div>
|
||
<div class="panel-body"><ul class="list">${data.do.map(x => `<li><strong>${esc(x)}</strong><span>模拟检查项,可点击右侧动作继续。</span></li>`).join("")}</ul></div>
|
||
</article>
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>今天不该先看什么</h2><p>避免低价值页面占用操作时间或制造错误口径。</p></div><span class="pill amber">不要先看</span></div>
|
||
<div class="panel-body"><ul class="list">${data.dont.map(x => `<li><strong>${esc(x)}</strong><span>必要时由异常、工单或复盘入口进入。</span></li>`).join("")}</ul></div>
|
||
</article>
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="panel">
|
||
<div class="panel-head"><div><h2>流程点击路径</h2><p>按业务顺序模拟从入口到关闭或复盘。</p></div><button class="btn small" data-action="drawer" data-kind="flow" data-route-key="${route}">查看写入对象</button></div>
|
||
<div class="panel-body">${flow(data.steps)}</div>
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="grid cols-2">
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>流程问题点</h2><p>来自05异常流程,点击处理会打开演示抽屉。</p></div><span class="pill red">异常</span></div>
|
||
<div class="panel-body grid">${data.issues.map((x, idx) => `<div class="issue-row"><strong>${esc(x)}</strong><span>处理状态:待处理 -> 处理中 -> 待复核 -> 已关闭</span><button class="btn small" data-action="drawer" data-kind="issue" data-title="${esc(x)}" data-route-target="exceptions">处理演示</button></div>`).join("")}</div>
|
||
</article>
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>可执行按钮</h2><p>按钮来自03盘点表,可跳转或执行演示。</p></div><span class="pill blue">${data.actions.length} 项</span></div>
|
||
<div class="panel-body" style="display:flex;flex-wrap:wrap;gap:8px">${data.actions.map(name => {
|
||
const action = actionRows.find(a => a.name === name);
|
||
return action ? `<button class="btn small" data-action-id="${action.id}">${esc(name)}</button>` : `<button class="btn small" data-action="drawer" data-kind="generic" data-title="${esc(name)}">${esc(name)}</button>`;
|
||
}).join("")}</div>
|
||
</article>
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="panel">
|
||
<div class="panel-head"><div><h2>将来复盘数据</h2><p>用于下一轮计划、资源、渠道和人员调度。</p></div><button class="btn small" data-route="retro">进入复盘</button></div>
|
||
<div class="panel-body">${data.review.map(x => `<span class="pill gray" style="margin:0 6px 8px 0">${esc(x)}</span>`).join("")}</div>
|
||
</section>
|
||
`;
|
||
}
|
||
|
||
function renderReferencePage(route) {
|
||
const item = referencePages.find(p => p.id === route) || referencePages[0];
|
||
const idx = referencePages.findIndex(p => p.id === item.id);
|
||
const next = referencePages[idx + 1]?.id || "dashboard";
|
||
const prev = referencePages[idx - 1]?.id || "dashboard";
|
||
byId("content").innerHTML = `
|
||
${pageHeader(pages[route], `<button class="btn" data-route="${prev}">上一页</button><button class="btn primary" data-route="${next}">下一操作页</button>`)}
|
||
<section class="grid cols-4">${item.metrics.map(m => metric(m[0], m[1], m[2])).join("")}</section>
|
||
<div class="spacer"></div>
|
||
<section class="grid cols-2">
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>参考页面与业务定位</h2><p>来自完整参考原型的页面级操作细化,保留0-1需求重构的角色、流程、异常和复盘口径。</p></div><span class="pill blue">${esc(item.ref)}</span></div>
|
||
<div class="panel-body">
|
||
${infoBox("页面目标", item.intent, "blue")}
|
||
${item.note ? infoBox("关键口径", item.note, "amber") : infoBox("适用边界", "本页数据均为模拟,主要用于需求验证、按钮盘点和后续开发拆分。", "amber")}
|
||
</div>
|
||
</article>
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>工作人员每天该看什么</h2><p>该页作为具体操作台时,先看阻断当日执行的状态和任务。</p></div><span class="pill green">日常入口</span></div>
|
||
<div class="panel-body">
|
||
<ul class="list">
|
||
<li><strong>先看</strong><span>${esc(item.metrics.map(m => m[0]).join("、"))}</span></li>
|
||
<li><strong>不先看</strong><span>不先下钻低优先级历史明细,不绕过真实人额度、风险复检、客服容量和计划状态。</span></li>
|
||
<li><strong>必须判断</strong><span>是否继续执行、暂停、补量、转免评、升级客服/财务/风险或进入复盘。</span></li>
|
||
</ul>
|
||
</div>
|
||
</article>
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="panel">
|
||
<div class="panel-head"><div><h2>流程点击路径</h2><p>用于从完整参考原型的页面拆出可开发的点击路径。</p></div><button class="btn small" data-action="drawer" data-kind="flow" data-route-key="${route}">查看写入对象</button></div>
|
||
<div class="panel-body">${flow(item.steps)}</div>
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="grid cols-2">
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>可执行按钮</h2><p>按钮先做点击演示,后续 Stage 2 再拆 API、权限和日志。</p></div><span class="pill blue">${item.buttons.length} 项</span></div>
|
||
<div class="panel-body" style="display:flex;flex-wrap:wrap;gap:8px">
|
||
${item.buttons.map(name => `<button class="btn small" data-action="drawer" data-kind="generic" data-title="${esc(name)}">${esc(name)}</button>`).join("")}
|
||
<button class="btn small" data-route="action-matrix">查看按钮矩阵</button>
|
||
</div>
|
||
</article>
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>流程问题点</h2><p>本页要重点避免的执行偏差。</p></div><span class="pill red">异常入口</span></div>
|
||
<div class="panel-body">
|
||
<ul class="list">
|
||
<li><strong>口径错位</strong><span>测评/回评、免评、客服跟进、KOC任务不能混用完成口径。</span></li>
|
||
<li><strong>状态未闭环</strong><span>按钮写入后必须能回到计划、订单、风险或复盘对象。</span></li>
|
||
<li><strong>权限越界</strong><span>客服、财务、风险、KOC/KOL角色只能看到完成工作所需字段。</span></li>
|
||
<li><strong>模拟数据</strong><span>当前数值只用于验证页面结构,不能作为真实经营数据。</span></li>
|
||
</ul>
|
||
</div>
|
||
</article>
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="panel">
|
||
<div class="panel-head"><div><h2>将来复盘数据</h2><p>这些指标会进入计划、ASIN、渠道、客服、真实人、KOC/KOL和财务复盘。</p></div><button class="btn small" data-route="retro">进入复盘看板</button></div>
|
||
<div class="panel-body">${item.retro.map(x => `<span class="pill gray" style="margin:0 6px 8px 0">${esc(x)}</span>`).join("")}</div>
|
||
</section>
|
||
`;
|
||
}
|
||
|
||
function renderActionMatrix() {
|
||
byId("content").innerHTML = `
|
||
${pageHeader(pages["action-matrix"], `<button class="btn primary" data-route="dashboard">返回主看板</button>`)}
|
||
<section class="grid cols-4">
|
||
${metric("按钮动作", actionRows.length, "全部可点击")}
|
||
${metric("V1必做", actionRows.filter(a => a.stage.includes("V1必做")).length, "第一版关键动作")}
|
||
${metric("V1预留", actionRows.filter(a => a.stage.includes("预留")).length, "保留入口/字段/状态")}
|
||
${metric("V2实现", actionRows.filter(a => a.stage.includes("V2")).length, "后续完整能力")}
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="panel">
|
||
<div class="panel-head"><div><h2>03 功能页面按钮盘点表</h2><p>每行提供执行演示和页面跳转。点击后会打开抽屉或跳转,不存在死按钮。</p></div><span class="pill amber">模拟写入</span></div>
|
||
<div class="panel-body table-wrap">
|
||
<table>
|
||
<thead><tr><th>ID</th><th>页面</th><th>按钮/动作</th><th>业务含义</th><th>读/写对象</th><th>状态变化</th><th>权限</th><th>阶段</th><th>操作</th></tr></thead>
|
||
<tbody>
|
||
${actionRows.map(a => `
|
||
<tr>
|
||
<td>${a.id}</td>
|
||
<td>${esc(a.page)}</td>
|
||
<td><strong>${esc(a.name)}</strong></td>
|
||
<td>${esc(a.meaning)}</td>
|
||
<td><span class="pill gray">读</span> ${esc(a.read)}<br><span class="pill gray">写</span> ${esc(a.write)}</td>
|
||
<td>${esc(a.change)}</td>
|
||
<td>${esc(a.role)}<br>审计:${esc(a.audit)}</td>
|
||
<td><span class="stage ${stageClass(a.stage)}">${esc(a.stage)}</span></td>
|
||
<td class="actions-cell"><button class="btn small" data-action-id="${a.id}">执行演示</button><button class="btn small" data-route="${a.route}">跳转页面</button></td>
|
||
</tr>
|
||
`).join("")}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
`;
|
||
}
|
||
|
||
function renderExceptions() {
|
||
byId("content").innerHTML = `
|
||
${pageHeader(pages.exceptions, `<button class="btn primary" data-route="dashboard">返回作战台</button>`)}
|
||
<section class="grid cols-4">
|
||
${metric("P0", "9", "当天处理,主管可见")}
|
||
${metric("P1", "18", "24小时内处理")}
|
||
${metric("P2", "31", "责任人跟进")}
|
||
${metric("P3", "12", "观察项")}
|
||
</section>
|
||
<div class="spacer"></div>
|
||
<section class="grid">
|
||
${exceptionGroups.map(group => `
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>${esc(group[0])}</h2><p>发现方式、处理动作、关闭条件后续进入测试用例。</p></div><span class="pill red">${group[1].length}</span></div>
|
||
<div class="panel-body table-wrap">
|
||
<table>
|
||
<thead><tr><th>异常</th><th>处理</th><th>阶段</th><th>操作</th></tr></thead>
|
||
<tbody>${group[1].map(row => `<tr><td><strong>${esc(row[0])}</strong></td><td>${esc(row[1])}</td><td><span class="stage ${stageClass(row[2])}">${esc(row[2])}</span></td><td><button class="btn small" data-action="drawer" data-kind="issue" data-title="${esc(row[0])}" data-route-target="exceptions">处理演示</button></td></tr>`).join("")}</tbody>
|
||
</table>
|
||
</div>
|
||
</article>
|
||
`).join("")}
|
||
</section>
|
||
`;
|
||
}
|
||
|
||
function renderValidation() {
|
||
byId("content").innerHTML = `
|
||
${pageHeader(pages.validation)}
|
||
<section class="grid cols-2">
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>已参考原型</h2><p>原型是需求验证材料,不是生产底座。</p></div><span class="pill blue">06</span></div>
|
||
<div class="panel-body">
|
||
<ul class="list">
|
||
<li><strong>C:\\XCODE\\USER\\input\\user-review-system</strong><span>React/Vite原型,参考菜单、路由、订单、客服、渠道、风险页面。</span></li>
|
||
<li><strong>C:\\XCODE\\USER\\src\\user_erp_mvp_admin_prototype_v10.html</strong><span>参考左侧模块栏、顶部角色/周期、抽屉/弹窗后台布局。</span></li>
|
||
<li><strong>C:\\XCODE\\USER\\input\\客服执行.html</strong><span>参考客服执行、分配、排班、绩效、目标管理。</span></li>
|
||
<li><strong>C:\\XCODE\\USER\\input\\amazon_operator_test_entry.html</strong><span>参考提评入口、IM账号、推送策略。</span></li>
|
||
<li><strong>C:\\XCODE\\USER\\input\\IM 推送业务流.mm</strong><span>参考IM分层和流程,已修正为真实人口径。</span></li>
|
||
</ul>
|
||
</div>
|
||
</article>
|
||
<article class="panel">
|
||
<div class="panel-head"><div><h2>本原型补强方向</h2><p>覆盖现有原型缺口。</p></div><span class="pill green">已补</span></div>
|
||
<div class="panel-body">
|
||
<ul class="list">
|
||
<li><strong>需求与计划调度</strong><span>从需求池到计划、资源、人群、客服、渠道、KOC/KOL任务。</span></li>
|
||
<li><strong>客服核心需求</strong><span>客服执行和客服管理均有页面、动作、异常与复盘指标。</span></li>
|
||
<li><strong>KOC/KOL完整需求域</strong><span>线索、分层、任务、内容、带货、佣金、风险均进入页面。</span></li>
|
||
<li><strong>免评独立闭环</strong><span>免评不再和评价提交混为同一终点。</span></li>
|
||
<li><strong>按钮矩阵</strong><span>03中动作全部以可点击入口呈现。</span></li>
|
||
</ul>
|
||
</div>
|
||
</article>
|
||
</section>
|
||
`;
|
||
}
|
||
|
||
function metric(label, value, note) {
|
||
return `<article class="panel metric"><span>${esc(label)}</span><strong>${esc(value)}</strong><p>${esc(note)}</p></article>`;
|
||
}
|
||
|
||
function infoBox(title, text, tone) {
|
||
return `<div class="issue-row"><span class="pill ${tone}">${esc(title)}</span><strong>${esc(text)}</strong></div>`;
|
||
}
|
||
|
||
function flow(items) {
|
||
return `<div class="flow">${items.map(x => `<span class="flow-step">${esc(x)}</span>`).join("")}</div>`;
|
||
}
|
||
|
||
function taskRow(row) {
|
||
const target = row.type === "客服" ? "branch-cs" : row.type === "风险" ? "branch-risk" : row.type === "免评" ? "branch-free" : "demand";
|
||
return `<div class="task-row"><div><strong>${esc(row.id)} · ${esc(row.type)} · ${esc(row.status)}</strong><span>${esc(row.asin)} · ${esc(row.owner)} · ${esc(row.note)}</span></div><div><span class="pill ${row.risk === "P0" ? "red" : "amber"}">${esc(row.risk)}</span> <button class="btn small" data-route="${target}">进入</button></div></div>`;
|
||
}
|
||
|
||
function openDrawer(kind, payload = {}) {
|
||
const drawer = byId("drawer");
|
||
const mask = byId("drawerMask");
|
||
const title = byId("drawerTitle");
|
||
const note = byId("drawerNote");
|
||
const body = byId("drawerBody");
|
||
const foot = byId("drawerFoot");
|
||
let route = payload.route || payload.routeTarget || state.route;
|
||
if (kind === "source") {
|
||
title.textContent = "来源与模拟说明";
|
||
note.textContent = "本HTML为本地点击参考原型,所有业务数据均为模拟。";
|
||
body.innerHTML = `<ul class="list">${sourceDocs.map(d => `<li><strong>${esc(d)}</strong><span>已作为页面结构、按钮、分支、异常、复盘或验证依据。</span></li>`).join("")}</ul>`;
|
||
foot.innerHTML = `<button class="btn primary" data-route="validation">查看验证记录</button>`;
|
||
} else if (kind === "action") {
|
||
const a = actionRows.find(x => x.id === payload.id);
|
||
route = a.route;
|
||
title.textContent = `${a.id} · ${a.name}`;
|
||
note.textContent = `${a.page} · ${a.stage} · 审计:${a.audit}`;
|
||
body.innerHTML = `
|
||
${infoBox("业务含义", a.meaning, "blue")}
|
||
${infoBox("读取对象", a.read, "gray")}
|
||
${infoBox("写入对象", a.write, "gray")}
|
||
${infoBox("状态变化", a.change, "green")}
|
||
${infoBox("权限", a.role, "amber")}
|
||
<div class="source-bar"><strong>演示结果</strong><span>已模拟生成操作日志、通知、状态变化和复盘引用。</span><span class="pill amber">未写入真实系统</span></div>
|
||
`;
|
||
foot.innerHTML = `<button class="btn" data-route="action-matrix">返回矩阵</button><button class="btn primary" data-route="${a.route}">跳转到相关页面</button>`;
|
||
} else if (kind === "flow") {
|
||
const data = workflowData[payload.routeKey] || workflowData.demand;
|
||
title.textContent = "流程写入对象";
|
||
note.textContent = "模拟展示流程节点与后续Stage 2对象设计的关系。";
|
||
body.innerHTML = `${flow(data.steps)}<ul class="list">${data.steps.map((s, i) => `<li><strong>${esc(s)}</strong><span>模拟写入:状态日志、负责人、时间戳、复检结果、复盘引用 #${i + 1}</span></li>`).join("")}</ul>`;
|
||
foot.innerHTML = `<button class="btn primary" data-route="${payload.routeKey}">返回当前页</button>`;
|
||
} else {
|
||
title.textContent = payload.title || "处理演示";
|
||
note.textContent = "模拟从发现到关闭的异常状态流。";
|
||
body.innerHTML = `
|
||
${flow(["待发现","已发现","待处理","处理中","待复核","已关闭"])}
|
||
${infoBox("处理要求", "当天能影响目标、资金、合规或账号安全的异常按P0/P1进入主管视图。", "red")}
|
||
${infoBox("关闭条件", "必须有处理结论、责任人、操作日志、是否回流计划/客服/风险/复盘。", "green")}
|
||
`;
|
||
foot.innerHTML = `<button class="btn" data-route="exceptions">查看异常总表</button><button class="btn primary" data-route="${route}">跳转相关页面</button>`;
|
||
}
|
||
drawer.classList.add("open");
|
||
mask.classList.add("open");
|
||
}
|
||
|
||
function closeDrawer() {
|
||
byId("drawer").classList.remove("open");
|
||
byId("drawerMask").classList.remove("open");
|
||
}
|
||
|
||
function toast(text) {
|
||
const el = byId("toast");
|
||
el.textContent = text;
|
||
el.classList.add("open");
|
||
clearTimeout(window.__toastTimer);
|
||
window.__toastTimer = setTimeout(() => el.classList.remove("open"), 1800);
|
||
}
|
||
|
||
function bindGlobalEvents() {
|
||
document.body.addEventListener("click", event => {
|
||
const moduleBtn = event.target.closest("[data-module]");
|
||
if (moduleBtn) {
|
||
const mod = modules.find(m => m.id === moduleBtn.dataset.module);
|
||
if (mod) setRoute(mod.pages[0]);
|
||
return;
|
||
}
|
||
const routeBtn = event.target.closest("[data-route]");
|
||
if (routeBtn) {
|
||
closeDrawer();
|
||
setRoute(routeBtn.dataset.route);
|
||
return;
|
||
}
|
||
const actionBtn = event.target.closest("[data-action-id]");
|
||
if (actionBtn) {
|
||
openDrawer("action", { id: actionBtn.dataset.actionId });
|
||
return;
|
||
}
|
||
const action = event.target.closest("[data-action]");
|
||
if (action) {
|
||
if (action.dataset.action === "closeDrawer") closeDrawer();
|
||
if (action.dataset.action === "drawer") openDrawer(action.dataset.kind, action.dataset);
|
||
return;
|
||
}
|
||
const roleCard = event.target.closest("[data-role-card]");
|
||
if (roleCard) {
|
||
state.role = roleCard.dataset.roleCard;
|
||
byId("roleSelect").value = state.role;
|
||
renderContent();
|
||
toast(`已切换到:${roles[state.role].name}`);
|
||
}
|
||
});
|
||
|
||
byId("drawerMask").addEventListener("click", closeDrawer);
|
||
byId("roleSelect").addEventListener("change", event => {
|
||
state.role = event.target.value;
|
||
if (state.route === "dashboard" || state.route === "role-workflow") renderContent();
|
||
byId("topPageSubtitle").textContent = `${pages[state.route].owner} · 当前角色 ${roles[state.role].name}`;
|
||
toast(`角色视图:${roles[state.role].name}`);
|
||
});
|
||
|
||
byId("period").addEventListener("click", event => {
|
||
const btn = event.target.closest("button[data-period]");
|
||
if (!btn) return;
|
||
state.period = btn.dataset.period;
|
||
byId("period").querySelectorAll("button").forEach(b => b.classList.toggle("active", b === btn));
|
||
setRoute(state.route, false);
|
||
toast(`已切换为${btn.textContent}视图`);
|
||
});
|
||
|
||
byId("globalSearch").addEventListener("keydown", event => {
|
||
if (event.key !== "Enter") return;
|
||
openDrawer("generic", { title: `搜索:${event.target.value || "空关键词"}`, routeTarget: "demand" });
|
||
});
|
||
|
||
window.addEventListener("hashchange", () => {
|
||
const route = location.hash.replace("#", "");
|
||
if (route && route !== state.route && pages[route]) setRoute(route, false);
|
||
});
|
||
}
|
||
|
||
init();
|
||
</script>
|
||
</body>
|
||
</html>
|