rename-mock-personnel-names.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * 将 DMS 人员底数中偏「测试/模拟」的姓名,改为更自然的真实人名风格。
  3. * 同步更新 title / c_name / c_payee_name(收款人与原姓名相同时一并改)。
  4. * 并尽量同步发放明细、告警里的人员姓名展示字段。
  5. *
  6. * 用法:node scripts/rename-mock-personnel-names.js
  7. */
  8. const http = require("http");
  9. const qs = require("querystring");
  10. const HOST = "121.43.55.7";
  11. const PORT = 2101;
  12. const PERSONNEL = { columnId: 1847, modelId: 1970 };
  13. const PAYMENT = { columnId: 1849, modelId: 1974 };
  14. const ALERT = { columnId: 1841, modelId: 1964 };
  15. const SURNAMES =
  16. "陈林黄赵吴周徐孙马朱胡郭何高罗郑梁谢宋唐许韩冯邓曹彭曾肖田董袁潘于蒋蔡余杜叶程苏魏吕丁任沈姚卢姜崔钟谭陆汪范金石廖贾夏韦傅方白邹孟熊秦邱江尹薛闫段雷侯龙史陶黎贺顾毛郝龚邵万钱严覃武戴莫孔向汤";
  17. const GIVEN = [
  18. "建国", "志强", "秀英", "桂英", "玉兰", "海燕", "丽华", "文斌", "晓东", "雅琴",
  19. "国强", "美玲", "建华", "春梅", "卫东", "秀兰", "永强", "桂芳", "俊杰", "秀珍",
  20. "立新", "慧敏", "德明", "玉珍", "志明", "秀云", "建军", "丽娟", "国平", "凤英",
  21. "永明", "秀芳", "学军", "玉梅", "伟强", "红梅", "建平", "金凤", "志华", "春花",
  22. "明华", "秀梅", "永华", "丽君", "国华", "玉华", "建民", "秀华", "志刚", "美华",
  23. "海波", "晓燕", "立军", "桂花", "文杰", "玉英", "永军", "淑芬", "建伟", "秀芬",
  24. "明辉", "玉芳", "国庆", "春兰", "志勇", "丽萍", "永刚", "秀琴", "建强", "美芳",
  25. "文华", "玉萍", "国栋", "桂兰", "志伟", "秀红", "永辉", "丽娜", "建辉", "美珍",
  26. "海峰", "玉红", "明强", "春燕", "立华", "秀萍", "文强", "桂珍", "永新", "丽敏",
  27. "建新", "美云", "国伟", "玉琴", "志军", "秀娟", "永平", "红英", "建龙", "美琴",
  28. ];
  29. function isMockName(name) {
  30. const n = String(name || "").trim();
  31. if (!n) return true;
  32. if (/测|测试|门禁|闭环|回盘|驳回|生命周期|暂停测|失败员|知晓请/.test(n)) return true;
  33. if (/^(张三|李四|王五|赵六|钱七|孙八|周九|吴十)$/.test(n)) return true;
  34. return false;
  35. }
  36. function post(urlPath, fields, token) {
  37. return new Promise((resolve, reject) => {
  38. const body = qs.stringify(fields || {});
  39. const headers = {
  40. "Content-Type": "application/x-www-form-urlencoded",
  41. "Content-Length": Buffer.byteLength(body),
  42. };
  43. if (token) {
  44. headers.Token = token;
  45. headers.token = token;
  46. }
  47. const req = http.request(
  48. { hostname: HOST, port: PORT, path: urlPath, method: "POST", headers },
  49. (res) => {
  50. let data = "";
  51. res.on("data", (c) => (data += c));
  52. res.on("end", () => {
  53. try {
  54. resolve(JSON.parse(data));
  55. } catch (e) {
  56. resolve({ raw: data, status: res.statusCode });
  57. }
  58. });
  59. }
  60. );
  61. req.on("error", reject);
  62. req.write(body);
  63. req.end();
  64. });
  65. }
  66. async function listAll(token, col) {
  67. const all = [];
  68. for (let page = 0; page < 100; page++) {
  69. const list = await post(
  70. "/proxy_dms/content/selectContentList",
  71. {
  72. columnId: String(col.columnId),
  73. modelId: String(col.modelId),
  74. page: String(page),
  75. pageSize: "100",
  76. states: "0",
  77. },
  78. token
  79. );
  80. const rows = (list.content && list.content.data) || [];
  81. all.push(...rows);
  82. if (rows.length < 100) break;
  83. }
  84. return all;
  85. }
  86. async function updateRow(token, col, patch) {
  87. return post(
  88. "/proxy_dms/content/updateContent",
  89. {
  90. columnId: String(col.columnId),
  91. modelId: String(col.modelId),
  92. content: JSON.stringify(patch),
  93. },
  94. token
  95. );
  96. }
  97. function buildNamePool(count) {
  98. const used = new Set();
  99. const out = [];
  100. let i = 0;
  101. while (out.length < count && i < count * 20) {
  102. i++;
  103. const sn = SURNAMES[out.length % SURNAMES.length];
  104. const gn = GIVEN[(out.length * 7 + i) % GIVEN.length];
  105. const name = sn + gn;
  106. if (used.has(name)) continue;
  107. used.add(name);
  108. out.push(name);
  109. }
  110. // 兜底:加序号避免撞名
  111. while (out.length < count) {
  112. const name = "陈" + GIVEN[out.length % GIVEN.length] + (out.length + 1);
  113. if (!used.has(name)) {
  114. used.add(name);
  115. out.push(name);
  116. }
  117. }
  118. return out;
  119. }
  120. (async () => {
  121. const login = await post("/proxy_oauth/user/login", {
  122. userName: "user_liu",
  123. password: "WE176852439@lmx",
  124. clientId: "1",
  125. });
  126. if (login.code != 200) throw new Error("login fail " + JSON.stringify(login));
  127. const token = login.message;
  128. const people = await listAll(token, PERSONNEL);
  129. const targets = people.filter((p) => isMockName(p.c_name || p.title));
  130. // 保留已像真人的(如 王忆),其余全改;若用户希望「都」改成更自然,对非 mock 也跳过
  131. console.log("personnel total=" + people.length + " rename=" + targets.length);
  132. const pool = buildNamePool(targets.length);
  133. const idToNew = new Map();
  134. const oldToNew = new Map();
  135. let ok = 0;
  136. let fail = 0;
  137. for (let i = 0; i < targets.length; i++) {
  138. const row = targets[i];
  139. const oldName = String(row.c_name || row.title || "").trim();
  140. const newName = pool[i];
  141. idToNew.set(String(row.id), newName);
  142. if (!oldToNew.has(oldName)) oldToNew.set(oldName, []);
  143. oldToNew.get(oldName).push(newName);
  144. const payee = String(row.c_payee_name || "").trim();
  145. const patch = {
  146. id: row.id,
  147. title: newName,
  148. c_name: newName,
  149. };
  150. if (!payee || payee === oldName || isMockName(payee)) {
  151. patch.c_payee_name = newName;
  152. }
  153. const res = await updateRow(token, PERSONNEL, patch);
  154. if (res.code == 200) {
  155. ok++;
  156. console.log("P", oldName, "->", newName, "id=" + row.id);
  157. } else {
  158. fail++;
  159. console.log("FAIL person", row.id, res.message || res.code);
  160. }
  161. }
  162. // 发放明细:按 personnelId 优先,否则按旧姓名匹配(同名多条时按出现顺序轮转)
  163. const details = await listAll(token, PAYMENT);
  164. const oldQueues = new Map();
  165. for (const [old, arr] of oldToNew) oldQueues.set(old, arr.slice());
  166. let dOk = 0;
  167. for (const row of details) {
  168. const pid = String(row.c_personnel_id || row.c_person_id || "");
  169. const oldName = String(row.c_name || row.c_personnel_name || "").trim();
  170. let newName = pid && idToNew.get(pid);
  171. if (!newName && oldName && isMockName(oldName)) {
  172. const q = oldQueues.get(oldName);
  173. if (q && q.length) newName = q.length === 1 ? q[0] : q.shift();
  174. else if (oldToNew.has(oldName)) newName = oldToNew.get(oldName)[0];
  175. }
  176. if (!newName) continue;
  177. const patch = { id: row.id, c_name: newName };
  178. if (row.title && isMockName(row.title)) patch.title = String(row.title).replace(oldName, newName);
  179. if (row.c_personnel_name && isMockName(row.c_personnel_name)) patch.c_personnel_name = newName;
  180. const res = await updateRow(token, PAYMENT, patch);
  181. if (res.code == 200) dOk++;
  182. }
  183. console.log("payment-detail renamed=" + dOk + "/" + details.length);
  184. // 告警
  185. const alerts = await listAll(token, ALERT);
  186. let aOk = 0;
  187. for (const row of alerts) {
  188. const pid = String(row.c_personnel_id || "");
  189. const oldName = String(row.c_personnel_name || "").trim();
  190. let newName = pid && idToNew.get(pid);
  191. if (!newName && oldName && isMockName(oldName) && oldToNew.has(oldName)) {
  192. newName = oldToNew.get(oldName)[0];
  193. }
  194. if (!newName) continue;
  195. const patch = { id: row.id, c_personnel_name: newName };
  196. if (row.title && isMockName(row.title)) {
  197. patch.title = String(row.title).split(oldName).join(newName);
  198. }
  199. const res = await updateRow(token, ALERT, patch);
  200. if (res.code == 200) aOk++;
  201. }
  202. console.log("alert renamed=" + aOk + "/" + alerts.length);
  203. console.log("DONE personnel ok=" + ok + " fail=" + fail);
  204. })().catch((e) => {
  205. console.error(e);
  206. process.exit(1);
  207. });