/* === Risk warning + SOP pages === */ /* global React, useToast, Icons */ const { useState: useWarnState, useMemo: useWarnMemo } = React; const LEVELS = { high: "高", mid: "中", low: "低" }; const TAG_CLASS = { 预警: "red", 安抚: "yellow", 增值: "green" }; const safeStr = (s, defaultVal = "") => (typeof s === "string" ? s : defaultVal); function PageRiskWarning({ openDrawer, onNav, watchState, setStage }) { const { products, CATEGORIES } = window.IRDATA; const [catFilter, setCatFilter] = useWarnState("all"); const [driverFilter, setDriverFilter] = useWarnState("all"); const list = watchState; // Resolve category for each event - prefer explicit bigClass, else from product const getCat = (e) => { if (e.bigClass) return e.bigClass; const p = products.find((pp) => pp.id === e.productId); return p?.catId; }; const filtered = useWarnMemo(() => list.filter((e) => { const cat = getCat(e); if (catFilter !== "all" && cat !== catFilter) return false; if (driverFilter !== "all" && e.driver !== driverFilter) return false; return true; }), [list, catFilter, driverFilter]); const counts = { high: list.filter((e) => e.level === "high").length, mid: list.filter((e) => e.level === "mid").length, low: list.filter((e) => e.level === "low").length, total: list.length }; const catCounts = {}; CATEGORIES.forEach((c) => {catCounts[c.id] = list.filter((e) => getCat(e) === c.id).length;}); return ( {/* Top stat row */}
高等级预警
{counts.high}
需立即处置
中等级预警
{counts.mid}
本周内跟进
低等级预警
{counts.low}
观察池
预警总数
{counts.total}
含投研驱动 {list.filter((e) => safeStr(e.driver).includes("投研")).length}
{/* Watchlist */}
内部强关注列表
大类: setCatFilter("all")}> 全部 {counts.total} {CATEGORIES.map((c) => setCatFilter(c.id)} style={catFilter === c.id ? { background: c.color, borderColor: c.color } : {}}> {c.name} {catCounts[c.id] || 0} )} 驱动: setDriverFilter("all")}>全部 setDriverFilter("产品驱动")}>产品驱动 setDriverFilter("投研驱动")}>投研驱动
{filtered.map((e) => { const p = products.find((pp) => pp.id === e.productId); const cat = CATEGORIES.find((c) => c.id === getCat(e)); return ( ); })} {filtered.length === 0 && }
产品 / 对象 大类 场景 驱动 标签 等级 触发原因
{p?.name || e.productId} {p?.code}
{cat && {cat.name}} {e.scene} {e.driver} {e.tag} {LEVELS[e.level]} {e.reason}
{Icons.empty}
暂无匹配的预警事件
); } function PageSOP({ openDrawer, watchState, setStage }) { const { products, STAGES, CATEGORIES } = window.IRDATA; const toast = useToast(); const list = watchState; const getCat = (e) => { if (e.bigClass) return e.bigClass; const p = products.find((pp) => pp.id === e.productId); return p?.catId; }; const counts = { stage0: list.filter((e) => e.stage === 0).length, stage1: list.filter((e) => e.stage === 1).length, valueAdd: list.filter((e) => e.tag === "增值").length, expire: 4 }; return (
{[ { label: "待一线确认", val: counts.stage0, color: "var(--red)" }, { label: "待客户触达", val: counts.stage1, color: "var(--orange)" }, { label: "可营销机会", val: counts.valueAdd, color: "var(--green)" }, { label: "今日到期任务", val: counts.expire, color: "var(--primary)" }]. map((m, i) =>
{m.label}
{m.val}
需在 24h 内处置
)}
售后 SOP · 处理流水
{list.map((e) => { const p = products.find((pp) => pp.id === e.productId); const cat = CATEGORIES.find((c) => c.id === getCat(e)); return (
{p?.name || e.productId}
{p?.code} · {p?.manager}
{cat ? {cat.name} : } {e.driver} {e.tag} {LEVELS[e.level]} · 等级
{e.scene}
{e.action}
{STAGES.map((s, i) =>
i ? "done" : e.stage === i ? "active" : "")}> {s.slice(0, 4)}
)}
{e.stage < STAGES.length - 1 ? : 已完成 }
); })}
); } function PageSystem() { return (
系统设置
{["账号与权限", "数据接入", "评分模型", "预警阈值", "通知偏好", "审计日志"].map((s, i) =>
{s}
)}
预警阈值配置
{[ { label: "最大回撤阈值 (%)", val: "6.0" }, { label: "净值单日下跌阈值 (%)", val: "1.5" }, { label: "波动率上升触发倍数", val: "1.6" }, { label: "夏普下降阈值", val: "0.5" }, { label: "卡玛恶化连续月份", val: "2" }, { label: "规模下降阈值 (%)", val: "15" }]. map((c, i) =>
{c.label}
{c.val}
)}
); } function PageWarnOverview({ onNav, watchState, setStage }) { const { products, STAGES, CATEGORIES } = window.IRDATA; const toast = useToast(); const list = watchState; const [catFilter, setCatFilter] = useWarnState("all"); const [driverFilter, setDriverFilter] = useWarnState("all"); const getCat = (e) => { if (e.bigClass) return e.bigClass; const p = products.find((pp) => pp.id === e.productId); return p?.catId; }; const riskCounts = { high: list.filter((e) => e.level === "high").length, mid: list.filter((e) => e.level === "mid").length, low: list.filter((e) => e.level === "low").length, total: list.length, }; const sopCounts = { stage0: list.filter((e) => e.stage === 0).length, stage1: list.filter((e) => e.stage === 1).length, valueAdd: list.filter((e) => e.tag === "增值").length, expire: 4, }; // Pick top urgent items: high-level + stage 0/1 const urgent = list .filter((e) => e.level === "high" || (e.level === "mid" && e.stage < 2)) .sort((a, b) => { const order = { high: 0, mid: 1, low: 2 }; return order[a.level] - order[b.level] || a.stage - b.stage; }) .slice(0, 6); // Full watchlist with filters applied const catCounts = {}; CATEGORIES.forEach((c) => { catCounts[c.id] = list.filter((e) => getCat(e) === c.id).length; }); const filtered = list.filter((e) => { const cat = getCat(e); if (catFilter !== "all" && cat !== catFilter) return false; if (driverFilter !== "all" && e.driver !== driverFilter) return false; return true; }); return ( {/* === 风险事件预警 metrics === */}
风险事件预警 · 实时概况
onNav("warn-risk")}>
高等级预警
{riskCounts.high}
需立即处置
onNav("warn-risk")}>
中等级预警
{riskCounts.mid}
本周内跟进
onNav("warn-risk")}>
低等级预警
{riskCounts.low}
观察池
onNav("warn-risk")}>
预警总数
{riskCounts.total}
含投研驱动 {list.filter((e) => safeStr(e.driver).includes("投研")).length}
{/* === 售后 SOP metrics === */}
售后 SOP · 任务概况
{[ { label: "待一线确认", val: sopCounts.stage0, color: "var(--red)", sub: "需 24h 内推进" }, { label: "待客户触达", val: sopCounts.stage1, color: "var(--orange)", sub: "投顾团队跟进" }, { label: "可营销机会", val: sopCounts.valueAdd, color: "var(--green)", sub: "增值事件" }, { label: "今日到期任务", val: sopCounts.expire, color: "var(--primary)", sub: "SLA 临近" }, ].map((m, i) => (
onNav("warn-sop")}>
{m.label}
{m.val}
{m.sub}
))}
{/* === 紧急处置清单 === */}
紧急处置清单
高等级或处于待确认/待触达阶段的事件 · 共 {urgent.length} 条
{urgent.map((e) => { const p = products.find((pp) => pp.id === e.productId); const cat = CATEGORIES.find((c) => c.id === getCat(e)); return ( ); })} {urgent.length === 0 && ( )}
产品 / 对象 大类 场景 驱动 标签 等级 触发原因 状态 / 推进
{p?.name || e.productId} {p?.code}
{cat && {cat.name}} {e.scene} {e.driver} {e.tag} {LEVELS[e.level]} {e.reason}
{STAGES.map((s, i) => (
i ? "done" : e.stage === i ? "active" : "")}> {s.slice(0, 4)}
))}
{e.stage < STAGES.length - 1 ? ( ) : ( 完成 )}
{Icons.empty}
当前无紧急事件
{/* === 内部强关注列表 === */}
内部强关注列表
大类: setCatFilter("all")}> 全部 {list.length} {CATEGORIES.map((c) => ( setCatFilter(c.id)} style={catFilter === c.id ? { background: c.color, borderColor: c.color } : {}}> {c.name} {catCounts[c.id] || 0} ))} 驱动: setDriverFilter("all")}>全部 setDriverFilter("产品驱动")}>产品驱动 setDriverFilter("投研驱动")}>投研驱动
{filtered.map((e) => { const p = products.find((pp) => pp.id === e.productId); const cat = CATEGORIES.find((c) => c.id === getCat(e)); return ( ); })} {filtered.length === 0 && ( )}
产品 / 对象 大类 场景 驱动 标签 等级 触发原因
{p?.name || e.productId} {p?.code}
{cat && {cat.name}} {e.scene} {e.driver} {e.tag} {LEVELS[e.level]} {e.reason}
{Icons.empty}
暂无匹配的事件
); } Object.assign(window, { PageRiskWarning, PageSOP, PageSystem, PageWarnOverview });