|
@@ -4280,6 +4280,156 @@ payload 里含模型里**不存在**的列时,`addContent` 会忽略该列照
|
|
|
切换说明)、`current-api-call-sites.md`(§0 A 表第 6 行、§三 的旧路径标注为已删)、
|
|
切换说明)、`current-api-call-sites.md`(§0 A 表第 6 行、§三 的旧路径标注为已删)、
|
|
|
`asr-realtime.md`(历史文档里指向已删文件的**链接**改成纯文本,避免 404 链接)
|
|
`asr-realtime.md`(历史文档里指向已删文件的**链接**改成纯文本,避免 404 链接)
|
|
|
|
|
|
|
|
|
|
+### 续 50:删掉政策列表「第三条腿」与 index.html 两处死枝(用户要求「动手删 1、2」)
|
|
|
|
|
+
|
|
|
|
|
+**用户指示**:在我列的"现存接口 + 可删项"清单里,让我**删 ① 和 ②**。
|
|
|
|
|
+
|
|
|
|
|
+**① 政策列表「第三条腿」:`{VITE_MODEL_SERVER}/v1/policies`**
|
|
|
|
|
+- 它需要「惠企政策库为空 **且** 本会话卡片也为空」才会走到 —— 实测从未触发
|
|
|
|
|
+- 删掉:`PolicyMatch.vue` 的 `fetchPolicyList` 里整段远端/本地分支(现在只剩"库 → 卡片兜底"两档)、
|
|
|
|
|
+ `policy-match-utils.ts` 的 4 个 helper(`buildPolicyListSearchParams` / `buildPolicyListUrl` /
|
|
|
|
|
+ `getLocalPolicyListResponse` / `extractPolicyListResponse`,共 136 行)及只被它们用到的
|
|
|
|
|
+ 类型与内部函数(`PolicyListQuery` / `PolicyListResponse` / `getAutoGrantedParam` /
|
|
|
|
|
+ `getPolicyText` / `readItems` / `readTotal`)、两份 env 的 `VITE_MODEL_SERVER`;
|
|
|
|
|
+ 顺带清掉随之失去写入点的 `policyListLoading` / `policyListRequestId`
|
|
|
|
|
+- ⚠️ **没有**碰 `<policy-list-updated>`(#11):它虽然也打这个接口,但走的是**后端给地址**那条
|
|
|
|
|
+ 独立路径(`PolicyListUpdatedMatch.vue`),删第三条腿不影响它
|
|
|
|
|
+
|
|
|
|
|
+**② `index.html` 里"写了没人读"的两处死枝**
|
|
|
|
|
+- `var cardURL = globalThis.modelServer;`(无读者)
|
|
|
|
|
+- `if (globalThis.isKnowledgeApi) { document.title = …; globalThis.cardInfo = {…} }` 整块 84 行
|
|
|
|
|
+ (`document.title` 上面已设过;`cardInfo` 全仓库无读者)
|
|
|
|
|
+- 连带删掉:`globalThis.isKnowledgeApi` 注入行、`globalThis.modelServer` 赋值、
|
|
|
|
|
+ 两份 env 的 `VITE_USE_KNOWLEDGE_API`
|
|
|
|
|
+- ⚠️ `VITE_API` **保留** —— 企业登录接口(`enterprise.ts`)在用,只是不再往 `globalThis.modelServer` 上放
|
|
|
|
|
+
|
|
|
|
|
+**过程中踩的坑(第 4 次 shell 引号问题)**:先用 `awk` 找"顶格 `}`"当块边界,结果 270 行那个 `}` 是
|
|
|
|
|
+**内层**的、删多了 → 内联脚本 `node --check` 报 `Unexpected end of input`;改用 `node -e '…'` 重写时
|
|
|
|
|
+脚本里的**单引号**又把 shell 字符串截断。最终**把一次性脚本写成 `harness/tools/_strip-*.mjs`
|
|
|
|
|
+(Write 工具落盘,跑完即删)**,用**括号配平**(跳过字符串与注释)定位块边界才删对。
|
|
|
|
|
+教训:改动 HTML/JS 块的边界不要靠"看缩进",要靠配平;一次性脚本落盘比塞进 shell 稳。
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `verify-policy-library` 43 → **49/49**(新增第 9 节 6 项:PolicyMatch 无 `VITE_MODEL_SERVER`/`v1/policies`
|
|
|
|
|
+ 调用、utils 不再导出那 4 个 helper、两份 env 都没有 `VITE_MODEL_SERVER`、index.html 无
|
|
|
|
|
+ `globalThis.modelServer`/`isKnowledgeApi`/`cardURL`/`cardInfo`、两份 env 都没有
|
|
|
|
|
+ `VITE_USE_KNOWLEDGE_API`、`VITE_API` 仍保留)。
|
|
|
|
|
+ ⚠️ 这 6 条断言第一版被**我自己写的「已移除」注释**绊红(约定要保留注释)→ 改成**先剥注释再查**
|
|
|
|
|
+- **变异测试**:把 `VITE_MODEL_SERVER` 引用放回 `PolicyMatch.vue` → 立刻 FAIL,还原后 49/49
|
|
|
|
|
+- `npm run build` 通过;`verify-inline-scripts` **6/6**(index.html 动过,这个必跑);
|
|
|
|
|
+ 政策卡列表 24/24、卡字段 8/8、详情反查 10/10;`vue-tsc` 仅既有 webpack-env
|
|
|
|
|
+- 顺手核对 dev server 提供出来的页面:`isKnowledgeApi`/`cardURL`/`modelServer`/`cardInfo`
|
|
|
|
|
+ **只剩注释里那两行**,`globalThis.orgTitle`、`globalThis.policiesPublic` 等关键全局都还在
|
|
|
|
|
+
|
|
|
|
|
+**🔴 删 ② 时误删了加载遮罩的收尾信号(同轮修回)**:
|
|
|
|
|
+用户反馈「遮罩层一直都在」→ 查证:`if (globalThis.isKnowledgeApi) { 硬编码 cardInfo }` 这一块的**最后 4 行**
|
|
|
|
|
+其实是**活的**(`globalThis.hasSequence = true;` + `dispatchEvent(dataLoaded)` +
|
|
|
|
|
+`dispatchEvent(sequenceLoaded)` + `addVersionInfo()`)—— 它们是**隐藏 `#loading-cover` 的信号**
|
|
|
|
|
+(`BusinessAssistant.vue` 的 `initSequence()` 靠 `hasSequence` 或等 `sequenceLoaded` 事件),
|
|
|
|
|
+被我用括号配平整块删掉了 → 页面永久卡在「正在初始化,请稍候...」。
|
|
|
|
|
+**为什么没被验证拦住**:`verify-inline-scripts` 只查**语法**(删完语法是对的),语义丢了它看不见 ✗
|
|
|
|
|
+⇒ 修法:把这 4 行移到 `initMessageChannel()` 之后**无条件执行**(原来是 `isKnowledgeApi` 为真才走,
|
|
|
|
|
+而两个环境都是 true → 语义等价);并在 `verify-inline-scripts.mjs` 加【3】3 条断言钉住
|
|
|
|
|
+(产物里必须有 `hasSequence = true`、`sequenceLoaded` 派发、`addVersionInfo()` 调用),
|
|
|
|
|
+**变异测试**:阉掉 `hasSequence` → 立刻 FAIL,还原后 9/9。
|
|
|
|
|
+另:逐条核对了被删块里的 5 条语句(`document.title` 重复设置 / `cardInfo` 76 行死数据 /
|
|
|
|
|
+上面那 4 行活信号),确认没有别的遗漏。
|
|
|
|
|
+
|
|
|
|
|
+**教训(同一天第二次"删多了")**:删代码块前要**逐条列出块内语句并判断活性**,
|
|
|
|
|
+不能只看"块名听起来是死的";语法检查拦不住语义丢失。
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 49:修「部门筛选出现了没有内容的项」(我 2026-09-24 的选项收集有 bug)
|
|
|
|
|
+
|
|
|
|
|
+**用户反馈**(附截图:下拉里 5 个正常部门之后,跟了一条又长又怪、还带换行的"部门"):
|
|
|
|
|
+「政策事项列表的部门筛选有问题,你确定使用的是政策所属字段吗」
|
|
|
|
|
+
|
|
|
|
|
+**先按用户的问题核对字段(结论:筛选用的字段没错)**:
|
|
|
|
|
+- 那个接口的 `department` 与 `政策所属部门` 实测**完全一致**(20/20)
|
|
|
|
|
+- 本地/DMS 那份 v2 库**没有**英文 `department`,`normalizePolicy` 的 `source` 取值链
|
|
|
|
|
+ (`department → 部门 → source → 政策所属部门`)最终落到 **`政策所属部门`** ✓
|
|
|
|
|
+- 拿真实数据逐个部门跑一遍筛选:**每个选项都筛得出内容**(区市场监管局 48、区经委 33、
|
|
|
|
|
+ 区文旅局 32、区人社局 22、区商务委 20、区农业农村委 7、区人才局 5、区卫健委/区民政局/区财政局 各 1)
|
|
|
|
|
+
|
|
|
|
|
+**真正的 bug 在"选项收集",不在字段**:我在 `collectDeptOptions` 里把
|
|
|
|
|
+**卡片里出现过的部门**(`policies.value.map(item => item?.source)`)也并进了下拉当兜底 ——
|
|
|
|
|
+而卡片的 `source` 可能是**多部门串**。实测原始回答里就有:
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+"source":"上海市商务委员会、上海市发展和改革委员会、上海市经济和信息化委员会、上海市科学技术委员会\n市商务委等"
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+于是下拉里出现了一个又长、又带换行、**还筛不出任何东西**的假部门(截图里那条就是它)。
|
|
|
|
|
+
|
|
|
|
|
+**修法**(`PolicyMatch.vue` 的 `collectDeptOptions`):
|
|
|
|
|
+1. **下拉只取政策库里 `政策所属部门` 的值**(按用户 2026-09-24 的要求:只列 JSON 里存在的部门),
|
|
|
|
|
+ 彻底不再并入卡片来源
|
|
|
|
|
+2. 顺手加 `looksLikeSingleDept` 守卫(长度 ≤12 且不含 `,,、` 与空白)—— 库里将来若真混进
|
|
|
|
|
+ 这种"多部门串",也不会被列成假选项
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:`verify-policy-library` 40 → **43/43**(新增 3 项:下拉只来自政策库、
|
|
|
|
|
+脏值守卫存在、**数据层面断言库里的部门取值都是单一部门名**);
|
|
|
|
|
+**变异测试**:把卡片并入恢复 + 去掉守卫 → **2 项立刻 FAIL**,还原后 43/43。
|
|
|
|
|
+回归:政策卡列表 24/24、问卷 36/36、内联脚本 6/6、`npm run build` 通过、
|
|
|
|
|
+`vue-tsc` 仅既有 webpack-env、`validate-harness` 通过。
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 仍需用户在浏览器确认**:下拉里应只剩那 10 个真部门,且每个都能筛出内容。
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 48:政策库远端改为 DMS 文件服务(用户要求,为"不再依赖旧政策接口"铺路)
|
|
|
|
|
+
|
|
|
|
|
+**用户要求**:「把 policies_public.v2.json 上传到 DMS,记住那个路径,那个路径就是新的远端政策接口,
|
|
|
|
|
+后续先从那个接口拿,拿不到再用本地的兜底,最终目标是不再依赖原来的政策相关接口。」
|
|
|
|
|
+
|
|
|
|
|
+**上传**(新增可复跑脚本 [`upload-policy-library.mjs`](tools/upload-policy-library.mjs),
|
|
|
|
|
+用**已有的上传模块** `uploadDmsAttachment`,与附件同一套实测契约):
|
|
|
|
|
+- 相对路径:`/static/file/1889-c_question-83859739-17d2-4b7f-b427-7ee27e098e79.json`
|
|
|
|
|
+- 前端取用(同源、拼了代理前缀):`/dms-api/static/file/1889-c_question-83859739-….json`
|
|
|
|
|
+- 脚本自带**自检**:上传后立刻 fetch 回来比对条数(170 ✓ 与本地一致),不一致就退出码 1
|
|
|
|
|
+
|
|
|
|
|
+**接线**(`index.html` + `.env.development` / `.env.production`):
|
|
|
|
|
+- 新增 `VITE_POLICY_REMOTE_URL` = 上面那个同源路径;`remoteURL = "%VITE_POLICY_REMOTE_URL%"`
|
|
|
|
|
+- **顺序固定为「先 dms、取不到再用 local」**;同时**删掉 `VITE_POLICY_LOCAL_FIRST` 开关**
|
|
|
|
|
+ (它当年是为了绕开"厂商远端那份没有市级政策id",远端换成 DMS 那份后不再需要)
|
|
|
|
|
+- 删掉 `VITE_DOWNLOAD_URL`(旧厂商下载域名)——它是"原来的政策相关接口"之一
|
|
|
|
|
+- `check-policy-sources.mjs` **改职责**:从"判断本地优先开关要不要留"改成
|
|
|
|
|
+ **核对 DMS 远端与本地副本内容是否一致**(跑通:170/170、部门 10 个,✅ 一致)
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:`verify-policy-library` 35 → **40/40**(新增第 8 节 5 项:远端用
|
|
|
|
|
+VITE_POLICY_REMOTE_URL、指向 `/dms-api/static/…`、本地兜底仍在、顺序固定 dms→local、
|
|
|
|
|
+本地优先开关已删);`check-policy-sources` ✅ 一致;政策卡列表 24/24、卡字段 8/8、
|
|
|
|
|
+详情反查 10/10;`npm run build` 通过且**产物核对**(`remoteURL`/`localFallbackURL` 两行与
|
|
|
|
|
+`label: "dms"` → `label: "local"` 的降级顺序);`verify-inline-scripts` 6/6;`validate-harness` 通过。
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 还剩两条"原来的政策相关接口"(用户目标是最终不再依赖,等指示再动)**:
|
|
|
|
|
+① `{VITE_MODEL_SERVER}/v1/policies`(政策「更多」列表的**第三档**——库与卡片都为空才走到,几乎不可达)
|
|
|
|
|
+② 正文里 `<policy-list-updated>{link,payload}` 给的地址(**后端驱动**,取出后还会写回
|
|
|
|
|
+`globalThis.policiesPublic`)—— 这条要动就得先改后端下发方式
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 生产注意**:`.env.production` 也写了同一个 `/dms-api/…` 路径,但要能用需
|
|
|
|
|
+① `VITE_DMS_API` 配好(技术债 #9)② nginx 转发 `/dms-api/`;取不到会自动退回本地副本,功能不受影响。
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 47:约定变更 —— 不再自动提交 / 推送(用户指示)
|
|
|
|
|
+
|
|
|
|
|
+**用户指示**:「后续不要再自动提交和推送了,只有我要求你做你才做」。
|
|
|
|
|
+
|
|
|
|
|
+**这条取代了仓库原先「每次改动完成后立即提交并推送」的约定**(该约定写在 `CLAUDE.md` 的
|
|
|
|
|
+"规则"与"提交约定"两处,2026-09-20 那次会话还专门把它写进了 `sops/session-end.md` 的首项)。
|
|
|
|
|
+改动落点(**本次全部未提交**,按新规矩留在工作区):
|
|
|
|
|
+- `CLAUDE.md`:规则里的那条改成「不要自动提交/推送 …… 只有用户明确要求时才 git commit/push」;
|
|
|
|
|
+ 「提交约定」整节重写:改完仍要跑验证 + 更新记录,但**不执行 git 命令**,
|
|
|
|
|
+ 收尾要**说明"改动未提交"**;用户的一次"提交"指示只对那一轮生效
|
|
|
|
|
+- `harness/sops/session-end.md`:收尾清单首项从「已提交并推送」改成
|
|
|
|
|
+ 「改动都在工作区、且已向用户说明」
|
|
|
|
|
+- `harness/sops/handoff.md`:命令区的 `git commit/push` 那行加了「⚠️ 只在用户明确要求提交时才执行」
|
|
|
|
|
+
|
|
|
|
|
+**验证**:`validate-harness` 通过;grep 确认没有别的"活文档"还在要求自动提交
|
|
|
|
|
+(`progress.md` 里那处是历史记录,保留)。
|
|
|
|
|
+
|
|
|
### 续 46:部门筛选改为「只列 JSON 里实际存在的部门」(用户要求)
|
|
### 续 46:部门筛选改为「只列 JSON 里实际存在的部门」(用户要求)
|
|
|
|
|
|
|
|
**用户要求**:「部门筛选只包含 JSON 里面存在的所有部门。」
|
|
**用户要求**:「部门筛选只包含 JSON 里面存在的所有部门。」
|
|
@@ -4585,4 +4735,529 @@ asrServerOptions 及其默认值)|方法表(`openMicroPhone` / `startRecor
|
|
|
harness 里也**没有** ASR 的自动化脚本(依赖麦克风与厂商服务,node 里无法稳定复现),
|
|
harness 里也**没有** ASR 的自动化脚本(依赖麦克风与厂商服务,node 里无法稳定复现),
|
|
|
所以文档给的是一条**手动自查清单**。
|
|
所以文档给的是一条**手动自查清单**。
|
|
|
|
|
|
|
|
|
|
+### 续 51:删掉 `<policy-list-updated>` 整条链 + 顺带只读排查旧协议标记(用户:「老对话仅测试,后续会全部清空」)
|
|
|
|
|
+
|
|
|
|
|
+**用户先问**:「`policy-list-updated` 在哪使用的,新的 AI 对话接口有没有返回类似的内容」
|
|
|
|
|
+→ 查证后回答:① 三处用(`stream-xml-filter.ts` 的标签规则、`BusinessRecord.vue` 的挂载点、
|
|
|
|
|
+`PolicyListUpdatedMatch.vue` 解析 `{link,payload}` → 拼 query → fetch → 交给 `PolicyMatch` 渲染
|
|
|
|
|
+→ 写回 `globalThis.policiesPublic`,即接口清单 #11);② 新接口**没有对应物**:政策卡片随
|
|
|
|
|
+`item` 事件**内联**到达,适配层翻成 `<!-- POLICY_TABLE -->`,从不产出 `policy-list-updated`。
|
|
|
|
|
+⇒ 它的唯一触发源就是旧会话历史。
|
|
|
|
|
+
|
|
|
|
|
+**用户决定**:回答里点明"要删得先确认历史不再回放该块"→ 用户给出「老对话仅测试,后续会全部清空」。
|
|
|
|
|
+再问清两种删法与范围,用户选:**全删(含标签规则)** + **顺带出一份只读清单**。
|
|
|
|
|
+
|
|
|
|
|
+**删除范围**:
|
|
|
|
|
+- `src/components/Chat/PolicyListUpdatedMatch.vue` 整文件
|
|
|
|
|
+- `BusinessRecord.vue`:挂载点 / import / `hasPolicyTableRow` 里的分支
|
|
|
|
|
+- `StreamXMLFilter`:`RecordRowTypes.PolicyListUpdated` 枚举成员 + 标签规则(原位留一行注释说明为何删)
|
|
|
|
|
+- `PolicyMatch.vue` 里那段"后端给地址那条走另一个组件"的说明注释(改为"已删")
|
|
|
|
|
+- 文档:`current-api-call-sites.md` 的 #11 / #10 注 / §5 注 / 三、保留表;
|
|
|
|
|
+ `README.md` 新增 `## 20260928` 节;新增 `docs/reference/legacy-content-markers.md` 并挂进该目录索引
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 副作用(用户已确认接受)**:标签规则删掉后,**清空之前**打开旧测试会话,
|
|
|
|
|
+正文里那串 `<policy-list-updated>{"link":…}</policy-list-updated>` 会**当普通文本显示**
|
|
|
|
|
+(既没有卡片列表,也不再被吞掉)。新会话不受影响。
|
|
|
|
|
+
|
|
|
|
|
+**顺带排查(只读,没改代码)—— 结论写进 [legacy-content-markers.md](docs/reference/legacy-content-markers.md)**:
|
|
|
|
|
+- ✅ 仍在用(适配层产出):`<scope>` / `<!-- POLICY_TABLE -->` / `<ref_links>` / `<question-cards>` / `<image-scope>`
|
|
|
|
|
+- ⚠️ 只有旧历史能触发(有渲染组件、src 里**无产出者**):`<form>` / `<link-url>` / `<file-docx>`
|
|
|
|
|
+- 💀 已经是死链:`<ui-form>`(两个壳组件 provide 的 `setFormOptions` **都是空函数**)、
|
|
|
|
|
+ `<followup>`(无人注册 `customProcessor`,`followupSuggestions` 全仓库无写入点)、
|
|
|
|
|
+ `<silence>`(只剩开发环境 mock 文本)、`<qingpu_enterprise_notificaion>`(无人注册、无产出者)
|
|
|
|
|
+- 建议:死链那批随时可删;`<form>`/`<link-url>`/`<file-docx>` 建议**等清空动作真的做完再删**
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `npm run build` 通过
|
|
|
|
|
+- 新增 `harness/tools/verify-stream-filter-rules.mjs`(**真实切行器**,配 `_entry-stream-filter.ts`)
|
|
|
|
|
+ —— **15/15**:新协议 5 个标记仍产出对应行 · 旧块不再产出行且整串当文本留下 · 保留的 3 个旧标记
|
|
|
|
|
+ 仍产出 · 源码级(组件文件已删、`BusinessRecord` 零引用、`PolicyMatch` 只在注释里提"已删")
|
|
|
|
|
+ - **变异测试**:用 `new StreamXMLFilter({tagRules:[旧的 policy-list-updated 规则]})` 跑一遍
|
|
|
|
|
+ → 立刻产出 `policy-list-updated` 类型 ⇒ 断言对规则是否回归**是敏感的**
|
|
|
|
|
+- `verify-question-cards` **36/36**(同一份切行器 + 真实往返,属回归)、`verify-policy-card-list` **24/24**
|
|
|
|
|
+- **产物核对**:`grep -rl "policy-list-updated|PolicyListUpdated" dist/` **0 命中**
|
|
|
|
|
+- `vue-tsc --noEmit`:仅既有 `webpack-env` 报错,涉及文件无报错
|
|
|
|
|
+- dev server 冒烟(8083 被占用,起在 **8084**,跑完已收掉):页面 200 ·
|
|
|
|
|
+ `BusinessRecord.vue` 开发态编译产物 0 命中该标记 · 切行器模块只剩注释里那处说明
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 本轮没做的**:
|
|
|
|
|
+- **真实浏览器交互**(打开页面发一轮对话)没做 —— 仓库里没有 playwright / puppeteer / chromium-cli,
|
|
|
|
|
+ 本轮不装浏览器驱动
|
|
|
|
|
+- 旧会话"显示原始 JSON"的实际观感**没有实测**(需要浏览器 + 带该块的旧会话)
|
|
|
|
|
+
|
|
|
|
|
+**功能状态无变化**:本次是死代码清理,`feature_list.json` 不改(仍 23 项、`in_progress` 1 项)。
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 52:生产接入暂缓,登记为技术债 #11(用户:「先标记待办」)
|
|
|
|
|
+
|
|
|
|
|
+**背景**:用户给出生产地址 —— **DMS `10.235.245.174`**、**AI 对话 `10.249.33.148`**,
|
|
|
|
|
+要求"配置好环境变量"。我先核了事实,并追问两件事(**端口**、**同源转发 vs 直连**),
|
|
|
|
|
+用户随后指示「**生产环境适配先不管,先标记待办,我们先处理别的问题**」
|
|
|
|
|
+→ **本轮不动 `.env.production`、无任何代码改动**。
|
|
|
|
|
+
|
|
|
|
|
+**顺便查明的状态(还没做,只是记下来)**:
|
|
|
|
|
+- `.env.production` **根本没有 `VITE_DMS_API`** → 生产产物走 DMS 那步直接 warn 跳过;
|
|
|
|
|
+ `VITE_CHAT_API` 还指着**测试后端** `192.168.2.23:8000`
|
|
|
|
|
+- `vite.config.ts` 的 `server.proxy` **只对 `npm run dev` 生效**,产物里没有代理
|
|
|
|
|
+ ⇒ 生产要转发**只能靠部署侧 nginx**;⚠️ `npm run preview` 会**复用同一份 proxy**
|
|
|
|
|
+ (vite 5.4.21:`proxy: preview?.proxy ?? server.proxy`)—— "本地 preview 通、上生产 404" 的坑
|
|
|
|
|
+- `VITE_CHAT_TARGET` / `VITE_DMS_TARGET` / `VITE_IP_TARGET` / `VITE_ALY_TARGET` **只有 dev 代理读**,
|
|
|
|
|
+ 写进 `.env.production` 对产物零作用
|
|
|
|
|
+- 生产页面是 HTTPS(`aixq.shqp.gov.cn` 内嵌 iframe)⇒ 直连 `http://10.x` 会被**混合内容拦掉**;
|
|
|
|
|
+ DMS 还要求**转发侧注入 token**(前端不持有 token)
|
|
|
|
|
+- 两台机器**本机探测不可达**(生产网段),配完只能由部署侧实测
|
|
|
|
|
+
|
|
|
|
|
+**登记位置**:[`tech-debt-tracker.md`](docs/exec-plans/tech-debt-tracker.md) **#11**(新建,
|
|
|
|
|
+"生产环境接入:地址已给,暂缓执行"),并在 **#9**(生产没配 DMS)末尾加了指向 #11 的补充。
|
|
|
|
|
+**没动的**:`.env.production` / 代码 / `feature_list.json`(仍 23 项、`in_progress` 1 项)。
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:`node harness/tools/validate-harness.mjs` 通过。
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 53:删掉打包体积报告 `stats.html` 及其配置(用户:「这个不需要,把它和相关代码删掉」)
|
|
|
|
|
+
|
|
|
|
|
+**起因**:用户问「`stats.html` 是干什么的」→ 答完顺手核出两件事:
|
|
|
|
|
+① 它是 `rollup-plugin-visualizer` 的体积报告(每次 `npm run build` 重新生成);
|
|
|
|
|
+② **它其实没落在配置写的 `dist/` 里** —— 插件 v5 的选项名是 **`filename`**,
|
|
|
|
|
+配置里的 `file: "./dist/stats.html"` 被忽略(`node_modules/.../index.js:42` 只读 `opts.filename`)
|
|
|
|
|
+→ 回落到默认名 `stats.html`,又因是相对路径、按 **cwd** 解析(`index.js:153` 直接 `writeFile`)
|
|
|
|
|
+→ 落在**仓库根目录**;`dist/stats.html` 从未存在过。
|
|
|
|
|
+用户据此决定:不需要,连同相关代码一起删。
|
|
|
|
|
+
|
|
|
|
|
+**删除范围**:
|
|
|
|
|
+- `vite.config.ts`:`import { visualizer }` + 插件块(7 行)
|
|
|
|
|
+- `package.json` / `package-lock.json`:`rollup-plugin-visualizer` devDependency
|
|
|
|
|
+ (lock `-112` 行,含它专用的 picomatch / source-map 副本)
|
|
|
|
|
+- `.gitignore`:`stats.html` 那两行(注释 + 规则)—— 已经没有生成者了
|
|
|
|
|
+- 仓库根目录的 `stats.html` 本体(1.78 MB)
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `npm run build` 通过,**9.17s**(此前 17.39s —— 少了报告要做的两遍压缩)
|
|
|
|
|
+- **构建后根目录与 `dist/` 都不再有 `stats.html`**;产物里 `grep "Rollup Visualizer"` 零命中
|
|
|
|
|
+- **产物零影响**:删除前后三个 chunk 的 hash 完全一致
|
|
|
|
|
+ (`main-o_7Ljas1` / `vendor-CtXnEyoM` / `three-DTC7gdj9`)⇒ 该插件只产报告、不改产物
|
|
|
|
|
+- `grep visualizer`:`package-lock.json` 0 命中、`node_modules` 已无该包
|
|
|
|
|
+- `node harness/tools/validate-harness.mjs` 通过
|
|
|
|
|
+
|
|
|
|
|
+**顺带查明(不影响功能,备查)**:Vite 报告的 chunk 大小与磁盘字节数对 `main` 对不上
|
|
|
|
|
+(报 389.29 kB、磁盘 449.22 kB),而 `vendor` / `three` 两边相等 —— 因为 Vite 报的是
|
|
|
|
|
+JS 字符串长度(UTF-16 码元),**中文一个字算 1、磁盘上算 3 字节**;`main` 里中文多才差这么多。
|
|
|
|
|
+不是缺陷,别当 bug 修。
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 54:修「Vite 依赖冷扫描失败」+ 加护栏(用户报错 → 问原因 → 问影响 → 「修改」)
|
|
|
|
|
+
|
|
|
|
|
+**现象**:用户贴出 dev server 的
|
|
|
|
|
+`Error: Failed to scan for dependencies from entries: index.html / redirect.html`,问「什么原因」。
|
|
|
|
|
+
|
|
|
|
|
+**根因(逐层验证,不是猜的)**:
|
|
|
|
|
+1. Vite 的依赖预扫描把 **`.vue` 也当 HTML**:`htmlTypesRE = /\.(html|vue|svelte|astro|imba)$/`(vite 5.4.21 源码 49455)
|
|
|
|
|
+2. 扫描前先做一次 `raw.replace(/<!--.*?-->/gs, "<!---->")`(49617 / 49702;带 `s`,**可跨行**)
|
|
|
|
|
+3. `BusinessRecord.vue` 的 `<script>` 里有两个**不成对**的标记,隔着 9 行:
|
|
|
|
|
+ 602 行注释里的起始符 + 611 行正则里的结束符 → 被整段吃掉 → 611 那行并进上面那条 `//` 注释
|
|
|
|
|
+ → 下一行以 `.replace(` 开头 → esbuild 报 `Unexpected "."`
|
|
|
|
|
+ - **数字对得上**:抽出脚本里那行原本是第 260 行,Vite 报 251 —— 正好少 9 行(9 个换行被吞)
|
|
|
|
|
+4. **为什么现在才炸**:这步只在依赖缓存失效时跑。本轮删 `rollup-plugin-visualizer` 改了
|
|
|
|
|
+ package.json / package-lock → 缓存失效 → 强制重扫 → 潜在问题浮出。`npx vite --force` 可稳定复现
|
|
|
|
|
+5. **与生产构建无关**:构建走 vue 插件路径,不做这步清扫(所以 `npm run build` 一直是绿的)
|
|
|
|
|
+6. 影响面只有 2 行(全仓库 `.vue` 逐行核对):另一处是 `const policyStartToken = "<!-- POLICY_TABLE"` ——
|
|
|
|
|
+ 它被吃掉后**不报语法错**,只是静默少两个常量(扫描内容只用于抽 import,所以 APP 行为不受影响)
|
|
|
|
|
+
|
|
|
|
|
+**修法(用户先问「是否会对功能造成影响」,确认后「修改」)**:
|
|
|
|
|
+- 两个字面量从 `.vue` 挪到 `.ts`:`stream-xml-filter.ts` 新增导出 `POLICY_TABLE_START` / `POLICY_TABLE_END`
|
|
|
|
|
+ (该文件内 3 处使用点改引用),`BusinessRecord.vue` 删掉本地两份、改 import ⇒ **顺带消掉一处重复**
|
|
|
|
|
+- 602 行注释改写(不再含那四个字符),并在 `.vue` 里注明「不要写字面量」
|
|
|
|
|
+- 新增 `harness/tools/verify-vue-script-html-comments.mjs`(纯 node,无需打包):扫 `src/**/*.vue` 的
|
|
|
|
|
+ `<script>` 区块,报出"同行没有配对结束符"的裸起始符(`<template>` 里的正常注释放行);
|
|
|
|
|
+ 并写进 `sops/verification.md` 的「改动类型 → 该跑什么」表与 `docs/architecture.md` 的关键约束
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- 🔑 **冷扫描**(本次问题的直接证据):`npx vite --force` → **0 错误**,`Scan completed in 188.71ms`、
|
|
|
|
|
+ `Dependencies bundled in 763.18ms`(修前同一条命令必然报错)
|
|
|
|
|
+- **新护栏**:`verify-vue-script-html-comments` 通过(28 个 .vue / 0 违规)。
|
|
|
|
|
+ ⚠️ **天然变异测试**:它第一次运行就抓出**我自己新写注释里的一个裸起始符**(`BusinessRecord.vue:1137`),
|
|
|
|
|
+ 修掉后才过 —— 说明断言真的有效
|
|
|
|
|
+- `npm run build` 通过;回归 `verify-stream-filter-rules` **15/15**、
|
|
|
|
|
+ `verify-question-cards` **36/36**(同一份切行器 + 真实往返)、`verify-policy-card-list` **24/24**;
|
|
|
|
|
+ `validate-harness` 通过
|
|
|
|
|
+- dev 冒烟:页面 200 · `BusinessRecord.vue` 开发态产物里**裸标记 0 处**(改走 import)·
|
|
|
|
|
+ 切行器模块里 `POLICY_TABLE_START` 出现 4 次
|
|
|
|
|
+- ⚠️ **产物 hash 变了**:`main-o_7Ljas1` → `main-D0U2AkA8`,449224 → 449154 字节(**-70**)。
|
|
|
|
|
+ 性质核实过:新产物里能看到 `.ts` 的模块级常量 `oo="<!-- POLICY_TABLE", io="POLICY_TABLE -->"`、
|
|
|
|
|
+ `.vue` 侧已无字面量 ⇒ 是**字面量去重 + 声明位置变化**导致的字节流差异,不是行为差异
|
|
|
|
|
+ (语义等价是构造性的:字符串值逐字不变,使用点只是 `indexOf` / `slice` 的比较对象)
|
|
|
|
|
+- ⚠️ **没做到、也不声称**:字节级基线对照。本打算 `git stash` 回退这两个文件重建旧产物,
|
|
|
|
|
+ 但旧版 `BusinessRecord.vue` import 了已删的 `PolicyListUpdatedMatch.vue` → 构建失败
|
|
|
|
|
+ (stash 已 `pop` 还原,工作区无损)。所以给的是"构造性等价 + 产物核对 + 运行期回归"三条证据
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 55:删掉百度统计(用户问「列出现在使用的接口」→ 逐层追问 → 「删掉」)
|
|
|
|
|
+
|
|
|
|
|
+**经过**:用户先要「列出现在使用的接口」→ 我按代码重核时发现清单**漏了一条**(第三方脚本);
|
|
|
|
|
+用户接着问「详细介绍百度统计接口」→「统计的是什么数据,传的是什么」→「现在有什么用」→ **「删掉」**。
|
|
|
|
|
+排查结论全部写进 [`current-api-call-sites.md`](docs/reference/current-api-call-sites.md) 的 #14。
|
|
|
|
|
+
|
|
|
|
|
+**查出来的事实(都有实测支撑)**:
|
|
|
|
|
+- `index.html` 底部**无条件**加载 `hm.baidu.com/hm.js?d6307cb…`(dev / 生产 / iframe 内都发)
|
|
|
|
|
+- 抓 hm.js 本体解出站点配置:**`dm:["demo.heijingai.com"]`(厂商演示域名,不是青浦的域)**、
|
|
|
|
|
+ `etrk/cetrk/cptrk/ctrk` 全空 ⇒ 只有默认 PV/UV,**数据进的是那个厂商账号**
|
|
|
|
|
+- **jsdom 实测三个域**(拦掉 img/xhr/sendBeacon,不真发请求):`aixq.shqp.gov.cn` / `demo.heijingai.com` /
|
|
|
|
|
+ `localhost` **都会**写 cookie(`HMACCOUNT` / `Hm_lvt_<id>` / `Hm_lpvt_<id>`,写在当前域)并上报
|
|
|
|
|
+ `hm.gif` ⇒ **`dm` 白名单不阻止客户端上报**(推翻了我最初的猜测;服务端是否过滤未验证)
|
|
|
|
|
+- 完整上报参数(抓到的 URL):`si` 站点 id · `hca` 访客 id · `u` 当前页 URL · `su` 来源页 ·
|
|
|
|
|
+ `tt` 标题 · `ds`/`ww`/`cl`/`ln`/`ja`/`ck` 环境 · `lv`/`vl` 深度与时长 · `et`/`ep` 事件 ·
|
|
|
|
|
+ `lo` 是否顶层;另有 `cm/cp/cw/ci/cf/cu` 六个**渠道参数**(从 URL/referrer 里解析
|
|
|
|
|
+ `utm_source/medium/campaign/term/content` + 百度自家 `hmsr/hmmd/hmpl/hmkw/hmci/hmcu`)
|
|
|
|
|
+- **业务数据一个都不传**:脚本字段表里没有聊天/输入/企业信息;唯一能塞业务数据的通道
|
|
|
|
|
+ `_hmt.push(['_setCustomVar',…])` —— `git log -S '_hmt.push'` **全历史为空**,一次都没用过
|
|
|
|
|
+- 结论:**对本项目零用途**(我们看不到厂商账号里的数据),且是全站**唯一**往第三方发请求、
|
|
|
|
|
+ 并在青浦域名上写 cookie 的东西 ⇒ 用户确认删除
|
|
|
|
|
+
|
|
|
|
|
+**改动**:`index.html` 删掉那 9 行整块(原位留一条 `[已删]` 说明注释,与文件里既有的
|
|
|
|
|
+`[已移除]` 风格一致)。全仓库无其它引用。
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `npm run build` 通过
|
|
|
|
|
+- **`verify-inline-scripts` 8/8**(改了 index.html 必跑;含"加载遮罩收尾信号仍在"那 3 条)
|
|
|
|
|
+- 引用复核:`grep -rn 'hm\.baidu|_hmt'`(排除 node_modules/dist)**只剩注释**;
|
|
|
|
|
+ `dist/index.html` 里同样只剩注释 —— 脚本已不在产物里
|
|
|
|
|
+- `node harness/tools/validate-harness.mjs` 通过
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 56:删掉死配置 `VITE_DOWNLOAD_URL`(用户:「删掉吧」)
|
|
|
|
|
+
|
|
|
|
|
+**背景**:续 55 的接口复核里顺带发现它是**死配置**(只定义在 `.env.production`,全仓库无读者 ——
|
|
|
|
|
+`index.html` 的本地兜底早已写死 `/merchant-agent/policies_public.v2.json`),向用户报告后确认删除。
|
|
|
|
|
+
|
|
|
|
|
+**改动**:
|
|
|
|
|
+- `.env.production`:那 5 行(含说明注释)换成 3 行 `[已删]` 说明 —— 与该文件里既有的
|
|
|
|
|
+ `[已删]` / `[已移除]` 风格一致;连带**生产侧 nginx 不必再转发 `/api/download/`**
|
|
|
|
|
+- `harness/tools/verify-policy-library.mjs`:新增**§10** 5 条断言(百度统计不在 index.html、
|
|
|
|
|
+ 两份 env 都没有 `VITE_DOWNLOAD_URL`、index.html 无 `/api/download/` 依赖,
|
|
|
|
|
+ 外加两条**防误伤**:政策库远端与本地兜底必须都还在)
|
|
|
|
|
+ - 顺带把 `stripComments` 提升到模块级,并新增 **`stripEnv`**(`.env` 用的是 `#` 注释)——
|
|
|
|
|
+ ⚠️ **第一版断言被我自己写进 env 的 `[已删] VITE_DOWNLOAD_URL=…` 说明注释绊红了**,加 `stripEnv` 才过
|
|
|
|
|
+ (这是本项目第三次踩"注释绊倒断言",`verify-policy-library` §9 的注释里记过前两次)
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `verify-policy-library` **54/54**(新增 §10 的 5 条)
|
|
|
|
|
+- **变异测试**:把 `VITE_DOWNLOAD_URL="/api/download/"` 追加回 `.env.production` → §10 立刻 **1 FAIL**;还原后 54/54
|
|
|
|
|
+- `npm run build` 通过,**主 chunk hash 未变**(`main-D0U2AkA8`)⇒ 删这条配置对产物零影响(本就无人读)
|
|
|
|
|
+- `node harness/tools/validate-harness.mjs` 通过
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 57:环境变量整理(用户:「整理一下环境变量」)
|
|
|
|
|
+
|
|
|
|
|
+**做法**:先把「两份 env 的实际定义 × 代码里的读者」逐项对一遍,再动手;改动用脚本**比对改写前后的
|
|
|
|
|
+key→value 映射**,确认没丢变量、没改值。
|
|
|
|
|
+
|
|
|
|
|
+**核查结果(12 个变量,全部有活读者,无死项)**:`VITE_VERSION` · `VITE_API` ·
|
|
|
|
|
+`VITE_POLICY_REMOTE_URL` · `VITE_PARENT_ORIGIN` · `VITE_CHAT_API` · `VITE_DMS_API`(**仅 dev**)·
|
|
|
|
|
+`VITE_IP_API` · `VITE_NLS_TOKEN_API` · `VITE_REDIRECT_MAP`(**仅生产**)·
|
|
|
|
|
+`VITE_CHAT_TARGET` / `VITE_DMS_TARGET` / `VITE_IP_TARGET`(仅 dev、只给代理读);
|
|
|
|
|
+`VITE_NLS_APPKEY` 只在 `.env.development.local` 与部署侧。
|
|
|
|
|
+
|
|
|
|
|
+- ⚠️ **差点误删**:`.env.development.local` 里的 `ALIYUN_NLS_AK` / `ALIYUN_NLS_SK` / `ALIYUN_NLS_APPKEY`
|
|
|
|
|
+ 看着像残留(前端已不自己换 token),但它们是 **harness 的 NLS 测试脚本**在读
|
|
|
|
|
+ (`nls-token.mjs` / `get-nls-token.mjs` / `probe-nls-realtime.mjs` / `verify-nls-*`)⇒ **保留**。
|
|
|
|
|
+ 写进记录,免得下次又被当死配置。
|
|
|
|
|
+
|
|
|
|
|
+**做了四件事**:
|
|
|
|
|
+1. **两份 env 重排为同一套分区**:① 构建信息 ② 接口地址(进产物)③(dev)只给代理读的 target
|
|
|
|
|
+ ④ 云服务同源路径 ⑤ 已删说明。逐项比对结果:dev **11 → 12**(只新增 `VITE_ALY_TARGET`)、
|
|
|
|
|
+ 生产 **8 → 8**,**删除 0 / 值变化 0**
|
|
|
|
|
+2. **补 `VITE_ALY_TARGET`**:`vite.config.ts` 的 `/aly-api/` 代理只认这个变量、缺了就落到硬编码兜底,
|
|
|
|
|
+ 与另外三个 target 不对称;填入的值就是原兜底地址 ⇒ **零行为变化**
|
|
|
|
|
+3. **删掉 `runtime-config.ts` 的 `getApiBaseUrl()`**:它读 `globalThis.VITE_API`,而全仓库
|
|
|
|
|
+ **没有任何地方给这个 global 赋值**(index.html 只注入 CHAT / DMS / IP 三个)⇒ 恒返回空串,纯死代码。
|
|
|
|
|
+ `VITE_API` 的 4 个真实读者走的是 `import.meta.env.VITE_API`。
|
|
|
|
|
+4. **重写 `architecture.md` 的「环境变量」表**:原表还列着已删的 `VITE_MODEL_SERVER` / `VITE_ASR` /
|
|
|
|
|
+ `VITE_STREAM_SERVER`,且缺一半现役变量 —— 现按「变量 / 用途 / 定义在哪些环境 / 谁在读」重列,
|
|
|
|
|
+ 并写明**改 env 要同步更新这张表**
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `npm run build` 通过,**主 chunk hash 未变**(`main-D0U2AkA8`)⇒ 删死函数 + 补 target 对产物零影响
|
|
|
|
|
+- `vue-tsc` 仅既有 `webpack-env` 报错
|
|
|
|
|
+- **dev 冒烟(含代理实测)**:页面 200 · `/aly-api/proxy/verify/getALYToken` 经**新加的 `VITE_ALY_TARGET`**
|
|
|
|
|
+ 返回真实 token `{"code":200,…}` · `/ip-api/…/getIPByBrowser` 返回真实 IP `116.232.248.128` · 日志无报错
|
|
|
|
|
+- `verify-policy-library` **54/54** · `verify-stream-filter-rules` **15/15** ·
|
|
|
|
|
+ `verify-vue-script-html-comments` 通过 · `validate-harness` 通过
|
|
|
|
|
+
|
|
|
|
|
+**未处理的(留给用户决定)**:`VITE_REDIRECT_MAP` **只有生产有** ⇒ 本地直接打开 `/redirect.html`
|
|
|
|
|
+是语法错误页(登录链不受影响,那行写的是线上硬编码地址)。要不要给 dev 也补一份?
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动全部未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 58:修过期说明 + 把 NLS appkey 内置进代码(用户:「更改过期的说明,同时,将 accesskey 直接写入使用的地方」)
|
|
|
|
|
+
|
|
|
|
|
+**① 过期说明(3 处)**:
|
|
|
|
|
+- `src/asr/nls.ts` 顶部注释仍写「dev 是 vite 的 `/nls-token/`」→ 改为「后端网关 `getALYToken`;
|
|
|
|
|
+ dev 走 vite 代理 `/aly-api/`,生产由 nginx 转发同一路径」
|
|
|
|
|
+- `harness/docs/reference/asr-nls.md`:①「生产要由后端/网关提供 `/nls-token/`」→ 改为
|
|
|
|
|
+ 「token 已由网关签发,生产只剩 nginx 转发」;②「旧实现(`asr/index.ts`)保留:切回它只改 import」
|
|
|
|
|
+ +「`VITE_ASR`/`VITE_XF_ASR` 仍在四份 env 里」→ **两项都已不成立**(2026-09-24 删掉,`src/asr/` 现在
|
|
|
|
|
+ 只有 `nls.ts` + `nls-protocol.ts`)
|
|
|
|
|
+- `harness/tools/verify-nls-realtime.mjs` 的断言标签「不再硬编码 appKey(改由端点下发)」→
|
|
|
|
|
+ 改为「由 runtime-config 统一提供」
|
|
|
|
|
+
|
|
|
|
|
+**② appkey 内置进代码** —— ⚠️ **先澄清再动手**:用户说「accesskey 直接写入使用的地方」,
|
|
|
|
|
+我确认后才知道指的是 **appkey**(不是 AK/SK)。**AK/SK 我没有写进仓库、也不会写**:
|
|
|
|
|
+`harness/` 是入库的且会推到共享远端 ⇒ 凭据会进 git 历史(事后只能轮换密钥补救),
|
|
|
|
|
+且这与用户 2026-09-23 自己的约定(「任何地方都不要把凭据值写进仓库文件」,就写在该文件顶部)相反。
|
|
|
|
|
+- 改动:`src/utils/runtime-config.ts` 新增 `NLS_APPKEY_BUILTIN = "<16 字符>"`,
|
|
|
|
|
+ `getNlsAppkey()` 的兜底从空串改成它;**覆盖链保留**(`globalThis` 注入 → 构建期 env → 内置值),
|
|
|
|
|
+ 临时换 appkey 仍不必改代码
|
|
|
|
|
+- 连带清掉「必须由部署侧注入」的旧口径:`.env.development` / `.env.production` 的注释、
|
|
|
|
|
+ `architecture.md` 的环境变量表、`asr-nls.md` 的表 + 待办、`tech-debt #10` 的待办 ②(**已消**)、
|
|
|
|
|
+ `current-api-call-sites.md` §D;并从 `.env.development.local` 删掉那行冗余的 `VITE_NLS_APPKEY`
|
|
|
|
|
+ (**AK/SK 保留** —— 那是 harness 测试脚本的本地签名兜底)
|
|
|
|
|
+- ⚠️ **如实记录**:appkey 现在**进产物、也进 git 历史**。可接受的理由:它**不是密钥**
|
|
|
|
|
+ (换 token 不需要它、网关也不校验它),而且每次识别请求本就把它明文发出去 ⇒ 它一直就在公开产物里。
|
|
|
|
|
+ 真正的密钥只有 AK/SK,那两个**仍在 gitignored 的 `.env.development.local`**,没进仓库。
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `npm run build` 通过;**产物核对**:内置 appkey 在 main chunk 命中 **1 次**、`index.html` **0 次**
|
|
|
|
|
+ (不再需要注入);主 chunk hash `main-D0U2AkA8` → `main-DLILXHYb`(+~20 字节,正是那个 16 字符常量)——预期内
|
|
|
|
|
+- `verify-nls-realtime` **44/44**(含**真实网关连接**:token + appkey + 识别全链路)
|
|
|
|
|
+- dev 冒烟:页面 200 · dev 下发的 `runtime-config.ts` 里内置值命中 1 次
|
|
|
|
|
+- `vue-tsc` 仅既有 `webpack-env` 报错;`validate-harness` 通过
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 59:删掉 `.env.development.local` 里的阿里云凭据(用户:「三个都删(含 AK/SK)」)
|
|
|
|
|
+
|
|
|
|
|
+**背景**:续 58 把 appkey 内置进代码后,用户问「local 的那个环境变量是不是可以删除了」。
|
|
|
|
|
+我先把三个 key 的**实际用途**查清再答:
|
|
|
|
|
+
|
|
|
|
|
+| key | 用途 |
|
|
|
|
|
+|---|---|
|
|
|
|
|
+| `ALIYUN_NLS_APPKEY` | harness 脚本的**启用条件** + StartTranscription 的 header 值 |
|
|
|
|
|
+| `ALIYUN_NLS_AK` / `SK` | ① `resolveNlsToken` 的**第三步兜底**(网关失败才自签)② `verify-nls-realtime`/`probe-nls-realtime` 的启用条件 ③ `get-nls-token.mjs` 存在的意义 |
|
|
|
|
|
+
|
|
|
|
|
+说明代价(删了会失去"网关挂了自签"的退路、那两个脚本的真实联网段会跳过)后,用户选择**三个都删**。
|
|
|
|
|
+
|
|
|
|
|
+**改动**:
|
|
|
|
|
+- `.env.development.local`:三个凭据 key 全删,改写成一段说明(为什么是空的、需要时怎么临时用 env 传、
|
|
|
|
|
+ 为什么凭据不进文件)⇒ 至此**磁盘上不再保存任何阿里云凭据**
|
|
|
|
|
+ (📌 该文件随后在**下一轮被整体删除**,见 续 60)
|
|
|
|
|
+- `harness/tools/nls-token.mjs`:新增 `readBuiltinAppkey()`(从 `src/utils/runtime-config.ts` 的
|
|
|
|
|
+ `NLS_APPKEY_BUILTIN` 读),`readNlsCredentials()` 的 appkey 改为「env → 内置值」;头部口径改写
|
|
|
|
|
+- `verify-nls-realtime.mjs` / `probe-nls-realtime.mjs`:启用条件从「`ak && sk && appkey`」放宽为
|
|
|
|
|
+ **只要有 appkey** ⇒ 删掉 AK/SK 后**真实网关段仍然会跑**(关键:那段是本仓库唯一的真实识别自动化证据)
|
|
|
|
|
+- `get-nls-token.mjs`:头部改为"平时不需要它;凭据临时用 env 传"
|
|
|
|
|
+- `src/network/api/dms/client.ts`:修掉一条**指错地方**的提示 —— DMS token 在本机 `.dms-token`
|
|
|
|
|
+ (gitignored,`npm run dms:token` 写入),不在 `.env.development.local`
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `get-nls-token --check`:AK/SK 报「未配置」、**AppKey 从内置值读到**(掩码显示 `3jRt****dh12`)
|
|
|
|
|
+ ⇒ `readBuiltinAppkey()` 生效
|
|
|
|
|
+- `verify-nls-realtime` **44/44**,且【3】**真实网关段跑起来了**(「收到 TranscriptionStarted(token/appkey 有效)」)
|
|
|
|
|
+ —— 全程**没有任何磁盘凭据**
|
|
|
|
|
+- `verify-nls-browser-path` **4/4**(同样真实联网,识别文本含关键词)
|
|
|
|
|
+- 清空 `.local` 后 dev 仍正常:页面 200;`/dms-api/...` 请求到达 DMS(DMS token 本就在 `.dms-token`,不受影响)
|
|
|
|
|
+- `npm run build` 通过 · `validate-harness` · `verify-vue-script-html-comments` · `verify-stream-filter-rules` 15/15
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 60:删掉 `.env.development.local` 整个文件(用户:「文件没用的话也删掉」)
|
|
|
|
|
+
|
|
|
|
|
+**先确认没有硬依赖**(都走 missing-file 容错):`vite` 的 `loadEnv` 找不到 `.env.*.local` 不会报错;
|
|
|
|
|
+`nls-token.mjs` 的 `readDotEnvFile` 有 try/catch;`.gitignore` 的 `.env.*.local` 模式仍在
|
|
|
|
|
+⇒ 将来谁要放本机覆盖,新建即可、仍然不会入库。
|
|
|
|
|
+
|
|
|
|
|
+**删除**:`.env.development.local`(删掉后仓库里只剩 `.env.development` / `.env.production` 两份)。
|
|
|
|
|
+**顺带修 4 处"凭据在那个文件里"的旧注释**:
|
|
|
|
|
+- `vite.config.ts` 的 DMS 代理注释:token 来源是 `.dms-token` / `DMS_TOKEN`,**不在** `.env.development.local`
|
|
|
|
|
+- `probe-nls-realtime.mjs` / `verify-nls-realtime.mjs` 的头部:改成"appkey 从代码内置值读"
|
|
|
|
|
+- `.env.development` 头部:本机覆盖改成"**需要时新建**"
|
|
|
|
|
+(`nls-token.mjs` 的 `readDotEnvFile` 保留 —— 它现在只对"你自己新建了某个 `.env.*.local`"有意义)
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证(都是删掉文件之后跑的)**:
|
|
|
|
|
+- `get-nls-token --check`:AK/SK 未配置、**AppKey 仍从代码内置值读到**(`3jRt****dh12`)
|
|
|
|
|
+- `verify-nls-realtime` **44/44**(含真实网关段)· `verify-nls-browser-path` 之前那轮 4/4
|
|
|
|
|
+- **dev 冒烟**:页面 200 · `/dms-api/content/selectContentList` 返回**真实数据**(`{"code":200,…}`,
|
|
|
|
|
+ DMS token 走 `.dms-token`,不受影响)· `/aly-api` 取到真实 token · dev 日志 0 条 error
|
|
|
|
|
+- `npm run build` 通过 · `validate-harness` 通过
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 61:DMS 默认服务账号写进代码(用户给账号并要求「直接写进代码里」)
|
|
|
|
|
+
|
|
|
|
|
+**用户要求**:给了默认账号(`user_yszs_web`)与密码,原话「以后未登录时 token 用这个账号获取,
|
|
|
|
|
+**直接写进代码里**」,并确认用途是 **DMS 那条链**(会话/问答/企业信息落库)。
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 我先拦了一次,用户明确选择"写进入库源码"**:
|
|
|
|
|
+- 这是**密码**(不是 appkey 那种非密钥),而 `harness/` 入库、仓库还推到共享远端
|
|
|
|
|
+ ⇒ 密码会**永久进 git 历史**,事后只能靠改密码补救;写进 `src/` 更糟(前端产物公开 = 把账号公开,
|
|
|
|
|
+ 而按技术债 #8,DMS 那个 token 权限极大)
|
|
|
|
|
+- 我给了三个选项(`.dms-account` / gitignored 的代码文件 / 入库源码),**用户选了第三个**
|
|
|
|
|
+ ⇒ 按用户要求执行,并在代码与本文里写明这是「凭据不落盘」规则的**唯一例外**
|
|
|
|
|
+- 同时把护栏写进代码注释:只准 node 侧(换 token)用,**绝不要复制进 `src/`**;建议它只作权限受限的服务账号
|
|
|
|
|
+
|
|
|
|
|
+**改动**(`harness/tools/dms-login.mjs`):
|
|
|
|
|
+- 新增 `DEFAULT_ACCOUNT = { userName, password }`(带一段 ⚠️ 例外说明)
|
|
|
|
|
+- `readAccount()` 优先级改为:**参数 → 环境变量 → 代码内置默认 → 本机 `.dms-account`(兜底)**
|
|
|
|
|
+- 头部注释的"凭据从哪来"补上 ③ 内置默认、并说明 ④ 已被覆盖
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `node harness/tools/dms-login.mjs` 登录成功:token 明示 **`用户 user_yszs_web`**,有效期 12.0 小时
|
|
|
|
|
+ (登录前那个 token 是 `user_gtx`)⇒ 内置账号可用,`.dms-token` 已换成服务账号的
|
|
|
|
|
+- **直连 DMS**(带新 token 的 `selectContentList`):HTTP 200 / `code=200` / 取到 10 行 ⇒ 有权限
|
|
|
|
|
+- **dev 冒烟**:页面 200 · 经 `/dms-api` 代理读 1887 也返回真实数据 · predev 因 token 仍有效而跳过续期(符合预期)
|
|
|
|
|
+- `npm run build` 通过 · `validate-harness` 通过
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 三条影响,写在这里免得以后惊讶**:
|
|
|
|
|
+1. **之后 DMS 里新写入的行,作者会变成 `user_yszs_web`**(旧行仍是 `user_gtx`)
|
|
|
|
|
+2. **密码现在还没进 git 历史**(本轮未提交)—— 一旦提交就撤不回来了;要反悔现在说
|
|
|
|
|
+3. 本机 `.dms-account` 里的旧账号**已被内置值覆盖**(它现在只是兜底),要不要删由用户定
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 62:删掉 `.dms-account`,**保留** `.dms-token`(用户:「没用就删掉」)
|
|
|
|
|
+
|
|
|
|
|
+**先分清两者性质不同**:
|
|
|
|
|
+- **`.dms-account`**(账号密码的本机文件):自 续 61 把默认服务账号写进代码后**已被内置值覆盖**
|
|
|
|
|
+ (优先级:参数 → env → **内置** → 文件),本机那份是永远轮不到的旧账号 ⇒ **删**
|
|
|
|
|
+- **`.dms-token`**(当前 token):**不能删** —— `vite.config.ts` 的 `/dms-api/` 代理**每个请求现读**它
|
|
|
|
|
+ 来注入 `token` 头(`readDmsToken`),删了 dev 的 DMS 读写立刻失灵。它是**自动生成物**
|
|
|
|
|
+ (`npm run dms:login` / `npm run dev` 的 predev 会写回),所以真删了也能自愈,但没有任何意义
|
|
|
|
|
+
|
|
|
|
|
+**改动**:删 `.dms-account`;`dms-login.mjs` 头部两处注释同步(④ 标为"仅当内置值为空时才用得上、
|
|
|
|
|
+本机已删";把"密码明文存在 `.dms-account`"改成"密码现在写在 `DEFAULT_ACCOUNT` 里,那条路已删除")。
|
|
|
|
|
+`.gitignore` 里 `/.dms-token` 与 `/.dms-account` 两个模式**都保留**(将来要用还有)。
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- 删掉 `.dms-account` 后,无参 `node harness/tools/dms-login.mjs` 仍登录成功(走内置账号 → 用户 `user_yszs_web`)
|
|
|
|
|
+- `node harness/tools/dms-login.mjs --if-needed`:token 仍有效 → 跳过 ✓
|
|
|
|
|
+- **dev 冒烟**:页面 200 · 经 `/dms-api` 读到真实数据(`.dms-token` 未受影响)
|
|
|
|
|
+- `node harness/tools/validate-harness.mjs` 通过
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 63:核对登录端点路径(用户:「token 使用接口获取 http://121.43.55.7:10086/api/user/login」)
|
|
|
|
|
+
|
|
|
|
|
+**用户说的路径与代码里的不一致**,所以先实测再改(没直接改):
|
|
|
|
|
+- `POST http://121.43.55.7:10086/api/user/login` → **HTTP 404**(该路径不存在)
|
|
|
|
|
+- `POST http://121.43.55.7:10086/oauth/api/user/login` → **HTTP 200 / code=200 / 返回 JWT(183 字符)** ✅
|
|
|
|
|
+
|
|
|
|
|
+⇒ **代码现状已经满足用户要求**(既走这个接口、又用他们给的默认账号),无需改动。
|
|
|
|
|
+只在 `dms-login.mjs` 的接口说明处加了一行防误改:**路径必须带 `/oauth`,别"顺手改短"**。
|
|
|
|
|
+
|
|
|
|
|
+**待用户澄清**:如果他们说的 `/api/user/login` 来自**另一个 host / 另一个服务**
|
|
|
|
|
+(比如管理端或网关的另一端口),把地址给我,我改 `OAUTH_TARGET`(现在支持 env 覆盖)或路径后实测。
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 64:代理前缀统一为「与服务真实路径同名」(用户指定)
|
|
|
|
|
+
|
|
|
|
|
+**用户要求**:`121.43.55.7:10086` 是 `/oauth`、`121.43.55.7:10081` 是 `/dms`,
|
|
|
|
|
+"只做这两个代理",随后补充:**再加一条 `/api`,指向 `121.43.55.7:10011`**,并提醒
|
|
|
|
|
+"/ip-api 和 /aly-api 的网址是一样的"(确实:两条都打 10011,只是端点不同)。
|
|
|
|
|
+
|
|
|
|
|
+**先实测决定改写规则**(没凭感觉):
|
|
|
|
|
+| 探测 | 结果 | 推论 |
|
|
|
|
|
+|---|---|---|
|
|
|
|
|
+| `POST :10086/oauth/api/user/login` | 200 + JWT | `/oauth` **直通**(真实路径带该前缀) |
|
|
|
|
|
+| `POST :10086/api/user/login` | **404** | 用户说的那条路径不存在(已在 续 63 记过) |
|
|
|
|
|
+| `GET :10011/proxy/verify/getALYToken` | 200 | —— |
|
|
|
|
|
+| `GET :10011/api/proxy/verify/getALYToken` | **404** | 网关不带 `/api` ⇒ `/api` 这条要**剥前缀** |
|
|
|
|
|
+
|
|
|
|
|
+**改动**:
|
|
|
|
|
+- `vite.config.ts`:四条代理(`/oauth` 直通 · `/dms` 直通 + 注入 token · `/api` 剥前缀 ·
|
|
|
|
|
+ `/chat-api` 保留剥前缀);删掉 `/dms-api`、`/ip-api`、`/aly-api` 与旧的 aixq `/api`
|
|
|
|
|
+- 两份 env:`VITE_DMS_API` `/dms-api`→`/dms`、`VITE_POLICY_REMOTE_URL`→`/dms/static/…`、
|
|
|
|
|
+ `VITE_IP_API`→`/api`、`VITE_NLS_TOKEN_API`→`/api/proxy/verify/getALYToken`;
|
|
|
|
|
+ target 收敛为 `VITE_CHAT_TARGET` / `VITE_DMS_TARGET` / `VITE_OAUTH_TARGET` / `VITE_API_TARGET`
|
|
|
|
|
+- **`.env.production` 首次配上 `VITE_DMS_API="/dms"`**(生产原来根本没有 ⇒ 技术债 #9 的"未配置"那半已还,
|
|
|
|
|
+ 只剩 nginx 转发 + 注入 token);⚠️ 影响:生产 DMS 请求从"静默跳过"变成"会尝试并发告警"
|
|
|
|
|
+- 名字跟着改的地方(共 16 个文件):6 个 verify 脚本的默认 base、`upload-policy-library.mjs`、
|
|
|
|
|
+ `verify-attachment-question.mjs`、`gen-company-info-mapping-doc.mjs`、`audit-company-info-coverage.mjs`、
|
|
|
|
|
+ `verify-policy-library.mjs` 的 §8 断言、以及 `shared.ts` / `client.ts` / `file-upload.ts` / `runtime-config.ts` 的注释
|
|
|
|
|
+- 活文档同步:`architecture.md`(env 表 + 代理方案 + 开发环境)、`asr-nls.md`、`current-api-call-sites.md` §D、
|
|
|
|
|
+ `tech-debt #9/#11`(#9 改成"已还一半")
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- **四条代理 dev 实测全通**:页面 200 · `/dms/content/selectContentList` 取到**真实数据**(代理注入 token)·
|
|
|
|
|
+ `/dms/static/…json` **200 / 392,833 字节** · `/api/proxy/verify/getALYToken` 取到 token ·
|
|
|
|
|
+ `/api/proxy/verify/getIPByBrowser` 取到真实 IP `116.232.248.128` · `/oauth/api/user/login` 用默认账号拿到 JWT
|
|
|
|
|
+- 校验套件:`verify-policy-library` **54/54** · `verify-attachment-question` **57/57** ·
|
|
|
|
|
+ `verify-dms-payload-fields` **19/19** · `verify-question-cards` **36/36** ·
|
|
|
|
|
+ `verify-vue-script-html-comments` 通过 · `validate-harness` 通过
|
|
|
|
|
+- `npm run build` 通过(主 chunk hash 变化属预期:env 值改了)
|
|
|
|
|
+- 悬空引用检查:`VITE_IP_TARGET` / `VITE_ALY_TARGET` 已无引用(`vite.config.ts` 顶部一处旧注释同步修掉)
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 65:`vite.config.ts` 不再读环境变量(用户:「不要加环境变量」)
|
|
|
|
|
+
|
|
|
|
|
+**用户要求**:代理的 target 不要从 env 读,直接写在 `vite.config.ts` 里。
|
|
|
|
|
+
|
|
|
|
|
+**改动**:
|
|
|
|
|
+- `vite.config.ts`:删掉 `loadEnv` 导入与 `const env = loadEnv(...)`;`defineConfig(({ mode }) => …)`
|
|
|
|
|
+ 改为 `defineConfig(() => …)`;四个 target 改成**字面量**(`/api`→`http://121.43.55.7:10011`、
|
|
|
|
|
+ `/oauth`→`…:10086`、`/dms`→`…:10081`、`/chat-api`→`http://192.168.2.23:8000`);
|
|
|
|
|
+ DMS token 那处 `readDmsToken(env.DMS_TOKEN)` → `readDmsToken()`(函数内部仍会兜底读
|
|
|
|
|
+ `process.env.DMS_TOKEN`,见 `dms-token.mjs`,不受影响)
|
|
|
|
|
+- `.env.development`:**删掉四个 `*_TARGET`**(`VITE_CHAT_TARGET` / `VITE_DMS_TARGET` /
|
|
|
|
|
+ `VITE_OAUTH_TARGET` / `VITE_API_TARGET`),原"target 区"改成一行说明(target 在 vite.config 里)
|
|
|
|
|
+- 文档同步:`architecture.md`(env 表删掉 target 行;把"地址往 env 里放"那条**反向**成
|
|
|
|
|
+ "target 写死在 `vite.config.ts`,换地址=改那四行")、`current-api-call-sites.md` §D、`tech-debt #11`
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- `grep 'env\.' vite.config.ts`:只剩注释里的字样(无实际读取)
|
|
|
|
|
+- `npm run build` 通过;主 chunk hash 与上一轮**完全一致**(`main-BadLEO6B`)⇒ 只动了 dev 侧配置,对产物零影响
|
|
|
|
|
+- **dev 冒烟(硬编码后复测四条)**:页面 200 · `/dms/content/selectContentList` 真实数据 ·
|
|
|
|
|
+ `/api/proxy/verify/getALYToken` 取到 token · `/api/proxy/verify/getIPByBrowser` 真实 IP ·
|
|
|
|
|
+ `/oauth/api/user/login` 到达业务层(用假凭据返回"用户不存在"= 链路通)· dev 日志 0 条 error
|
|
|
|
|
+- `node harness/tools/validate-harness.mjs` 通过
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
+### 续 66:未登录访客的 DMS token 改由**前端自己换**(用户要求)
|
|
|
|
|
+
|
|
|
|
|
+**用户要求**:「未登录时 token 通过 oauth 的默认账号获取」。我给了两条路
|
|
|
|
|
+(代理侧换 / 前端换)并写清代价,**用户选前端换**。
|
|
|
|
|
+
|
|
|
|
|
+**实现**:
|
|
|
|
|
+- 新增 `src/network/api/dms/service-token.ts`:内置服务账号(`user_yszs_web`),
|
|
|
|
|
+ 经 `POST {VITE_OAUTH_LOGIN_URL}`(默认 `/oauth/api/user/login`,同源代理)换 JWT
|
|
|
|
|
+ (⚠️ token 在响应 **`message`** 里,过期时间取 `content.failureTime`),内存缓存 +
|
|
|
|
|
+ 提前 5 分钟刷新 + 并发共用同一个在途请求;文件顶部写明两个已知代价
|
|
|
|
|
+- `src/utils/runtime-config.ts`:新增 `getOauthLoginUrl()`(globalThis → env → 默认值)
|
|
|
|
|
+- `src/network/api/dms/client.ts`:请求带 `token` 头;遇 **201/212 → 丢缓存重换一次**再试;
|
|
|
|
|
+ 换 token 失败时降级为不带 token(dev 由代理兜底并 warn)
|
|
|
|
|
+- `vite.config.ts` 的 `/dms/`:代理**只在请求没带 `token` 时注入**(否则会覆盖前端刚换的)
|
|
|
|
|
+- 两份 env 新增 `VITE_OAUTH_LOGIN_URL`;生产需 nginx **直通 `/oauth/` → 121.43.55.7:10086**
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 两个已知代价(用户知悉后仍要求这样做)**:
|
|
|
|
|
+1. **服务账号的密码进了公开产物**(构建核对:main chunk 命中 1 次)—— 任何人抠出来都能登录 DMS
|
|
|
|
|
+2. **token 落在浏览器内存**(能打开站点的人都能拿到一个"能读 DMS 数据"的令牌)
|
|
|
|
|
+⇒ 已在 `service-token.ts` 顶部、`architecture.md`、技术债 **#8**(改为"暴露面扩大")写明;
|
|
|
|
|
+#8 的后端行级授权方案仍是"生产接入前必须处理"。
|
|
|
|
|
+
|
|
|
|
|
+**📌 用户随后澄清(本轮内)**:该账号**是专门准备的「默认账号」**("已处理过了")——
|
|
|
|
|
+按要求把上面几处的措辞从"**建议**它只作权限受限的服务账号"改成**事实陈述**
|
|
|
|
|
+(`service-token.ts` / `dms-login.mjs` / `architecture.md` / 技术债 #8 各一处),
|
|
|
|
|
+避免后来人把它当未决风险反复提;"要收紧就改密码并同步改两处代码"这条操作说明保留。
|
|
|
|
|
+
|
|
|
|
|
+**📌 同日另一个决定:`.dms-token` 保留、机制不动**(用户问"可以删除吗" → 选"先不删,保持现状")。
|
|
|
|
|
+查清后的口径:**前端已不依赖它**(自己经 `/oauth` 换),但它是**命令行工具**经 dev 代理读写 DMS
|
|
|
|
|
+的凭据缓存(6 个走代理的工具 + 4 个直接读它的脚本),且 `predev` 会自动重建 ⇒ 单独删等于白删。
|
|
|
|
|
+"要彻底不落盘得改哪三件事"已写进 `harness/tools/dms-token.mjs` 头部与 `architecture.md`,
|
|
|
|
|
+下次不用再从头查。
|
|
|
|
|
+
|
|
|
|
|
+**运行过的验证**:
|
|
|
|
|
+- **新增 `harness/tools/verify-dms-service-token.mjs` 5/5**(打真实服务、经 dev 代理):
|
|
|
|
|
+ ① 前端模块换到 JWT(长度 183)② 二次调用命中缓存 ③ 带真 token → `/dms` code 200 有数据
|
|
|
|
|
+ ④ **带假 token → DMS 拒(code 212 无效token)⇒ 证明代理没有覆盖前端带的 token**(关键断言)
|
|
|
|
|
+ ⑤ 不带 token → 代理兜底注入 → 200(命令行排查方式未受影响)
|
|
|
|
|
+- `npm run build` 通过(main chunk 389.24 → **390.63 kB**:新增模块 + 服务账号)
|
|
|
|
|
+- `vue-tsc` 仅既有 `webpack-env` 报错;`validate-harness` 通过
|
|
|
|
|
+
|
|
|
|
|
+**本轮改动未提交**(用户 2026-09-24 起要求不自动提交)。
|
|
|
|
|
+
|
|
|
|
|
|