| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- const fs = require('fs');
- const path = require('path');
- const javaRoot = path.join(__dirname, '..', 'fs-service', 'src', 'main', 'java');
- const adminRoots = [
- path.join(__dirname, '..', 'fs-admin', 'src', 'main', 'java'),
- path.join(__dirname, '..', 'fs-saas-admin', 'src', 'main', 'java'),
- ];
- function u(...codes) {
- return String.fromCharCode(...codes);
- }
- function w(rel, content, root = javaRoot) {
- const full = path.join(root, rel);
- fs.mkdirSync(path.dirname(full), { recursive: true });
- fs.writeFileSync(full, content, 'utf8');
- console.log('Wrote', path.relative(path.join(__dirname, '..'), full));
- }
- function patch(rel, fn, root = javaRoot) {
- const full = path.join(root, rel);
- if (!fs.existsSync(full)) return;
- w(rel, fn(fs.readFileSync(full, 'utf8')), root);
- }
- function replaceClassComment(content, commentLine) {
- return content.replace(/\/\*\*[\s\S]*?\*\//, `/**\n * ${commentLine}\n */`);
- }
- const T = {
- 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),
- courseLiveTab: u(0x770b,0x8bfe,0x2f,0x76f4,0x64ad),
- 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),
- 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),
- outboundTab: u(0x5916,0x547c,0x8bb0,0x5f55),
- unknown: u(0x672a,0x77e5),
- connected: u(0x5df2,0x63a5,0x901a),
- notConnected: u(0x672a,0x63a5,0x901a),
- statusPrefix: u(0x72b6,0x6001),
- watching: u(0x770b,0x8bfe,0x4e2d),
- finishedCourse: u(0x5b8c,0x8bfe),
- pendingCourse: u(0x5f85,0x770b,0x8bfe),
- interrupted: u(0x770b,0x8bfe,0x4e2d,0x65ad),
- finishedDay: u(0x5df2,0x5b8c,0x8bfe),
- noRecord: u(0x65e0,0x8bb0,0x5f55),
- live: u(0x76f4,0x64ad),
- replay: u(0x56de,0x653e),
- 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),
- 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),
- statsDelta: u(0x753b,0x50cf,0x7edf,0x8ba1,0x589e,0x91cf,0xff08,0x524d,0x540e,0x5feb,0x7167,0x5dee,0xff09,0x3002),
- 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),
- factLoader: u(0x4ece) + ' customer_fact / customer_habit ' + u(0x52a0,0x8f7d,0x7a33,0x5b9a,0x753b,0x50cf,0xff0c,0x5408,0x5e76,0x8fdb,0x5165) + ' profile ' + u(0x89c6,0x56fe,0x3002),
- projectionSync: u(0x4f1a,0x8bdd,0x6458,0x8981,0x5199,0x5165,0x753b,0x50cf,0x8868,0x65f6,0xff0c,0x6295,0x5f71,0x5b57,0x6bb5,0x540c,0x6b65,0x5de5,0x5177,0x3002),
- statsRecorder: u(0x753b,0x50cf,0x5199,0x5165,0x540e,0x89e6,0x53d1,0x7edf,0x8ba1,0x8868,0x589e,0x91cf,0x66f4,0x65b0,0x3002),
- 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),
- 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),
- 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),
- bindingStats: u(0x7ED1,0x5B9A,0x6267,0x884C,0x7EDF,0x8BA1,0xFF08,0x6C47,0x603B,0x20,0x2B,0x20,0x5237,0x65B0,0xFF09,0x3002),
- 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),
- stageBracket: u(0x3010,0x9636,0x6bb5,0x3011),
- pipe: u(0xff5c),
- ellipsis: u(0x2026),
- touchTask: u(0x3010) + '${channel}' + u(0x3011,0x89e6,0x8fbe,0x4efb,0x52a1),
- nodeBracket: u(0x8282,0x70b9,0x5b),
- highQuality: u(0x9ad8,0x8d28,0x91cf,0x56de,0x590d),
- customerLabel: u(0x5ba2,0x6237),
- replyLabel: u(0x56de,0x590d),
- noInstances: u(0x672a,0x9009,0x62e9,0x4efb,0x4f55,0x5b9e,0x4f8b),
- instancePrefix: u(0x5b9e,0x4f8b),
- noAccess: u(0x65e0,0x6743,0x9650,0x6216,0x4e0d,0x5b58,0x5728),
- opFailed: u(0x64cd,0x4f5c,0x5931,0x8d25),
- splitChars: u(0xff0c,0xff1b),
- terminated: u(0x5df2,0x7ec8,0x6b62),
- switchedHuman: u(0x5df2,0x5207,0x6362,0x4eba,0x5de5),
- instUnit: u(0x4e2a,0x5b9e,0x4f8b),
- skipPart: u(0xff0c,0x8df3,0x8fc7),
- unit: u(0x4e2a),
- allTenants: u(0x5168,0x90e8,0x79df,0x6237),
- };
- // fix broken canvasSync and bindingStats - use proper unicode
- 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);
- T.bindingStats = u(0x7ed1,0x5b9a,0x6267,0x884c,0x7edf,0x8ba1,0xff08,0x6c47,0x603b,0x20,0x2b,0x20,0x5237,0x65b0,0xff09,0x3002);
- 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);
- w('com/fs/company/service/workflow/profile/panel/CustomerProfileBehaviorTrajectoryService.java', `package com.fs.company.service.workflow.profile.panel;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import org.springframework.util.StringUtils;
- import java.util.LinkedHashMap;
- import java.util.Map;
- /**
- * ${T.behaviorSvcComment}
- */
- @Service
- public class CustomerProfileBehaviorTrajectoryService {
- @Autowired
- private CustomerProfileMediaTrajectoryService mediaTrajectoryService;
- @Autowired
- private CustomerProfileCallTrajectoryService callTrajectoryService;
- public Map<String, Object> loadBehaviorTrajectory(Long companyId, String channelType, String profileKey,
- Long customerId, Long contactId, Integer days) {
- String channel = normalizeChannel(channelType);
- Map<String, Object> result = new LinkedHashMap<>();
- result.put("channelType", channel);
- if ("WX".equals(channel)) {
- Map<String, Object> call = callTrajectoryService.loadCallTrajectory(companyId, customerId, days);
- result.put("behaviorType", call.get("behaviorType"));
- result.put("tabLabel", call.get("tabLabel"));
- result.put("days", call.get("days"));
- result.put("stats", call.get("stats"));
- result.put("callEvents", call.get("callEvents"));
- result.put("courseDays", java.util.Collections.emptyList());
- result.put("liveEvents", java.util.Collections.emptyList());
- return result;
- }
- Map<String, Object> media = mediaTrajectoryService.loadMediaTrajectory(
- companyId, channel, profileKey, customerId, contactId, days);
- result.put("behaviorType", "course_live");
- result.put("tabLabel", "${T.courseLiveTab}");
- result.put("days", media.get("days"));
- result.put("stats", media.get("stats"));
- result.put("courseDays", media.get("courseDays"));
- result.put("liveEvents", media.get("liveEvents"));
- result.put("callEvents", java.util.Collections.emptyList());
- result.put("externalContactId", media.get("externalContactId"));
- return result;
- }
- private String normalizeChannel(String channelType) {
- if (!StringUtils.hasText(channelType)) {
- return "QW";
- }
- return channelType.trim().toUpperCase();
- }
- }
- `);
- patch('com/fs/company/service/workflow/profile/panel/CustomerProfileMediaTrajectoryService.java', (c) => {
- let s = c;
- s = replaceClassComment(s, T.mediaSvcComment);
- s = s.replace(/labels\.put\(1, "[^"]+"\);[\s\S]*?labels\.put\(4, "[^"]+"\);/,
- `labels.put(1, "${T.watching}");\n labels.put(2, "${T.finishedCourse}");\n labels.put(3, "${T.pendingCourse}");\n labels.put(4, "${T.interrupted}");`);
- s = s.replace(/item\.put\("statusLabel", "[^"]+"\);/g, `item.put("statusLabel", "${T.noRecord}");`);
- s = s.replace(/LOG_TYPE_LABELS\.getOrDefault\(logType, "[^"]+"\)/g, `LOG_TYPE_LABELS.getOrDefault(logType, "${T.unknown}")`);
- s = s.replace(/if \("finished"\.equals\(status\)\) \{\s*return "[^"]+";/, `if ("finished".equals(status)) {\n return "${T.finishedDay}";`);
- s = s.replace(/if \("watching"\.equals\(status\)\) \{\s*return "[^"]+";/, `if ("watching".equals(status)) {\n return "${T.watching}";`);
- s = s.replace(/if \("interrupted"\.equals\(status\)\) \{\s*return "[^"]+";/, `if ("interrupted".equals(status)) {\n return "${T.interrupted}";`);
- s = s.replace(/if \("pending"\.equals\(status\)\) \{\s*return "[^"]+";/, `if ("pending".equals(status)) {\n return "${T.pendingCourse}";`);
- s = s.replace(/return "[^"]+";\s*\}\s*\n\s*private String watchTypeLabel/, `return "${T.noRecord}";\n }\n\n private String watchTypeLabel`);
- s = s.replace(/if \(watchType == 1\) \{\s*return "[^"]+";/, `if (watchType == 1) {\n return "${T.live}";`);
- s = s.replace(/if \(watchType == 2\) \{\s*return "[^"]+";/, `if (watchType == 2) {\n return "${T.replay}";`);
- return s;
- });
- patch('com/fs/company/service/workflow/profile/panel/CustomerProfileCallTrajectoryService.java', (c) => {
- let s = c;
- s = replaceClassComment(s, T.callSvcComment);
- s = s.replace(/result\.put\("tabLabel", "[^"]+"\);/, `result.put("tabLabel", "${T.outboundTab}");`);
- s = s.replace(/private String callStatusLabel[\s\S]*?return "[^"]*" \+ s;/,
- `private String callStatusLabel(Object status) {
- Integer s = toInteger(status);
- if (s == null) {
- return "${T.unknown}";
- }
- if (s == 1) {
- return "${T.connected}";
- }
- if (s == 0) {
- return "${T.notConnected}";
- }
- return "${T.statusPrefix}" + s;`);
- return s;
- });
- const commentMap = {
- 'com/fs/company/service/workflow/profile/panel/ProfileListAggregateHelper.java': T.listHub,
- 'com/fs/company/service/workflow/profile/panel/ProfileStatsSnapshot.java': T.statsSnapshot,
- 'com/fs/company/service/workflow/profile/panel/ProfileStatsDelta.java': T.statsDelta,
- 'com/fs/company/service/workflow/profile/panel/ConversationSummaryViewHelper.java': T.summaryView,
- 'com/fs/company/service/workflow/profile/panel/CustomerProfileFactLoader.java': T.factLoader,
- 'com/fs/company/service/workflow/profile/panel/ProfileSummaryProjectionSync.java': T.projectionSync,
- 'com/fs/company/service/workflow/profile/LobsterProfileStatsRecorder.java': T.statsRecorder,
- 'com/fs/company/service/workflow/profile/LobsterProfileStatsService.java': T.statsService,
- 'com/fs/company/service/workflow/trigger/TimeIntentDetector.java': T.timeIntent,
- 'com/fs/company/service/workflow/ILobsterBindingExecStatsService.java': T.bindingStats,
- 'com/fs/company/service/workflow/execution/LobsterBindingProvisionServiceImpl.java': T.bindingProvision,
- };
- for (const [rel, text] of Object.entries(commentMap)) {
- patch(rel, (c) => replaceClassComment(c, text));
- }
- patch('com/fs/company/service/workflow/canvas/WorkflowCanvasSyncUtil.java', (c) =>
- c.replace(/\/\*\*[^*]*\*\//, `/** ${T.canvasSync} */`));
- patch('com/fs/company/service/workflow/profile/panel/ProfileSummaryProjectionSync.java', (c) => {
- let s = c;
- s = s.replace(/clipPreview\("[^"]*" \+ stage\.trim\(\) \+ " [^"]* " \+ snippet\)/,
- `clipPreview("${T.stageBracket}" + stage.trim() + "${T.pipe}" + snippet)`);
- s = s.replace(/clipPreview\("[^"]*" \+ stage\.trim\(\)\)/, `clipPreview("${T.stageBracket}" + stage.trim())`);
- s = s.replace(/PREVIEW_MAX\) \+ "[^"]+"/, `PREVIEW_MAX) + "${T.ellipsis}"`);
- return s;
- });
- patch('com/fs/company/service/workflow/trigger/TimeIntentDetector.java', (c) =>
- c.replace(/\[\u007cu70b9:\?\?\]/g, '[\\u70b9:\\uFF1A]').replace(/\[:\\?\?\]/g, '[:\\uFF1A]'));
- patch('com/fs/company/service/workflow/execution/LobsterBindingProvisionServiceImpl.java', (c) =>
- c.replace(/setTaskName\("[^"]*" \+ channelType \+ "[^"]*"\)/,
- `setTaskName("${u(0x3010)}" + channelType + "${u(0x3011,0x89e6,0x8fbe,0x4efb,0x52a1)}")`));
- patch('com/fs/company/service/workflow/learning/impl/LobsterSkillManageServiceImpl.java', (c) => {
- let s = c;
- s = s.replace(/sb\.append\("[^"]*\["\)/, `sb.append("${T.nodeBracket}")`);
- s = s.replace(/append\("\] [^"]* \("/, `append("] ${T.highQuality} ("`);
- let n = 0;
- s = s.replace(/sb\.append\("[^"]*: "\)/g, () => {
- n += 1;
- return n === 1 ? `sb.append("${T.customerLabel}: ")` : `sb.append("${T.replyLabel}: ")`;
- });
- return s;
- });
- patch('com/fs/company/service/workflow/impl/LobsterInstanceOpsService.java', (c) => {
- let s = c;
- s = s.replace(/result\.put\("message", "[^"]+"\)/, `result.put("message", "${T.noInstances}")`);
- s = s.replace(/errors\.add\("[^"]* " \+ instanceId \+ " [^"]+"\)/,
- `errors.add("${T.instancePrefix} " + instanceId + " ${T.noAccess}")`);
- s = s.replace(/ajax\.get\("msg"\) : "[^"]+"\)/, `ajax.get("msg") : "${T.opFailed}")`);
- s = s.replace(/errors\.add\("[^"]* " \+ instanceId \+ ": "/g, `errors.add("${T.instancePrefix} " + instanceId + ": "`);
- s = s.replace(/split\("\[,;[^"]+"\)/, `split("[,;${T.splitChars}]")`);
- s = s.replace(/\? \("[^"]* " \+ success \+ " [^"]*"\)/,
- `? ("${T.terminated} " + success + " ${T.instUnit}" + (skipped > 0 ? "${T.skipPart} " + skipped + " ${T.unit}" : "") )`);
- s = s.replace(/:\("[^"]* " \+ success \+ " [^"]*"\)/,
- `: ("${T.switchedHuman} " + success + " ${T.instUnit}" + (skipped > 0 ? "${T.skipPart} " + skipped + " ${T.unit}" : "") )`);
- return s;
- });
- for (const root of adminRoots) {
- patch('com/fs/lobster/controller/LobsterOptimizationController.java', (c) =>
- c.replace(/scopeInfo\.put\("label", "[^"]+"\)/, `scopeInfo.put("label", "${T.allTenants}")`), root);
- }
- function scanGarbled(dir) {
- const bad = [];
- (function walk(d) {
- for (const ent of fs.readdirSync(d, { withFileTypes: true })) {
- const p = path.join(d, ent.name);
- if (ent.isDirectory()) walk(p);
- else if (ent.name.endsWith('.java')) {
- const c = fs.readFileSync(p, 'utf8');
- if (/\?\?\?/.test(c)) bad.push(path.relative(path.join(__dirname, '..'), p));
- }
- }
- })(dir);
- return bad;
- }
- console.log('Remaining ??? in fs-service:', scanGarbled(javaRoot));
- console.log('Done');
|