/** * 对照 docs/松江农民土地退补系统字段名称.xlsx 补齐 DMS 缺口(2026-09-04) * * 缺口结论: * 1. 人员表缺独立「死亡状态」字段 c_death_status(原仅靠 c_biz_status=FUNERAL / c_death_date) * 2. 人员表 c_supplement_start_month 别名损坏(补发��始年月)→ 修成「补发开始年月」 * * 用法:node migrate-excel-field-gaps-20260904.js */ const http = require("http"); const qs = require("querystring"); const fs = require("fs"); const path = require("path"); const HOST = "121.43.55.7"; const PORT = 2101; const PERSONNEL_MODEL = 1970; function post(urlPath, fields, token) { return new Promise((resolve, reject) => { const body = qs.stringify(fields || {}); const headers = { "Content-Type": "application/x-www-form-urlencoded", "Content-Length": Buffer.byteLength(body), }; if (token) { headers.Token = token; headers.token = token; } const req = http.request( { hostname: HOST, port: PORT, path: urlPath, method: "POST", headers }, (res) => { let data = ""; res.on("data", (c) => (data += c)); res.on("end", () => { try { resolve(JSON.parse(data)); } catch (e) { resolve({ raw: data, status: res.statusCode }); } }); } ); req.on("error", reject); req.write(body); req.end(); }); } function text(shortName, alias, must, seq) { return { alias, customType: "", describe: "格式为富文本", frontType: "content", id: 2, must: !!must, name: "c_" + shortName, searchType: "2", sequence: seq || 1, showParam: "name,alias,desc,type,front_type,must,default_value", type: "text", }; } function normalizeFieldList(raw) { let fl = raw; if (typeof fl === "string") fl = JSON.parse(fl); const out = {}; Object.keys(fl || {}).forEach((k) => { let v = fl[k]; if (typeof v === "string") v = JSON.parse(v); out[k] = v; }); return out; } async function getModel(token, modelId) { const res = await post("/proxy_dms/model/getModelById", { modelId: String(modelId) }, token); if (res.code != 200) throw new Error("getModel " + modelId + " fail: " + JSON.stringify(res)); return res.content; } async function applyUpdates(token, modelId, addMap, renameAliasMap) { const model = await getModel(token, modelId); const fieldList = normalizeFieldList(model.fieldList); if (Object.keys(fieldList).length < 2) { throw new Error("model " + modelId + " fieldList 异常,拒绝覆盖"); } const addfieldList = {}; Object.keys(addMap || {}).forEach((shortName) => { const full = "c_" + shortName; if (fieldList[full]) return; const p = addMap[shortName]; p.name = full; fieldList[full] = p; addfieldList[shortName] = { alias: p.alias, type: p.type, frontType: p.frontType, must: p.must, name: shortName, describe: p.describe, searchType: p.searchType, sortType: p.sortType, sequence: p.sequence, showParam: p.showParam, customType: p.customType || "", id: p.id, }; }); // 仅改 alias:只更新 fieldList 元数据,勿走 updatefieldList(生产 DMS 对 rename 会 500) const aliasFixed = []; Object.keys(renameAliasMap || {}).forEach((full) => { if (!fieldList[full]) return; const nextAlias = renameAliasMap[full]; if (fieldList[full].alias === nextAlias) return; fieldList[full] = Object.assign({}, fieldList[full], { alias: nextAlias }); aliasFixed.push(full); }); if (Object.keys(addfieldList).length === 0 && aliasFixed.length === 0) { return { modelId, modelName: model.modelName, code: 200, message: "无需变更", added: [], updated: [], }; } const res = await post( "/proxy_dms/model/updateFieldList", { modelId: String(modelId), fieldList: JSON.stringify(fieldList), addfieldList: JSON.stringify(addfieldList), delfieldList: JSON.stringify({}), updatefieldList: JSON.stringify({}), }, token ); const verify = await getModel(token, modelId); const vfl = normalizeFieldList(verify.fieldList); return { modelId, modelName: model.modelName, code: res.code, message: res.message || res.content, added: Object.keys(addfieldList), updated: aliasFixed, deathStatus: vfl.c_death_status || null, supplementAlias: vfl.c_supplement_start_month ? vfl.c_supplement_start_month.alias : null, }; } async function main() { const login = await post("/proxy_oauth/user/login", { userName: "user_liu", password: "WE176852439@lmx", clientId: "1", }); const token = login.message; if (!token) throw new Error("login failed: " + JSON.stringify(login)); const result = await applyUpdates( token, PERSONNEL_MODEL, { // 大数据死亡状态匹配专用;与业务态 c_biz_status=FUNERAL 并存 death_status: text("death_status", "死亡状态", false, 40), }, { // 仅修复损坏别名;其余 Excel 名与现有 alias 语义等价,不强制改名以免影响管理端展示习惯 c_supplement_start_month: "补发开始年月", } ); const outPath = path.join( __dirname, "../../docs/_migrate_excel_field_gaps_20260904.json" ); fs.writeFileSync(outPath, JSON.stringify(result, null, 2), "utf8"); console.log(JSON.stringify(result, null, 2)); } main().catch((e) => { console.error(e); process.exit(1); });