| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611 |
- /**
- * 把业务流程从备注协议迁到正式字段(2026-08-13)
- * 用法:node scripts/migrate-remarks-to-fields.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;
- 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 num(shortName, alias, must, seq) {
- return {
- alias,
- customType: "",
- describe: "number",
- frontType: "float_num",
- id: 6,
- must: !!must,
- name: "c_" + shortName,
- searchType: "1,3",
- sequence: seq || 5,
- showParam: "name,alias,desc,type,front_type,must,default_value",
- sortType: "1,2",
- type: "double",
- };
- }
- function ts(shortName, alias, must, seq) {
- return {
- alias,
- customType: "",
- describe: "时间戳",
- frontType: "date_time",
- id: 3,
- must: !!must,
- name: "c_" + shortName,
- searchType: "3",
- sequence: seq || 2,
- showParam: "name,alias,describe,type,front_type,must,date_type,date_picker",
- sortType: "1,2",
- type: "timestamp",
- };
- }
- function intf(shortName, alias, must, seq) {
- return {
- alias,
- customType: "",
- describe: "number",
- frontType: "int_num",
- id: 5,
- must: !!must,
- name: "c_" + shortName,
- searchType: "1,3",
- sequence: seq || 4,
- showParam: "name,alias,desc,type,front_type,must,default_value",
- sortType: "1,2",
- type: "integer",
- };
- }
- 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 updateFieldList(token, modelId, addMap) {
- 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,
- };
- });
- if (Object.keys(addfieldList).length === 0) {
- return {
- modelId,
- modelName: model.modelName,
- code: 200,
- message: "无需新增",
- added: [],
- fields: Object.keys(fieldList).sort(),
- };
- }
- 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);
- return {
- modelId,
- modelName: model.modelName,
- code: res.code,
- message: res.message || res.content,
- added: Object.keys(addfieldList),
- fields: Object.keys(normalizeFieldList(verify.fieldList)).sort(),
- };
- }
- function remarkTag(remarks, key) {
- if (!remarks || !key) return null;
- const parts = String(remarks).split("|");
- for (const p of parts) {
- const i = p.indexOf("=");
- if (i > 0 && p.slice(0, i).trim() === key) return p.slice(i + 1).trim();
- }
- return null;
- }
- function pipeVal(remarks, key) {
- if (!remarks || !key) return null;
- const token = "|" + key + "|";
- const s = String(remarks);
- const i = s.indexOf(token);
- if (i < 0) return null;
- const rest = s.slice(i + token.length);
- const cut = rest.indexOf("|");
- const v = cut >= 0 ? rest.slice(0, cut) : rest;
- return v ? v : null;
- }
- async function listAll(token, columnId, modelId) {
- const all = [];
- for (let page = 0; page < 50; page++) {
- const list = await post(
- "/proxy_dms/content/selectContentList",
- { columnId: String(columnId), modelId: String(modelId), page: String(page), pageSize: "100", states: "0" },
- token
- );
- const rows = (list.content && list.content.data) || [];
- all.push(...rows);
- if (rows.length < 100) break;
- }
- return all;
- }
- async function updateRow(token, columnId, modelId, content) {
- return post(
- "/proxy_dms/content/updateContent",
- { columnId: String(columnId), modelId: String(modelId), content: JSON.stringify(content) },
- token
- );
- }
- function extractBizId(remarks) {
- if (!remarks) return null;
- const parts = String(remarks).split("|");
- for (const p of parts) {
- if (/^P\d+$/.test(p.trim())) return p.trim();
- }
- return null;
- }
- function cleanPersonnelRemarks(remarks) {
- if (!remarks) return "";
- let s = String(remarks);
- s = s.replace(/^DELETED\|/, "").replace(/^PURGED\|/, "");
- s = s.replace(/^MOCK_SEED_\d+\|/, "");
- s = s.replace(/^P\d+\|/, "");
- s = s.replace(/\|FUNERAL_PAID\|[^|]*/g, "");
- s = s.replace(/\|heirRelation=[^|]*/g, "");
- s = s.replace(/\|ALLOW_DIRECT/g, "");
- s = s.replace(/\|+/g, "|").replace(/^\||\|$/g, "").trim();
- if (s === "管理员修改" || s === "村级录入" || s === "Excel导入") return s;
- return s;
- }
- async function backfillPersonnel(token) {
- const rows = await listAll(token, 1847, 1970);
- let updated = 0;
- for (const row of rows) {
- const remarks = row.c_remarks || "";
- const content = { id: row.id };
- let dirty = false;
- const biz = row.c_biz_id || extractBizId(remarks);
- if (biz && biz !== row.c_biz_id) {
- content.c_biz_id = biz;
- dirty = true;
- }
- const heir = row.c_heir_relation || remarkTag(remarks, "heirRelation");
- if (heir && heir !== row.c_heir_relation) {
- content.c_heir_relation = heir;
- dirty = true;
- }
- if (/FUNERAL_PAID/.test(remarks) && row.c_funeral_paid !== "true") {
- content.c_funeral_paid = "true";
- dirty = true;
- }
- const cleaned = cleanPersonnelRemarks(remarks);
- if (cleaned !== remarks) {
- content.c_remarks = cleaned;
- dirty = true;
- }
- if (!dirty) continue;
- const res = await updateRow(token, 1847, 1970, content);
- if (res.code == 200) updated++;
- }
- return { total: rows.length, updated };
- }
- async function backfillRegion(token) {
- const rows = await listAll(token, 1842, 1965);
- let updated = 0;
- for (const row of rows) {
- const remarks = row.c_remarks || "";
- const content = { id: row.id };
- let dirty = false;
- const bank = row.c_default_bank || remarkTag(remarks, "bank");
- if (bank && bank !== row.c_default_bank) {
- content.c_default_bank = bank;
- dirty = true;
- }
- const enabledTag = remarkTag(remarks, "enabled");
- const enabled = row.c_enabled || (enabledTag === "false" ? "false" : "true");
- if (enabled && enabled !== row.c_enabled) {
- content.c_enabled = enabled;
- dirty = true;
- }
- const d = row.c_district_share_percent || remarkTag(remarks, "DISTRICT_SHARE") || remarkTag(remarks, "districtShare");
- if (d != null && d !== "" && String(d) !== String(row.c_district_share_percent)) {
- content.c_district_share_percent = Number(String(d).replace("%", ""));
- dirty = true;
- }
- const t = row.c_town_share_percent || remarkTag(remarks, "TOWN_SHARE") || remarkTag(remarks, "townShare");
- if (t != null && t !== "" && String(t) !== String(row.c_town_share_percent)) {
- content.c_town_share_percent = Number(String(t).replace("%", ""));
- dirty = true;
- }
- let cleaned = String(remarks)
- .replace(/(^|\|)(level|code|parent|plan|entrust|bank|enabled|DISTRICT_SHARE|TOWN_SHARE|districtShare|townShare)=[^|]*/g, "")
- .replace(/\|+/g, "|")
- .replace(/^\||\|$/g, "")
- .trim();
- if (cleaned !== remarks) {
- content.c_remarks = cleaned;
- dirty = true;
- }
- if (!dirty) continue;
- const res = await updateRow(token, 1842, 1965, content);
- if (res.code == 200) updated++;
- }
- return { total: rows.length, updated };
- }
- async function backfillBatch(token) {
- const rows = await listAll(token, 1845, 1968);
- let updated = 0;
- for (const row of rows) {
- const remarks = String(row.c_remarks || "");
- const content = { id: row.id };
- let dirty = false;
- const m = remarks.match(/SUBMIT_TIME\|(\d+)/);
- if (m && !row.c_submit_time) {
- content.c_submit_time = Number(m[1]);
- dirty = true;
- }
- if (/CALC_LOCKED\|true/.test(remarks) && row.c_calc_locked !== "true") {
- content.c_calc_locked = "true";
- dirty = true;
- }
- if ((/YEARLY_ADJUST/.test(remarks) || /调标/.test(remarks)) && row.c_yearly_adjust !== "true") {
- content.c_yearly_adjust = "true";
- dirty = true;
- }
- if (/DELETED\|/.test(remarks) && row.c_deleted !== "true") {
- content.c_deleted = "true";
- dirty = true;
- }
- const rf = remarks.match(/RETURN_FILE\|([^|]+)/);
- if (rf && !row.c_return_file_name) {
- content.c_return_file_name = rf[1];
- dirty = true;
- }
- let cleaned = remarks
- .replace(/SUBMIT_TIME\|\d+/g, "")
- .replace(/\|?CALC_LOCKED\|(true|false)/g, "")
- .replace(/^MOCK_SEED_\d+\|/, "")
- .replace(/^API创建\|/, "")
- .replace(/RETURN_FILE\|[^|]+\|/g, "")
- .replace(/^DELETED\|/, "")
- .replace(/^PURGED\|/, "")
- .replace(/\|+/g, "|")
- .replace(/^\||\|$/g, "")
- .trim();
- if (cleaned !== remarks) {
- content.c_remarks = cleaned;
- dirty = true;
- }
- if (!dirty) continue;
- const res = await updateRow(token, 1845, 1968, content);
- if (res.code == 200) updated++;
- }
- return { total: rows.length, updated };
- }
- async function backfillPayment(token) {
- const rows = await listAll(token, 1849, 1974);
- let updated = 0;
- for (const row of rows) {
- const remarks = String(row.c_remarks || "");
- const content = { id: row.id };
- let dirty = false;
- const dist = remarkTag(remarks, "DIST_AMT") || pipeVal(remarks, "DIST_AMT");
- const town = remarkTag(remarks, "TOWN_AMT") || pipeVal(remarks, "TOWN_AMT");
- if (dist && row.c_district_amount == null) {
- content.c_district_amount = Number(dist);
- dirty = true;
- }
- if (town && row.c_town_amount == null) {
- content.c_town_amount = Number(town);
- dirty = true;
- }
- const oldM = remarks.match(/旧月标\s*([0-9.]+)/);
- const newM = remarks.match(/新月标\s*([0-9.]+)/);
- if (oldM && row.c_old_monthly_amount == null) {
- content.c_old_monthly_amount = Number(oldM[1]);
- dirty = true;
- }
- if (newM && row.c_new_monthly_amount == null) {
- content.c_new_monthly_amount = Number(newM[1]);
- dirty = true;
- }
- const km = remarks.match(/应发\s*(\d+)\s*月/);
- if (km && row.c_adjust_months == null) {
- content.c_adjust_months = Number(km[1]);
- dirty = true;
- }
- if (!dirty) continue;
- const res = await updateRow(token, 1849, 1974, content);
- if (res.code == 200) updated++;
- }
- return { total: rows.length, updated };
- }
- async function backfillStandard(token) {
- const rows = await listAll(token, 1843, 1966);
- let updated = 0;
- for (const row of rows) {
- const remarks = String(row.c_remarks || "");
- if (!/DELETED\|/.test(remarks) || row.c_deleted === "true") continue;
- const res = await updateRow(token, 1843, 1966, { id: row.id, c_deleted: "true" });
- if (res.code == 200) updated++;
- }
- return { total: rows.length, updated };
- }
- async function backfillProcess(token) {
- const rows = await listAll(token, 1844, 1967);
- let updated = 0;
- for (const row of rows) {
- const remarks = String(row.c_remarks || "");
- const content = { id: row.id };
- let dirty = false;
- if (remarks.includes("|SPECIAL|")) {
- const amt = pipeVal(remarks, "AMT");
- const town = pipeVal(remarks, "TOWN");
- const batches = pipeVal(remarks, "BATCHES");
- const death = pipeVal(remarks, "DEATH_DATE");
- if (amt && row.c_amount == null) {
- content.c_amount = Number(amt);
- dirty = true;
- }
- if (town && !row.c_town_id) {
- content.c_town_id = town;
- dirty = true;
- }
- if (batches && !row.c_related_batch_ids) {
- content.c_related_batch_ids = batches;
- dirty = true;
- }
- if (death && !row.c_death_date) {
- content.c_death_date = death;
- dirty = true;
- }
- const namePart = remarks.split("|SPECIAL|")[1] || "";
- const nm = namePart.split("|AMT|")[0];
- if (nm && !row.c_personnel_name) {
- content.c_personnel_name = nm.trim();
- dirty = true;
- }
- }
- const rp = pipeVal(remarks, "REFUND_PROGRESS");
- if (rp && !row.c_refund_progress) {
- content.c_refund_progress = rp;
- dirty = true;
- }
- if (remarks.includes("|EXPORTED|") && row.c_exported !== "true") {
- content.c_exported = "true";
- dirty = true;
- }
- if (remarks.includes("STANDARD_PAYLOAD|") && !row.c_payload) {
- const part = remarks.split("STANDARD_PAYLOAD|")[1] || "";
- const cut = part.indexOf("|SPECIAL|");
- content.c_payload = cut >= 0 ? part.slice(0, cut) : part;
- dirty = true;
- }
- const events = pipeVal(remarks, "EVENTS");
- if (events && !row.c_events) {
- content.c_events = events;
- dirty = true;
- }
- if (row.c_biz_type === "CALC_ROUND" || remarks.match(/^\d+\|\d+\|/)) {
- const segs = remarks.split("|");
- if (segs.length >= 3 && row.c_calc_version == null) {
- content.c_calc_version = Number(segs[0]);
- content.c_people_count = Number(segs[1]);
- if (row.c_amount == null) content.c_amount = Number(segs[2]);
- dirty = true;
- }
- }
- if (!dirty) continue;
- const res = await updateRow(token, 1844, 1967, content);
- if (res.code == 200) updated++;
- }
- return { total: rows.length, updated };
- }
- (async () => {
- const login = await post("/proxy_oauth/user/login", {
- userName: "user_liu",
- password: "WE176852439@lmx",
- clientId: "1",
- });
- if (login.code != 200) throw new Error("login fail " + JSON.stringify(login));
- const token = login.message;
- console.log("login ok");
- const results = [];
- results.push(
- await updateFieldList(token, 1970, {
- biz_id: text("biz_id", "人员业务号", false, 50),
- heir_relation: text("heir_relation", "继承人与逝者关系", false, 51),
- funeral_paid: text("funeral_paid", "丧葬是否已发放", false, 52),
- })
- );
- console.log("personnel", results[results.length - 1]);
- results.push(
- await updateFieldList(token, 1965, {
- enabled: text("enabled", "是否启用", false, 20),
- default_bank: text("default_bank", "默认发放银行", false, 21),
- district_share_percent: intf("district_share_percent", "区级资金承担比例", false, 22),
- town_share_percent: intf("town_share_percent", "镇级资金承担比例", false, 23),
- sort_no: intf("sort_no", "排序号", false, 24),
- })
- );
- console.log("region", results[results.length - 1]);
- results.push(
- await updateFieldList(token, 1974, {
- district_amount: num("district_amount", "区级承担金额", false, 40),
- town_amount: num("town_amount", "镇级承担金额", false, 41),
- old_monthly_amount: num("old_monthly_amount", "调标前月补", false, 42),
- new_monthly_amount: num("new_monthly_amount", "调标后月补", false, 43),
- adjust_months: intf("adjust_months", "调标应发月数", false, 44),
- })
- );
- console.log("payment", results[results.length - 1]);
- results.push(
- await updateFieldList(token, 1968, {
- submit_time: ts("submit_time", "提交初审时间", false, 50),
- calc_locked: text("calc_locked", "测算是否锁定", false, 51),
- yearly_adjust: text("yearly_adjust", "是否年调标批", false, 52),
- deleted: text("deleted", "是否已删除", false, 53),
- return_file_name: text("return_file_name", "回盘文件名", false, 54),
- })
- );
- console.log("batch", results[results.length - 1]);
- results.push(
- await updateFieldList(token, 1966, {
- deleted: text("deleted", "是否已删除", false, 20),
- })
- );
- console.log("amount", results[results.length - 1]);
- results.push(
- await updateFieldList(token, 1967, {
- events: text("events", "待补发事件流水", false, 60),
- amount: num("amount", "业务金额", false, 61),
- related_batch_ids: text("related_batch_ids", "关联批次ID列表", false, 62),
- death_date: text("death_date", "死亡日期", false, 63),
- refund_method: text("refund_method", "退款方式", false, 64),
- refund_progress: text("refund_progress", "退款进度", false, 65),
- payload: text("payload", "审批载荷", false, 66),
- heir_name: text("heir_name", "继承人姓名", false, 67),
- heir_id_number: text("heir_id_number", "继承人身份证", false, 68),
- heir_bank_card: text("heir_bank_card", "继承人银行卡", false, 69),
- heir_phone: text("heir_phone", "继承人电话", false, 70),
- calc_version: intf("calc_version", "测算轮次", false, 71),
- people_count: intf("people_count", "测算人数", false, 72),
- exported: text("exported", "特殊业务是否已出盘", false, 73),
- funeral_paid: text("funeral_paid", "丧葬是否已发放", false, 74),
- })
- );
- console.log("process", results[results.length - 1]);
- const bad = results.filter((r) => r.code != 200);
- if (bad.length) {
- console.error("add fields fail", JSON.stringify(bad, null, 2));
- process.exit(1);
- }
- const backfill = {
- personnel: await backfillPersonnel(token),
- region: await backfillRegion(token),
- batch: await backfillBatch(token),
- payment: await backfillPayment(token),
- amount: await backfillStandard(token),
- process: await backfillProcess(token),
- };
- console.log("backfill", backfill);
- const out = { results, backfill };
- const outPath = path.join(__dirname, "migrate-remarks-to-fields-result.json");
- fs.writeFileSync(outPath, JSON.stringify(out, null, 2), "utf8");
- console.log("DONE ->", outPath);
- })().catch((e) => {
- console.error(e);
- process.exit(1);
- });
|