Browse Source

chore(env): 环境只保留开发与生产(用户要求),删除 qingpu / test 两个模式

用户要求:「环境只保留开发和生产环境」。

动手前先 diff(这次没踩坑):.env.qingpu 里有两项 production 没有的配置 ——
VITE_DOWNLOAD_URL="/api/download/" 与 VITE_REDIRECT_MAP(production 完全没有)。
若直接删文件,redirect.html 里的 %VITE_REDIRECT_MAP% 会原样留在产物里,
那行 var redirectMap = …; 直接语法错误 —— 也就是说:以前 npm run build 打出来的生产包,
那个页面本来就是坏的,只有 qingpu 构建是对的;这次合并顺带修掉了。
.env.test 独有的只是测试主机与 VITE_USE_KNOWLEDGE_API=false,无保留价值。

改动:
- 把 qingpu 那两项合并进 .env.production(各自加了说明注释:/api/download/ 需部署侧 nginx
  转发;VITE_REDIRECT_MAP 不能缺),然后删 .env.qingpu / .env.test
- package.json:删 build:qingpu / build:test;保留 zip;新增 deploy:qingpu = build + zip
- index.html:删掉两处本来就是死的 qingpu 分支(globalThis.isQingpuEnv 写的是字面量 "MODE"、
  永远 false 且无人读;let isLanMode = … 赋值后从未使用);
  ["development","test"].includes(mode) 改为 mode === "development"

验证:npm run build 通过;产物核对 dist/redirect.html 的 redirectMap 有值、
dist/index.html 的 downloadURL = "/api/download/" + …(合并确实生效);dev server 正常;
NLS 43/43、附件 57/57、toast 27/27、DMS 字段契约 19/19、DMS 端到端 89/89、validate-harness 通过。

⚠️ 新发现的待清理项(只报告,未动):index.html 的 initToken()(openid_to_token + VITE_APP_KEY)
挂在 if (isKnowledgeApi) else initToken() 的 else 上,而 VITE_USE_KNOWLEDGE_API 在剩下两个 env
里都是 true(唯一为 false 的 .env.test 已删)—— 这条路径两个环境都走不到;删它前要先理清它与
initCardInfo() 的关系。已记进 current-api-call-sites.md §6。

Co-Authored-By: Claude Code <noreply@anthropic.com>
gongtianxiao 1 tháng trước cách đây
mục cha
commit
6f15af69f4

+ 17 - 3
.env.production

@@ -1,6 +1,5 @@
 VITE_VERSION=${npm_package_version}
 VITE_API="//qingpu-data-api.metamaker.cn"
-VITE_DOWNLOAD_URL="https://qingpu-data-api.metamaker.cn/llm/download/"
 # 政策库来源顺序:false = 远端优先、本地兜底(见 index.html)
 VITE_POLICY_LOCAL_FIRST="false"
 VITE_APP_KEY="e61a4f61170a4b2f8f88ee946e2e635b"
@@ -11,11 +10,26 @@ VITE_USE_KNOWLEDGE_API=true
 # 生产部署时请改为实际后端地址(当前为内网测试地址)
 VITE_CHAT_API="http://192.168.2.23:8000"
 
-# 取 OSS 上传签名的接口(当前为厂商 metamaker 提供,实测无需鉴权)。
-# 换自建签名服务时只改这里(见 harness/docs/reference/current-api-call-sites.md)
+# 政策库 json 的下载前缀(index.html 用它拼 `merchant-agent/policies_public.v1.json`)。
+# ⚠️ 这个值**原先只写在 `.env.qingpu` 里**:2026-09-24 用户要求「环境只保留开发和生产」,
+#    合并进 production。走同源 `/api/download/`(由部署侧 nginx 转发,与 `/ip-api/` 同理),
+#    而不是直连厂商域名 —— 如果部署侧没有这个转发,改回绝对地址即可。
+VITE_DOWNLOAD_URL="/api/download/"
+
+# 跳转映射(`redirect.html` 用:`?redirect=<key>` → 目标地址)。
+# ⚠️ 同样原先只在 `.env.qingpu` 里,2026-09-24 合并进 production。
+# **不能删**:缺了它 redirect.html 里的 `%VITE_REDIRECT_MAP%` 会原样留下、页面脚本直接语法错误。
+VITE_REDIRECT_MAP={"demo":"https://demo.heijingai.com/FTA-c2p/%23/overview","zhaoshang":"https://demo.heijingai.com/policy-application/%23/"}
 
 # 取本机 IP 的接口(DMS 访客归属:访客_<IP>,见 src/utils/client-ip.ts)
 # ⚠️ 它只有 HTTP,页面是 HTTPS —— 生产**必须由 nginx 把 /ip-api/ 转发到
 #    http://121.43.55.7:10011/ 并去掉前缀**,否则请求会被浏览器按混合内容拦掉
 #    (拦掉不致命:拿不到 IP 会退回 访客_<浏览器随机 id>,只是访客归属不稳定)
 VITE_IP_API="/ip-api"
