2026-09-10 10:57:40 +08:00
|
|
|
|
<section class="module" id="module-4">
|
|
|
|
|
|
<div class="module-inner">
|
|
|
|
|
|
<p class="eyebrow animate-in">模块 4 · 未接线</p>
|
|
|
|
|
|
<h1 class="module-title animate-in">菜单有 ≠ API 已接<br>Chat 还有 B 方案三端点</h1>
|
|
|
|
|
|
<p class="module-lead animate-in">
|
2026-09-10 22:30:07 +08:00
|
|
|
|
前端 P0 主链路已真接(含风控三页 · 问数标签 · Dashboard hooks),但仍有<strong>分析对话占位、看板无钻取</strong>等缝。
|
|
|
|
|
|
开发态若 Dashboard「先闪错再正常」,多半是 StrictMode 双请求——已用 <code>useAsyncSequence</code> 丢弃过期响应。
|
2026-09-10 10:57:40 +08:00
|
|
|
|
</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="screen animate-in">
|
2026-09-10 22:30:07 +08:00
|
|
|
|
<h2>仍开放 / 已修清单(2026-09-10)</h2>
|
2026-09-10 10:57:40 +08:00
|
|
|
|
<div class="pattern-cards">
|
|
|
|
|
|
<div class="pattern-card">
|
2026-09-10 22:30:07 +08:00
|
|
|
|
<h3>风控 UI</h3>
|
|
|
|
|
|
<p>台账筛选 · 适当性校验 · AML 扫描页已接 REST;高级运营能力仍简版。</p>
|
2026-09-10 10:57:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="pattern-card">
|
|
|
|
|
|
<h3>问数</h3>
|
2026-09-10 22:30:07 +08:00
|
|
|
|
<p><code>AnalystChatShell</code> 占位 · 真问数在 <code>AnalystQueryPage</code>(模板/缓存标签 + dashboard/assets)。</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="pattern-card">
|
|
|
|
|
|
<h3>竞态修复</h3>
|
|
|
|
|
|
<p><code>useAsyncSequence</code> 用于 Dashboard hooks、ChatPanel、风控/客户列表页等。</p>
|
2026-09-10 10:57:40 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="pattern-card">
|
|
|
|
|
|
<h3>游客</h3>
|
|
|
|
|
|
<p><code>VisitorChatWidget</code> 首页试聊 · 与登录 ChatPanel 不同 API。</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<h2>Chat 方案 B:三端点 + SSE 注意点</h2>
|
|
|
|
|
|
<div class="translation-block">
|
|
|
|
|
|
<div class="translation-code">
|
|
|
|
|
|
<span class="translation-label">会话 API</span>
|
|
|
|
|
|
<pre><code><span class="code-line">GET /api/chat/sessions</span>
|
|
|
|
|
|
<span class="code-line">GET /api/chat/sessions/{id}/messages</span>
|
|
|
|
|
|
<span class="code-line">POST /api/chat/sessions/{id}/close</span>
|
|
|
|
|
|
<span class="code-line">POST /api/chat/stream → customer SSE</span></code></pre>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="translation-english">
|
|
|
|
|
|
<span class="translation-label">白话</span>
|
|
|
|
|
|
<div class="translation-lines">
|
|
|
|
|
|
<p class="tl">列表/历史/关闭与发消息共用同一套鉴权(Bearer + X-Agent-Type)。</p>
|
|
|
|
|
|
<p class="tl">SSE 无心跳:断连可能留下半空回合——排障时查 session 表 + 是否 uvicorn 重启。</p>
|
|
|
|
|
|
<p class="tl">HashRouter:URL 带 <code>#</code>,生产 Nginx 要配 SPA fallback。</p>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="screen animate-in">
|
|
|
|
|
|
<h2>改 URL 进别人工作台</h2>
|
|
|
|
|
|
<p><code>RequireAuth</code> 只验「有没有 token」,<strong>不</strong>验「这个角色能不能进 /app/risk」。菜单隐藏 ≠ 安全——后端 <code>AGENT_ACCESS_MATRIX</code> 和平台 RBAC 才拒 403。</p>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="quiz-container" id="quiz-frontend-m4">
|
|
|
|
|
|
<div class="quiz-question-block"
|
|
|
|
|
|
data-correct="option-b"
|
|
|
|
|
|
data-explanation-right="对。前端藏菜单是 UX;越权要靠后端模块鉴权(deps.py)矩阵和 SessionGuard 403。"
|
|
|
|
|
|
data-explanation-wrong="仅改前端路由守卫不够,必须对后端入口断言。">
|
|
|
|
|
|
<h3 class="quiz-question">客户账号手动打开 /app/risk/alerts,只靠前端能拦住吗?</h3>
|
|
|
|
|
|
<div class="quiz-options">
|
|
|
|
|
|
<button class="quiz-option" data-value="option-a" onclick="selectOption(this)">
|
|
|
|
|
|
<div class="quiz-option-radio"></div><span>能,RequireAuth 够了</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button class="quiz-option" data-value="option-b" onclick="selectOption(this)">
|
|
|
|
|
|
<div class="quiz-option-radio"></div><span>不能,必须后端 risk 角色 + X-Agent-Type: risk</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button class="quiz-option" data-value="option-c" onclick="selectOption(this)">
|
|
|
|
|
|
<div class="quiz-option-radio"></div><span>能,Hash 路由自动 404</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="quiz-feedback"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<button class="quiz-check-btn" onclick="checkQuiz('quiz-frontend-m4')">检查答案</button>
|
|
|
|
|
|
<button class="quiz-reset-btn" onclick="resetQuiz('quiz-frontend-m4')">重做</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</section>
|