fix-java-encoding-all.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. const fs = require('fs');
  2. const path = require('path');
  3. const javaRoot = path.join(__dirname, '..', 'fs-service', 'src', 'main', 'java');
  4. const adminRoots = [
  5. path.join(__dirname, '..', 'fs-admin', 'src', 'main', 'java'),
  6. path.join(__dirname, '..', 'fs-saas-admin', 'src', 'main', 'java'),
  7. ];
  8. function u(...codes) {
  9. return String.fromCharCode(...codes);
  10. }
  11. function w(rel, content, root = javaRoot) {
  12. const full = path.join(root, rel);
  13. fs.mkdirSync(path.dirname(full), { recursive: true });
  14. fs.writeFileSync(full, content, 'utf8');
  15. console.log('Wrote', path.relative(path.join(__dirname, '..'), full));
  16. }
  17. function patch(rel, fn, root = javaRoot) {
  18. const full = path.join(root, rel);
  19. if (!fs.existsSync(full)) return;
  20. w(rel, fn(fs.readFileSync(full, 'utf8')), root);
  21. }
  22. function replaceClassComment(content, commentLine) {
  23. return content.replace(/\/\*\*[\s\S]*?\*\//, `/**\n * ${commentLine}\n */`);
  24. }
  25. const T = {
  26. behaviorSvcComment: u(0x6309,0x6e20,0x9053,0x805a,0x5408,0x884c,0x4e3a,0x8f68,0x8ff9,0xff1a,0x4f01,0x5fae,0x770b,0x8bfe,0x2f,0x76f4,0x64ad,0xff0c,0x4e2a,0x5fae,0x5916,0x547c,0x7b49,0x3002),
  27. courseLiveTab: u(0x770b,0x8bfe,0x2f,0x76f4,0x64ad),
  28. mediaSvcComment: u(0x4f01,0x5fae,0x6e20,0x9053,0xff1a,0x770b,0x8bfe,0x20,0x2b,0x20,0x76f4,0x64ad,0x8f68,0x8ff9,0xff08,0x8fd1,0x20,0x4e,0x20,0x5929,0x6309,0x65e5,0x805a,0x5408,0xff09,0x3002),
  29. callSvcComment: u(0x4e2a,0x5fae,0x7b49,0x6e20,0x9053,0xff1a,0x5916,0x547c,0x2f,0x901a,0x8bdd,0x8f68,0x8ff9,0xff08,0x63,0x6f,0x6d,0x70,0x61,0x6e,0x79,0x5f,0x76,0x6f,0x69,0x63,0x65,0x5f,0x6c,0x6f,0x67,0x73,0xff09,0x3002),
  30. outboundTab: u(0x5916,0x547c,0x8bb0,0x5f55),
  31. unknown: u(0x672a,0x77e5),
  32. connected: u(0x5df2,0x63a5,0x901a),
  33. notConnected: u(0x672a,0x63a5,0x901a),
  34. statusPrefix: u(0x72b6,0x6001),
  35. watching: u(0x770b,0x8bfe,0x4e2d),
  36. finishedCourse: u(0x5b8c,0x8bfe),
  37. pendingCourse: u(0x5f85,0x770b,0x8bfe),
  38. interrupted: u(0x770b,0x8bfe,0x4e2d,0x65ad),
  39. finishedDay: u(0x5df2,0x5b8c,0x8bfe),
  40. noRecord: u(0x65e0,0x8bb0,0x5f55),
  41. live: u(0x76f4,0x64ad),
  42. replay: u(0x56de,0x653e),
  43. listHub: u(0x5217,0x8868,0x20,0x48,0x75,0x62,0x20,0x805a,0x5408,0x6587,0x6848,0xff1a,0x7a33,0x5b9a,0x753b,0x50cf,0x20,0x2b,0x20,0x6700,0x65b0,0x6458,0x8981,0x20,0x2b,0x20,0x914d,0x7f6e,0x5b57,0x6bb5,0x20,0x2192,0x20,0x4f9b,0x641c,0x7d22,0x2f,0x5217,0x8868,0x5c55,0x793a,0x3002),
  44. statsSnapshot: u(0x753b,0x50cf,0x7edf,0x8ba1,0x5feb,0x7167,0xff08,0x5bf9,0x5e94,0x20,0x6c,0x6f,0x62,0x73,0x74,0x65,0x72,0x5f,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x5f,0x73,0x74,0x61,0x74,0x73,0xff09,0x3002),
  45. statsDelta: u(0x753b,0x50cf,0x7edf,0x8ba1,0x589e,0x91cf,0xff08,0x524d,0x540e,0x5feb,0x7167,0x5dee,0xff09,0x3002),
  46. summaryView: u(0x5c06,0x4f1a,0x8bdd,0x6458,0x8981,0x5b9e,0x4f53,0x8f6c,0x4e3a,0x9762,0x677f,0x2f,0x8fd0,0x884c,0x65f6,0x53ef,0x7528,0x7684,0x7ed3,0x6784,0x5316,0x89c6,0x56fe,0xff08,0x542b,0x20,0x31,0x31,0x20,0x7ef4,0x20,0x65,0x78,0x74,0x65,0x6e,0x64,0x65,0x64,0x53,0x75,0x6d,0x6d,0x61,0x72,0x79,0xff09,0x3002),
  47. factLoader: u(0x4ece) + ' customer_fact / customer_habit ' + u(0x52a0,0x8f7d,0x7a33,0x5b9a,0x753b,0x50cf,0xff0c,0x5408,0x5e76,0x8fdb,0x5165) + ' profile ' + u(0x89c6,0x56fe,0x3002),
  48. projectionSync: u(0x4f1a,0x8bdd,0x6458,0x8981,0x5199,0x5165,0x753b,0x50cf,0x8868,0x65f6,0xff0c,0x6295,0x5f71,0x5b57,0x6bb5,0x540c,0x6b65,0x5de5,0x5177,0x3002),
  49. statsRecorder: u(0x753b,0x50cf,0x5199,0x5165,0x540e,0x89e6,0x53d1,0x7edf,0x8ba1,0x8868,0x589e,0x91cf,0x66f4,0x65b0,0x3002),
  50. statsService: u(0x5ba2,0x6237,0x753b,0x50cf,0x7edf,0x8ba1,0x4e2d,0x95f4,0x5c42,0xff1a,0x589e,0x91cf,0x66f4,0x65b0,0x20,0x2b,0x20,0x6309,0x9700,0x91cd,0x7b97,0xff08,0x975e,0x5b9a,0x65f6,0x5168,0x91cf,0x626b,0x63cf,0xff09,0x3002),
  51. timeIntent: u(0x4ece,0x5ba2,0x6237,0x6d88,0x606f,0x89e3,0x6790,0x7ea6,0x5b9a,0x65f6,0x95f4,0x610f,0x56fe,0xff0c,0x7528,0x4e8e,0x20,0x77,0x61,0x69,0x74,0x55,0x6e,0x74,0x69,0x6c,0x20,0x8282,0x70b9,0x3002),
  52. canvasSync: u(0x5c06,0x20,0x62,0x72,0x61,0x6e,0x63,0x68,0x65,0x73,0x20,0x4e,0x20,0x6c,0x65,0x67,0x61,0x63,0x79,0x20,0x6E,0x65,0x78,0x74,0x4E,0x6F,0x64,0x65,0x20,0x5F52,0x4E00,0x4E3A,0x20,0x6E,0x65,0x78,0x74,0x4E,0x6F,0x64,0x65,0x43,0x6F,0x64,0x65),
  53. bindingStats: u(0x7ED1,0x5B9A,0x6267,0x884C,0x7EDF,0x8BA1,0xFF08,0x6C47,0x603B,0x20,0x2B,0x20,0x5237,0x65B0,0xFF09,0x3002),
  54. bindingProvision: u(0x7ED1,0x5B9A,0x5F00,0x901A,0xFF1A,0x6309,0x20,0x72,0x65,0x6C,0x20,0x6279,0x91CF,0x751F,0x6210,0x89E6,0x8FBE,0x4EFB,0x52A1,0xFF08,0x5F02,0x6B65,0x5206,0x6279,0xFF09,0x3002),
  55. stageBracket: u(0x3010,0x9636,0x6bb5,0x3011),
  56. pipe: u(0xff5c),
  57. ellipsis: u(0x2026),
  58. touchTask: u(0x3010) + '${channel}' + u(0x3011,0x89e6,0x8fbe,0x4efb,0x52a1),
  59. nodeBracket: u(0x8282,0x70b9,0x5b),
  60. highQuality: u(0x9ad8,0x8d28,0x91cf,0x56de,0x590d),
  61. customerLabel: u(0x5ba2,0x6237),
  62. replyLabel: u(0x56de,0x590d),
  63. noInstances: u(0x672a,0x9009,0x62e9,0x4efb,0x4f55,0x5b9e,0x4f8b),
  64. instancePrefix: u(0x5b9e,0x4f8b),
  65. noAccess: u(0x65e0,0x6743,0x9650,0x6216,0x4e0d,0x5b58,0x5728),
  66. opFailed: u(0x64cd,0x4f5c,0x5931,0x8d25),
  67. splitChars: u(0xff0c,0xff1b),
  68. terminated: u(0x5df2,0x7ec8,0x6b62),
  69. switchedHuman: u(0x5df2,0x5207,0x6362,0x4eba,0x5de5),
  70. instUnit: u(0x4e2a,0x5b9e,0x4f8b),
  71. skipPart: u(0xff0c,0x8df3,0x8fc7),
  72. unit: u(0x4e2a),
  73. allTenants: u(0x5168,0x90e8,0x79df,0x6237),
  74. };
  75. // fix broken canvasSync and bindingStats - use proper unicode
  76. T.canvasSync = u(0x5c06,0x20,0x62,0x72,0x61,0x6e,0x63,0x68,0x65,0x73,0x20,0x4e,0x20,0x6c,0x65,0x67,0x61,0x63,0x79,0x20,0x6e,0x65,0x78,0x74,0x4e,0x6f,0x64,0x65,0x20,0x5f52,0x4e00,0x4e3A,0x20,0x6e,0x65,0x78,0x74,0x4e,0x6f,0x64,0x65,0x43,0x6f,0x64,0x65);
  77. T.bindingStats = u(0x7ed1,0x5b9a,0x6267,0x884c,0x7edf,0x8ba1,0xff08,0x6c47,0x603b,0x20,0x2b,0x20,0x5237,0x65b0,0xff09,0x3002);
  78. T.bindingProvision = u(0x7ed1,0x5b9a,0x5f00,0x901a,0xff1a,0x6309,0x20,0x72,0x65,0x6c,0x20,0x6279,0x91cf,0x751f,0x6210,0x89e6,0x8fbe,0x4efb,0x52a1,0xff08,0x5f02,0x6b65,0x5206,0x6279,0xff09,0x3002);
  79. w('com/fs/company/service/workflow/profile/panel/CustomerProfileBehaviorTrajectoryService.java', `package com.fs.company.service.workflow.profile.panel;
  80. import org.springframework.beans.factory.annotation.Autowired;
  81. import org.springframework.stereotype.Service;
  82. import org.springframework.util.StringUtils;
  83. import java.util.LinkedHashMap;
  84. import java.util.Map;
  85. /**
  86. * ${T.behaviorSvcComment}
  87. */
  88. @Service
  89. public class CustomerProfileBehaviorTrajectoryService {
  90. @Autowired
  91. private CustomerProfileMediaTrajectoryService mediaTrajectoryService;
  92. @Autowired
  93. private CustomerProfileCallTrajectoryService callTrajectoryService;
  94. public Map<String, Object> loadBehaviorTrajectory(Long companyId, String channelType, String profileKey,
  95. Long customerId, Long contactId, Integer days) {
  96. String channel = normalizeChannel(channelType);
  97. Map<String, Object> result = new LinkedHashMap<>();
  98. result.put("channelType", channel);
  99. if ("WX".equals(channel)) {
  100. Map<String, Object> call = callTrajectoryService.loadCallTrajectory(companyId, customerId, days);
  101. result.put("behaviorType", call.get("behaviorType"));
  102. result.put("tabLabel", call.get("tabLabel"));
  103. result.put("days", call.get("days"));
  104. result.put("stats", call.get("stats"));
  105. result.put("callEvents", call.get("callEvents"));
  106. result.put("courseDays", java.util.Collections.emptyList());
  107. result.put("liveEvents", java.util.Collections.emptyList());
  108. return result;
  109. }
  110. Map<String, Object> media = mediaTrajectoryService.loadMediaTrajectory(
  111. companyId, channel, profileKey, customerId, contactId, days);
  112. result.put("behaviorType", "course_live");
  113. result.put("tabLabel", "${T.courseLiveTab}");
  114. result.put("days", media.get("days"));
  115. result.put("stats", media.get("stats"));
  116. result.put("courseDays", media.get("courseDays"));
  117. result.put("liveEvents", media.get("liveEvents"));
  118. result.put("callEvents", java.util.Collections.emptyList());
  119. result.put("externalContactId", media.get("externalContactId"));
  120. return result;
  121. }
  122. private String normalizeChannel(String channelType) {
  123. if (!StringUtils.hasText(channelType)) {
  124. return "QW";
  125. }
  126. return channelType.trim().toUpperCase();
  127. }
  128. }
  129. `);
  130. patch('com/fs/company/service/workflow/profile/panel/CustomerProfileMediaTrajectoryService.java', (c) => {
  131. let s = c;
  132. s = replaceClassComment(s, T.mediaSvcComment);
  133. s = s.replace(/labels\.put\(1, "[^"]+"\);[\s\S]*?labels\.put\(4, "[^"]+"\);/,
  134. `labels.put(1, "${T.watching}");\n labels.put(2, "${T.finishedCourse}");\n labels.put(3, "${T.pendingCourse}");\n labels.put(4, "${T.interrupted}");`);
  135. s = s.replace(/item\.put\("statusLabel", "[^"]+"\);/g, `item.put("statusLabel", "${T.noRecord}");`);
  136. s = s.replace(/LOG_TYPE_LABELS\.getOrDefault\(logType, "[^"]+"\)/g, `LOG_TYPE_LABELS.getOrDefault(logType, "${T.unknown}")`);
  137. s = s.replace(/if \("finished"\.equals\(status\)\) \{\s*return "[^"]+";/, `if ("finished".equals(status)) {\n return "${T.finishedDay}";`);
  138. s = s.replace(/if \("watching"\.equals\(status\)\) \{\s*return "[^"]+";/, `if ("watching".equals(status)) {\n return "${T.watching}";`);
  139. s = s.replace(/if \("interrupted"\.equals\(status\)\) \{\s*return "[^"]+";/, `if ("interrupted".equals(status)) {\n return "${T.interrupted}";`);
  140. s = s.replace(/if \("pending"\.equals\(status\)\) \{\s*return "[^"]+";/, `if ("pending".equals(status)) {\n return "${T.pendingCourse}";`);
  141. s = s.replace(/return "[^"]+";\s*\}\s*\n\s*private String watchTypeLabel/, `return "${T.noRecord}";\n }\n\n private String watchTypeLabel`);
  142. s = s.replace(/if \(watchType == 1\) \{\s*return "[^"]+";/, `if (watchType == 1) {\n return "${T.live}";`);
  143. s = s.replace(/if \(watchType == 2\) \{\s*return "[^"]+";/, `if (watchType == 2) {\n return "${T.replay}";`);
  144. return s;
  145. });
  146. patch('com/fs/company/service/workflow/profile/panel/CustomerProfileCallTrajectoryService.java', (c) => {
  147. let s = c;
  148. s = replaceClassComment(s, T.callSvcComment);
  149. s = s.replace(/result\.put\("tabLabel", "[^"]+"\);/, `result.put("tabLabel", "${T.outboundTab}");`);
  150. s = s.replace(/private String callStatusLabel[\s\S]*?return "[^"]*" \+ s;/,
  151. `private String callStatusLabel(Object status) {
  152. Integer s = toInteger(status);
  153. if (s == null) {
  154. return "${T.unknown}";
  155. }
  156. if (s == 1) {
  157. return "${T.connected}";
  158. }
  159. if (s == 0) {
  160. return "${T.notConnected}";
  161. }
  162. return "${T.statusPrefix}" + s;`);
  163. return s;
  164. });
  165. const commentMap = {
  166. 'com/fs/company/service/workflow/profile/panel/ProfileListAggregateHelper.java': T.listHub,
  167. 'com/fs/company/service/workflow/profile/panel/ProfileStatsSnapshot.java': T.statsSnapshot,
  168. 'com/fs/company/service/workflow/profile/panel/ProfileStatsDelta.java': T.statsDelta,
  169. 'com/fs/company/service/workflow/profile/panel/ConversationSummaryViewHelper.java': T.summaryView,
  170. 'com/fs/company/service/workflow/profile/panel/CustomerProfileFactLoader.java': T.factLoader,
  171. 'com/fs/company/service/workflow/profile/panel/ProfileSummaryProjectionSync.java': T.projectionSync,
  172. 'com/fs/company/service/workflow/profile/LobsterProfileStatsRecorder.java': T.statsRecorder,
  173. 'com/fs/company/service/workflow/profile/LobsterProfileStatsService.java': T.statsService,
  174. 'com/fs/company/service/workflow/trigger/TimeIntentDetector.java': T.timeIntent,
  175. 'com/fs/company/service/workflow/ILobsterBindingExecStatsService.java': T.bindingStats,
  176. 'com/fs/company/service/workflow/execution/LobsterBindingProvisionServiceImpl.java': T.bindingProvision,
  177. };
  178. for (const [rel, text] of Object.entries(commentMap)) {
  179. patch(rel, (c) => replaceClassComment(c, text));
  180. }
  181. patch('com/fs/company/service/workflow/canvas/WorkflowCanvasSyncUtil.java', (c) =>
  182. c.replace(/\/\*\*[^*]*\*\//, `/** ${T.canvasSync} */`));
  183. patch('com/fs/company/service/workflow/profile/panel/ProfileSummaryProjectionSync.java', (c) => {
  184. let s = c;
  185. s = s.replace(/clipPreview\("[^"]*" \+ stage\.trim\(\) \+ " [^"]* " \+ snippet\)/,
  186. `clipPreview("${T.stageBracket}" + stage.trim() + "${T.pipe}" + snippet)`);
  187. s = s.replace(/clipPreview\("[^"]*" \+ stage\.trim\(\)\)/, `clipPreview("${T.stageBracket}" + stage.trim())`);
  188. s = s.replace(/PREVIEW_MAX\) \+ "[^"]+"/, `PREVIEW_MAX) + "${T.ellipsis}"`);
  189. return s;
  190. });
  191. patch('com/fs/company/service/workflow/trigger/TimeIntentDetector.java', (c) =>
  192. c.replace(/\[\u007cu70b9:\?\?\]/g, '[\\u70b9:\\uFF1A]').replace(/\[:\\?\?\]/g, '[:\\uFF1A]'));
  193. patch('com/fs/company/service/workflow/execution/LobsterBindingProvisionServiceImpl.java', (c) =>
  194. c.replace(/setTaskName\("[^"]*" \+ channelType \+ "[^"]*"\)/,
  195. `setTaskName("${u(0x3010)}" + channelType + "${u(0x3011,0x89e6,0x8fbe,0x4efb,0x52a1)}")`));
  196. patch('com/fs/company/service/workflow/learning/impl/LobsterSkillManageServiceImpl.java', (c) => {
  197. let s = c;
  198. s = s.replace(/sb\.append\("[^"]*\["\)/, `sb.append("${T.nodeBracket}")`);
  199. s = s.replace(/append\("\] [^"]* \("/, `append("] ${T.highQuality} ("`);
  200. let n = 0;
  201. s = s.replace(/sb\.append\("[^"]*: "\)/g, () => {
  202. n += 1;
  203. return n === 1 ? `sb.append("${T.customerLabel}: ")` : `sb.append("${T.replyLabel}: ")`;
  204. });
  205. return s;
  206. });
  207. patch('com/fs/company/service/workflow/impl/LobsterInstanceOpsService.java', (c) => {
  208. let s = c;
  209. s = s.replace(/result\.put\("message", "[^"]+"\)/, `result.put("message", "${T.noInstances}")`);
  210. s = s.replace(/errors\.add\("[^"]* " \+ instanceId \+ " [^"]+"\)/,
  211. `errors.add("${T.instancePrefix} " + instanceId + " ${T.noAccess}")`);
  212. s = s.replace(/ajax\.get\("msg"\) : "[^"]+"\)/, `ajax.get("msg") : "${T.opFailed}")`);
  213. s = s.replace(/errors\.add\("[^"]* " \+ instanceId \+ ": "/g, `errors.add("${T.instancePrefix} " + instanceId + ": "`);
  214. s = s.replace(/split\("\[,;[^"]+"\)/, `split("[,;${T.splitChars}]")`);
  215. s = s.replace(/\? \("[^"]* " \+ success \+ " [^"]*"\)/,
  216. `? ("${T.terminated} " + success + " ${T.instUnit}" + (skipped > 0 ? "${T.skipPart} " + skipped + " ${T.unit}" : "") )`);
  217. s = s.replace(/:\("[^"]* " \+ success \+ " [^"]*"\)/,
  218. `: ("${T.switchedHuman} " + success + " ${T.instUnit}" + (skipped > 0 ? "${T.skipPart} " + skipped + " ${T.unit}" : "") )`);
  219. return s;
  220. });
  221. for (const root of adminRoots) {
  222. patch('com/fs/lobster/controller/LobsterOptimizationController.java', (c) =>
  223. c.replace(/scopeInfo\.put\("label", "[^"]+"\)/, `scopeInfo.put("label", "${T.allTenants}")`), root);
  224. }
  225. function scanGarbled(dir) {
  226. const bad = [];
  227. (function walk(d) {
  228. for (const ent of fs.readdirSync(d, { withFileTypes: true })) {
  229. const p = path.join(d, ent.name);
  230. if (ent.isDirectory()) walk(p);
  231. else if (ent.name.endsWith('.java')) {
  232. const c = fs.readFileSync(p, 'utf8');
  233. if (/\?\?\?/.test(c)) bad.push(path.relative(path.join(__dirname, '..'), p));
  234. }
  235. }
  236. })(dir);
  237. return bad;
  238. }
  239. console.log('Remaining ??? in fs-service:', scanGarbled(javaRoot));
  240. console.log('Done');