+
+# 阿里云 NLS 的 token 端点(实时语音识别)—— 后端网关提供,同源路径
+# ⚠️ 生产**必须由 nginx 把 /aly-api/ 转发到 http://121.43.55.7:10011/** (去前缀,与 /ip-api/ 同法)
+VITE_NLS_TOKEN_API="/aly-api/proxy/verify/getALYToken"
+# ⚠️ NLS 的 appkey:**不是密钥**,但按约定不写进仓库文件 —— 由部署侧注入
+#    (开发期在 .env.development.local)。缺了它识别请求会被网关拒。
+# VITE_NLS_APPKEY="<部署时注入>"

+ 0 - 21
.env.qingpu

@@ -1,21 +0,0 @@
-VITE_VERSION=${npm_package_version}
-VITE_API="//qingpu-data-api.metamaker.cn"
-VITE_DOWNLOAD_URL="/api/download/"
-# 政策库来源顺序:false = 远端优先、本地兜底(见 index.html)
-VITE_POLICY_LOCAL_FIRST="false"
-VITE_APP_KEY="e61a4f61170a4b2f8f88ee946e2e635b"
-VITE_PARENT_ORIGIN = 'https://aixq.shqp.gov.cn/'
-VITE_MODEL_SERVER="https://qingpu-data-api.metamaker.cn/llms/qingpu"
-VITE_USE_KNOWLEDGE_API=true
-VITE_CHAT_API="http://192.168.2.23:8000"
-
-VITE_REDIRECT_MAP={"demo":"https://demo.heijingai.com/FTA-c2p/%23/overview","zhaoshang":"https://demo.heijingai.com/policy-application/%23/"}
-
-# 取 OSS 上传签名的接口(当前为厂商 metamaker 提供,实测无需鉴权)。
-# 换自建签名服务时只改这里(见 harness/docs/reference/current-api-call-sites.md)
-
-# 取本机 IP 的接口(DMS 访客归属:访客_<IP>,见 src/utils/client-ip.ts)
-# ⚠️ 它只有 HTTP,页面是 HTTPS —— 生产**必须由 nginx 把 /ip-api/ 转发到
-#    http://121.43.55.7:10011/ 并去掉前缀**,否则请求会被浏览器按混合内容拦掉
-#    (拦掉不致命:拿不到 IP 会退回 访客_<浏览器随机 id>,只是访客归属不稳定)
-VITE_IP_API="/ip-api"

+ 0 - 17
.env.test

@@ -1,17 +0,0 @@
-VITE_VERSION=${npm_package_version}
-VITE_API="//human-card-mini.metamaker.cn"
-VITE_APP_KEY="e61a4f61170a4b2f8f88ee946e2e635b"
-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"
-
-# 取 OSS 上传签名的接口(当前为厂商 metamaker 提供,实测无需鉴权)。
-# 换自建签名服务时只改这里(见 harness/docs/reference/current-api-call-sites.md)
-
-# 取本机 IP 的接口(DMS 访客归属:访客_<IP>,见 src/utils/client-ip.ts)
-# ⚠️ 它只有 HTTP,页面是 HTTPS —— 生产**必须由 nginx 把 /ip-api/ 转发到
-#    http://121.43.55.7:10011/ 并去掉前缀**,否则请求会被浏览器按混合内容拦掉
-#    (拦掉不致命:拿不到 IP 会退回 访客_<浏览器随机 id>,只是访客归属不稳定)
-VITE_IP_API="/ip-api"

