/** * 清空流程测试相关 DMS 数据,便于重新走全流程。 * * 说明:远端 delContentById 接口参数有缺陷无法物理删; * 这里将 state 置为 -1(业务查询固定 states=0,列表不可见,等同清空)。 * * 处理栏目:批次 / 发放明细 / 批次统计 / 流程日志 / 告警 / 金额标准 * 保留:区划、人员 * * 用法: * node purge-flow-test-data.js * node purge-flow-test-data.js --seed-standards */ 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 SEED_STANDARDS = process.argv.includes("--seed-standards") || !process.argv.includes("--no-seed"); const TARGETS = [ { key: "pcb", name: "批次", columnId: 1845, modelId: 1968 }, { key: "ffmx", name: "发放明细", columnId: 1849, modelId: 1974 }, { key: "pctj", name: "批次统计", columnId: 1846, modelId: 1969 }, { key: "lcb", name: "流程/特殊业务/待补发", columnId: 1844, modelId: 1967 }, { key: "alart", name: "告警", columnId: 1841, modelId: 1964 }, { key: "jebz", name: "金额标准", columnId: 1843, modelId: 1966 }, ]; 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 ); // 202 = 无数据 if (res.code == 202) break; if (res.code != 200) { throw new Error("list " + col.key + " fail: " + JSON.stringify(res).slice(0, 300)); } const data = (res.content && res.content.data) || []; rows.push.apply(rows, data); const count = Number((res.content && res.content.count) || 0); if (rows.length >= count || data.length === 0) break; } return rows; } async function softDelete(token, col, id) { return request( "POST", "/proxy_dms/content/updateContent", { columnId: String(col.columnId), modelId: String(col.modelId), content: JSON.stringify({ id: id, state: -1, c_remarks: "FLOW_TEST_PURGED|" + Date.now(), }), }, token ); } async function seedYearlyStandards(token) { const towns = [ { code: "T_YEXIE", name: "叶榭镇" }, { code: "T_SHESHAN", name: "佘山镇" }, { code: "T_CHEDUN", name: "车墩镇" }, { code: "T_SHIHUDANG", name: "石湖荡镇" }, { code: "T_MAOGANG", name: "泖港镇" }, { code: "T_XINBANG", name: "新浜镇" }, { code: "T_XIAOKUNSHAN", name: "小昆山镇" }, ]; const now = Date.now(); const ids = []; for (const t of towns) { const content = { title: t.name + "-年度标准", c_town_id: t.code, c_amount: 1280, c_funeral_amount: 6000, c_date_time: now, c_standard_type: "YEARLY_ADJUST", c_current_flag: "true", c_adjust_reason: "流程测试初始年度标准", c_remarks: "FLOW_TEST_RESET|YEARLY_ADJUST|" + t.code, content: "FLOW_TEST_RESET", }; const res = await request( "POST", "/proxy_dms/content/addContent", { columnId: "1843", modelId: "1966", content: JSON.stringify(content), }, token ); if (res.code == 200) { ids.push({ townId: t.code, id: res.content }); console.log(" + standard", t.code, res.content); } else { console.log(" x standard", t.code, res.code, res.message); } } return ids; } (async () => { const token = await login(); console.log("login ok; seedStandards=", SEED_STANDARDS); const summary = { mode: "soft-delete state=-1", deleted: {}, kept: ["xzqh(区划)", "ryjbxx(人员)"], seededStandards: [], }; for (const col of TARGETS) { const rows = await listAll(token, col); console.log("\n[" + col.key + "] " + col.name + " count=" + rows.length); let ok = 0; let fail = 0; const errors = []; for (const row of rows) { if (!row.id) continue; const res = await softDelete(token, col, row.id); if (res.code == 200) ok++; else { fail++; if (errors.length < 5) errors.push({ id: row.id, code: res.code, message: res.message }); } } const left = await listAll(token, col); summary.deleted[col.key] = { name: col.name, before: rows.length, deleted: ok, failed: fail, left: left.length, sampleErrors: errors, }; console.log(" purged=" + ok + " failed=" + fail + " left=" + left.length); } if (SEED_STANDARDS) { console.log("\n[seed] 写入干净年度标准(土地1280 + 丧葬6000)…"); summary.seededStandards = await seedYearlyStandards(token); } const outPath = path.join(__dirname, "purge-flow-test-data-result.json"); fs.writeFileSync(outPath, JSON.stringify(summary, null, 2), "utf8"); console.log("\nDONE ->", outPath); const anyLeft = Object.keys(summary.deleted).some((k) => summary.deleted[k].left > 0); const anyFail = Object.keys(summary.deleted).some((k) => summary.deleted[k].failed > 0); if (anyLeft || anyFail) { console.error("仍有残留或失败,请检查结果文件"); process.exit(2); } console.log("\n已清空流程数据;保留区划与人员。可开始重新测试。"); })().catch((e) => { console.error(e); process.exit(1); });