@kezh/my-custom-js-converter 1.4.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/plan.md +52 -40
- package/TASKS.md +397 -34
- package/core/context/map_context.js +6 -4
- package/core/decode/index.js +12 -5
- package/core/encode/index.js +14 -6
- package/core/scanf/index.js +3 -1
- package/core/util/ast.js +5 -2
- package/core/util/logger.d.ts +15 -0
- package/core/util/logger.js +28 -0
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/.claude/plan.md
CHANGED
|
@@ -1,53 +1,65 @@
|
|
|
1
|
-
#
|
|
1
|
+
# 日志优化方案
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
在 `config.js` 中添加开关配置,支持 `@` 写法:`const mod = require('@/util/@3.0.0/mod.js')`,其中 `@` 代表项目根目录(baseDir)。
|
|
3
|
+
## 现状问题
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
1. **格式不统一** — 有的用 `=>` 分隔,有的直接打印数组,风格混乱
|
|
6
|
+
2. **缺少层级结构** — 所有日志平铺输出,无法区分步骤/阶段
|
|
7
|
+
3. **信息不完整** — `scanf dirs => ` 和数组分两行打印,`the map is not found!` 没有上下文
|
|
8
|
+
4. **缺少状态标识** — 没有成功/失败/警告等视觉区分
|
|
9
|
+
5. **中英混杂** — `路径不存在[...]忽略` vs `scanf dirs` vs `the map is not found!`
|
|
10
|
+
6. **缺少汇总** — 处理完成后没有统计摘要
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
在 `EncodeConfig` 中添加 `useAlias: boolean` 开关(默认 `false`)。
|
|
12
|
+
## 优化方案
|
|
10
13
|
|
|
11
|
-
###
|
|
12
|
-
在 `defConfig.encode` 中添加 `useAlias: false`。
|
|
14
|
+
### 1. 新建 `src/util/logger.ts` — 统一日志工具
|
|
13
15
|
|
|
14
|
-
### 3. `src/scanf/index.ts` — `scanfRequieMod` 支持 @ 路径
|
|
15
|
-
当 `modPath` 以 `@/` 或 `@\\` 开头时,将 `@` 替换为 `baseDir`(项目根目录),然后再进行路径解析。
|
|
16
|
-
|
|
17
|
-
修改逻辑:
|
|
18
16
|
```typescript
|
|
19
|
-
export function
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
export function createLogger(scope: string) {
|
|
18
|
+
return {
|
|
19
|
+
info(msg: string) { console.log(`[${scope}] ✔ ${msg}`); },
|
|
20
|
+
warn(msg: string) { console.log(`[${scope}] ⚠ ${msg}`); },
|
|
21
|
+
error(msg: string) { console.log(`[${scope}] ✖ ${msg}`); },
|
|
22
|
+
step(title: string) {
|
|
23
|
+
console.log(`\n[${scope}] ── ${title} ${'─'.repeat(Math.max(0, 50 - title.length))}`);
|
|
24
|
+
},
|
|
25
|
+
};
|
|
25
26
|
}
|
|
26
27
|
```
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
decode 时生成 require 语句,如果 `config.encode.useAlias` 为 `true`,则生成 `@/...` 格式而非相对路径。
|
|
29
|
+
简洁、无外部依赖、终端友好。
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
### 2. 日志对照表
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
33
|
+
| 原始 | 优化后 |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `console.log("scanf dirs => ")` + `console.log(targetDirs)` | `logger.info('scanf dirs: ' + targetDirs.join(', '))` |
|
|
36
|
+
| `console.log(\`scanf file => ${inPath}\`)` | `logger.info(\`scanf file: ${inPath}\`)` |
|
|
37
|
+
| `console.log(\`output file => ${outPath}\`)` | `logger.info(\`output: ${outPath}\`)` |
|
|
38
|
+
| `console.log(\`output => ${outPath}\`)` | `logger.info(\`output: ${outPath}\`)` |
|
|
39
|
+
| `console.log(\`input map => ${inPath}\`)` | `logger.info(\`read map: ${inPath}\`)` |
|
|
40
|
+
| `console.log("the map is not found!")` | `logger.warn('map file not found')` |
|
|
41
|
+
| `console.log(\`output map => ${outPath}\`)` | `logger.info(\`write map: ${outPath}\`)` |
|
|
42
|
+
| `console.log(\`not found entry => ${entry}\`)` | `logger.warn(\`entry not found: ${entry}\`)` |
|
|
43
|
+
| `console.log(\`路径不存在[${dirPath}]忽略\`)` | `logger.warn(\`dir not found, skipping: ${dirPath}\`)` |
|
|
44
|
+
| `console.log(\`ignore module => ${item.id.name}\`)` | `logger.info(\`ignore module: ${item.id.name}\`)` |
|
|
45
|
+
|
|
46
|
+
### 3. 增加步骤分隔和汇总
|
|
47
|
+
|
|
48
|
+
**encode** 流程增加:
|
|
49
|
+
- 步骤标题:扫描目录 → 查找文件 → 编码处理
|
|
50
|
+
- 汇总:处理文件数、方法总数、版本号
|
|
51
|
+
|
|
52
|
+
**decode** 流程增加:
|
|
53
|
+
- 步骤标题:扫描目录 → 查找文件 → 解码处理
|
|
54
|
+
- 汇总:处理文件数
|
|
43
55
|
|
|
44
|
-
###
|
|
45
|
-
`importMods` 调用处需要传递 config 信息。
|
|
56
|
+
### 4. 修改文件清单
|
|
46
57
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
58
|
+
| 文件 | 变更 |
|
|
59
|
+
|---|---|
|
|
60
|
+
| `src/util/logger.ts` | **新建** — 日志工具模块 |
|
|
61
|
+
| `src/encode/index.ts` | 替换 4 处 console.log,增加步骤和汇总 |
|
|
62
|
+
| `src/decode/index.ts` | 替换 4 处 console.log,增加步骤和汇总 |
|
|
63
|
+
| `src/context/map_context.ts` | 替换 3 处 console.log |
|
|
64
|
+
| `src/scanf/index.ts` | 替换 1 处 console.log |
|
|
65
|
+
| `src/util/ast.ts` | 替换 1 处 console.log |
|
package/TASKS.md
CHANGED
|
@@ -1,36 +1,399 @@
|
|
|
1
1
|
# 任务
|
|
2
|
-
|
|
2
|
+
在其他项目依赖该项目时执行`npx decode`结果和当前项目测试结果不一致:
|
|
3
|
+
+ decode后的依赖路径错误,@会紧贴util,导致依赖路径错误:
|
|
4
|
+
```js
|
|
5
|
+
const form = require("@util/@3.0.0/form");
|
|
6
|
+
const http = require("@util/@3.0.0/http");
|
|
7
|
+
const message = require("@util/@3.0.0/message");
|
|
8
|
+
const dom = require("@util/@3.0.0/dom");
|
|
9
|
+
const vue = require("@util/@3.0.0/vue");
|
|
10
|
+
const tch = require("@util/@3.0.0/tch");
|
|
11
|
+
const customEvent = {
|
|
12
|
+
onFormReady() {
|
|
13
|
+
this.initForm();
|
|
14
|
+
this.initHangupBtn();
|
|
15
|
+
},
|
|
16
|
+
onFormSubmit() {
|
|
17
|
+
if (form.getValue("REASON_TYPE_ORIGIN")) {
|
|
18
|
+
form.setValue(
|
|
19
|
+
"REASON_TYPE",
|
|
20
|
+
form.getSelectOptionLabel("REASON_TYPE_ORIGIN")
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
if ("挂起" == form.getValue("SUSPENDED_STATE")) {
|
|
24
|
+
message.warning("该流程已挂起,请解挂后提交工单!");
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return true;
|
|
28
|
+
},
|
|
29
|
+
initForm() {
|
|
30
|
+
form.hidden("hiddenInfo");
|
|
31
|
+
if (form.getValue("SUSPENDED_STATE")) {
|
|
32
|
+
form.show("hangupInfo");
|
|
33
|
+
} else {
|
|
34
|
+
form.hidden("hangupInfo");
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
initHangupBtn() {
|
|
38
|
+
if ("告警处理" !== tch.getCurTchName()) {
|
|
39
|
+
return;
|
|
40
|
+
} // 注入弹出框样式
|
|
41
|
+
dom.addCss(
|
|
42
|
+
`
|
|
43
|
+
.hangup-dialog-overlay {
|
|
44
|
+
position: fixed; top: 0; left: 0; right: 0; bottom: 0;
|
|
45
|
+
background: rgba(0, 0, 0, 0.5); z-index: 2000;
|
|
46
|
+
display: flex; align-items: center; justify-content: center;
|
|
47
|
+
}
|
|
48
|
+
.hangup-dialog {
|
|
49
|
+
background: #fff; border-radius: 4px; width: 420px; padding: 20px;
|
|
50
|
+
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.3);
|
|
51
|
+
}
|
|
52
|
+
.hangup-dialog__title {
|
|
53
|
+
font-size: 16px; font-weight: bold; margin-bottom: 16px; color: #303133;
|
|
54
|
+
}
|
|
55
|
+
.hangup-dialog__label {
|
|
56
|
+
display: block; font-size: 14px; color: #606266; margin-bottom: 6px;
|
|
57
|
+
}
|
|
58
|
+
.hangup-dialog__input {
|
|
59
|
+
width: 100%; box-sizing: border-box; padding: 8px 12px;
|
|
60
|
+
border: 1px solid #dcdfe6; border-radius: 4px; font-size: 14px;
|
|
61
|
+
margin-bottom: 16px; outline: none;
|
|
62
|
+
}
|
|
63
|
+
.hangup-dialog__input:focus {
|
|
64
|
+
border-color: #409eff;
|
|
65
|
+
}
|
|
66
|
+
.hangup-dialog__textarea {
|
|
67
|
+
width: 100%; box-sizing: border-box; padding: 8px 12px;
|
|
68
|
+
border: 1px solid #dcdfe6; border-radius: 4px; font-size: 14px;
|
|
69
|
+
margin-bottom: 16px; outline: none; resize: vertical; min-height: 80px;
|
|
70
|
+
}
|
|
71
|
+
.hangup-dialog__textarea:focus {
|
|
72
|
+
border-color: #409eff;
|
|
73
|
+
}
|
|
74
|
+
.hangup-dialog__footer {
|
|
75
|
+
text-align: right; margin-top: 8px;
|
|
76
|
+
}
|
|
77
|
+
.hangup-dialog__btn {
|
|
78
|
+
padding: 8px 20px; border-radius: 4px; font-size: 14px;
|
|
79
|
+
cursor: pointer; border: 1px solid #dcdfe6; margin-left: 10px;
|
|
80
|
+
}
|
|
81
|
+
.hangup-dialog__btn--primary {
|
|
82
|
+
background: #409eff; color: #fff; border-color: #409eff;
|
|
83
|
+
}
|
|
84
|
+
.hangup-dialog__btn--primary:hover {
|
|
85
|
+
background: #66b1ff; border-color: #66b1ff;
|
|
86
|
+
}
|
|
87
|
+
.hangup-dialog__btn--default {
|
|
88
|
+
background: #fff; color: #606266;
|
|
89
|
+
}
|
|
90
|
+
.hangup-dialog__btn--default:hover {
|
|
91
|
+
color: #409eff; border-color: #c6e2ff; background: #ecf5ff;
|
|
92
|
+
}
|
|
93
|
+
`,
|
|
94
|
+
"hangup-dialog-style"
|
|
95
|
+
); // 等待DOM渲染完成后注入按钮
|
|
96
|
+
vue.nextTick(() => {
|
|
97
|
+
this.renderHangupBtn();
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
renderHangupBtn() {
|
|
101
|
+
const suspendedState = form.getValue("SUSPENDED_STATE", ""); // 查找锚点元素:优先按ID查找提交按钮,兜底查找菜单栏最后一个按钮
|
|
102
|
+
const submitBtn =
|
|
103
|
+
document.getElementById("220001") ||
|
|
104
|
+
document.querySelector(".fi-workflow-menu-item.btn:last-child");
|
|
105
|
+
if (!submitBtn) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (suspendedState === "挂起") {
|
|
109
|
+
// 当前已挂起,显示解挂按钮
|
|
110
|
+
submitBtn.insertAdjacentHTML(
|
|
111
|
+
"afterend",
|
|
112
|
+
'<div class="fi-workflow-menu-item btn" id="hangupBtn"><div> <i class="fi el-icon-lock icon"></i>解挂</div></div>'
|
|
113
|
+
);
|
|
114
|
+
document.getElementById("hangupBtn").addEventListener("click", () => {
|
|
115
|
+
this.showResumeDialog();
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
// 当前未挂起,默认显示挂起按钮
|
|
119
|
+
submitBtn.insertAdjacentHTML(
|
|
120
|
+
"afterend",
|
|
121
|
+
'<div class="fi-workflow-menu-item btn" id="hangupBtn"><div> <i class="fi el-icon-unlock icon"></i>挂起</div></div>'
|
|
122
|
+
);
|
|
123
|
+
document.getElementById("hangupBtn").addEventListener("click", () => {
|
|
124
|
+
this.showHangupDialog();
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
showHangupDialog() {
|
|
129
|
+
const overlay = document.createElement("div");
|
|
130
|
+
overlay.className = "hangup-dialog-overlay";
|
|
131
|
+
overlay.id = "hangupDialogOverlay";
|
|
132
|
+
overlay.innerHTML = `
|
|
133
|
+
<div class="hangup-dialog">
|
|
134
|
+
<div class="hangup-dialog__title">挂起工单</div>
|
|
135
|
+
<label class="hangup-dialog__label">挂起原因</label>
|
|
136
|
+
<textarea class="hangup-dialog__textarea" id="hangupReason" placeholder="请输入挂起原因"></textarea>
|
|
137
|
+
<label class="hangup-dialog__label"><span style="color:#f56c6c">*</span> 自动解挂时间</label>
|
|
138
|
+
<input class="hangup-dialog__input" type="datetime-local" id="hangupUnbanTime" />
|
|
139
|
+
<div class="hangup-dialog__footer">
|
|
140
|
+
<button class="hangup-dialog__btn hangup-dialog__btn--default" id="hangupCancelBtn">取 消</button>
|
|
141
|
+
<button class="hangup-dialog__btn hangup-dialog__btn--primary" id="hangupConfirmBtn">确 定</button>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
`;
|
|
145
|
+
document.body.appendChild(overlay); // 设置自动解挂时间默认值为当前时间+1天
|
|
146
|
+
var defaultTime = new Date(Date.now() + 24 * 60 * 60 * 1000);
|
|
147
|
+
var pad = function (n) {
|
|
148
|
+
return n < 10 ? "0" + n : "" + n;
|
|
149
|
+
};
|
|
150
|
+
var defaultTimeStr =
|
|
151
|
+
defaultTime.getFullYear() +
|
|
152
|
+
"-" +
|
|
153
|
+
pad(defaultTime.getMonth() + 1) +
|
|
154
|
+
"-" +
|
|
155
|
+
pad(defaultTime.getDate()) +
|
|
156
|
+
"T" +
|
|
157
|
+
pad(defaultTime.getHours()) +
|
|
158
|
+
":" +
|
|
159
|
+
pad(defaultTime.getMinutes());
|
|
160
|
+
document.getElementById("hangupUnbanTime").value = defaultTimeStr; // 点击遮罩层关闭
|
|
161
|
+
overlay.addEventListener("click", (e) => {
|
|
162
|
+
if (e.target === overlay) {
|
|
163
|
+
this.closeDialog("hangupDialogOverlay");
|
|
164
|
+
}
|
|
165
|
+
}); // 取消按钮
|
|
166
|
+
document.getElementById("hangupCancelBtn").addEventListener("click", () => {
|
|
167
|
+
this.closeDialog("hangupDialogOverlay");
|
|
168
|
+
}); // 确定按钮
|
|
169
|
+
document
|
|
170
|
+
.getElementById("hangupConfirmBtn")
|
|
171
|
+
.addEventListener("click", () => {
|
|
172
|
+
this.confirmHangup();
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
async confirmHangup() {
|
|
176
|
+
const reason = document.getElementById("hangupReason").value;
|
|
177
|
+
const unbanTimeRaw = document.getElementById("hangupUnbanTime").value;
|
|
178
|
+
if (!unbanTimeRaw) {
|
|
179
|
+
message.warning("请填写自动解挂时间");
|
|
180
|
+
return;
|
|
181
|
+
} // datetime-local的值格式为 yyyy-MM-ddTHH:mm,转为 yyyy-MM-dd HH:mm:ss
|
|
182
|
+
const unbanTime = unbanTimeRaw.replace("T", " ") + ":00";
|
|
183
|
+
const orderCode = form.getValue("ORDER_CODE", "");
|
|
184
|
+
const flowId = form.getValue("FLOW_ID", "");
|
|
185
|
+
if (!orderCode) {
|
|
186
|
+
message.error("集团工单号为空,无法挂起");
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (!flowId) {
|
|
190
|
+
message.error("工单ID为空,无法挂起");
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
try {
|
|
194
|
+
const result = await http.post(
|
|
195
|
+
"/aiops/api/v1/flow/group/province/alarm/dispatch/order/hangupOrder",
|
|
196
|
+
{
|
|
197
|
+
ORDER_CODE: orderCode,
|
|
198
|
+
FLOW_ID: flowId,
|
|
199
|
+
TYPE: "1",
|
|
200
|
+
REASON: reason,
|
|
201
|
+
UNBAN_TIME: unbanTime
|
|
202
|
+
}
|
|
203
|
+
);
|
|
204
|
+
if (result && result.resultCode === 0) {
|
|
205
|
+
message.success("挂起成功");
|
|
206
|
+
this.closeDialog("hangupDialogOverlay"); // 更新按钮状态为解挂
|
|
207
|
+
this.updateHangupBtnState("解挂");
|
|
208
|
+
} else {
|
|
209
|
+
message.error((result && result.resultMsg) || "挂起失败");
|
|
210
|
+
}
|
|
211
|
+
} catch (e) {
|
|
212
|
+
message.error("挂起请求异常");
|
|
213
|
+
console.error(e);
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
showResumeDialog() {
|
|
217
|
+
const overlay = document.createElement("div");
|
|
218
|
+
overlay.className = "hangup-dialog-overlay";
|
|
219
|
+
overlay.id = "resumeDialogOverlay";
|
|
220
|
+
overlay.innerHTML = `
|
|
221
|
+
<div class="hangup-dialog">
|
|
222
|
+
<div class="hangup-dialog__title">解挂工单</div>
|
|
223
|
+
<label class="hangup-dialog__label">解挂原因</label>
|
|
224
|
+
<textarea class="hangup-dialog__textarea" id="resumeReason" placeholder="请输入解挂原因"></textarea>
|
|
225
|
+
<div class="hangup-dialog__footer">
|
|
226
|
+
<button class="hangup-dialog__btn hangup-dialog__btn--default" id="resumeCancelBtn">取 消</button>
|
|
227
|
+
<button class="hangup-dialog__btn hangup-dialog__btn--primary" id="resumeConfirmBtn">确 定</button>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
`;
|
|
231
|
+
document.body.appendChild(overlay); // 点击遮罩层关闭
|
|
232
|
+
overlay.addEventListener("click", (e) => {
|
|
233
|
+
if (e.target === overlay) {
|
|
234
|
+
this.closeDialog("resumeDialogOverlay");
|
|
235
|
+
}
|
|
236
|
+
}); // 取消按钮
|
|
237
|
+
document.getElementById("resumeCancelBtn").addEventListener("click", () => {
|
|
238
|
+
this.closeDialog("resumeDialogOverlay");
|
|
239
|
+
}); // 确定按钮
|
|
240
|
+
document
|
|
241
|
+
.getElementById("resumeConfirmBtn")
|
|
242
|
+
.addEventListener("click", () => {
|
|
243
|
+
this.confirmResume();
|
|
244
|
+
});
|
|
245
|
+
},
|
|
246
|
+
async confirmResume() {
|
|
247
|
+
const reason = document.getElementById("resumeReason").value;
|
|
248
|
+
const orderCode = form.getValue("ORDER_CODE", "");
|
|
249
|
+
const flowId = form.getValue("FLOW_ID", "");
|
|
250
|
+
if (!orderCode) {
|
|
251
|
+
message.error("集团工单号为空,无法解挂");
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (!flowId) {
|
|
255
|
+
message.error("工单ID为空,无法解挂");
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const result = await http.post(
|
|
260
|
+
"/aiops/api/v1/flow/group/province/alarm/dispatch/order/resumeOrder",
|
|
261
|
+
{ ORDER_CODE: orderCode, FLOW_ID: flowId, REASON: reason }
|
|
262
|
+
);
|
|
263
|
+
if (result && result.resultCode === 0) {
|
|
264
|
+
message.success("解挂成功");
|
|
265
|
+
this.closeDialog("resumeDialogOverlay"); // 更新按钮状态为挂起
|
|
266
|
+
this.updateHangupBtnState("挂起");
|
|
267
|
+
} else {
|
|
268
|
+
message.error((result && result.resultMsg) || "解挂失败");
|
|
269
|
+
}
|
|
270
|
+
} catch (e) {
|
|
271
|
+
message.error("解挂请求异常");
|
|
272
|
+
console.error(e);
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
updateHangupBtnState(prevState) {
|
|
276
|
+
const hangupBtn = document.getElementById("hangupBtn");
|
|
277
|
+
if (!hangupBtn) {
|
|
278
|
+
return;
|
|
279
|
+
} // 移除旧按钮的事件监听(通过替换节点实现)
|
|
280
|
+
const newBtn = hangupBtn.cloneNode(false);
|
|
281
|
+
if (prevState === "挂起") {
|
|
282
|
+
// 从挂起变为解挂 → 显示挂起按钮
|
|
283
|
+
newBtn.innerHTML =
|
|
284
|
+
'<div> <i class="fi el-icon-unlock icon"></i>挂起</div>';
|
|
285
|
+
newBtn.addEventListener("click", () => {
|
|
286
|
+
this.showHangupDialog();
|
|
287
|
+
}); // 同步更新表单字段
|
|
288
|
+
form.setValue("SUSPENDED_STATE", "解挂");
|
|
289
|
+
} else {
|
|
290
|
+
// 从解挂变为挂起 → 显示解挂按钮
|
|
291
|
+
newBtn.innerHTML = '<div> <i class="fi el-icon-lock icon"></i>解挂</div>';
|
|
292
|
+
newBtn.addEventListener("click", () => {
|
|
293
|
+
this.showResumeDialog();
|
|
294
|
+
}); // 同步更新表单字段
|
|
295
|
+
form.setValue("SUSPENDED_STATE", "挂起");
|
|
296
|
+
}
|
|
297
|
+
hangupBtn.parentNode.replaceChild(newBtn, hangupBtn);
|
|
298
|
+
},
|
|
299
|
+
closeDialog(overlayId) {
|
|
300
|
+
const overlay = document.getElementById(overlayId);
|
|
301
|
+
if (overlay) {
|
|
302
|
+
document.body.removeChild(overlay);
|
|
303
|
+
}
|
|
304
|
+
},
|
|
305
|
+
async receiveOrder() {
|
|
306
|
+
const orderCode = form.getValue("ORDER_CODE", "");
|
|
307
|
+
const flowId = form.getValue("FLOW_ID", "");
|
|
308
|
+
if (!orderCode) {
|
|
309
|
+
message.error("集团工单号为空,无法接单");
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
if (!flowId) {
|
|
313
|
+
message.error("工单ID为空,无法接单");
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
try {
|
|
317
|
+
const result = await http.post(
|
|
318
|
+
"/aiops/api/v1/flow/group/province/alarm/dispatch/order/receiveOrder",
|
|
319
|
+
this.form
|
|
320
|
+
);
|
|
321
|
+
if (result && result.resultCode === 0) {
|
|
322
|
+
message.success("接单成功");
|
|
323
|
+
return true;
|
|
324
|
+
} else {
|
|
325
|
+
message.error((result && result.resultMsg) || "接单失败");
|
|
326
|
+
}
|
|
327
|
+
} catch (e) {
|
|
328
|
+
message.error("接单请求异常");
|
|
329
|
+
console.error(e);
|
|
330
|
+
}
|
|
331
|
+
return false;
|
|
332
|
+
},
|
|
333
|
+
async handleAlarm() {
|
|
334
|
+
const orderCode = form.getValue("ORDER_CODE", "");
|
|
335
|
+
const flowId = form.getValue("FLOW_ID", "");
|
|
336
|
+
if (!orderCode) {
|
|
337
|
+
message.error("集团工单号为空,无法处理");
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
if (!flowId) {
|
|
341
|
+
message.error("工单ID为空,无法处理");
|
|
342
|
+
return false;
|
|
343
|
+
} // 1. 调用关联变更单接口(不判断结果)
|
|
344
|
+
try {
|
|
345
|
+
await http.post(
|
|
346
|
+
"/aiops/api/v1/flow/group/province/alarm/dispatch/order/relateChangeOrder",
|
|
347
|
+
this.form
|
|
348
|
+
);
|
|
349
|
+
} catch (e) {
|
|
350
|
+
console.error(e);
|
|
351
|
+
} // 2. 调用定位接口(不判断结果)
|
|
352
|
+
try {
|
|
353
|
+
await http.post(
|
|
354
|
+
"/aiops/api/v1/flow/group/province/alarm/dispatch/order/positioningOrder",
|
|
355
|
+
this.form
|
|
356
|
+
);
|
|
357
|
+
} catch (e) {
|
|
358
|
+
console.error(e);
|
|
359
|
+
} // 3. 调用回单接口
|
|
360
|
+
try {
|
|
361
|
+
const returnResult = await http.post(
|
|
362
|
+
"/aiops/api/v1/flow/group/province/alarm/dispatch/order/returnOrder",
|
|
363
|
+
this.form
|
|
364
|
+
);
|
|
365
|
+
if (returnResult && returnResult.resultCode === 0) {
|
|
366
|
+
message.success("告警处理成功");
|
|
367
|
+
return true;
|
|
368
|
+
}
|
|
369
|
+
message.error((returnResult && returnResult.resultMsg) || "回单失败");
|
|
370
|
+
return false;
|
|
371
|
+
} catch (e) {
|
|
372
|
+
message.error("回单请求异常");
|
|
373
|
+
console.error(e);
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
},
|
|
377
|
+
onChange_IF_RELATED_CHANGEORDER() {
|
|
378
|
+
form.removeRequired("CHANGE_ORDER");
|
|
379
|
+
if ("是" == form.getValue("IF_RELATED_CHANGEORDER")) {
|
|
380
|
+
const orderStr = form.getValue("CHANGE_ORDERS", "");
|
|
381
|
+
const orders = orderStr
|
|
382
|
+
.split(",")
|
|
383
|
+
.filter((order) => order.trim())
|
|
384
|
+
.map((order) => ({
|
|
385
|
+
label: order,
|
|
386
|
+
value: order,
|
|
387
|
+
children: null,
|
|
388
|
+
isShow: true,
|
|
389
|
+
pid: null,
|
|
390
|
+
state: null
|
|
391
|
+
}));
|
|
392
|
+
form.setSelectOptions("CHANGE_ORDER", orders);
|
|
393
|
+
form.setRequired("CHANGE_ORDER");
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
};
|
|
397
|
+
module.exports = customEvent;
|
|
3
398
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
在 `EncodeConfig` 中添加 `useAlias: boolean` 开关:
|
|
7
|
-
- `useAlias: true` — encode 阶段解析 `@/` 路径别名(`@` 代表项目根目录),decode 阶段生成 `@/` 路径
|
|
8
|
-
- `useAlias: false`(默认)— 使用传统的相对路径
|
|
9
|
-
|
|
10
|
-
### 修改的文件
|
|
11
|
-
|
|
12
|
-
| 文件 | 改动 |
|
|
13
|
-
|------|------|
|
|
14
|
-
| `src/config/main_config.ts` | `EncodeConfig` 添加 `useAlias` 字段 |
|
|
15
|
-
| `src/config/index.ts` | 默认 `useAlias: false`;`__dirname` 不含 `node_modules` 时回退到 `process.cwd()`;尝试 `config.js` 和 `config.json` 两种配置文件 |
|
|
16
|
-
| `src/scanf/index.ts` | `scanfRequieMod` 添加 `rootDir` 参数,支持 `@/` 路径解析 |
|
|
17
|
-
| `src/util/ast.ts` | `getRequireModPaths` 传递 `rootDir`;`importMods` 根据 `useAlias` 生成 `@/` 或相对路径;修复相对路径缺少 `./` 前缀的问题 |
|
|
18
|
-
| `src/util/parent_path.ts` | `getParentRootDir` 在 junction symlink 场景下回退到 `config.baseDir` |
|
|
19
|
-
| `src/context/map_context.ts` | `buildMapContext` 根据 `useAlias` 条件传递 `rootDir` |
|
|
20
|
-
| `src/decode/index.ts` | 传递 `config.encode.useAlias` 给 `importMods` |
|
|
21
|
-
|
|
22
|
-
# 测试结果 ✅
|
|
23
|
-
|
|
24
|
-
### useAlias: true
|
|
25
|
-
- **Encode**: `@/src/util/index` 正确解析为绝对路径,方法正确内联并添加 `__modName` 后缀
|
|
26
|
-
- **Decode**: 生成 `require("@/src/util")` 和 `require("@/src/helper")`,`__modName` 后缀正确移除
|
|
27
|
-
|
|
28
|
-
### useAlias: false
|
|
29
|
-
- **Encode**: 相对路径 `./util/index` 正常解析
|
|
30
|
-
- **Decode**: 生成 `require("./util")` 和 `require("./helper")`,路径以 `./` 开头
|
|
31
|
-
|
|
32
|
-
### 修复的问题
|
|
33
|
-
1. `useAlias` 无效 — `scanfRequieMod` 缺少 `rootDir` 参数,`@` 路径无法解析
|
|
34
|
-
2. `Error: src\@\util\index.js is not exists!` — junction symlink 导致 `__dirname` 不含 `node_modules`,`getParentRootDir()` 返回 undefined
|
|
35
|
-
3. `require("util")` 缺少 `./` 前缀 — `path.relative()` 返回的路径不以 `./` 开头,Node.js 会当作 npm 包名
|
|
36
|
-
4. 配置文件查找失败 — 只尝试 `config.js`,不尝试 `config.json`
|
|
399
|
+
```
|
|
@@ -11,6 +11,8 @@ const ast_1 = require("../util/ast");
|
|
|
11
11
|
const parent_path_1 = require("../util/parent_path");
|
|
12
12
|
const config_1 = require("../config");
|
|
13
13
|
const os_1 = require("os");
|
|
14
|
+
const logger_1 = require("../util/logger");
|
|
15
|
+
const logger = (0, logger_1.createLogger)("map");
|
|
14
16
|
class MapContext {
|
|
15
17
|
constructor(srcPath = "", entry = "", outDir = "", initMap = false) {
|
|
16
18
|
this.map = new map_config_1.MapConfig();
|
|
@@ -59,7 +61,7 @@ class MapContext {
|
|
|
59
61
|
}
|
|
60
62
|
static readFromLocal(inDir) {
|
|
61
63
|
const inPath = path_1.default.join(inDir, MapContext.SAVE_FILE);
|
|
62
|
-
|
|
64
|
+
logger.info(`read map: ${inPath}`);
|
|
63
65
|
try {
|
|
64
66
|
const json = fs_1.default.readFileSync(inPath, { encoding: "utf-8" });
|
|
65
67
|
const map = JSON.parse(json);
|
|
@@ -68,7 +70,7 @@ class MapContext {
|
|
|
68
70
|
return mapContext;
|
|
69
71
|
}
|
|
70
72
|
catch (err) {
|
|
71
|
-
|
|
73
|
+
logger.warn("map file not found");
|
|
72
74
|
// console.log(err);
|
|
73
75
|
}
|
|
74
76
|
return new MapContext();
|
|
@@ -81,7 +83,7 @@ class MapContext {
|
|
|
81
83
|
}
|
|
82
84
|
writeToLocal() {
|
|
83
85
|
const outPath = path_1.default.join(this.outDir, MapContext.SAVE_FILE);
|
|
84
|
-
|
|
86
|
+
logger.info(`write map: ${outPath}`);
|
|
85
87
|
const json = JSON.stringify(this.map, null, 4);
|
|
86
88
|
try {
|
|
87
89
|
fs_1.default.accessSync(this.outDir);
|
|
@@ -95,7 +97,7 @@ class MapContext {
|
|
|
95
97
|
const srcAst = (0, ast_1.parseSrcAst)(inPath);
|
|
96
98
|
const srcMethodNames = (0, ast_1.getObjectMethodNames)((0, ast_1.getObjectMethodsByEntryAndMethodNames)(srcAst, entry));
|
|
97
99
|
if (!srcMethodNames.length) {
|
|
98
|
-
|
|
100
|
+
logger.warn(`entry not found: ${entry}`);
|
|
99
101
|
this.appendModMap(new map_config_1.Mod(inPath, new map_config_1.Dependencies()), root, entry);
|
|
100
102
|
return;
|
|
101
103
|
}
|
package/core/decode/index.js
CHANGED
|
@@ -26,19 +26,26 @@ const map_context_1 = require("../context/map_context");
|
|
|
26
26
|
const scanf_1 = require("../scanf");
|
|
27
27
|
const ast_1 = require("../util/ast");
|
|
28
28
|
const version_1 = require("../util/version");
|
|
29
|
+
const logger_1 = require("../util/logger");
|
|
30
|
+
const logger = (0, logger_1.createLogger)("decode");
|
|
29
31
|
(function decoding(config) {
|
|
30
32
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
33
|
const targetDirs = (0, scanf_1.scanfCodeDirs)(config.baseDir, config.target);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
logger.step("扫描目录");
|
|
35
|
+
logger.info(`目标目录: ${targetDirs.join(", ")}`);
|
|
34
36
|
const codeFiles = (0, scanf_1.scanfCodeFiles)(targetDirs, config.decode.file);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
+
logger.info(`找到 ${codeFiles.length} 个编码文件 (${config.decode.file})`);
|
|
38
|
+
for (let i = 0; i < codeFiles.length; i++) {
|
|
39
|
+
const inPath = codeFiles[i];
|
|
37
40
|
const outPath = path_1.default.join(path_1.default.dirname(inPath), config.decode.output);
|
|
38
41
|
const settingDir = path_1.default.join(path_1.default.dirname(inPath), config.settingDir);
|
|
42
|
+
logger.step(`解码处理 [${i + 1}/${codeFiles.length}]`);
|
|
43
|
+
logger.info(`源文件: ${inPath}`);
|
|
39
44
|
yield decoding$0(inPath, outPath, config, settingDir);
|
|
40
|
-
|
|
45
|
+
logger.info(`输出: ${outPath}`);
|
|
41
46
|
}
|
|
47
|
+
logger.step("完成");
|
|
48
|
+
logger.info(`共处理 ${codeFiles.length} 个文件`);
|
|
42
49
|
});
|
|
43
50
|
})(config_1.config);
|
|
44
51
|
/**
|
package/core/encode/index.js
CHANGED
|
@@ -11,18 +11,24 @@ const map_context_1 = require("../context/map_context");
|
|
|
11
11
|
const ast_1 = require("../util/ast");
|
|
12
12
|
const version_1 = require("../util/version");
|
|
13
13
|
const core_1 = require("@babel/core");
|
|
14
|
+
const logger_1 = require("../util/logger");
|
|
15
|
+
const logger = (0, logger_1.createLogger)("encode");
|
|
14
16
|
(function encoding(config) {
|
|
15
17
|
const encodeConfig = config.encode;
|
|
16
18
|
const targetDirs = (0, scanf_1.scanfCodeDirs)(config.baseDir, config.target);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
logger.step("扫描目录");
|
|
20
|
+
logger.info(`目标目录: ${targetDirs.join(", ")}`);
|
|
19
21
|
const codeFiles = (0, scanf_1.scanfCodeFiles)(targetDirs, encodeConfig.file);
|
|
20
|
-
|
|
22
|
+
logger.info(`找到 ${codeFiles.length} 个入口文件 (${encodeConfig.file})`);
|
|
23
|
+
let totalMethods = 0;
|
|
24
|
+
codeFiles.forEach((inPath, index) => {
|
|
21
25
|
const workDir = path_1.default.dirname(inPath);
|
|
22
26
|
const settingDir = path_1.default.join(workDir, config.settingDir);
|
|
23
|
-
|
|
27
|
+
logger.step(`编码处理 [${index + 1}/${codeFiles.length}]`);
|
|
28
|
+
logger.info(`源文件: ${inPath}`);
|
|
24
29
|
const mapContext = new map_context_1.MapContext(inPath, encodeConfig.entry, settingDir, true);
|
|
25
30
|
const methods = encoding$0(mapContext, encodeConfig.entry);
|
|
31
|
+
totalMethods += methods.length;
|
|
26
32
|
// 读取或创建版本号
|
|
27
33
|
const version = (0, version_1.readOrCreateVersion)(settingDir);
|
|
28
34
|
// 在onFormReady方法中注入版本日志
|
|
@@ -30,17 +36,19 @@ const core_1 = require("@babel/core");
|
|
|
30
36
|
// 将onFormReady和onFormSubmit排到最前面
|
|
31
37
|
reorderMethods(methods);
|
|
32
38
|
const outPath = path_1.default.join(workDir, encodeConfig.output);
|
|
33
|
-
console.log(`output file => ${outPath}`);
|
|
34
39
|
(0, ast_1.outputObjectMethods)(outPath, methods);
|
|
40
|
+
logger.info(`方法数: ${methods.length}, 版本: ${version}`);
|
|
41
|
+
logger.info(`输出: ${outPath}`);
|
|
35
42
|
// 版本号递增并写入
|
|
36
43
|
(0, version_1.incrementVersion)(settingDir);
|
|
37
44
|
});
|
|
45
|
+
logger.step("完成");
|
|
46
|
+
logger.info(`共处理 ${codeFiles.length} 个文件, ${totalMethods} 个方法`);
|
|
38
47
|
})(config_1.config);
|
|
39
48
|
function encoding$0(mapContext, entry) {
|
|
40
49
|
const modNames = mapContext.getModNames();
|
|
41
50
|
return modNames.flatMap((name) => {
|
|
42
51
|
const srcAst = (0, ast_1.parseSrcAst)(mapContext.getAbsoluteSrcPathByMod(name));
|
|
43
|
-
// console.log(`import => ${name}`);
|
|
44
52
|
const srcMethods = [];
|
|
45
53
|
const self = name === "self";
|
|
46
54
|
if (self) {
|
package/core/scanf/index.js
CHANGED
|
@@ -8,6 +8,8 @@ exports.scanfCodeDirs = scanfCodeDirs;
|
|
|
8
8
|
exports.scanfRequieMod = scanfRequieMod;
|
|
9
9
|
const fs_1 = __importDefault(require("fs"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const logger_1 = require("../util/logger");
|
|
12
|
+
const logger = (0, logger_1.createLogger)("scanf");
|
|
11
13
|
function scanfCodeFiles(dirPaths, filterName = "") {
|
|
12
14
|
if (typeof dirPaths === "string") {
|
|
13
15
|
return scanfCodeFiles$0(dirPaths, filterName);
|
|
@@ -20,7 +22,7 @@ function scanfCodeFiles(dirPaths, filterName = "") {
|
|
|
20
22
|
function scanfCodeFiles$0(dirPath, filterName = "") {
|
|
21
23
|
const filePaths = [];
|
|
22
24
|
if (!fs_1.default.existsSync(dirPath)) {
|
|
23
|
-
|
|
25
|
+
logger.warn(`dir not found, skipping: ${dirPath}`);
|
|
24
26
|
return filePaths;
|
|
25
27
|
}
|
|
26
28
|
const files = fs_1.default.readdirSync(dirPath, {
|
package/core/util/ast.js
CHANGED
|
@@ -25,6 +25,8 @@ const path_1 = require("path");
|
|
|
25
25
|
const os_1 = require("os");
|
|
26
26
|
const parent_path_1 = require("./parent_path");
|
|
27
27
|
const config_1 = require("../config");
|
|
28
|
+
const logger_1 = require("./logger");
|
|
29
|
+
const logger = (0, logger_1.createLogger)("ast");
|
|
28
30
|
function parseSrcAst(srcPath) {
|
|
29
31
|
if (!srcPath) {
|
|
30
32
|
return;
|
|
@@ -70,7 +72,7 @@ function getRequireModPaths(baseDir, srcAst, ignoreMod, rootDir) {
|
|
|
70
72
|
if (item.init.callee.name === "require") {
|
|
71
73
|
if (core_1.types.isIdentifier(item.id)) {
|
|
72
74
|
if (ignoreMod === null || ignoreMod === void 0 ? void 0 : ignoreMod.includes(item.id.name)) {
|
|
73
|
-
|
|
75
|
+
logger.info(`ignore module: ${item.id.name}`);
|
|
74
76
|
}
|
|
75
77
|
else {
|
|
76
78
|
return true;
|
|
@@ -344,7 +346,8 @@ function importMods(outDir, srcAst, mapContext, useAlias = false) {
|
|
|
344
346
|
.replace(/\\/g, "/")
|
|
345
347
|
.replace(/\/index\.js$/, "")
|
|
346
348
|
.replace(/\.js$/, "");
|
|
347
|
-
|
|
349
|
+
// 确保 @ 别名路径格式为 @/xxx(@ 与路径之间必须有 /)
|
|
350
|
+
requireFrom = aliasPath.startsWith("/") ? "@" + aliasPath : "@/" + aliasPath;
|
|
348
351
|
}
|
|
349
352
|
else {
|
|
350
353
|
requireFrom = (0, path_1.relative)(outDir, srcPath.replace(/\/index\.js$/, "").replace(/\\index\.js$/, "").replace(/\.js$/, ""))
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 统一日志工具模块
|
|
3
|
+
* 提供带 scope 前缀和状态图标的日志函数
|
|
4
|
+
*/
|
|
5
|
+
export interface Logger {
|
|
6
|
+
info(msg: string): void;
|
|
7
|
+
warn(msg: string): void;
|
|
8
|
+
error(msg: string): void;
|
|
9
|
+
step(title: string): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 创建带 scope 前缀的 logger
|
|
13
|
+
* @param scope - 日志前缀,如 'encode' / 'decode'
|
|
14
|
+
*/
|
|
15
|
+
export declare function createLogger(scope: string): Logger;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* 统一日志工具模块
|
|
4
|
+
* 提供带 scope 前缀和状态图标的日志函数
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.createLogger = createLogger;
|
|
8
|
+
/**
|
|
9
|
+
* 创建带 scope 前缀的 logger
|
|
10
|
+
* @param scope - 日志前缀,如 'encode' / 'decode'
|
|
11
|
+
*/
|
|
12
|
+
function createLogger(scope) {
|
|
13
|
+
return {
|
|
14
|
+
info(msg) {
|
|
15
|
+
console.log(`[${scope}] ✔ ${msg}`);
|
|
16
|
+
},
|
|
17
|
+
warn(msg) {
|
|
18
|
+
console.log(`[${scope}] ⚠ ${msg}`);
|
|
19
|
+
},
|
|
20
|
+
error(msg) {
|
|
21
|
+
console.log(`[${scope}] ✖ ${msg}`);
|
|
22
|
+
},
|
|
23
|
+
step(title) {
|
|
24
|
+
const line = "─".repeat(Math.max(0, 50 - title.length));
|
|
25
|
+
console.log(`\n[${scope}] ── ${title} ${line}`);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
package/package.json
CHANGED
package/tsconfig.tsbuildinfo
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["./src/config/index.ts","./src/config/main_config.ts","./src/config/map_config.ts","./src/context/map_context.ts","./src/decode/index.ts","./src/encode/index.ts","./src/scanf/index.ts","./src/util/ast.ts","./src/util/parent_path.ts","./src/util/version.ts"],"version":"6.0.3"}
|
|
1
|
+
{"root":["./src/config/index.ts","./src/config/main_config.ts","./src/config/map_config.ts","./src/context/map_context.ts","./src/decode/index.ts","./src/encode/index.ts","./src/scanf/index.ts","./src/util/ast.ts","./src/util/logger.ts","./src/util/parent_path.ts","./src/util/version.ts"],"version":"6.0.3"}
|