Files
tuanwei-admin/scripts/selfcheck-module-registry.mjs
T
weicw 74f801a081 feat(gxmu): 模块下拉改由模块注册表驱动,审批链每级支持审批人规则
- 新增模块注册表 api 与进程内缓存(首次使用拉一次、并发共用同一个请求),
  启用清单驱动「可新建审批链」的模块下拉与审核列表模块筛选
- reviewFlowConfigEdit 不再维护硬编码模块清单;停用模块的历史配置按
  「标题(已停用)」回显,避免下拉空白
- module → detailKey 的映射收敛到 detailKeyOf 一处,moduleDetailConfig
  未命中注册表时回退 module 本身(停用模块的详情仍可打开)
- 审核流每级新增「审批人规则」输入(USER:<userId> / COLLEGE_ROLE:<roleCode>,
  分号拼装多段,留空沿用「指定人」),随该级提交 reviewerRule 并回显
- 新增 scripts/selfcheck-module-registry.mjs:前端无单测基建时验证下拉过滤、
  detailKey 回退与停用模块回显
2026-11-03 22:40:43 +08:00

109 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* 模块注册表前端逻辑的最小自检(仓库无单测基建,用 Node + typescript.transpileModule 跑纯函数)。
*
* 覆盖 ticket #65 的可见行为:
* 1. 「可新建审批链」下拉只含 enabled=1 的模块,按 sortNumber 升序,标题取注册表 title;
* 2. module → detailKey 的映射收在 resolveDetailKey 一处,注册表里没有该模块时回退 module 本身,
* 保证停用模块的历史审批链仍能回显标题、仍能打开详情;
* 3. 编辑历史配置时把停用的模块补进下拉(带「已停用」标记),不重复添加。
*
* 运行:node scripts/selfcheck-module-registry.mjs
*/
import { readFileSync } from 'node:fs';
import { createRequire } from 'node:module';
import { dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const require = createRequire(import.meta.url);
const ts = require('typescript');
const root = resolve(dirname(fileURLToPath(import.meta.url)), '..');
const loadTs = (relative) => {
const file = resolve(root, relative);
const source = readFileSync(file, 'utf8');
const { outputText } = ts.transpileModule(source, {
compilerOptions: {
module: ts.ModuleKind.CommonJS,
target: ts.ScriptTarget.ES2019
},
fileName: file
});
const mod = { exports: {} };
new Function('exports', 'require', 'module', outputText)(
mod.exports,
require,
mod
);
return mod.exports;
};
let failed = 0;
const assert = (name, condition, detail) => {
if (condition) {
console.log(' ok ' + name);
return;
}
failed += 1;
console.log(' FAIL ' + name + (detail ? ' -> ' + detail : ''));
};
const core = loadTs('src/utils/module-registry-core.ts');
// 与后端种子数据一致:10 个模块里只有 4 个 enabled=1
const REGISTRY = [
{ module: 'gxmu_sjqn', detailKey: 'gxmu_sjqn', title: '十佳青年岗位能手', enabled: 1, sortNumber: 1 },
{ module: 'gxmu_sjtbzbsj', detailKey: 'gxmu_sjtbzbsj', title: '十佳团支部书记', enabled: 0, sortNumber: 2 },
{ module: 'gxmu_tzbcy_form', detailKey: 'gxmu_tzbcy_form', title: '挑战杯', enabled: 1, sortNumber: 7 },
{ module: 'gxmu_qmgc_form', detailKey: 'gxmu_qmgc_form', title: '青马工程', enabled: 1, sortNumber: 8 },
{ module: 'gxmu_wxxzx_project', detailKey: 'gxmu_wxxzx_project', title: '未来学术之星', enabled: 1, sortNumber: 9 },
{ module: 'cms_manuscript', detailKey: 'cms_manuscript', title: '稿件', enabled: 0, sortNumber: 10 }
];
console.log('新建审批链的模块下拉(enabled=1,按 sortNumber)');
const options = core.toModuleOptions(REGISTRY);
assert(
'只含已启用模块',
options.map((o) => o.value).join(',') ===
'gxmu_sjqn,gxmu_tzbcy_form,gxmu_qmgc_form,gxmu_wxxzx_project',
JSON.stringify(options)
);
assert('label 取注册表标题', options[0].label === '十佳青年岗位能手');
assert('停用模块不出现', !options.some((o) => o.value === 'gxmu_sjtbzbsj'));
console.log('审核列表的模块筛选项(同理,按注册表顺序)');
assert(
'与新建下拉同源',
core.toModuleOptions(REGISTRY).length === options.length
);
console.log('module → detailKey 映射(收在一处)');
assert('走注册表 detailKey', core.resolveDetailKey(REGISTRY, 'gxmu_sjqn') === 'gxmu_sjqn');
assert(
'注册表缺该模块时回退 module(停用模块的详情仍可解析)',
core.resolveDetailKey(REGISTRY, 'legacy_module') === 'legacy_module'
);
assert('空模块返回空', core.resolveDetailKey(REGISTRY, undefined) === undefined);
console.log('标题解析(历史配置回显)');
assert('注册表命中', core.resolveModuleTitle(REGISTRY, 'gxmu_qmgc_form') === '青马工程');
assert('注册表未命中回退 module 本身', core.resolveModuleTitle(REGISTRY, 'legacy_module') === 'legacy_module');
console.log('编辑历史配置:把停用模块补进下拉');
const merged = core.ensureModuleOption(options, 'gxmu_sjtbzbsj', '十佳团支部书记');
assert('补进来的项标记已停用', merged[0]?.label === '十佳团支部书记(已停用)', JSON.stringify(merged[0]));
assert('补进来的项在最前面且可回显', merged[0]?.value === 'gxmu_sjtbzbsj');
assert('原有选项保留', merged.length === options.length + 1);
const duplicated = core.ensureModuleOption(options, 'gxmu_sjqn');
assert('已在选项里则不重复添加', duplicated.length === options.length);
assert(
'无 moduleName 时用 module 当标题',
core.ensureModuleOption(options, 'legacy_module')[0]?.label === 'legacy_module(已停用)'
);
if (failed) {
console.error('\n自检失败:' + failed + ' 项');
process.exit(1);
}
console.log('\n自检通过:' + 5 + ' 组行为');