Jelajahi Sumber

fix(policy): 开发环境政策库改用本地 json,修「政策名称」点不开

政策详情面板的「政策名称」显示为纯文本,真因是两个数据源的字段不一致:
本地 public/merchant-agent/policies_public.v1.json 262 条里 261 条带
data.市级政策id,而远端 VITE_DOWNLOAD_URL 的 327 条一条都没有(它有的
policy_id 是 40 位、与该条 id 相同,属另一套 id 体系,拼不出一网通办地址)。
index.html 原本是远端优先,且远端带 CORS 头(实测 ACAO 会回显 localhost
与 gov 域),所以浏览器里远端确实会赢,于是取不到 id、生成不了链接。
此前怀疑的「HMR 状态陈旧」「走了兜底路径」两个猜测均排除。

改动:
- 新增环境变量 VITE_POLICY_LOCAL_FIRST:仅 .env.development 为 true,
  其余三份 env 显式写 false(四份都写,避免占位符不被替换)
- index.html 按该开关排来源顺序:开发环境本地优先、远端兜底;生产仍
  远端优先、本地兜底。失败日志按来源名打印,不再用布尔反推
- 新增 harness/tools/check-policy-sources.mjs(按约定不入库):对比两个
  来源的条数与字段覆盖率,并在远端补齐 id 后提醒可移除该开关

验证:npm run build 通过;生产产物 dist/index.html 的 localFirst 为 false
(生产行为未变),dev server(8083 与 8084)均为 true;dev 提供的本地 json
与仓库文件 sha256 一致(262 条 / 261 带 id);verify-policy-library.mjs
21/21 通过。

注意:生产环境「政策名称」仍不可点——远端那份没有 data.市级政策id,
属后端数据问题,需后端在远端补该字段;开发环境这份比远端少 65 条申报事项。

Co-Authored-By: Claude Code <noreply@anthropic.com>
gongtianxiao 3 hari lalu
induk
melakukan
6b69af8466
6 mengubah file dengan 49 tambahan dan 7 penghapusan
  1. 5 0
      .env.development
  2. 2 0
      .env.production
  3. 2 0
      .env.qingpu
  4. 2 0
      .env.test
  5. 14 0
      README.md
  6. 24 7
      index.html

+ 5 - 0
.env.development

@@ -24,6 +24,11 @@ VITE_PLUGIN_ASR = wss://human-card-mini.metamaker.cn/open
 # VITE_API="/api"
 VITE_USE_KNOWLEDGE_API=true
 VITE_DOWNLOAD_URL="https://qingpu-data-api.metamaker.cn/llm/download/"
+# 政策库优先用仓库内的本地副本(/merchant-agent/policies_public.v1.json)
+# 原因:远端那份 327 条**全都没有** data.市级政策id,取不到 id 就拼不出政策详情地址,
+# 表现为详情面板的「政策名称」是纯文本、点不开;本地这份 261/262 有该字段。
+# 仅开发环境打开(见 index.html),生产仍远端优先
+VITE_POLICY_LOCAL_FIRST="true"
 VITE_ASR="https://qingpu-data-api.metamaker.cn"
 VITE_XF_ASR="/asr"
 VITE_STREAM_SERVER="/stream"

+ 2 - 0
.env.production

@@ -4,6 +4,8 @@ VITE_ASR="wss://qingpu-data-api.metamaker.cn"
 VITE_STREAM_SERVER="//flv-enc.metamaker.cn"
 VITE_HUMAN_IDLE_MP4_URL="https://img.metamaker.cn/flv_generated_videos/a5c13fcc6339fae8a0492f60480ca03c.mp4"
 VITE_DOWNLOAD_URL="https://qingpu-data-api.metamaker.cn/llm/download/"
+# 政策库来源顺序:false = 远端优先、本地兜底(见 index.html)
+VITE_POLICY_LOCAL_FIRST="false"
 VITE_APP_KEY="e61a4f61170a4b2f8f88ee946e2e635b"
 VITE_STREAM_TOKEN="AW+11d70e17340143ac9ecbfd15c16bd4b9%3AMTczOTk1NjQ5OTp6PtY%2FSQyU2jrPXUEiDyPCEcQWsgq2WEFvz7eIAnJ3sQ%3D%3D"
 VITE_PARENT_ORIGIN = 'https://aixq.shqp.gov.cn/'

+ 2 - 0
.env.qingpu

@@ -5,6 +5,8 @@ VITE_ASR="wss://qingpu-data-api.metamaker.cn"
 VITE_XF_ASR="/asr"
 VITE_STREAM_SERVER="/stream"
 VITE_DOWNLOAD_URL="/api/download/"