+ 10 - 0
README.md

@@ -422,6 +422,16 @@
     `harness/tools/get-nls-token.mjs` 与 dev 端点共用;带 5 分钟提前刷新 + 并发去重
   - 验证:端点 200;**拿端点发的 token 真调通一次识别**(`status:20000000 SUCCESS`);
     `npm run build` 后**产物里搜三个凭据值 0 命中**
+- **环境只保留开发与生产**(用户 2026-09-24):删掉 qingpu / test 两个构建模式 ——
+  `.env.qingpu` / `.env.test` 删除前,先把它俩**独有的配置合并进 `.env.production`**:
+  `VITE_DOWNLOAD_URL="/api/download/"` 与 **`VITE_REDIRECT_MAP`**(后者 production 原本没有,
+  直接删会让 `redirect.html` 的产物变成 JS 语法错误 —— **顺带修掉了**:以前 `npm run build`
+  打出来的生产包里那个页面就是坏的)
+  - 脚本:删 `build:qingpu` / `build:test`,保留 `zip`,新增 `npm run deploy:qingpu`(= build + zip)
+  - `index.html` 里两处**本来就是死的** qingpu 分支一并删掉(`isQingpuEnv` 写的是字面量 `"MODE"`、
+    永远 false 且无人读;`isLanMode` 赋值后从未使用)
+  - 另记一个**待清理项**(未动):`initToken()`(`openid_to_token` + `VITE_APP_KEY`)现在两个
+    环境都走不到(唯一为 false 的 test 环境已删),删它前要先理清与 `initCardInfo()` 的关系
 - **死代码清理**(用户 2026-09-24「B 全部删掉」,清单见
   [`harness/docs/reference/current-api-call-sites.md`](harness/docs/reference/current-api-call-sites.md)):
   - 删掉:厂商 OSS 上传的停用实现(含 `VITE_UPLOAD_SIGN_URL`)、旧厂商 ASR 全套

+ 2 - 2
harness/docs/exec-plans/tech-debt-tracker.md

@@ -97,7 +97,7 @@
 ### 9. 生产 / 青浦构建没配 DMS:附件传不上去、DMS 落库静默跳过
 
 - **是什么**:`.env.development` 里有 `VITE_DMS_API="/dms-api"` + `VITE_DMS_TARGET`,
-  而 `.env.production` / `.env.qingpu` / `.env.test` **三份都没有**。
+  而 `.env.production` **也没有**(2026-09-24 起只剩开发/生产两份 env,见 progress.md 续 38)。
   这些环境构建出的包里 `getDmsApiBaseUrl()` 返回空串,后果两条:
   ①`uploadDmsAttachment` 直接抛「未配置 DMS 接口地址,无法上传附件」→ **附件功能在这些环境整体不可用**;
   ②DMS 会话/问答/反馈请求走 `client.ts` 的「未配置就跳过」,**静默不落库**。
@@ -123,7 +123,7 @@
 > vite 里那段自签中间件已删除。
 > **剩下的(部署侧,仍未做)**:
 > ① nginx 把 `/aly-api/` 转发到 `http://121.43.55.7:10011/`(去掉前缀,与 `/ip-api/` 同法);
