| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- /**
- * 对比政策库的**两个来源**,确认「开发环境本地优先」这个开关还有没有必要。
- *
- * 背景(2026-09-17):
- * 政策详情面板的「政策名称」跳转地址由 `data.市级政策id` 拼出
- * (见 src/components/Chat/policy-library-utils.ts 的 buildPolicyDetailUrl)。
- * 但两个来源的字段并不一致:
- * - 本地 public/merchant-agent/policies_public.v1.json → 有 市级政策id
- * - 远端 VITE_DOWNLOAD_URL → 327 条全无该字段
- * 而 index.html 原本是**远端优先**,于是浏览器里取不到 id,「政策名称」是纯文本。
- * 为此加了 VITE_POLICY_LOCAL_FIRST(仅 .env.development 为 true)。
- *
- * 这个脚本干什么:
- * 把两个来源的条数与 市级政策id 覆盖率打出来,并判断那个开关是否仍然需要。
- *
- * 怎么跑(在项目根目录):
- * node harness/tools/check-policy-sources.mjs
- *
- * 退出码:0 = 与预期一致;1 = 情况变了,需要有人看一眼(见输出末尾的提示)
- */
- import { readFileSync } from 'node:fs';
- const LOCAL_PATH = 'public/merchant-agent/policies_public.v1.json';
- const ENV_PATH = '.env.development';
- /** 从 .env.development 读 VITE_DOWNLOAD_URL,避免把地址写死在脚本里 */
- const readDownloadUrl = () => {
- const env = readFileSync(ENV_PATH, 'utf8');
- const line = env.split(/\r?\n/).find((l) => l.trim().startsWith('VITE_DOWNLOAD_URL'));
- const raw = line?.split('=').slice(1).join('=').trim().replace(/^["']|["']$/g, '');
- return raw ? raw + 'merchant-agent/policies_public.v1.json' : '';
- };
- const toList = (json) => (Array.isArray(json) ? json : json?.data) || [];
- /** 统计 data.市级政策id 的覆盖率(buildPolicyDetailUrl 读的就是这个字段) */
- const countCityId = (list) => {
- const missing = [];
- let has = 0;
- for (const item of list) {
- const value = (item?.data || {})['市级政策id'];
- if (value && String(value).trim()) has++;
- else missing.push(item?.name || '(无名)');
- }
- return { has, total: list.length, missing };
- };
- const localList = toList(JSON.parse(readFileSync(LOCAL_PATH, 'utf8')));
- const localId = countCityId(localList);
- console.log('本地 ' + LOCAL_PATH);
- console.log(' 条数: ' + localList.length + ' | 市级政策id: ' + localId.has + '/' + localId.total);
- let remoteList = [];
- let remoteId = { has: 0, total: 0, missing: [] };
- let remoteError = '';
- const url = readDownloadUrl();
- console.log('\n远端 ' + (url || '(未在 ' + ENV_PATH + ' 找到 VITE_DOWNLOAD_URL)'));
- if (url) {
- try {
- const res = await fetch(url);
- if (!res.ok) throw new Error('HTTP ' + res.status);
- remoteList = toList(await res.json());
- remoteId = countCityId(remoteList);
- console.log(' 条数: ' + remoteList.length + ' | 市级政策id: ' + remoteId.has + '/' + remoteId.total);
- } catch (err) {
- remoteError = err.message;
- console.log(' 拉取失败: ' + remoteError + '(跳过远端对比)');
- }
- }
- const localOk = localId.has > 0;
- const remoteHasId = remoteId.has > 0;
- console.log('\n结论:');
- console.log(' 本地这份带 市级政策id:' + (localOk ? '是' : '否'));
- if (url && !remoteError) {
- console.log(' 远端这份带 市级政策id:' + (remoteHasId ? '是' : '否'));
- }
- let exitCode = 0;
- if (!localOk) {
- console.log(' ⚠️ 本地这份也没有 id 了 —— 「本地优先」这个开关失去意义,需重新找 id 来源');
- exitCode = 1;
- } else if (url && !remoteError && remoteHasId) {
- console.log(' ⚠️ 远端现在也带 id 了 —— 「开发环境本地优先」已无必要,可以去掉 VITE_POLICY_LOCAL_FIRST');
- exitCode = 1;
- } else {
- console.log(' ✅ 与预期一致:远端无 id,开发环境仍需本地优先');
- }
- if (remoteList.length && localList.length !== remoteList.length) {
- const localNames = new Set(localList.map((x) => x.name));
- const remoteNames = new Set(remoteList.map((x) => x.name));
- console.log(
- '\n条数差异(本地少 ' +
- (remoteList.length - localList.length) +
- ' 条):仅远端有的政策名 ' +
- [...remoteNames].filter((n) => !localNames.has(n)).length +
- ' 个,仅本地有的 ' +
- [...localNames].filter((n) => !remoteNames.has(n)).length +
- ' 个'
- );
- console.log(' ⚠️ 开发环境用本地这份意味着比远端少 ' + (remoteList.length - localList.length) + ' 条申报事项');
- }
- process.exit(exitCode);
|