// 一次性脚本:把课题管理模块(yudao-module-research)的补丁并入 config_export_all_20260928.sql 的阶段一
|
const fs = require('node:fs');
|
const path = require('node:path');
|
|
const dir = __dirname;
|
const TARGET = path.join(dir, 'config_export_all_20260928.sql');
|
const BPM = path.join(dir, '_research_bpm_export.sql');
|
const MODULE = path.join(dir, 'research_module.sql');
|
|
const EOL = '\r\n';
|
let doc = fs.readFileSync(TARGET, 'utf8');
|
const bpmLines = fs.readFileSync(BPM, 'utf8').split(/\r?\n/);
|
const moduleLines = fs.readFileSync(MODULE, 'utf8').split(/\r?\n/);
|
|
if (!doc.includes(EOL)) throw new Error('目标文件不是 CRLF');
|
|
/** 断言锚点唯一 */
|
function anchor(text) {
|
const n = doc.split(text).length - 1;
|
if (n !== 1) throw new Error(`锚点出现 ${n} 次,期望 1 次:${text.slice(0, 80)}`);
|
}
|
/** 在锚点前插入 */
|
function insertBefore(text, before) {
|
anchor(text);
|
doc = doc.replace(text, before + EOL + EOL + text);
|
}
|
/** 替换一次 */
|
function replaceOnce(from, to) {
|
anchor(from);
|
doc = doc.replace(from, to);
|
}
|
|
// ---------------------------------------------------------------- 1. 表数量
|
replaceOnce(
|
'-- 范围:全库 BASE TABLE 共 423 张(0918 的 419 张 + 2 张 finance_* + 2 张 ums_*),全部输出 CREATE TABLE;',
|
'-- 范围:全库 BASE TABLE 共 427 张(0918 的 419 张 + 2 张 finance_* + 2 张 ums_* + 4 张 research_*),全部输出 CREATE TABLE;',
|
);
|
|
// ------------------------------------------------- 2. 前言补丁登记块
|
const PREAMBLE = [
|
'-- 补丁内容(2026-09-28,课题管理模块 yudao-module-research):',
|
'-- ① 补 4 张 research_* 表结构(课题指南 / 课题申报书 / 专家评审明细 / 经费拨付记录,仅建空结构,无数据):',
|
'-- research_guideline、research_application、research_topic_review、research_fund_record',
|
'-- ② 补 5 个字典类型 + 13 条字典数据(并入阶段一的 system_dict_type / system_dict_data):',
|
'-- research_guideline_category(重点课题/一般课题)',
|
'-- research_guideline_status(草稿/已发布/已截止)',
|
'-- research_application_status(草稿/审批中/已立项/已驳回)',
|
'-- research_review_conclusion(推荐立项/不推荐立项)',
|
'-- research_fund_status(待拨付/已拨付)',
|
'-- ③ 补 1 条 BPM 分类(并入阶段一的 bpm_category):',
|
'-- id=8002 \'课题立项审批\' / code=\'research_topic_approve\'',
|
'-- ④ 补 1 条 BPM 流程定义(课题申报三级审批:秘书处形式审查→专家评审→学会立项审批),',
|
'-- 分别落 act_re_deployment / act_re_procdef / act_ge_bytearray(3 条) / act_re_model /',
|
'-- bpm_process_definition_info 五张表,流程 key=\'research_topic_approve\'。',
|
'-- bpm_process_definition_info.form_type=20(自定义表单),',
|
'-- form_custom_create_path=/research/application/index、',
|
'-- form_custom_view_path=/research/application/detail/approve/index.vue。',
|
'-- ⚠ 该流程的 BPMN 为手写三节点,**不是** bpm_deploy_flow_from_template 生成的单节点流程。',
|
'-- ⑤ 补 22 条课题管理菜单:1075510「课题管理」(**顶级目录**,parent_id=0,path=/research)',
|
'-- + 1075511「课题指南」/ 1075512「课题申报」(菜单,挂 1075510 下)',
|
'-- + 1075520~1075524(指南查询/创建/更新/删除/发布截止)、',
|
'-- 1075530~1075535(申报查询/创建/更新/删除/提交审批/发布立项通知)、',
|
'-- 1075540~1075543(专家评审查询/录入/修改/删除)、',
|
'-- 1075550~1075553(经费拨付查询/登记/修改/删除)。',
|
'-- **菜单段本文件无需为此改动**:阶段② 的写法是 `INSERT INTO system_menu SELECT *',
|
'-- FROM \\`mom-jssm\\`.system_menu WHERE deleted=b\'0\'`,是执行期跨库全量拷贝,',
|
'-- 只要来源库 mom-jssm 有这几行就会被带过去 —— 与阶段一的字面量 INSERT 不同。',
|
'-- 在此登记只为说明「这版文件确实覆盖了该变更」,避免后来者以为漏了。',
|
'',
|
].join(EOL);
|
insertBefore('-- 历史补丁内容(2026-09-18):', PREAMBLE);
|
|
// --------------------------------------------- 3. 4 张 research_* 表 DDL
|
// 从 research_module.sql 抽取 CREATE TABLE 段(第 10~30 / 34~70 / 74~96 / 100~116 行,1-based)
|
function ddlBlock(fromLine, toLine, tableName) {
|
const body = moduleLines.slice(fromLine - 1, toLine).join(EOL);
|
return [
|
`-- ============ 表:${tableName}(仅 DDL,无数据) ============`,
|
body,
|
'',
|
].join(EOL);
|
}
|
const RESEARCH_DDL = [
|
ddlBlock(10, 30, 'research_guideline'),
|
ddlBlock(34, 70, 'research_application'),
|
ddlBlock(74, 96, 'research_topic_review'),
|
ddlBlock(100, 116, 'research_fund_record'),
|
].join(EOL);
|
insertBefore('-- ============ 表:yudao_demo01_contact(仅 DDL,无数据) ============', RESEARCH_DDL);
|
|
// --------------------------------------------- 4. BPM 流程 INSERT(7 条语句)
|
// _research_bpm_export.sql 的第 10~16 行(1-based)
|
const bpmInserts = bpmLines.slice(9, 16).filter((l) => l.trim() !== '');
|
if (bpmInserts.length !== 7) throw new Error(`BPM INSERT 条数 ${bpmInserts.length},期望 7`);
|
const pick = (prefix) => {
|
const hit = bpmInserts.filter((l) => l.startsWith(prefix));
|
return hit;
|
};
|
const insProcdef = pick('INSERT INTO `act_re_procdef`');
|
const insDeployment = pick('INSERT INTO `act_re_deployment`');
|
const insBytearray = pick('INSERT INTO `act_ge_bytearray`');
|
const insModel = pick('INSERT INTO `act_re_model`');
|
const insProcInfo = pick('INSERT INTO `bpm_process_definition_info`');
|
if (insProcdef.length !== 1 || insDeployment.length !== 1 || insBytearray.length !== 3 || insModel.length !== 1 || insProcInfo.length !== 1) {
|
throw new Error('BPM INSERT 分类数量不符');
|
}
|
|
// 4.1 act_re_procdef
|
replaceOnce(
|
'-- ============ 表:act_re_deployment(导出 21 行) ============',
|
'-- ============ 表:act_re_deployment(导出 22 行) ============',
|
);
|
insertBefore(
|
'-- ============ 表:act_re_deployment(导出 22 行) ============',
|
[...insProcdef, ''].join(EOL),
|
);
|
|
// 4.2 act_re_deployment
|
replaceOnce(
|
'-- ============ 表:act_ge_bytearray(导出 22 行) ============',
|
'-- ============ 表:act_ge_bytearray(导出 25 行) ============',
|
);
|
insertBefore(
|
'-- ============ 表:act_ge_bytearray(导出 25 行) ============',
|
[...insDeployment, ''].join(EOL),
|
);
|
|
// 4.3 act_ge_bytearray(bpmn / diagram / source 三条)
|
replaceOnce(
|
'-- ============ 表:act_re_model(导出 21 行) ============',
|
'-- ============ 表:act_re_model(导出 22 行) ============',
|
);
|
insertBefore(
|
'-- ============ 表:act_re_model(导出 22 行) ============',
|
[...insBytearray, ''].join(EOL),
|
);
|
|
// 4.4 act_re_model
|
replaceOnce(
|
'-- ============ 表:bpm_process_definition_info(导出 21 行) ============',
|
'-- ============ 表:bpm_process_definition_info(导出 22 行) ============',
|
);
|
insertBefore(
|
'-- ============ 表:bpm_process_definition_info(导出 22 行) ============',
|
[...insModel, ''].join(EOL),
|
);
|
|
// 4.5 bpm_process_definition_info(插在 ② 分组横幅之前)
|
const BANNER2 = [
|
'-- ***********************************************************************',
|
'-- ② 协同(业务附件配置 + 分类 + 表单 + 扩展配置)(DDL + 数据)',
|
'-- ***********************************************************************',
|
].join(EOL);
|
insertBefore(BANNER2, [...insProcInfo, ''].join(EOL));
|
|
// 4.6 bpm_category 补 1 行
|
replaceOnce(
|
'-- ============ 表:bpm_form(导出 4 行) ============',
|
'-- ============ 表:bpm_form(导出 4 行) ============',
|
);
|
insertBefore(
|
'-- ============ 表:bpm_form(导出 4 行) ============',
|
[
|
'INSERT INTO `bpm_category` (`id`, `name`, `code`, `description`, `status`, `sort`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)',
|
'VALUES (\'8002\', \'课题立项审批\', \'research_topic_approve\', \'课题申报三级审批(秘书处形式审查→专家评审→学会立项审批)\', \'0\', \'3\', \'1\', \'2026-09-28 20:00:00\', \'1\', \'2026-09-28 20:00:00\', X\'00\');',
|
'',
|
].join(EOL),
|
);
|
replaceOnce(
|
'-- ============ 表:bpm_category(导出 24 行) ============',
|
'-- ============ 表:bpm_category(导出 25 行) ============',
|
);
|
|
// --------------------------------------- 5. 字典类型 5 条 + 字典数据 13 条
|
const DICT_TYPES = [
|
['81000', '课题指南类别', 'research_guideline_category', '0', '重点课题/一般课题分类标注'],
|
['81001', '课题指南状态', 'research_guideline_status', '0', '课题指南发布状态:草稿/已发布/已截止'],
|
['81002', '课题申报状态', 'research_application_status', '0', '课题申报书审批状态:草稿/审批中/已立项/已驳回'],
|
['81003', '专家评审结论', 'research_review_conclusion', '0', '专家评审推荐立项/不推荐立项'],
|
['81004', '经费拨付状态', 'research_fund_status', '0', '课题经费待拨付/已拨付'],
|
];
|
const dictTypeRows = DICT_TYPES.map(
|
([id, name, type, status, remark]) =>
|
`('${id}', '${name}', '${type}', '${status}', '${remark}', '1', '2026-09-28 20:00:00', '1', '2026-09-28 20:00:00', X'00', NULL),`,
|
).join(EOL);
|
insertBefore(
|
'-- ============ 表:system_dict_data(导出 1192 行) ============',
|
[
|
'INSERT INTO `system_dict_type` (`id`, `name`, `type`, `status`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`, `deleted_time`)',
|
'VALUES',
|
dictTypeRows.replace(/,$/, ';'),
|
'',
|
].join(EOL),
|
);
|
replaceOnce(
|
'-- ============ 表:system_dict_type(导出 249 行) ============',
|
'-- ============ 表:system_dict_type(导出 254 行) ============',
|
);
|
|
const DICT_DATA = [
|
['8100001', 1, '重点课题', '1', 'research_guideline_category', 'danger'],
|
['8100002', 2, '一般课题', '2', 'research_guideline_category', 'default'],
|
['8100101', 1, '草稿', '0', 'research_guideline_status', 'default'],
|
['8100102', 2, '已发布', '20', 'research_guideline_status', 'success'],
|
['8100103', 3, '已截止', '30', 'research_guideline_status', 'info'],
|
['8100201', 1, '草稿', '0', 'research_application_status', 'default'],
|
['8100202', 2, '审批中', '15', 'research_application_status', 'processing'],
|
['8100203', 3, '已立项', '20', 'research_application_status', 'success'],
|
['8100204', 4, '已驳回', '35', 'research_application_status', 'danger'],
|
['8100301', 1, '推荐立项', '1', 'research_review_conclusion', 'success'],
|
['8100302', 2, '不推荐立项', '2', 'research_review_conclusion', 'danger'],
|
['8100401', 1, '待拨付', '0', 'research_fund_status', 'warning'],
|
['8100402', 2, '已拨付', '20', 'research_fund_status', 'success'],
|
];
|
const dictDataRows = DICT_DATA.map(
|
([id, sort, label, value, type, color]) =>
|
`('${id}', '${sort}', '${label}', '${value}', '${type}', '0', '${color}', '', '', '1', '2026-09-28 20:00:00', '1', '2026-09-28 20:00:00', X'00'),`,
|
).join(EOL);
|
insertBefore(
|
'-- ============ 表:system_tenant(导出 3 行) ============',
|
[
|
'INSERT INTO `system_dict_data` (`id`, `sort`, `label`, `value`, `dict_type`, `status`, `color_type`, `css_class`, `remark`, `creator`, `create_time`, `updater`, `update_time`, `deleted`)',
|
'VALUES',
|
dictDataRows.replace(/,$/, ';'),
|
'',
|
].join(EOL),
|
);
|
replaceOnce(
|
'-- ============ 表:system_dict_data(导出 1192 行) ============',
|
'-- ============ 表:system_dict_data(导出 1205 行) ============',
|
);
|
|
// ---------------------------------------------------------------- 写出
|
fs.writeFileSync(TARGET, doc, 'utf8');
|
console.log('合并完成');
|