crabatool 1.0.856 → 1.0.860

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.
@@ -162,4 +162,132 @@ crabatool -runEv -evSavePath "ev保存音频的路径,如c:\\Users\\grasp\\ev
162
162
 
163
163
  - 所有日志都包含时间戳
164
164
  - 详细记录文件监控、大小变化等信息
165
- - 错误信息清晰明了
165
+ - 错误信息清晰明了
166
+
167
+
168
+
169
+ ## 方案二:windows【命令版ev服务工具】使用步骤
170
+
171
+ 1. **Node.js 环境**【仅首次安装】
172
+
173
+ 若电脑尚未安装 Node.js,请先下载并安装:[Node.js 下载地址](https://nodejs.cn/download/)
174
+
175
+ 2. [下载工具包](setup/evtool.zip) 然后解压到本地
176
+
177
+ 3. 双击安装软件.bat【仅首次安装】
178
+
179
+ 后期通知软件有更新的情况,就需要双击更新软件.bat,平时不用【仅有更新的时候】
180
+
181
+ 4. 右键启动软件.bat---编辑---根据你当前的情况修改ev的存储路径【仅首次】
182
+
183
+ 如果不清楚怎么修改ev存储路径,继续看下面的介绍
184
+
185
+ 5. 双击启动软件.bat【**每次**】
186
+
187
+ 平时需要采集音视频的时候
188
+
189
+ -----如果只是使用步骤,到此结束即可------
190
+
191
+ 还需更多了解,可以继续往下看
192
+
193
+
194
+
195
+ # crabatool + EV录屏 集成服务介绍
196
+
197
+ ## 功能说明
198
+
199
+ `crabatool` 提供 EV 录屏自动化集成功能。启动服务后,工具将自动监听 EV 录屏生成的文件(视频/音频),检测录制完成并自动上传至七牛云存储,最终将生成的 URL 回填至教学录制页面中,实现教学音视频的自动化采集与上传。
200
+
201
+ ## 适用场景
202
+
203
+ - 录制教学视频或音频,自动上传至七牛云
204
+ - 无需手动操作,自动获取录制文件的访问链接
205
+ - 支持 EV 录屏路径自动检测,简化配置流程
206
+
207
+ ## 依赖环境
208
+
209
+ 1. **Node.js 环境**(仅首次安装)
210
+ 若电脑尚未安装 Node.js,请先下载并安装:[Node.js 下载地址](https://nodejs.cn/download/)
211
+
212
+ 2. **全局安装 crabatool**(仅首次安装)
213
+ 打开命令行工具,执行以下命令:
214
+ ```bash
215
+ npm install crabatool -g
216
+ ```
217
+
218
+ ## 启动服务
219
+
220
+ ### 命令格式
221
+
222
+ ```bash
223
+ crabatool -runEv -evSavePath "<EV录屏保存路径>"
224
+ ```
225
+
226
+ ### 参数说明
227
+
228
+ | 参数 | 说明 |
229
+ |------|------|
230
+ | `-runEv` | 启动 EV 录屏集成服务 |
231
+ | `-evSavePath` | EV 录屏保存视频和音频的目录路径,需与 EV 录屏软件中的“保存路径”设置一致 |
232
+
233
+ > 💡 **如何查看或修改 EV 录屏的保存路径?**
234
+ > 参考官方帮助文档:[EV录屏 - 如何查看/修改保存路径](https://www.ieway.cn/help/desc-evcapture-pc-2141.html)
235
+
236
+ ### 示例
237
+
238
+ ```bash
239
+ crabatool -runEv -evSavePath "C:\Users\用户名\Documents\EV录屏"
240
+ ```
241
+
242
+ ### 快捷启动(推荐)
243
+
244
+ 建议将启动命令保存为 **批处理文件(.bat)**,便于后续快速启动服务,无需重复输入命令。
245
+
246
+ **创建方法:**
247
+ 1. 新建文本文件,输入上述命令
248
+ 2. 将文件扩展名改为 `.bat`
249
+ 3. 双击即可启动服务
250
+
251
+ ## 详细操作流程
252
+
253
+ 1. **启动集成服务**
254
+ 执行启动命令(或双击已保存的 `.bat` 文件),服务开始监听 EV 录屏的保存目录。
255
+
256
+ 2. **触发录制**
257
+ 在教学录制页面中,点击 **“采集这一步的音/视频”** 图标。
258
+
259
+ 3. **启动 EV 录屏**
260
+ 系统将自动打开 EV 录屏工具,请手动点击 EV 录屏的 **“开始录制”** 按钮或使用预设的快捷键开始录制。
261
+
262
+ 4. **自动上传与回填**
263
+ 录制完成后,文件将自动上传至七牛云,上传成功后生成的音频/视频 URL 将自动填入当前教学步骤,图标变为红色,表示处理完成。
264
+
265
+ ## 注意事项
266
+
267
+ - 请确保 EV 录屏的保存路径与 `-evSavePath` 参数填写路径**完全一致**
268
+ - 录制过程中请勿手动删除或移动正在写入的文件,否则可能导致上传失败
269
+ - 若录制完成后长时间未触发上传,请检查网络连接及七牛云配置是否正常
270
+ - 服务启动后请保持命令行窗口运行状态,关闭窗口将停止监听
271
+
272
+
273
+ ## 使用 crabatool 与原生 EV 录屏的对比
274
+
275
+ | 对比项 | 原生 EV 录屏 | crabatool 集成方案 |
276
+ |--------|--------------|--------------------|
277
+ | **启动方式** | 手动打开 EV 录屏,点击录制 | 双击 `.bat` 文件启动服务,教学页面一键触发录制 |
278
+ | **录制触发** | 手动点击 EV 录屏界面按钮 | 在教学页面点击“采集音/视频”,工具自动唤起 EV 录屏并开始监听 |
279
+ | **文件处理** | 录制完成后,需手动找到文件、重命名、上传至云存储 | 工具自动检测录制结束,自动上传至七牛云 |
280
+ | **URL 回填** | 手动复制云存储链接,粘贴到教学步骤中 | 上传成功后 URL 自动回填,图标状态自动更新 |
281
+ | **多步骤支持** | 需手动记录每次录制的文件对应关系 | 自动关联当前步骤,无需人工核对 |
282
+ | **出错处理** | 依赖人工检查是否遗漏 | 工具实时监控,有错误日志可追溯 |
283
+ | **适用场景** | 适合临时、少量录制 | 适合批量、流程化的教学音视频采集 |
284
+
285
+ 通过集成 `crabatool`,可将原本需要 5~8 步的手动操作简化为 **一键触发 → 自动完成**,大幅提升录制上传效率,避免人工失误。
286
+
287
+ ## 常见问题
288
+
289
+ **Q:为什么服务启动后没有反应?**
290
+ A:请检查 EV 录屏保存路径是否正确,以及该目录是否存在。
291
+
292
+ **Q:录制完成后未自动上传?**
293
+ A:可检查网络连接,或查看命令行窗口是否有错误日志输出。
package/index.js CHANGED
@@ -338,6 +338,7 @@ async function checkFast(args) {
338
338
  if (args.includes('-runEv')) {
339
339
  start.bindConfigByArgv('-evSavePath');
340
340
  start.bindConfigByArgv('-port');
341
+ start.bindConfigByArgv('-local', 'boolean');
341
342
  start.runEvServer();
342
343
  return false;
343
344
  }
package/lib/utils.js CHANGED
@@ -9,6 +9,7 @@ var compressing = require('compressing');
9
9
  var axios = require('axios');
10
10
  var os = require('os');
11
11
  const { execSync } = require('child_process');
12
+ const { execFileSync } = require('child_process');
12
13
  /*
13
14
  const util = require('util');
14
15
  const execPromise = util.promisify(execSync);
@@ -984,7 +985,9 @@ class Utils {
984
985
  execSync('git add --all', { cwd: webPath }); // 暂存
985
986
 
986
987
  console.log('git commit -m "' + msg + '"'); // 提交日志
987
- execSync('git commit -m "' + msg + '"', { cwd: webPath }); // 提交日志
988
+ //execSync('git commit -m "' + msg + '"', { cwd: webPath }); // 提交日志
989
+ execFileSync('git', ['commit', '-m', msg]);
990
+
988
991
 
989
992
  //console.log('git pull --rebase origin ' + branchName); // 拉取分支
990
993
  //execSync('git pull --rebase origin ' + branchName, { cwd: webPath }); // 拉取分支
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crabatool",
3
- "version": "1.0.856",
3
+ "version": "1.0.860",
4
4
  "description": "crabatool",
5
5
  "main": "index.js",
6
6
  "bin": {
package/tool/checkjs.js CHANGED
@@ -10,6 +10,7 @@ var gspx = require('./checkgspx.js');
10
10
  var iconfont = require('./checkiconfont.js');
11
11
  var eslint = require('eslint');
12
12
  const upgrade = require('./upgrade.js');
13
+ const javaEnum = require('./javaEnum.js');
13
14
 
14
15
 
15
16
  // js超过多少kb给与提示
@@ -46,6 +47,9 @@ module.exports.start = async function() {
46
47
 
47
48
  iconfont.start(); // 检查收集各项目组iconfont使用情况
48
49
 
50
+ //javaEnum.start(); // 执行代码检测时,搜集当前webPath路径下面所有java枚举类(1. 普通枚举,2. 含@EnumDbMapping注解的枚举)
51
+
52
+
49
53
  //utils.copyFile(jsonPath, path.join(process.cwd(), '.eslintrc.json'));
50
54
  var jsFiles = utils.getFiles({ source: config.webPath, exts: '.js', ignores: config.ignoreCheck });
51
55
 
@@ -19,6 +19,9 @@ var evConfig = {
19
19
  // 监控的文件
20
20
  var monitoringFiles = {};
21
21
 
22
+ // 已完成的文件(防止重复处理)
23
+ var completedFiles = {};
24
+
22
25
  // 确保输出目录存在
23
26
  if (!fs.existsSync(evConfig.outputDir)) {
24
27
  fs.mkdirSync(evConfig.outputDir, { recursive: true });
@@ -62,6 +65,9 @@ function init() {
62
65
  // 直接启动runEv服务时,什么都不用做
63
66
  // 等待前端连接和start消息,如果等到的是连接消息,记录连接时间。
64
67
  log('evsockettool 初始化完成,等待前端连接');
68
+ if (config.local) {
69
+ startEvRecording();
70
+ }
65
71
  }
66
72
 
67
73
  // 启动ev录屏
@@ -132,10 +138,21 @@ function stopEvRecording(conn) {
132
138
  // 清理监控文件
133
139
  for (var filePath in monitoringFiles) {
134
140
  if (monitoringFiles.hasOwnProperty(filePath)) {
135
- clearInterval(monitoringFiles[filePath]);
141
+ if (monitoringFiles[filePath].timer) {
142
+ clearInterval(monitoringFiles[filePath].timer);
143
+ }
136
144
  delete monitoringFiles[filePath];
137
145
  }
138
146
  }
147
+ log('清理监控文件');
148
+
149
+ // 清理已完成文件标记
150
+ for (var completedFile in completedFiles) {
151
+ if (completedFiles.hasOwnProperty(completedFile)) {
152
+ delete completedFiles[completedFile];
153
+ }
154
+ }
155
+ log('清理已完成文件标记');
139
156
 
140
157
  // 清理watcher
141
158
  if (evConfig.watcher) {
@@ -169,15 +186,21 @@ function watchEvOutput(conn) {
169
186
  evConfig.watcher.on('add', function(filePath) {
170
187
  var ext = path.extname(filePath).toLowerCase();
171
188
  if (ext === '.mp3' || ext === '.wav' || ext === '.mp4') {
172
- log('发现新的媒体文件:', filePath);
189
+ // 检查文件是否已完成
190
+ if (completedFiles[filePath]) {
191
+ log('文件已处理完成,跳过:', filePath);
192
+ return;
193
+ }
194
+ console.log('\r\n\r\n');
195
+ log('---------发现新的媒体文件---------', filePath);
173
196
 
174
197
  // 检查文件创建时间是否大于启动时间
175
198
  try {
176
199
  var stats = fs.statSync(filePath);
177
200
  var fileCreateTime = stats.ctime.getTime();
178
201
  if (fileCreateTime > evConfig.startTime) {
179
- log('录屏开始,文件已生成:', filePath);
180
202
  sendEvMessage(conn, 'msg', '录屏已开始,正在录制中');
203
+ startFileMonitoring(conn, filePath);
181
204
  }
182
205
  } catch (ex) {
183
206
  log('检查文件信息失败:', ex.message);
@@ -188,25 +211,29 @@ function watchEvOutput(conn) {
188
211
  evConfig.watcher.on('change', function(filePath) {
189
212
  var ext = path.extname(filePath).toLowerCase();
190
213
  if (ext === '.mp3' || ext === '.wav' || ext === '.mp4') {
191
- log('文件变化:', filePath);
214
+ //log('文件变化:', filePath);
215
+
216
+ // 检查文件是否已完成
217
+ if (completedFiles[filePath]) {
218
+ log('文件已处理完成,跳过:', filePath);
219
+ return;
220
+ }
192
221
 
193
222
  // 检查文件创建时间和大小
194
223
  try {
195
224
  var stats = fs.statSync(filePath);
196
225
  var fileCreateTime = stats.ctime.getTime();
197
-
198
226
  // 文件创建时间必须大于启动时间
199
227
  if (fileCreateTime > evConfig.startTime) {
200
- log('文件创建时间符合要求:', new Date(fileCreateTime).toISOString());
201
-
202
- // 如果文件还没有被监控,开始监控
203
- if (!monitoringFiles[filePath]) {
204
- log('开始监控文件:', filePath, '当前大小:', stats.size, 'bytes');
205
- // 先标记为监控中,防止短时间内重复触发
206
- monitoringFiles[filePath] = true;
207
- startMonitoringFile(conn, filePath);
228
+ log('文件发生改变:', filePath, '当前大小:', stats.size, 'bytes');
229
+
230
+ // 如果文件已经在监控中,重置成功计数
231
+ if (monitoringFiles[filePath]) {
232
+ log('文件在监控中发生变化,重置成功计数:', filePath);
233
+ monitoringFiles[filePath].successCount = 0;
208
234
  } else {
209
- log('文件已在监控中,跳过:', filePath);
235
+ // 开始监控文件
236
+ startFileMonitoring(conn, filePath);
210
237
  }
211
238
  } else {
212
239
  log('文件创建时间不符合要求,跳过:', filePath);
@@ -222,74 +249,60 @@ function watchEvOutput(conn) {
222
249
  });
223
250
  }
224
251
 
225
- // 监控文件大小变化,判断录制是否真正结束
226
- function startMonitoringFile(conn, filePath) {
227
- // 如果已经是一个有效的interval,说明已经在监控中
228
- if (monitoringFiles[filePath] && monitoringFiles[filePath] !== true) {
229
- log('文件已在监控中,跳过:', filePath);
252
+ // 开始监控文件,每隔1秒尝试重命名检测,连续3次成功才算完成
253
+ function startFileMonitoring(conn, filePath) {
254
+ // 如果已经在监控中,跳过
255
+ if (monitoringFiles[filePath]) {
256
+ //log('文件已在监控中,跳过:', filePath);
230
257
  return;
231
258
  }
259
+ var stats = fs.statSync(filePath);
260
+ log('开始监控文件是否录制完成:', filePath, '当前大小:', stats.size, 'bytes');
261
+
262
+ // 标记为监控中,存储状态
263
+ monitoringFiles[filePath] = {
264
+ timer: null,
265
+ successCount: 0,
266
+ requiredSuccessCount: 3 // 需要连续3次成功
267
+ };
232
268
 
233
- var lastSize = 0;
234
- var stableCount = 0;
235
- var hasGrowth = false;
236
-
237
- // 根据文件类型设置不同的阈值
238
- var ext = path.extname(filePath).toLowerCase();
239
- var isVideo = ext === '.mp4';
240
- var isAudio = ext === '.mp3' || ext === '.wav';
241
-
242
- // MP4视频:帧率20fps,文件增长快,检查间隔1秒,稳定3次(3秒)即可判定完成
243
- // MP3音频:码率128kbps,文件增长慢,检查间隔3秒,稳定2次(6秒)即可判定完成
244
- var checkInterval = isVideo ? 1000 : (isAudio ? 3000 : 2000); // MP4: 1秒, MP3: 3秒, 其他: 2秒
245
- var stableThreshold = isVideo ? 3 : (isAudio ? 2 : 3); // MP4: 3次(3秒), MP3: 2次(6秒), 其他: 3次
246
- var minFileSize = isVideo ? 5000 : (isAudio ? 3000 : 1000); // MP4: 5KB, MP3: 3KB, 其他: 1KB
247
-
248
- log('开始监控文件:', path.basename(filePath), '类型:', isVideo ? '视频' : (isAudio ? '音频' : '其他'),
249
- '检查间隔:', checkInterval + 'ms', '稳定阈值:', stableThreshold + '次');
250
-
251
- // 清除之前的标记,设置为真正的interval
252
- if (monitoringFiles[filePath] === true) {
253
- delete monitoringFiles[filePath];
254
- }
255
-
256
- monitoringFiles[filePath] = setInterval(function() {
257
- try {
258
- var stats = fs.statSync(filePath);
259
- var currentSize = stats.size;
260
-
261
- if (currentSize > lastSize) {
262
- hasGrowth = true;
263
- stableCount = 0; // 重置计数
264
- log('文件大小增长:', filePath, '当前大小:', currentSize, 'bytes');
265
- } else if (currentSize === lastSize) {
266
- stableCount++;
267
- log('文件大小稳定:', filePath, '连续稳定次数:', stableCount, '稳定时间:', (stableCount * checkInterval / 1000).toFixed(1), '秒');
268
- }
269
-
270
- lastSize = currentSize;
271
-
272
- // 当文件大小连续稳定5次(15秒)且至少有过一次增长,并且文件大小大于最小阈值时,认为录制真正结束
273
- if (stableCount >= stableThreshold && hasGrowth && currentSize >= minFileSize) {
274
- clearInterval(monitoringFiles[filePath]);
275
- delete monitoringFiles[filePath];
276
- log('文件录制真正完成:', filePath, '最终大小:', currentSize, 'bytes');
277
- processEvFile(conn, filePath);
269
+ const state = monitoringFiles[filePath];
270
+
271
+ state.timer = setInterval(function() {
272
+ // 尝试重命名检测文件是否被占用
273
+ checkFileLock(filePath, function(isLocked) {
274
+ if (!isLocked) {
275
+ // 重命名成功,增加成功计数
276
+ state.successCount++;
277
+ log('文件重命名成功,连续成功次数:', state.successCount + '/' + state.requiredSuccessCount, filePath);
278
+
279
+ // 连续3次成功,说明文件未被占用,录制完成
280
+ if (state.successCount >= state.requiredSuccessCount) {
281
+ clearInterval(state.timer);
282
+ delete monitoringFiles[filePath];
283
+ // 标记文件为已完成
284
+ completedFiles[filePath] = true;
285
+ log('【文件录制完成】:', filePath);
286
+ processEvFile(conn, filePath);
287
+ }
288
+ } else {
289
+ // 重命名失败,重置成功计数,文件仍被占用,继续监控
290
+ state.successCount = 0;
291
+ //log('文件仍被占用,重置成功计数:', filePath);
278
292
  }
279
- } catch (ex) {
280
- log('监控文件失败:', ex.message);
281
- clearInterval(monitoringFiles[filePath]);
282
- delete monitoringFiles[filePath];
283
- }
284
- }, checkInterval);
293
+ });
294
+ }, 1000); // 每隔1秒检查一次
285
295
  }
286
296
 
287
297
  // 处理ev生成的文件
288
298
  function processEvFile(conn, filePath) {
299
+ var stats = fs.statSync(filePath);
300
+ log('【开始上传文件到七牛】:', filePath, '当前大小:', stats.size, 'bytes');
301
+
289
302
  // 检查是否有七牛token
290
303
  if (!evConfig.qiniuToken) {
291
- log('没有七牛token,无法上传文件');
292
- sendEvMessage(conn, 'error', '录制完成,但没有七牛token,无法上传文件');
304
+ log('但没有七牛token,无法上传文件');
305
+ sendEvMessage(conn, 'error', '【录制完成】,但没有七牛token,无法上传文件');
293
306
  return;
294
307
  }
295
308
 
@@ -307,8 +320,6 @@ function processEvFile(conn, filePath) {
307
320
  var formUploader = new qiniu.form_up.FormUploader();
308
321
  var putExtra = new qiniu.form_up.PutExtra();
309
322
 
310
- log('开始上传文件到七牛服务器:', filePath);
311
-
312
323
  // 上传文件
313
324
  formUploader.putFile(evConfig.qiniuToken, qiniuFileName, filePath, putExtra, function(respErr, respBody, respInfo) {
314
325
  if (respErr) {
@@ -343,6 +354,9 @@ function processEvFile(conn, filePath) {
343
354
 
344
355
  // 发送ev消息给前端
345
356
  function sendEvMessage(conn, status, message, data) {
357
+ if (!conn) {
358
+ return;
359
+ }
346
360
  var response = {
347
361
  mode: 'evRecord',
348
362
  status: status,
@@ -359,6 +373,50 @@ function sendEvMessage(conn, status, message, data) {
359
373
  }
360
374
  }
361
375
 
376
+ // 检查文件是否被占用(通过重命名检测)
377
+ function checkFileLock(filePath, callback) {
378
+ // 生成临时文件名(在原文件名后添加递增数字)
379
+ const dir = path.dirname(filePath);
380
+ const ext = path.extname(filePath);
381
+ const baseName = path.basename(filePath, ext);
382
+
383
+ // 生成带递增数字的临时文件名
384
+ let tempName = baseName + '_temp' + ext;
385
+ let tempPath = path.join(dir, tempName);
386
+ let counter = 1;
387
+
388
+ // 确保临时文件名不冲突
389
+ while (fs.existsSync(tempPath)) {
390
+ tempName = baseName + '_temp' + counter + ext;
391
+ tempPath = path.join(dir, tempName);
392
+ counter++;
393
+ }
394
+
395
+ //log('尝试重命名文件:', filePath, '→', tempPath);
396
+
397
+ // 尝试重命名文件
398
+ fs.rename(filePath, tempPath, function(err) {
399
+ if (err) {
400
+ // 重命名失败,说明文件被占用
401
+ //log('文件被占用,重命名失败:', err.message);
402
+ callback(true);
403
+ } else {
404
+ // 重命名成功,说明文件未被占用
405
+ //log('文件未被占用,重命名成功');
406
+
407
+ // 恢复原文件名
408
+ fs.rename(tempPath, filePath, function(restoreErr) {
409
+ if (restoreErr) {
410
+ log('恢复文件名失败:', restoreErr.message);
411
+ } else {
412
+ log('文件未被占用,重命名成功:', filePath);
413
+ }
414
+ callback(false);
415
+ });
416
+ }
417
+ });
418
+ }
419
+
362
420
  // 自动检测ev录屏工具路径
363
421
  function autoDetectEvPath() {
364
422
  var possiblePaths = [
@@ -0,0 +1,141 @@
1
+ var fs = require('fs');
2
+ var path = require('path');
3
+ var utils = require('../lib/utils.js');
4
+ var config = require('../lib/config.js');
5
+
6
+
7
+ function processJavaFile(filePath, enumInfos) {
8
+ try {
9
+ const content = fs.readFileSync(filePath, 'utf8');
10
+
11
+ const hasEnumDbMapping = content.includes('@EnumDbMapping');
12
+ const isEnum = content.includes('public enum');
13
+
14
+ if (!hasEnumDbMapping || !isEnum) {
15
+ return;
16
+ }
17
+
18
+ const packageMatch = content.match(/package\s+([\w\.]+);/);
19
+ const packageName = packageMatch ? packageMatch[1] : '';
20
+
21
+ const classNameMatch = content.match(/public\s+(?:enum|class)\s+(\w+)\s+(?:implements|extends)/);
22
+ let className = '';
23
+ if (!classNameMatch) {
24
+ const enumNameMatch = content.match(/public\s+enum\s+(\w+)/);
25
+ if (!enumNameMatch) {
26
+ return;
27
+ }
28
+ className = enumNameMatch[1];
29
+ } else {
30
+ className = classNameMatch[1];
31
+ }
32
+
33
+ let dbMap = '';
34
+ if (hasEnumDbMapping) {
35
+ let annotationMatch = content.match(/@EnumDbMapping\s*\(\s*"([^"]+)"\s*\)/);
36
+ if (!annotationMatch) {
37
+ annotationMatch = content.match(/@EnumDbMapping\s*\(\s*value\s*=\s*"([^"]+)"\s*\)/);
38
+ }
39
+ if (!annotationMatch) {
40
+ annotationMatch = content.match(/@EnumDbMapping\s*\(\s*value\s*=\s*\{\s*"([^"]+)"/);
41
+ }
42
+ if (!annotationMatch) {
43
+ annotationMatch = content.match(/@EnumDbMapping\s*\(\s*\{\s*"([^"]+)"/);
44
+ }
45
+ if (annotationMatch) {
46
+ dbMap = annotationMatch[1];
47
+ }
48
+ }
49
+
50
+ const values = [];
51
+
52
+ // 提取枚举体内容(在enum声明和第一个private字段之间)
53
+ // 支持有implements和没有implements两种情况
54
+ let enumBodyMatch = content.match(/public\s+enum\s+\w+\s+implements[^{]*\{([\s\S]*?)\n\s+private/);
55
+ if (!enumBodyMatch) {
56
+ enumBodyMatch = content.match(/public\s+enum\s+\w+\s*\{([\s\S]*?)\n\s+private/);
57
+ }
58
+ if (enumBodyMatch) {
59
+ const enumBody = enumBodyMatch[1];
60
+ // 使用更宽松的正则匹配枚举值:枚举名(参数1, 参数2, ...)
61
+ const valuePattern = /([A-Za-z_]\w*)\(([^)]+)\)/g;
62
+ let match;
63
+ while ((match = valuePattern.exec(enumBody)) !== null) {
64
+ const valueStr = match[2];
65
+ // 分割参数
66
+ const parts = valueStr.split(',');
67
+ if (parts.length >= 2) {
68
+ let part1 = parts[0].trim();
69
+ let part2 = parts[1].trim();
70
+ // 去除引号
71
+ part1 = part1.replace(/^"|"$/g, '');
72
+ part2 = part2.replace(/^"|"$/g, '');
73
+
74
+ // 判断哪个是code,哪个是name
75
+ // 如果第一个是数字,第二个是中文 -> (数字, "中文名")
76
+ // 如果第一个是中文,第二个是数字 -> ("中文名", 数字)
77
+ let code, name;
78
+ if (/^\d+$/.test(part1)) {
79
+ code = part1;
80
+ name = part2;
81
+ } else if (/^\d+$/.test(part2)) {
82
+ code = part2;
83
+ name = part1;
84
+ } else {
85
+ // 无法判断,使用第一个作为name,第二个作为code
86
+ name = part1;
87
+ code = part2;
88
+ }
89
+
90
+ if (code && name) {
91
+ values.push(code + '=' + name);
92
+ }
93
+ }
94
+ }
95
+ }
96
+
97
+ const valueStr = values.join(',');
98
+
99
+ const enumInfo = {
100
+ name: packageName + "." + className,
101
+ dbMap: dbMap,
102
+ value: valueStr
103
+ };
104
+
105
+ enumInfos.push(enumInfo);
106
+ } catch (error) {
107
+ console.error(`Error processing file ${filePath}:`, error.message);
108
+ }
109
+ }
110
+
111
+ function generateEnumsJson(enumInfos) {
112
+ try {
113
+ var jsonContent = JSON.stringify(enumInfos, null, 2);
114
+ fs.writeFileSync(path.join(__dirname, '../enums.json'), jsonContent, 'utf8');
115
+ console.log('Successfully generated enums.json with ' + enumInfos.length + ' entries');
116
+ } catch (error) {
117
+ console.error('Error generating enums.json:', error.message);
118
+ }
119
+ }
120
+
121
+ module.exports.start = function() {
122
+ var enumInfos = [];
123
+
124
+ console.log('Scanning Java files...');
125
+ var webPath = config.webPath;
126
+ if (!webPath) {
127
+ console.error('config.webPath is not defined');
128
+ return;
129
+ }
130
+
131
+ var javaFiles = utils.getFiles({ source: webPath, exts: '.java', ignores: config.ignoreCheck });
132
+ console.log('Found ' + javaFiles.length + ' Java files');
133
+
134
+ console.log('Processing files...');
135
+ for (var i = 0; i < javaFiles.length; i++) {
136
+ processJavaFile(javaFiles[i], enumInfos);
137
+ }
138
+
139
+ console.log('Generating enums.json...');
140
+ generateEnumsJson(enumInfos);
141
+ };
@@ -136,7 +136,7 @@ function _copyFiles() {
136
136
 
137
137
  // 更新完成后推送平台并提交日志
138
138
  function pushGitLog() {
139
- var msg = "ngp皮肤和图标库更新完成";
139
+ var msg = "ngp皮肤和图标库更新完成【无需测试】";
140
140
  console.log(msg);
141
141
  utils.gitpush(msg);
142
142
  }
@@ -53,7 +53,6 @@ function createSocket() {
53
53
  }
54
54
  } catch (ex) { }
55
55
  });
56
-
57
56
  conn.on('connect', function(code, reason) {
58
57
  utils.log('connect连接成功');
59
58
  broadcast('ws connect success');
@@ -61,9 +60,7 @@ function createSocket() {
61
60
  conn.on("close", function(code, reason) {
62
61
  utils.debug("connect关闭");
63
62
  });
64
- conn.on("error", function(code, reason) {
65
-
66
- });
63
+ conn.on("error", function(code, reason) {});
67
64
  }).listen(config.socketPort);
68
65
 
69
66
  socketServer.on('connection', function(code, reason) {