check-policy-sources.mjs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. /**
  2. * 政策库的**远端(DMS 里那份)与本地副本**是否一致 —— 保证前端"远端优先"拿到的是同一份数据。
  3. *
  4. * 背景沿革:
  5. * 2026-09-17 这个脚本比的是「本地副本 vs 厂商远端(VITE_DOWNLOAD_URL)」,用来判断
  6. * 「开发环境本地优先」那个开关还有没有必要(当年厂商远端 327 条全都没有 `data.市级政策id`,
  7. * 导致政策详情点不开,所以开发环境一度本地优先)。
  8. * 2026-09-24 用户把政策库的远端换成 **DMS 文件服务里的那份**
  9. * (`node harness/tools/upload-policy-library.mjs` 上传,路径记在 `VITE_POLICY_REMOTE_URL`),
  10. * 顺序也固定成"先远端、取不到再用本地兜底",那个开关随之删除。
  11. * 于是本脚本的职责变成:**核对两边内容是否一致**(远端上传后忘了同步、或本地被换过,这里会报)。
  12. *
  13. * 怎么跑(需要 dev server 起着;远端地址从 .env.development 读,不写死在脚本里):
  14. * node harness/tools/check-policy-sources.mjs
  15. *
  16. * 退出码:0 = 两边一致;1 = 不一致或取不到远端(需要有人看一眼)
  17. */
  18. process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // dev server 是自签证书
  19. import { readFileSync } from 'node:fs';
  20. const LOCAL_PATH = 'public/merchant-agent/policies_public.v2.json';
  21. const ENV_PATH = '.env.development';
  22. /** 从 .env.development 读 VITE_POLICY_REMOTE_URL(只取路径,脚本不关心 host) */
  23. const readRemoteUrl = () => {
  24. const env = readFileSync(ENV_PATH, 'utf8');
  25. const line = env.split(/\r?\n/).find((l) => l.trim().startsWith('VITE_POLICY_REMOTE_URL'));
  26. const raw = line?.split('=').slice(1).join('=').trim().replace(/^["']|["']$/g, '');
  27. return raw;
  28. };
  29. const toList = (json) => (Array.isArray(json) ? json : json?.data) || [];
  30. const nameOf = (item) => String(item?.['政策名称'] ?? item?.name ?? '').trim();
  31. const deptOf = (item) => String(item?.['政策所属部门'] ?? item?.department ?? '').trim();
  32. const localList = toList(JSON.parse(readFileSync(LOCAL_PATH, 'utf8')));
  33. const remoteUrl = readRemoteUrl();
  34. console.log('本地 ' + LOCAL_PATH);
  35. console.log(' 条数: ' + localList.length + ' | 政策名去重: ' + new Set(localList.map(nameOf)).size + ' 个');
  36. let remoteList = [];
  37. let remoteError = '';
  38. console.log('\n远端 ' + (remoteUrl || '(未在 ' + ENV_PATH + ' 找到 VITE_POLICY_REMOTE_URL)'));
  39. if (remoteUrl) {
  40. // 环境变量里存的是同源相对路径(dev 由 vite 代理),脚本里补上 dev server 的 origin 再取
  41. const absolute = /^https?:\/\//.test(remoteUrl) ? remoteUrl : 'https://localhost:8083' + remoteUrl;
  42. try {
  43. const res = await fetch(absolute);
  44. const text = await res.text();
  45. if (!res.ok) throw new Error('HTTP ' + res.status);
  46. remoteList = toList(JSON.parse(text));
  47. console.log(' 条数: ' + remoteList.length + ' | 政策名去重: ' + new Set(remoteList.map(nameOf)).size + ' 个');
  48. } catch (err) {
  49. remoteError = err instanceof Error ? err.message : String(err);
  50. console.log(' 拉取失败: ' + remoteError);
  51. }
  52. }
  53. console.log('\n结论:');
  54. let exitCode = 0;
  55. if (!remoteUrl) {
  56. console.log(' ⚠️ 没有配 VITE_POLICY_REMOTE_URL —— 前端会走本地兜底(功能可用,但没有"远端优先"了)');
  57. exitCode = 1;
  58. } else if (remoteError) {
  59. console.log(' ⚠️ 远端取不到(' + remoteError + ')—— 前端会退回本地副本;检查 DMS/代理是否正常');
  60. exitCode = 1;
  61. } else if (localList.length !== remoteList.length) {
  62. console.log(' ⚠️ 两边条数不同(本地 ' + localList.length + ' / 远端 ' + remoteList.length + ')');
  63. const localNames = new Set(localList.map(nameOf));
  64. const remoteNames = new Set(remoteList.map(nameOf));
  65. console.log(' 仅远端有的政策名 ' + [...remoteNames].filter((n) => !localNames.has(n)).length + ' 个,' +
  66. '仅本地有的 ' + [...localNames].filter((n) => !remoteNames.has(n)).length + ' 个');
  67. exitCode = 1;
  68. } else {
  69. const localDepts = [...new Set(localList.map(deptOf))].sort().join('、');
  70. const remoteDepts = [...new Set(remoteList.map(deptOf))].sort().join('、');
  71. if (localDepts !== remoteDepts) {
  72. console.log(' ⚠️ 部门取值不同:本地 ' + localDepts + ' / 远端 ' + remoteDepts);
  73. exitCode = 1;
  74. } else {
  75. console.log(' ✅ 远端与本地内容一致(' + localList.length + ' 条,部门 ' +
  76. [...new Set(localList.map(deptOf))].filter(Boolean).length + ' 个)—— 远端优先拿到的就是这份');
  77. }
  78. }
  79. if (exitCode && remoteList.length && localList.length === remoteList.length) {
  80. console.log(' (内容有差异时:重新上传本地这份即可 —— node harness/tools/upload-policy-library.mjs)');
  81. }
  82. process.exit(exitCode);