// Three main views: DR Roster, Alert Triage, Dashboard Overview
function FilterChip({ active, onClick, children, dotColor }) {
return (
);
}
function TopBar({ now, activeTab = "dashboard", onSelectTab }) {
const time = now.toLocaleTimeString("zh-CN", { hour12: false });
return (
实时同步
{time}
·
{MOCK.GLOBAL.totalGroups.toLocaleString()} 群在册 · {MOCK.GLOBAL.activeToday} 今日活跃
);
}
function FilterBar({ view, setView, drFilter, setDrFilter, timeRange, setTimeRange, statusFilter, setStatusFilter }) {
return (
时间
{[["today","今日"],["week","本周"],["month","本月"]].map(([k,v]) => (
setTimeRange(k)}>{v}
))}
状态
setStatusFilter("all")}>全部
setStatusFilter("critical")} dotColor="var(--critical)">紧急
setStatusFilter("warning")} dotColor="var(--warning)">告警
setStatusFilter("silent")} dotColor="var(--silent)">沉默
DR
setDrFilter("all")}>全部 10 人
{MOCK.DRS.slice(0, 5).map(d => (
setDrFilter(d.id)}>
{d.name}
))}
{}} active={false}>+5
);
}
function StatStrip() {
const G = MOCK.GLOBAL;
return (
);
}
function RosterView({ density, drFilter, statusFilter, onOpenDr, onOpenGroup }) {
let drs = MOCK.DRS;
if (drFilter !== "all") drs = drs.filter(d => d.id === drFilter);
// sort by severity (criticals first, then warnings, then by score asc)
drs = [...drs].sort((a, b) =>
b.critical - a.critical ||
b.warning - a.warning ||
a.score - b.score
);
return (
);
}
function AlertsView({ statusFilter, drFilter, onOpenGroup }) {
let alerts = MOCK.ALERTS;
if (statusFilter !== "all") {
alerts = alerts.filter(a =>
statusFilter === "critical" ? a.severity === "critical" :
statusFilter === "warning" ? (a.severity === "warning" && a.type !== "silent") :
statusFilter === "silent" ? a.type === "silent" : true
);
}
if (drFilter !== "all") alerts = alerts.filter(a => a.drId === drFilter);
const grouped = {
critical: alerts.filter(a => a.severity === "critical"),
warning: alerts.filter(a => a.severity === "warning" && a.type !== "silent"),
silent: alerts.filter(a => a.type === "silent"),
};
const sectionDef = [
{ key: "critical", title: "紧急 · 立即处理", desc: "客户消息命中风险关键词或长时间未回复", color: "var(--critical)" },
{ key: "warning", title: "告警 · 待跟进", desc: "DR 响应超出 SLA", color: "var(--warning)" },
{ key: "silent", title: "沉默 · 关注", desc: "DR 已超过 24 小时未在群内发言", color: "var(--silent)" },
];
return (
{sectionDef.map(s => grouped[s.key].length > 0 && (
{s.title}
{grouped[s.key].length} 项
{s.desc}
{grouped[s.key].slice(0, 12).map(a => (
onOpenGroup(a.group)} />
))}
{grouped[s.key].length > 12 && (
还有 {grouped[s.key].length - 12} 项 · 展开全部 →
)}
))}
{sectionDef.every(s => grouped[s.key].length === 0) && (
✓
所有群组当前状态良好
无紧急告警、超时或沉默情况
)}
);
}
function OverviewView({ aiOn, onOpenDr, onOpenGroup }) {
const G = MOCK.GLOBAL;
const drsRanked = [...MOCK.DRS].sort((a, b) => a.score - b.score);
const nowHr = new Date().getHours();
return (
{aiOn && (
今日态势:共发现 {G.criticalAlerts} 起紧急告警与 {G.warningAlerts} 起一般告警。
周梓涵 名下 云汐科技-项目交付群 客户连续两次提到「退款」,建议优先介入;
黄俊杰 名下有 4 个群已超 24 小时无 DR 发言,请确认是否在休假。
全员平均响应时间为 {G.avgResponseMin} 分钟,较上周下降 12%。
)}
{/* DR 排行 */}
DR 健康度排行
10 人 · 升序
分值越低越需关注
#DR
14天活跃
响应/告警
分值
{drsRanked.map((d, i) => (
onOpenDr(d)}>
{String(i + 1).padStart(2, "0")}
{d.name}
{d.activeGroups} 群 · {d.todayMessages} 消息
{d.avgResponseMin}m
{(d.critical + d.warning) > 0 && (
0 ? "var(--critical)" : "var(--warning)", marginLeft: 6 }}>
⚠{d.critical + d.warning}
)}
{d.score}
))}
{/* Right column */}
24h 消息流量
总 {G.todayMessages} 条
{G.hourly.map((v, i) => {
const max = Math.max(...G.hourly);
return (
);
})}
0006121823
状态分布
{MOCK.GROUPS.length} 活跃群
{[
{ k: "critical", l: "紧急", n: MOCK.GROUPS.filter(g => g.status === "critical").length, c: "var(--critical)" },
{ k: "warning", l: "告警", n: MOCK.GROUPS.filter(g => g.status === "warning").length, c: "var(--warning)" },
{ k: "silent", l: "沉默", n: MOCK.GROUPS.filter(g => g.status === "silent").length, c: "var(--silent)" },
{ k: "healthy", l: "正常", n: MOCK.GROUPS.filter(g => g.status === "healthy").length, c: "var(--healthy)" },
].map(s => {
const pct = (s.n / MOCK.GROUPS.length) * 100;
return (
{s.l}
{s.n} · {pct.toFixed(0)}%
);
})}
{/* Top alert preview */}
{MOCK.ALERTS.slice(0, 6).map(a => (
onOpenGroup(a.group)} />
))}
);
}
// Drawer contents
function DRDetailContent({ dr, onOpenGroup, aiOn }) {
const groups = MOCK.groupsForDr(dr.id);
const [tab, setTab] = useState("groups");
return (
{/* DR header summary */}
{dr.name}
活跃 {dr.activeGroups} 群 · 总计 {dr.totalGroups} · 最近活跃 {fmtMin(dr.lastActiveMinutes)}
{aiOn && (
{dr.name} 今日共参与 {dr.todayMessages} 条消息,回复 {dr.todayReplies} 条;
{dr.critical > 0 && 有 {dr.critical} 个群处于紧急状态,}
{dr.silent > 0 && {dr.silent} 个群已沉默超过 24 小时,}
建议优先处理列表顶部的标红群组。
)}
{tab === "groups" && (
{groups.map(g => onOpenGroup(g)} />)}
)}
{tab === "stats" && (
)}
);
}
function GroupConvContent({ group, aiOn }) {
const dr = MOCK.DRS.find(d => d.id === group.drId);
const conv = MOCK.conversationFor(group.id);
return (
{group.name}
{group.members} 人 · 客户主联系人:{group.customerName}
{group.alerts.length > 0 && (
{group.alerts.map((a, i) => (
⚠ {a.label}
))}
)}
{aiOn && (
对话摘要:客户主要咨询集成方案进度,并追问报表 bug。
{group.status === "critical" && 最新一条消息含负面情绪关键词,需立即跟进。}
{group.status === "warning" && 客户已等待多次,建议尽快给出明确时间。}
)}
最近对话 · {conv.length} 条
{conv.map((m, i) => {
const flagged = m.who === "customer" && i === conv.length - 1 && group.status === "critical";
return (
{m.who === "dr" ? dr.initial : group.customerName[0]}
{m.text}
{m.author} · {fmtMin(m.minutesAgo)}
);
})}
);
}
Object.assign(window, {
TopBar, FilterBar, StatStrip, RosterView, AlertsView, OverviewView,
DRDetailContent, GroupConvContent
});