-> ② **生产三份 env 都要配 `VITE_NLS_APPKEY`**(实测:`.env.production` / `.env.qingpu` / `.env.test`
+> ② **生产 env 要配 `VITE_NLS_APPKEY`**(实测:`.env.production`
 > 都没有 → 生产构建打出来的包里 appkey 为空 → 识别会失败)。
 > 详见 [`../reference/asr-nls.md`](../reference/asr-nls.md)。
 

+ 10 - 8
harness/docs/reference/asr-realtime.md

@@ -179,16 +179,18 @@ asr.clear();
 `openMicroPhone()` → `openSocket()` → (录)→ `await asr.transform()` 一次性拿整段文本。
 SDK 注释说这是"手机长按说话"的形态。当前两端都没走这条路。
 
-## 8. 环境变量现状(2026-09-23)
+## 8. 环境变量现状
 
-| 变量 | 开发 | 生产 | 青浦 | 测试 | 用在哪 |
-|---|---|---|---|---|---|
-| `VITE_ASR` | `https://qingpu-data-api.metamaker.cn` | `wss://qingpu-data-api.metamaker.cn` | `wss://…` | `https://…` | **当前分支的 socket host**(只取 host,协议按页面推) |
-| `VITE_XF_ASR` | `/asr` | (无) | `/asr` | (无) | 讯飞分支:既做 gen_auth 前缀,也做 socket host(走 vite 代理) |
-| `VITE_APP_KEY` | 有值 | 有值 | 有值 | 有值 | 语音这边用不到;**但不是死配置** —— `index.html` 的 `openid_to_token` 在用(2026-09-24 更正:只 grep `src/` 会误判) |
+**这套实现用到的变量已全部删除**(2026-09-24,用户要求「B 全部删掉」):
 
-> `VITE_ASR` 写成 `https://…` 或 `wss://…` 都能用(SDK 只取 `.host`);写成 `/asr` 这种相对路径则
-> host 取当前页面域名 —— 这条早先的写法在 `.env.qingpu` 里以注释形式留着一行(`# VITE_ASR="/asr"`)。
+| 变量 | 原来是什么 | 现在 |
+|---|---|---|
+| `VITE_ASR` | 厂商 `asr_hub` 的 socket host(`https://…` 或 `wss://…` 都行,SDK 只取 `.host`) | **已删**(四份 env 里的定义 + 实现一起删) |
+| `VITE_XF_ASR` | 讯飞分支前缀(`/asr`),既做 `gen_auth` 前缀也做 socket host(走 vite 代理) | **已删**(连同 vite 的 `/asr/` 代理) |
+| `index.html` 的 `globalThis.isXF` | 讯飞分支开关(硬编码 `false`) | **已删** |
+
+> `VITE_APP_KEY` 语音这边用不到,**但不是死配置** —— `index.html` 的 `openid_to_token` 在用
+> (2026-09-24 更正:只 grep `src/` 会误判)。
 
 ## 9. 已知行为与坑(**改之前先读**)
 

+ 15 - 5
harness/docs/reference/current-api-call-sites.md

@@ -66,10 +66,15 @@
 
 `VITE_API`(#8 + index.html 的 modelServer)· `VITE_CHAT_API` · `VITE_DMS_API` · `VITE_IP_API` ·
 `VITE_NLS_TOKEN_API` · `VITE_NLS_APPKEY` · `VITE_DOWNLOAD_URL` · `VITE_POLICY_LOCAL_FIRST` ·
-`VITE_MODEL_SERVER` · `VITE_PARENT_ORIGIN` · `VITE_REDIRECT_MAP` · `VITE_APP_KEY` · `VITE_VERSION` ·
+`VITE_MODEL_SERVER` · `VITE_PARENT_ORIGIN` · `VITE_REDIRECT_MAP` · `VITE_VERSION` ·
 四个 `*_TARGET`(vite 代理用)· `VITE_USE_KNOWLEDGE_API`(经 `globalThis.isKnowledgeApi`,
 **`index.html` 在用它切「政策解读」卡片** —— 2026-09-24 更正:只 grep `src/` 会把它误判成死配置)。
-(`VITE_ASR` / `VITE_XF_ASR` 已随旧 ASR 删除。)
+(`VITE_ASR` / `VITE_XF_ASR` 已随旧 ASR 删除;`VITE_APP_KEY` 只在 §6 那条**已走不到**的
+`openid` 路径里用 —— 见 §6。)
+
+**环境只剩两份(2026-09-24 用户要求)**:`.env.development` + `.env.development.local`(本机凭据,
+gitignored)+ `.env.production`。`qingpu` / `test` 两个模式已删除,脚本也随之调整
+(`npm run build` 出生产包,`npm run zip` 打部署 zip,`npm run deploy:qingpu` = 两者串起来)。
 
 ## 一、已经迁到新接口的(不用管)
 
@@ -191,10 +196,15 @@ wss://{VITE_XF_ASR}/api/human_asr/v2/asr?Authorization=...
 - 现状:`fetchPolicyList` 里前面两档(惠企政策库 262 条 / 本轮卡片兜底)**几乎总能命中**,
   第三档基本走不到
 
-### 6. `openid` 换 token —— **只在 test 构建**
+### 6. `openid` 换 token —— **⚠️ 现在走不到了(2026-09-24 起)**
 
-- 触发:页面初始化的内联脚本
-- 现状:只在 `VITE_USE_KNOWLEDGE_API === false` 时执行,四份 env 里**只有 `.env.test` 是 false**
+- 触发:`index.html` 的 `initToken()`(`POST {modelServer}/open/openid_to_token`,带 `app_key=VITE_APP_KEY`)
+- 现状:它挂在 `if (globalThis.isKnowledgeApi) {…} else { initToken(); }` 的 **else** 上,
+  而 `isKnowledgeApi` 来自 `VITE_USE_KNOWLEDGE_API` —— **开发与生产两个 env 都是 `true`**。
+  原先唯一为 `false` 的是 `.env.test`,该环境已按用户要求删除 → **这条路径在两个环境里都执行不到**。
+- **待用户决定**:`initToken()` / `VITE_APP_KEY` / 那段 `openid` 引导可以删(删前要确认
+  `cardInfo` 的另一条来源足够 —— `isKnowledgeApi` 分支里是写死的「政策解读」卡片,
+  生产实际用的是 `initCardInfo()` 拉回来的卡片,两者关系需先理清)。
 
 ### 6b. 附件上传 —— **已改走 DMS 文件服务(2026-09-23)**
 

+ 37 - 0
harness/progress.md

@@ -4208,6 +4208,43 @@ payload 里含模型里**不存在**的列时,`addContent` 会忽略该列照
 其实 **`index.html` 第 321 行在用它**切「政策解读」卡片 → **没删**,并在清单里更正。
 (同上次 `VITE_APP_KEY` 的教训 —— **`index.html` 里的内联脚本必须一起 grep**。)
 
+### 续 38:环境只保留开发与生产(用户要求)
+
+**用户要求**:「环境只保留开发和生产环境」→ 删掉 `qingpu` 与 `test` 两个构建模式。
+
+**动手前先查牵连**(这次没踩坑,因为先 diff 了):
+- `.env.qingpu` 里有**两项 production 没有的配置**:`VITE_DOWNLOAD_URL="/api/download/"`
+  (生产是绝对地址)和 **`VITE_REDIRECT_MAP`(production 完全没有)**。
+  ⚠️ 若直接删文件,`redirect.html` 里的 `%VITE_REDIRECT_MAP%` 会原样留在产物里 →
+  **`var redirectMap = %VITE_REDIRECT_MAP%;` 直接语法错误**(顺带说明:**以前 `npm run build`
+  打出来的生产包,那个页面就是坏的**,只有 qingpu 构建是对的 —— 这次合并顺带修掉了)
+- `.env.test` 独有的是测试主机(`human-card-mini.metamaker.cn`)与 `VITE_USE_KNOWLEDGE_API=false`
+  → 无保留价值
+
+**做法**:
+- 把 qingpu 那两项**合并进 `.env.production`**(都加了说明注释:`VITE_DOWNLOAD_URL` 走同源
+  `/api/download/`,需部署侧 nginx 转发;`VITE_REDIRECT_MAP` 不能缺),然后删 `.env.qingpu` / `.env.test`
+- `package.json`:删 `build:qingpu` / `build:test`;保留 `zip`(青浦部署包),
+  新增 **`deploy:qingpu` = `npm run build && npm run zip`**(原来一条命令出包的习惯不变)
+- `index.html`:删掉两处**本来就是死的** qingpu 分支 —— `globalThis.isQingpuEnv = "MODE" === "qingpu"`
+  (写的是字面量,永远 false;全仓库无人读它)与 `let isLanMode = globalThis.isQingpuEnv`
+  (赋值后从未使用);`["development","test"].includes(mode)` → `mode === "development"`
+
+**运行过的验证**:
+- `npm run build` 通过;**产物核对**:`dist/redirect.html` 的 `redirectMap` **有值** ✓、
+  `dist/index.html` 的 `downloadURL = "/api/download/" + …` ✓(合并确实生效)
+- dev server 正常(HTTP 200)
+- 全套脚本绿:NLS **43/43**、附件 **57/57**、toast **27/27**、DMS 字段契约 **19/19**、
+  DMS 端到端(打真实库)**89/89**、`validate-harness` 通过
+
+**⚠️ 新发现的待清理项(只报告,未动)**:`index.html` 的 `initToken()`
+(`POST {modelServer}/open/openid_to_token`,用 `appKey=VITE_APP_KEY`)挂在
+`if (isKnowledgeApi) … else initToken()` 的 **else** 上,而 `VITE_USE_KNOWLEDGE_API` 在
+**剩下两个 env 里都是 `true`**(唯一为 false 的 `.env.test` 已删)→ **这条路径现在两个环境都走不到**,
+`initToken()` / `VITE_APP_KEY` / `openid` 引导成为可清理项。删它之前要先理清它与
+`initCardInfo()` 拉回的卡片之间的关系(`isKnowledgeApi` 分支里是写死的「政策解读」卡片)。
+已记进 [`docs/reference/current-api-call-sites.md`](docs/reference/current-api-call-sites.md) §6。
+
 **🔴 部署必配(已写进技术债 #10 与 asr-nls.md)**:
 ① nginx 要把 `/aly-api/` 转发到 `http://121.43.55.7:10011/`(去掉前缀);
 ② **`.env.production` / `.env.qingpu` / `.env.test` 都没有 `VITE_NLS_APPKEY`** ——

+ 4 - 3
index.html

@@ -20,7 +20,9 @@
       // DMS 数据管理服务(会话/问答记录/反馈)。token 由 vite 代理注入,前端不持有
       globalThis.VITE_DMS_API = "%VITE_DMS_API%" || "";
       globalThis.VITE_IP_API = "%VITE_IP_API%" || "";
-      globalThis.isQingpuEnv = "MODE" === "qingpu";
+      // [已移除] globalThis.isQingpuEnv = "MODE" === "qingpu";
+      // 2026-09-24 用户要求「环境只保留开发和生产」:qingpu 模式已删除,这行本身也是死的
+      // (写的是字面量 "MODE",永远不会等于 "qingpu";且全仓库没有任何地方读 isQingpuEnv)
       globalThis.__ZHAOSHANG_LLM_MODELS = ["zhaoshang", "zhaoshang_staging", "zhaoshang_safe"];
       globalThis.__isZhaoshangLLM = function (model) {
         return globalThis.__ZHAOSHANG_LLM_MODELS.indexOf(model || globalThis.llmModel || "") > -1;
@@ -94,7 +96,7 @@
         console.log("%c@@@version===>", "color:green;font-size:15px", version, mode);
 
         document.title += " Ver. " + version;
-        if (["development", "test"].includes(mode)) {
+        if (mode === "development") {
           document.title += " " + mode.toUpperCase();
         }
       }
@@ -239,7 +241,6 @@
       }
 
       (function initSystem() {
-        let isLanMode = globalThis.isQingpuEnv;
         var requestedPolicyMode = getQueryObj("mode");
         var isZhaoshangMode =
           requestedPolicyMode === "zhaoshang" ||

+ 2 - 3
package.json

@@ -5,15 +5,14 @@
   "type": "module",
   "scripts": {
     "dev": "vite --host --port 8083 --mode development",
-    "build:qingpu": "vite build --mode qingpu && powershell -ExecutionPolicy Bypass -File ./build/zip-to-qingpu.ps1",
     "zip": "powershell -ExecutionPolicy Bypass -File ./build/zip-to-qingpu.ps1",
-    "build:test": "vite build --mode test",
     "build": "vite build --mode production ",
     "preview": "vite preview",
     "test": "jest",
     "dms:token": "node harness/tools/set-dms-token.mjs",
     "dms:login": "node harness/tools/dms-login.mjs",
-    "predev": "node harness/tools/dms-login.mjs --if-needed"
+    "predev": "node harness/tools/dms-login.mjs --if-needed",
+    "deploy:qingpu": "npm run build && npm run zip"
   },
   "dependencies": {
     "@types/three": "0.143.0",