| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053 |
- #!/usr/bin/env node
- /**
- * 模拟前 3 个月(202605 / 202606 / 202607)全区月批 + 镇统计完整生命周期与流程日志。
- * 对齐现行模型:DB{yyyyMM} 全区批、TB{yyyyMM}-{townId} 镇统计。
- *
- * 用法:
- * node scripts/seed-history-3months.js
- * node scripts/seed-history-3months.js --dry-run
- */
- const http = require("http");
- const qs = require("querystring");
- const fs = require("fs");
- const path = require("path");
- const HOST = process.env.DMS_HOST || "121.43.55.7";
- const PORT = Number(process.env.DMS_PORT || 2101);
- const DRY = process.argv.includes("--dry-run");
- const MARKER = "HISTORY_SEED_20260828";
- const COL = {
- pcb: { columnId: 1845, modelId: 1968 },
- ffmx: { columnId: 1849, modelId: 1974 },
- lcb: { columnId: 1844, modelId: 1967 },
- alart: { columnId: 1841, modelId: 1964 },
- };
- const TOWNS = [
- { id: "T_YEXIE", name: "叶榭镇", plan: "17010002" },
- { id: "T_SHESHAN", name: "佘山镇", plan: "17010003" },
- { id: "T_CHEDUN", name: "车墩镇", plan: "17010004" },
- { id: "T_MAOGANG", name: "泖港镇", plan: "17010005" },
- { id: "T_XINBANG", name: "新浜镇", plan: "17010006" },
- { id: "T_XIAOKUNSHAN", name: "小昆山镇", plan: "17010007" },
- ];
- function request(method, 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: 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();
- });
- }
- async function login() {
- const res = await request("POST", "/proxy_oauth/user/login", {
- userName: "user_liu",
- password: "WE176852439@lmx",
- clientId: "1",
- });
- if (res.code != 200) throw new Error("login fail: " + JSON.stringify(res));
- return res.message;
- }
- async function listAll(token, col) {
- const rows = [];
- for (let page = 0; page < 80; page++) {
- const res = await request(
- "POST",
- "/proxy_dms/content/selectContentList",
- {
- columnId: String(col.columnId),
- modelId: String(col.modelId),
- page: String(page),
- pageSize: "100",
- states: "0",
- },
- token
- );
- if (res.code == 202) break;
- if (res.code != 200) throw new Error("list fail: " + JSON.stringify(res).slice(0, 200));
- const data = (res.content && res.content.data) || [];
- rows.push(...data);
- const count = Number((res.content && res.content.count) || 0);
- if (rows.length >= count || data.length === 0) break;
- }
- return rows;
- }
- async function addContent(token, col, row) {
- if (DRY) return { code: 200, content: "dry-" + Math.random() };
- return request(
- "POST",
- "/proxy_dms/content/addContent",
- {
- columnId: String(col.columnId),
- modelId: String(col.modelId),
- content: JSON.stringify(row),
- },
- token
- );
- }
- async function softDelete(token, col, dmsId) {
- if (DRY) return { code: 200 };
- return request(
- "POST",
- "/proxy_dms/content/updateContent",
- {
- columnId: String(col.columnId),
- modelId: String(col.modelId),
- content: JSON.stringify({ id: dmsId, state: -1, c_remarks: "PURGED|" + MARKER }),
- },
- token
- );
- }
- /** 北京时间某时刻 → 毫秒时间戳 */
- function ts(y, m, d, h = 10, min = 0) {
- return Date.UTC(y, m - 1, d, h - 8, min, 0, 0);
- }
- function payDate(ym) {
- const y = ym.slice(0, 4);
- const m = ym.slice(4, 6);
- return `${y}-${m}-20`;
- }
- function returnDate(ym, day = 25) {
- const y = ym.slice(0, 4);
- const m = ym.slice(4, 6);
- return `${y}-${m}-${String(day).padStart(2, "0")}`;
- }
- function mkDistrict(ym, opts) {
- const id = "DB" + ym;
- return {
- title: ym + "-全区月批",
- c_batch_number: id,
- c_batch_level: "DISTRICT",
- c_pay_month: ym,
- c_district_id: "D_SJ",
- c_current_stage: opts.stage,
- c_status: opts.status,
- c_people_count: opts.people,
- c_normal_amount: opts.normal,
- c_supplementary_payment_amount: opts.supplement || 0,
- c_funeral_amount: opts.funeral || 0,
- c_deduct_amount: opts.deduct || 0,
- c_total_amount: opts.total,
- c_export_status: opts.exportStatus || "未出盘",
- c_return_status: opts.returnStatus || "未回盘",
- c_pay_date: payDate(ym),
- c_return_date: opts.returnDate || null,
- c_submitter: opts.submitter || null,
- c_submit_time: opts.submitTime || null,
- c_remarks: `${MARKER}|DISTRICT_MONTH|${ym}|${opts.note || ""}`,
- content: MARKER,
- };
- }
- function mkTown(ym, town, opts) {
- const id = "TB" + ym + "-" + town.id;
- const dbId = "DB" + ym;
- return {
- title: `${ym}-${town.name}-镇统计`,
- c_batch_number: id,
- c_batch_level: "TOWN",
- c_pay_month: ym,
- c_district_id: "D_SJ",
- c_town_id: town.id,
- c_parent_batch_id: dbId,
- c_entrust_plan_code: town.plan || "",
- c_current_stage: opts.stage,
- c_status: opts.status,
- c_people_count: opts.people,
- c_normal_amount: opts.normal,
- c_supplementary_payment_amount: opts.supplement || 0,
- c_funeral_amount: opts.funeral || 0,
- c_deduct_amount: opts.deduct || 0,
- c_total_amount: opts.total,
- c_export_disk_no: opts.exportDiskNo || null,
- c_export_file_name: opts.exportFileName || null,
- c_export_status: opts.exportStatus || "未出盘",
- c_return_status: opts.returnStatus || "未回盘",
- c_summary_no: opts.summaryNo || null,
- c_pay_bank: "农商",
- c_pay_date: payDate(ym),
- c_return_date: opts.returnDate || null,
- c_submitter: opts.submitter || "镇社区事务受理中心-业务科",
- c_submit_time: opts.submitTime || null,
- c_town_opinion: opts.townOpinion || null,
- c_return_file_name: opts.returnFileName || null,
- c_remarks: `${MARKER}|PARENT_BATCH=${dbId}|${opts.failCount ? "FAIL_CNT=" + opts.failCount + "|" : ""}${opts.note || ""}`,
- content: MARKER,
- };
- }
- function mkLog(seq, row) {
- return {
- title: row.title,
- c_process_number: "PN" + seq,
- c_batch_id: row.batchId,
- c_batch_no: row.batchNo || row.batchId.replace(/^DB|^TB/, "").slice(0, 6),
- c_town_id: row.townId || "",
- c_village_id: row.villageId || "",
- c_stage: row.stage,
- c_biz_type: row.bizType || "月度批次",
- c_approve_node: row.node,
- c_operator: row.operator,
- c_operator_role: row.role || "",
- c_operator_org: row.org || "",
- c_action: row.action,
- c_opinion: row.opinion || "",
- c_result: row.result,
- c_status: "已完成",
- c_operate_time: row.time,
- c_remarks: `${MARKER}|${row.remark || ""}`,
- content: MARKER,
- };
- }
- function mkDetail(ym, town, person, batchId) {
- const monthly = person.monthly || 1380;
- const supplement = person.supplement || 0;
- const funeral = person.funeral || 0;
- const deduct = person.deduct || 0;
- const total = person.total != null ? person.total : monthly + supplement + funeral - deduct;
- return {
- title: `${person.name}-${ym}`,
- c_batch_id: "DB" + ym,
- c_batch_number: "DB" + ym,
- c_user_id: person.id,
- c_name: person.name,
- c_id_number: person.idNo,
- c_pay_month: ym,
- c_town_id: town.id,
- c_village_id: person.villageId || "",
- c_district_id: "D_SJ",
- c_standard_amount: monthly,
- c_one_time_amount: 0,
- c_supplementary_payment_amount: supplement,
- c_death_amount: funeral,
- c_funeral_amount: funeral,
- c_deduct_amount: deduct,
- c_total_amount: total,
- c_actual_amount: total,
- c_pay_bank: person.bank || "农商",
- c_bank_card_number: person.card || "",
- c_exported: person.exported != null ? String(person.exported) : "true",
- c_return_success: person.returnOk != null ? String(person.returnOk) : "true",
- c_remarks: `${MARKER}|${person.note || ""}`,
- content: MARKER,
- };
- }
- function mkFailDetail(ym, town, person) {
- const reason = person.failReason || "账户冻结";
- const code = person.failCode || "CODE_003";
- const row = mkDetail(ym, town, person);
- row.c_actual_amount = 0;
- row.c_return_success = "false";
- row.c_return_result = "失败";
- row.c_fail_reason_code = code;
- row.c_remarks = `${MARKER}|回盘失败|${reason}|RETURN_FAIL|${code}`;
- return row;
- }
- function mkSuccessDetail(ym, town, person) {
- const row = mkDetail(ym, town, person);
- row.c_return_success = "true";
- row.c_return_result = "成功";
- row.c_remarks = `${MARKER}|回盘成功`;
- return row;
- }
- function mkAlert(ym, town, person, type, content, status) {
- return {
- title: `AL-${type}-${person.name}`,
- c_batch_no: ym,
- c_batch_id: "TB" + ym + "-" + town.id,
- c_personnel_id: person.id,
- c_personnel_name: person.name,
- c_town_id: town.id,
- c_village_id: person.villageId || "",
- c_level: type.includes("FAIL") || type.includes("DEATH") ? "HIGH" : "MEDIUM",
- c_type: type,
- c_content: content,
- c_handle_status: status === "CLOSED" ? "CLOSED" : status === "PENDING" ? "PENDING" : "PROCESSING",
- c_initiator: "系统",
- c_recipient: "镇社区事务受理中心-业务部门",
- c_status: status === "CLOSED" ? "已关闭" : status === "PENDING" ? "待处理" : "处理中",
- c_remarks: MARKER,
- content: MARKER,
- };
- }
- /** 标准 8 步生命周期日志(镇统计视角,含全区节点) */
- function lifecycleLogs(ym, town, tbId, scenario, t0) {
- const logs = [];
- let seq = Number(ym) * 100;
- const push = (row) => logs.push(mkLog(++seq, row));
- push({
- title: `${ym}-生成全区月批`,
- batchId: "DB" + ym,
- batchNo: ym,
- stage: "STAGE3_INSURANCE_MATCH",
- node: "系统调度",
- operator: "系统",
- role: "定时任务",
- org: "区平台",
- action: "生成全区月批",
- opinion: "每月1日自动生成全区批次并纳入符合条件人员",
- result: "成功",
- time: t0,
- remark: "DISTRICT_GENERATE",
- });
- push({
- title: `${ym}-居保状态匹配`,
- batchId: "DB" + ym,
- batchNo: ym,
- townId: town.id,
- stage: "STAGE4_MONTHLY_LIST",
- node: "社区事务中心-业务部门",
- operator: "李经办",
- role: "镇社区事务受理中心",
- org: town.name + "社区事务受理中心",
- action: "居保匹配",
- opinion: scenario.insuranceNote || "本镇人员居保匹配完成",
- result: scenario.insuranceResult || "成功",
- time: t0 + 86400000,
- remark: "INSURANCE_MATCH",
- });
- if (scenario.submitLeader !== false) {
- push({
- title: `${ym}-${town.name}-提交领导`,
- batchId: tbId,
- batchNo: ym,
- townId: town.id,
- stage: "STAGE5_LEADER_ONLINE_APPROVE",
- node: "社区事务中心-业务部门",
- operator: "王专员",
- role: "镇社区事务受理中心",
- org: town.name + "社区事务受理中心",
- action: "提交领导",
- opinion: "本镇居保已闭环,特殊业务已全部通过,提交分管领导审批",
- result: "成功",
- time: t0 + 86400000 * 4,
- remark: "SUBMIT_LEADER",
- });
- }
- if (scenario.leaderReject) {
- push({
- title: `${ym}-${town.name}-领导驳回`,
- batchId: tbId,
- batchNo: ym,
- townId: town.id,
- stage: "STAGE5_LEADER_ONLINE_APPROVE",
- node: "分管领导",
- operator: "张分管",
- role: "分管领导",
- org: town.name + "社区事务受理中心",
- action: "驳回",
- opinion: scenario.rejectOpinion || "清单人数波动较大,请核对补发明细后重提",
- result: "失败",
- time: t0 + 86400000 * 5,
- remark: "LEADER_REJECT",
- });
- push({
- title: `${ym}-${town.name}-调整后重提`,
- batchId: tbId,
- batchNo: ym,
- townId: town.id,
- stage: "STAGE5_LEADER_ONLINE_APPROVE",
- node: "社区事务中心-业务部门",
- operator: "王专员",
- role: "镇社区事务受理中心",
- org: town.name + "社区事务受理中心",
- action: "提交领导",
- opinion: "已核对补发与扣减,再次提交",
- result: "成功",
- time: t0 + 86400000 * 7,
- remark: "RESUBMIT_LEADER",
- });
- }
- if (scenario.leaderPass !== false && scenario.status !== "REJECTED") {
- push({
- title: `${ym}-${town.name}-领导通过`,
- batchId: tbId,
- batchNo: ym,
- townId: town.id,
- stage: "STAGE6_COMPARE_FILE",
- node: "分管领导",
- operator: "张分管",
- role: "分管领导",
- org: town.name + "社区事务受理中心",
- action: "通过",
- opinion: scenario.passOpinion || "同意发放",
- result: "成功",
- time: t0 + 86400000 * (scenario.leaderReject ? 8 : 6),
- remark: "LEADER_PASS",
- });
- }
- if (["EXPORTED", "RETURNED", "ARCHIVED"].includes(scenario.status)) {
- push({
- title: `${ym}-${town.name}-出盘`,
- batchId: tbId,
- batchNo: ym,
- townId: town.id,
- stage: "STAGE7_OFFLINE_SIGN_PAY",
- node: "社区事务中心-业务部门",
- operator: "王专员",
- role: "镇社区事务受理中心",
- org: town.name + "社区事务受理中心",
- action: "出盘",
- opinion: "已生成 N7C 对照文件并导出",
- result: "成功",
- time: t0 + 86400000 * 17,
- remark: "EXPORT_DISK",
- });
- }
- if (["RETURNED", "ARCHIVED"].includes(scenario.status)) {
- push({
- title: `${ym}-${town.name}-回盘确认`,
- batchId: tbId,
- batchNo: ym,
- townId: town.id,
- stage: "STAGE8_RETURN_CONFIRM",
- node: "社区事务中心-业务部门",
- operator: "王专员",
- role: "镇社区事务受理中心",
- org: town.name + "社区事务受理中心",
- action: "回盘确认",
- opinion: scenario.returnNote || "回盘全部成功",
- result: scenario.returnResult || "成功",
- time: t0 + 86400000 * 22,
- remark: "RETURN_CONFIRM",
- });
- }
- if (scenario.status === "ARCHIVED") {
- push({
- title: `${ym}-${town.name}-归档`,
- batchId: tbId,
- batchNo: ym,
- townId: town.id,
- stage: "STAGE8_RETURN_CONFIRM",
- node: "社区事务中心-业务部门",
- operator: "王专员",
- role: "镇社区事务受理中心",
- org: town.name + "社区事务受理中心",
- action: "归档",
- opinion: "本月业务闭环完成",
- result: "成功",
- time: t0 + 86400000 * 24,
- remark: "ARCHIVE",
- });
- }
- return logs;
- }
- function buildPlan() {
- const yexie = TOWNS[0];
- const sheshan = TOWNS[1];
- const chedun = TOWNS[2];
- const maogang = TOWNS[3];
- const xinbang = TOWNS[4];
- const xiaokun = TOWNS[5];
- const batches = [];
- const logs = [];
- const details = [];
- const alerts = [];
- // ===== 202605:完整闭环月(多镇已归档,佘山部分回盘失败) =====
- const ym5 = "202605";
- const t5 = ts(2026, 5, 1, 1, 0);
- batches.push(
- mkDistrict(ym5, {
- stage: "STAGE8_RETURN_CONFIRM",
- status: "ARCHIVED",
- people: 42150,
- normal: 58182000,
- funeral: 248680,
- total: 58430680,
- exportStatus: "已导出",
- returnStatus: "全部成功",
- returnDate: returnDate(ym5),
- note: "前三月历史-五月全区已归档",
- })
- );
- batches.push(
- mkTown(ym5, yexie, {
- stage: "STAGE8_RETURN_CONFIRM",
- status: "ARCHIVED",
- people: 9882,
- normal: 13635780,
- funeral: 84632,
- total: 13720412,
- exportDiskNo: "DP605Y001",
- exportFileName: "LSJ20260520.N7C",
- exportStatus: "已导出",
- returnStatus: "全部成功",
- summaryNo: "170000061805",
- returnDate: returnDate(ym5),
- submitTime: t5 + 86400000 * 4,
- townOpinion: "同意发放",
- note: "叶榭镇-完整闭环",
- })
- );
- batches.push(
- mkTown(ym5, sheshan, {
- stage: "STAGE8_RETURN_CONFIRM",
- status: "ARCHIVED",
- people: 5620,
- normal: 7755600,
- supplement: 2760,
- funeral: 24868,
- total: 7783228,
- exportDiskNo: "DP605S001",
- exportFileName: "LSJ20260520-SH.N7C",
- exportStatus: "已导出",
- returnStatus: "部分异常",
- returnDate: returnDate(ym5, 26),
- submitTime: t5 + 86400000 * 4,
- townOpinion: "同意发放",
- failCount: 1,
- returnFileName: "N7R202605SH.txt",
- note: "佘山镇-回盘1人账户冻结",
- })
- );
- batches.push(
- mkTown(ym5, chedun, {
- stage: "STAGE8_RETURN_CONFIRM",
- status: "ARCHIVED",
- people: 3180,
- normal: 4388400,
- total: 4388400,
- exportDiskNo: "DP605C001",
- exportFileName: "LSJ20260520-CD.N7C",
- exportStatus: "已导出",
- returnStatus: "全部成功",
- returnDate: returnDate(ym5),
- submitTime: t5 + 86400000 * 5,
- townOpinion: "同意",
- note: "车墩镇-正常归档",
- })
- );
- logs.push(
- ...lifecycleLogs(ym5, yexie, "TB" + ym5 + "-T_YEXIE", { status: "ARCHIVED" }, t5)
- );
- logs.push(
- ...lifecycleLogs(
- ym5,
- sheshan,
- "TB" + ym5 + "-T_SHESHAN",
- {
- status: "ARCHIVED",
- returnNote: "1人账户冻结失败,已纳入下月补发台账",
- returnResult: "部分异常",
- },
- t5 + 3600000
- )
- );
- logs.push(
- ...lifecycleLogs(ym5, chedun, "TB" + ym5 + "-T_CHEDUN", { status: "ARCHIVED" }, t5 + 7200000)
- );
- const p605 = [
- { id: "H605001", name: "姜小妹", idNo: "31022719650312424X", villageId: "V_YX_001", card: "6228480030001111001" },
- { id: "H605002", name: "封纪昌", idNo: "310227195804084251", villageId: "V_YX_001", card: "6228480030001111002" },
- { id: "H605003", name: "张洪芳", idNo: "310227194912014268", villageId: "V_YX_002", supplement: 1380, card: "6228480030001111003" },
- ];
- p605.forEach((p) => details.push(mkSuccessDetail(ym5, yexie, p)));
- details.push(
- mkFailDetail(ym5, sheshan, {
- id: "H605101",
- name: "陈阿伯",
- idNo: "310227195001011234",
- villageId: "V_SS_001",
- card: "6228480030005555001",
- monthly: 1380,
- failReason: "账户冻结",
- failCode: "CODE_003",
- })
- );
- details.push(
- mkSuccessDetail(ym5, sheshan, {
- id: "H605102",
- name: "王荷香",
- idNo: "310227196203156789",
- villageId: "V_SS_001",
- card: "6228480030005555002",
- })
- );
- alerts.push(
- mkAlert(
- ym5,
- sheshan,
- { id: "H605101", name: "陈阿伯", villageId: "V_SS_001" },
- "RETURN_FAIL",
- "回盘失败:账户冻结(失败码003)",
- "PENDING"
- )
- );
- // ===== 202606:领导驳回重提 + 部分回盘失败 + 一镇仍驳回 =====
- const ym6 = "202606";
- const t6 = ts(2026, 6, 1, 1, 0);
- batches.push(
- mkDistrict(ym6, {
- stage: "STAGE4_MONTHLY_LIST",
- status: "PENDING_STATUS_MAINTAIN",
- people: 42280,
- normal: 58351200,
- funeral: 124340,
- total: 58475540,
- note: "六月全区-居保已完成,各镇推进不一",
- })
- );
- batches.push(
- mkTown(ym6, yexie, {
- stage: "STAGE8_RETURN_CONFIRM",
- status: "ARCHIVED",
- people: 9920,
- normal: 13689600,
- supplement: 5520,
- deduct: 1380,
- total: 13693740,
- exportDiskNo: "DP606Y001",
- exportFileName: "LSJ20260620.N7C",
- exportStatus: "已导出",
- returnStatus: "部分异常",
- returnDate: returnDate(ym6, 27),
- submitTime: t6 + 86400000 * 7,
- townOpinion: "同意发放",
- failCount: 2,
- returnFileName: "N7R202606YX.txt",
- note: "叶榭-领导驳回后重提并成功归档",
- })
- );
- batches.push(
- mkTown(ym6, maogang, {
- stage: "STAGE4_MONTHLY_LIST",
- status: "REJECTED",
- people: 2105,
- normal: 2904900,
- total: 2904900,
- exportStatus: "未出盘",
- returnStatus: "未回盘",
- submitTime: t6 + 86400000 * 5,
- townOpinion: "清单与上月差异说明不充分,请补充",
- note: "泖港-领导驳回待调整",
- })
- );
- batches.push(
- mkTown(ym6, xinbang, {
- stage: "STAGE7_OFFLINE_SIGN_PAY",
- status: "EXPORTED",
- people: 1850,
- normal: 2553000,
- total: 2553000,
- exportDiskNo: "DP606X001",
- exportFileName: "LSJ20260620-XB.N7C",
- exportStatus: "已导出",
- returnStatus: "待确认",
- submitTime: t6 + 86400000 * 6,
- townOpinion: "同意",
- note: "新浜-已出盘待回盘",
- })
- );
- logs.push(
- ...lifecycleLogs(
- ym6,
- yexie,
- "TB" + ym6 + "-T_YEXIE",
- {
- status: "ARCHIVED",
- leaderReject: true,
- rejectOpinion: "补发 5520 元缺少附件说明,请补充后重提",
- returnNote: "2人卡号变更失败,已生成待补发",
- returnResult: "部分异常",
- },
- t6
- )
- );
- logs.push(
- ...lifecycleLogs(
- ym6,
- maogang,
- "TB" + ym6 + "-T_MAOGANG",
- {
- status: "REJECTED",
- leaderPass: false,
- leaderReject: false,
- submitLeader: true,
- },
- t6 + 3600000
- )
- );
- logs.push({
- ...mkLog(202606999, {
- title: `${ym6}-泖港-领导驳回`,
- batchId: "TB" + ym6 + "-T_MAOGANG",
- batchNo: ym6,
- townId: maogang.id,
- stage: "STAGE5_LEADER_ONLINE_APPROVE",
- node: "分管领导",
- operator: "张分管",
- role: "分管领导",
- org: "泖港镇社区事务受理中心",
- action: "驳回",
- opinion: "清单与上月差异说明不充分,请补充",
- result: "失败",
- time: t6 + 86400000 * 6,
- remark: "LEADER_REJECT_FINAL",
- }),
- });
- logs.push(
- ...lifecycleLogs(
- ym6,
- xinbang,
- "TB" + ym6 + "-T_XINBANG",
- { status: "EXPORTED", leaderPass: true },
- t6 + 7200000
- )
- );
- details.push(
- mkSuccessDetail(ym6, yexie, {
- id: "H606001",
- name: "陆建民",
- idNo: "310227196811221234",
- villageId: "V_YX_001",
- card: "6228480030002222001",
- supplement: 1380,
- })
- );
- details.push(
- mkFailDetail(ym6, yexie, {
- id: "H606002",
- name: "顾秀珍",
- idNo: "310227195503156789",
- villageId: "V_YX_002",
- card: "6228480030002222002",
- monthly: 1380,
- failReason: "卡号变更未生效",
- failCode: "CODE_005",
- })
- );
- details.push(
- mkFailDetail(ym6, yexie, {
- id: "H606003",
- name: "朱福根",
- idNo: "310227194708081122",
- villageId: "V_YX_001",
- card: "6228480030002222003",
- monthly: 1380,
- failReason: "账户冻结",
- failCode: "CODE_003",
- })
- );
- alerts.push(
- mkAlert(
- ym6,
- yexie,
- { id: "H606002", name: "顾秀珍", villageId: "V_YX_002" },
- "RETURN_FAIL",
- "回盘失败:卡号变更未生效",
- "PROCESSING"
- )
- );
- // ===== 202607:当月前一月,多阶段并行 =====
- const ym7 = "202607";
- const t7 = ts(2026, 7, 1, 1, 0);
- batches.push(
- mkDistrict(ym7, {
- stage: "STAGE4_MONTHLY_LIST",
- status: "PENDING_STATUS_MAINTAIN",
- people: 42410,
- normal: 58525800,
- total: 58525800,
- note: "七月全区-居保已完成",
- })
- );
- batches.push(
- mkTown(ym7, yexie, {
- stage: "STAGE5_LEADER_ONLINE_APPROVE",
- status: "PENDING_LEADER_APPROVE",
- people: 9955,
- normal: 13737900,
- total: 13737900,
- exportStatus: "未出盘",
- returnStatus: "未回盘",
- submitTime: t7 + 86400000 * 5,
- note: "叶榭-已提交待领导审批",
- })
- );
- batches.push(
- mkTown(ym7, sheshan, {
- stage: "STAGE4_MONTHLY_LIST",
- status: "PENDING_STATUS_MAINTAIN",
- people: 5655,
- normal: 7803900,
- total: 7803900,
- exportStatus: "未出盘",
- returnStatus: "未回盘",
- note: "佘山-居保已完成,特殊业务未齐",
- })
- );
- batches.push(
- mkTown(ym7, xiaokun, {
- stage: "STAGE6_COMPARE_FILE",
- status: "READY_EXPORT",
- people: 1420,
- normal: 1959600,
- total: 1959600,
- exportStatus: "未出盘",
- returnStatus: "未回盘",
- submitTime: t7 + 86400000 * 6,
- townOpinion: "同意",
- note: "小昆山-领导已通过待出盘",
- })
- );
- logs.push(
- ...lifecycleLogs(
- ym7,
- yexie,
- "TB" + ym7 + "-T_YEXIE",
- { status: "PENDING_LEADER_APPROVE", leaderPass: false, submitLeader: true },
- t7
- )
- );
- logs.push(
- ...lifecycleLogs(
- ym7,
- sheshan,
- "TB" + ym7 + "-T_SHESHAN",
- {
- status: "PENDING_STATUS_MAINTAIN",
- submitLeader: false,
- leaderPass: false,
- insuranceNote: "本镇 3 笔特殊业务待领导审批,暂不可提交月补",
- },
- t7 + 3600000
- )
- );
- logs.push(
- ...lifecycleLogs(
- ym7,
- xiaokun,
- "TB" + ym7 + "-T_XIAOKUNSHAN",
- { status: "READY_EXPORT", leaderPass: true },
- t7 + 7200000
- )
- );
- details.push(
- mkDetail(ym7, yexie, {
- id: "H607001",
- name: "杨春梅",
- idNo: "31022719720315****",
- villageId: "V_YX_001",
- exported: false,
- note: "待领导审批",
- })
- );
- return { batches, logs, details, alerts };
- }
- async function listBySearch(token, col, search) {
- const rows = [];
- for (let page = 0; page < 200; page++) {
- const res = await request(
- "POST",
- "/proxy_dms/content/selectContentList",
- {
- columnId: String(col.columnId),
- modelId: String(col.modelId),
- page: String(page),
- pageSize: "100",
- states: "0",
- search: JSON.stringify(search),
- },
- token
- );
- if (res.code == 202) break;
- if (res.code != 200) throw new Error("search fail: " + JSON.stringify(res).slice(0, 200));
- const data = (res.content && res.content.data) || [];
- rows.push(...data);
- const count = Number((res.content && res.content.count) || 0);
- if (rows.length >= count || data.length === 0) break;
- }
- return rows;
- }
- async function purgeExisting(token) {
- const targets = [
- { col: COL.pcb, match: (r) => isHistoryRow(r, ["c_pay_month", "c_batch_number", "c_remarks"]) },
- { col: COL.lcb, match: (r) => isHistoryRow(r, ["c_batch_no", "c_batch_id", "c_remarks"]) },
- { col: COL.ffmx, match: (r) => isHistoryRow(r, ["c_pay_month", "c_remarks"]), useSearch: true },
- { col: COL.alart, match: (r) => isHistoryRow(r, ["c_batch_no", "c_remarks"]) },
- ];
- const months = ["202605", "202606", "202607"];
- const ids = months.flatMap((ym) => [
- "DB" + ym,
- ...TOWNS.map((t) => "TB" + ym + "-" + t.id),
- ]);
- let purged = 0;
- for (const t of targets) {
- let rows;
- if (t.useSearch) {
- const seen = new Set();
- rows = [];
- const markerRows = await listBySearch(token, t.col, [
- { field: "content", searchType: 1, content: { value: MARKER } },
- ]);
- for (const r of markerRows) {
- if (!seen.has(r.id)) {
- seen.add(r.id);
- rows.push(r);
- }
- }
- for (const ym of months) {
- const monthRows = await listBySearch(token, t.col, [
- { field: "c_pay_month", searchType: 1, content: { value: ym } },
- ]);
- for (const r of monthRows) {
- if (!seen.has(r.id)) {
- seen.add(r.id);
- rows.push(r);
- }
- }
- }
- } else {
- rows = await listAll(token, t.col);
- }
- for (const r of rows) {
- const remark = String(r.c_remarks || r.content || "");
- const payMonth = String(r.c_pay_month || "");
- const batchNo = String(r.c_batch_number || r.c_batch_id || "");
- const hit =
- remark.includes(MARKER) ||
- ids.some((id) => batchNo === id || batchNo.includes(id)) ||
- months.includes(payMonth);
- if (hit && t.match(r)) {
- await softDelete(token, t.col, r.id);
- purged++;
- }
- }
- }
- return purged;
- }
- function isHistoryRow(r, fields) {
- const months = ["202605", "202606", "202607"];
- for (const f of fields) {
- const v = String(r[f] || "");
- if (v.includes(MARKER)) return true;
- if (months.some((m) => v.includes(m))) return true;
- }
- return false;
- }
- async function seedRows(token, col, rows, label) {
- let ok = 0;
- let fail = 0;
- for (const row of rows) {
- const res = await addContent(token, col, row);
- if (res.code == 200) ok++;
- else {
- fail++;
- console.log(" x", label, res.code, res.message || res.content, row.title);
- }
- }
- return { ok, fail };
- }
- (async () => {
- console.log(DRY ? "[dry-run]" : "[write]", "seed history 202605-202607 →", HOST + ":" + PORT);
- const token = await login();
- console.log("login ok");
- console.log("\n[0] 清理同月旧数据…");
- const purged = await purgeExisting(token);
- console.log(" purged rows:", purged);
- const plan = buildPlan();
- console.log("\n[1] 批次", plan.batches.length);
- const b = await seedRows(token, COL.pcb, plan.batches, "pcb");
- console.log(" ok", b.ok, "fail", b.fail);
- console.log("\n[2] 流程日志", plan.logs.length);
- const l = await seedRows(token, COL.lcb, plan.logs, "lcb");
- console.log(" ok", l.ok, "fail", l.fail);
- console.log("\n[3] 发放明细样例", plan.details.length);
- const d = await seedRows(token, COL.ffmx, plan.details, "ffmx");
- console.log(" ok", d.ok, "fail", d.fail);
- console.log("\n[4] 关联告警", plan.alerts.length);
- const a = await seedRows(token, COL.alart, plan.alerts, "alart");
- console.log(" ok", a.ok, "fail", a.fail);
- const summary = {
- marker: MARKER,
- months: ["202605", "202606", "202607"],
- purged,
- batches: b,
- logs: l,
- details: d,
- alerts: a,
- scenarios: {
- "202605": "叶榭/车墩完整归档;佘山部分回盘失败",
- "202606": "叶榭驳回后重提归档;泖港领导驳回;新浜已出盘待回盘",
- "202607": "叶榭待领导审;佘山居保完成未提交;小昆山待出盘",
- },
- at: new Date().toISOString(),
- };
- const out = path.join(__dirname, "seed-history-3months-result.json");
- fs.writeFileSync(out, JSON.stringify(summary, null, 2));
- console.log("\nWrote", out);
- console.log("\n场景摘要:");
- Object.entries(summary.scenarios).forEach(([k, v]) => console.log(" ", k, v));
- })().catch((e) => {
- console.error(e);
- process.exit(1);
- });
|