+# 政策库来源顺序:false = 远端优先、本地兜底(见 index.html)
+VITE_POLICY_LOCAL_FIRST="false"
 VITE_APP_KEY="e61a4f61170a4b2f8f88ee946e2e635b"
 VITE_STREAM_TOKEN="AW+11d70e17340143ac9ecbfd15c16bd4b9%3AMTczOTk1NjQ5OTp6PtY%2FSQyU2jrPXUEiDyPCEcQWsgq2WEFvz7eIAnJ3sQ%3D%3D"
 VITE_PARENT_ORIGIN = 'https://aixq.shqp.gov.cn/'

+ 2 - 0
.env.test

@@ -7,5 +7,7 @@ VITE_HUMAN_IDLE_MP4_URL="https://img.metamaker.cn/flv_generated_videos/a5c13fcc6
 VITE_APP_KEY="e61a4f61170a4b2f8f88ee946e2e635b"
 VITE_STREAM_TOKEN="AW+eef97275de3740efad56300cf601eca2%3AMTczOTk1NjkzMzocw1%2F%2BDrD8OqaznNbK0mTFh6mQ75paDgztknq1PFq6UQ%3D%3D"
 VITE_USE_KNOWLEDGE_API=false
+# 政策库来源顺序:false = 远端优先、本地兜底(见 index.html)
+VITE_POLICY_LOCAL_FIRST="false"
 # 新版聊天协议后端(POST /api/chat,SSE),直连模式
 VITE_CHAT_API="http://192.168.2.23:8000"

+ 14 - 0
README.md

@@ -80,3 +80,17 @@
     零散对应、且混有内网地址(25 条指向 `http://10.235.238.34:7202/imanage/login`),
     不能作为来源。`市级政策id` 有 261/262 条,可靠
   - 没有 id 时不给链接(**不猜**),宁可没有也不指向打不开的地址
+- 查明「政策名称」显示为纯文本的真因,并调整政策库数据源(**开发环境改用本地 json**):
+  - 政策库其实有**两个来源**,字段并不一致:
+    - 本地 `public/merchant-agent/policies_public.v1.json`:262 条,`data.市级政策id` 有 **261** 条
+    - 远端 `VITE_DOWNLOAD_URL`:327 条,该字段**一条都没有**(它有的 `policy_id` 是 40 位、
+      与条目 `id` 相同,与 24 位的 市级政策id 是**两套 id 体系**)
+  - 而 `index.html` 原本是**远端优先**(远端带 CORS 头,浏览器里确实会赢),
+    于是取不到 id → 拼不出详情地址 → 「政策名称」是纯文本。
+    此前怀疑的「HMR 状态陈旧」「走了兜底路径」均**排除**
+  - 新增环境变量 `VITE_POLICY_LOCAL_FIRST`:**仅开发环境**打开(本地优先、远端兜底),
+    **生产仍远端优先**——生产该问题属后端数据缺失,需远端那份补上 `data.市级政策id`,
+    前端无法修
+  - 新增 `harness/tools/check-policy-sources.mjs`:对比两个来源的条数与字段覆盖率,
+    并在「远端也带上 id 了」时提醒可以移除该开关
+  - 代价:开发环境用的这份比远端少 65 条申报事项(262 vs 327)

+ 24 - 7
index.html

@@ -274,21 +274,38 @@
               );
             }
 
-            function loadPolicies(url, isFallback) {
-              return fetch(url)
+            function loadPolicies(source) {
+              return fetch(source.url)
                 .then(function (response) {
                   if (!response.ok) throw new Error("HTTP " + response.status);
                   return response.json();
                 })
                 .then(function (data) {
-                  applyPolicies(data, isFallback ? "local" : "remote");
+                  applyPolicies(data, source.label);
                 });
             }
 
-            loadPolicies(downloadURL, false).catch(function (err) {
-              console.warn("[zhaoshang] 政策列表下载失败,尝试本地兜底:", err);
-              loadPolicies(localFallbackURL, true).catch(function (fallbackErr) {
-                console.warn("[zhaoshang] 本地政策列表也加载失败:", fallbackErr);
+            // 开发环境优先读本地副本:远端那份 327 条全都没有 data.市级政策id,
+            // 政策详情面板的「政策名称」会因此拼不出地址、点不开;本地这份有 261/262。
+            // 由 VITE_POLICY_LOCAL_FIRST 控制(仅 .env.development 为 true)
+            var localFirst = "%VITE_POLICY_LOCAL_FIRST%" === "true";
+            var sources = localFirst
+              ? [
+                  { url: localFallbackURL, label: "local" },
+                  { url: downloadURL, label: "remote" },
+                ]
+              : [
+                  { url: downloadURL, label: "remote" },
+                  { url: localFallbackURL, label: "local" },
+                ];
+
+            loadPolicies(sources[0]).catch(function (err) {
+              console.warn(
+                "[zhaoshang] 政策列表(" + sources[0].label + ")加载失败,尝试另一个来源:",
+                err
+              );
+              loadPolicies(sources[1]).catch(function (fallbackErr) {
+                console.warn("[zhaoshang] 政策列表两个来源都加载失败:", fallbackErr);
                 globalThis.policiesPublic = [];
               });
             });