@whyour/qinglong 2.21.0-1 → 2.21.0-2

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.
Files changed (43) hide show
  1. package/package.json +1 -1
  2. package/static/build/api/cron.js +2 -2
  3. package/static/build/api/dashboard.js +13 -6
  4. package/static/build/config/index.js +0 -4
  5. package/static/build/config/util.js +3 -3
  6. package/static/build/data/sock.js +1 -0
  7. package/static/build/loaders/initTask.js +3 -2
  8. package/static/build/services/cron.js +8 -5
  9. package/static/build/services/dependence.js +19 -18
  10. package/static/build/services/notify.js +5 -5
  11. package/static/build/services/system.js +12 -2
  12. package/static/build/services/user.js +28 -6
  13. package/static/build/shared/i18n.js +41 -1
  14. package/static/build/shared/pLimit.js +3 -2
  15. package/static/dist/8826.6879b271.async.js +1 -0
  16. package/static/dist/index.html +2 -2
  17. package/static/dist/{preload_helper.0431c0f3.js → preload_helper.c1c91aaa.js} +1 -1
  18. package/static/dist/{src__pages__crontab__detail.b9c36808.async.js → src__pages__crontab__detail.cf4a6aaf.async.js} +1 -1
  19. package/static/dist/src__pages__crontab__index.5b67b1a2.async.js +1 -0
  20. package/static/dist/{src__pages__crontab__logModal.0b8cce8c.async.js → src__pages__crontab__logModal.831d5e4b.async.js} +1 -1
  21. package/static/dist/src__pages__dashboard__index.58177357.async.js +1 -0
  22. package/static/dist/src__pages__dependence__index.b7bbc795.async.js +1 -0
  23. package/static/dist/src__pages__env__index.9a565d2b.async.js +1 -0
  24. package/static/dist/src__pages__log__index.9c66639f.async.js +1 -0
  25. package/static/dist/src__pages__script__index.e869812f.async.js +1 -0
  26. package/static/dist/src__pages__setting__checkUpdate.34d773f2.async.js +1 -0
  27. package/static/dist/src__pages__setting__dependence.29f13e8c.async.js +1 -0
  28. package/static/dist/src__pages__setting__index.7a39d415.async.js +1 -0
  29. package/static/dist/src__pages__setting__other.707cfafe.async.js +1 -0
  30. package/static/dist/src__pages__setting__systemLog.1a5c855f.async.js +1 -0
  31. package/static/dist/{umi.ca04a019.js → umi.97fb5a40.js} +1 -1
  32. package/static/dist/8826.2447a104.async.js +0 -1
  33. package/static/dist/src__pages__crontab__index.fed99fd0.async.js +0 -1
  34. package/static/dist/src__pages__dashboard__index.b30f2f47.async.js +0 -1
  35. package/static/dist/src__pages__dependence__index.3d87ceac.async.js +0 -1
  36. package/static/dist/src__pages__env__index.baa27d4e.async.js +0 -1
  37. package/static/dist/src__pages__log__index.e0978bae.async.js +0 -1
  38. package/static/dist/src__pages__script__index.2765d1b8.async.js +0 -1
  39. package/static/dist/src__pages__setting__checkUpdate.46efe057.async.js +0 -1
  40. package/static/dist/src__pages__setting__dependence.8a7a9529.async.js +0 -1
  41. package/static/dist/src__pages__setting__index.cc85fdfb.async.js +0 -1
  42. package/static/dist/src__pages__setting__other.b22d2165.async.js +0 -1
  43. package/static/dist/src__pages__setting__systemLog.67406721.async.js +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@whyour/qinglong",
3
3
  "packageManager": "pnpm@8.3.1",
4
- "version": "2.21.0-1",
4
+ "version": "2.21.0-2",
5
5
  "description": "Timed task management platform supporting Python3, JavaScript, Shell, Typescript",
6
6
  "repository": {
7
7
  "type": "git",
@@ -247,8 +247,8 @@ exports.default = (app) => {
247
247
  const logger = typedi_1.Container.get('logger');
248
248
  try {
249
249
  const cronService = typedi_1.Container.get(cron_1.default);
250
- const data = await cronService.log(req.params.id);
251
- return res.send({ code: 200, data });
250
+ const result = await cronService.log(req.params.id);
251
+ return res.send({ code: 200, data: result.content, logStatus: result.status });
252
252
  }
253
253
  catch (e) {
254
254
  return next(e);
@@ -10,6 +10,8 @@ const cronStats_1 = require("../data/cronStats");
10
10
  const runningInstance_1 = require("../data/runningInstance");
11
11
  const dayjs_1 = __importDefault(require("dayjs"));
12
12
  const os_1 = __importDefault(require("os"));
13
+ const lodash_1 = require("lodash");
14
+ const i18n_1 = require("../shared/i18n");
13
15
  const route = (0, express_1.Router)();
14
16
  exports.default = (app) => {
15
17
  app.use('/dashboard', route);
@@ -153,7 +155,7 @@ exports.default = (app) => {
153
155
  crons.forEach((c) => { nameMap[c.id] = c.name || c.command; });
154
156
  const data = rows.map((r, i) => ({
155
157
  rank: i + 1,
156
- name: nameMap[Number(r.ref_id)] || `任务#${r.ref_id}`,
158
+ name: nameMap[Number(r.ref_id)] || (0, i18n_1.tf)('任务#%s', r.ref_id),
157
159
  avgTime: Math.round(Number(r.total_time) / Number(r.run_count)),
158
160
  maxTime: Number(r.max_time),
159
161
  }));
@@ -188,7 +190,7 @@ exports.default = (app) => {
188
190
  crons.forEach((c) => { nameMap[c.id] = c.name || c.command; });
189
191
  const data = rows.map((r, i) => ({
190
192
  rank: i + 1,
191
- name: nameMap[Number(r.ref_id)] || `任务#${r.ref_id}`,
193
+ name: nameMap[Number(r.ref_id)] || (0, i18n_1.tf)('任务#%s', r.ref_id),
192
194
  runCount: Number(r.run_count),
193
195
  avgTime: Math.round(Number(r.total_time) / Number(r.run_count)),
194
196
  successRate: Number(r.run_count) > 0
@@ -232,7 +234,7 @@ exports.default = (app) => {
232
234
  return {
233
235
  instanceId: inst.id,
234
236
  id: inst.cron_id,
235
- name: (cron === null || cron === void 0 ? void 0 : cron.name) || (cron === null || cron === void 0 ? void 0 : cron.command) || `任务#${inst.cron_id}`,
237
+ name: (cron === null || cron === void 0 ? void 0 : cron.name) || (cron === null || cron === void 0 ? void 0 : cron.command) || (0, i18n_1.tf)('任务#%s', inst.cron_id),
236
238
  pid: inst.pid,
237
239
  elapsed: inst.started_at ? now - inst.started_at : 0,
238
240
  logPath: inst.log_path,
@@ -257,7 +259,7 @@ exports.default = (app) => {
257
259
  running,
258
260
  idleTasks: idleTasks.map((c) => ({
259
261
  id: c.id,
260
- name: c.name || c.command || `任务#${c.id}`,
262
+ name: c.name || c.command || (0, i18n_1.tf)('任务#%s', c.id),
261
263
  lastRun: c.last_execution_time
262
264
  ? dayjs_1.default.unix(c.last_execution_time).format('MM-DD HH:mm')
263
265
  : '-',
@@ -283,7 +285,12 @@ exports.default = (app) => {
283
285
  let rawLabels = c.labels;
284
286
  if (typeof rawLabels === 'string')
285
287
  rawLabels = JSON.parse(rawLabels);
286
- const labels = Array.isArray(rawLabels) && rawLabels.length > 0 ? rawLabels : ['未分类'];
288
+ const labels = Array.isArray(rawLabels)
289
+ ? [...new Set(rawLabels.filter((l) => !(0, lodash_1.isEmpty)(l)))]
290
+ : [];
291
+ if (labels.length === 0) {
292
+ labels.push((0, i18n_1.t)('未分类'));
293
+ }
287
294
  const st = statMap[c.id];
288
295
  labels.forEach((label) => {
289
296
  if (!labelMap[label])
@@ -318,7 +325,7 @@ exports.default = (app) => {
318
325
  code: 200,
319
326
  data: {
320
327
  platform: os_1.default.platform(),
321
- uptime: Math.floor(os_1.default.uptime()),
328
+ uptime: Math.floor(process.uptime()),
322
329
  memTotal: os_1.default.totalmem(),
323
330
  memFree: os_1.default.freemem(),
324
331
  memUsagePercent: ((1 - os_1.default.freemem() / os_1.default.totalmem()) * 100).toFixed(1),
@@ -87,8 +87,6 @@ const extraFile = path_1.default.join(configPath, 'extra.sh');
87
87
  const confBakDir = path_1.default.join(dataPath, 'config/bak/');
88
88
  const sampleFile = path_1.default.join(samplePath, 'config.sample.sh');
89
89
  const sqliteFile = path_1.default.join(samplePath, 'database.sqlite');
90
- const authError = '错误的用户名密码,请重试';
91
- const loginFaild = '请先登录!';
92
90
  const configString = 'config sample crontab shareCode diy';
93
91
  const versionFile = path_1.default.join(rootPath, 'version.yaml');
94
92
  const dataTgzFile = path_1.default.join(tmpPath, 'data.tgz');
@@ -105,8 +103,6 @@ exports.default = Object.assign(Object.assign({}, config), { jwt: config.jwt, ba
105
103
  shareShellFile,
106
104
  dependenceProxyFile,
107
105
  configString,
108
- loginFaild,
109
- authError,
110
106
  logPath,
111
107
  extraFile,
112
108
  authConfigFile,
@@ -498,7 +498,7 @@ function safeJSONParse(value) {
498
498
  return JSON.parse(value);
499
499
  }
500
500
  catch (error) {
501
- logger_1.default.error('[safeJSONParse失败]', error);
501
+ logger_1.default.error('[safeJSONParse error]', error);
502
502
  return {};
503
503
  }
504
504
  }
@@ -511,7 +511,7 @@ async function rmPath(path) {
511
511
  }
512
512
  }
513
513
  catch (error) {
514
- logger_1.default.error('[rmPath失败]', error);
514
+ logger_1.default.error('[rmPath error]', error);
515
515
  }
516
516
  }
517
517
  exports.rmPath = rmPath;
@@ -525,7 +525,7 @@ async function setSystemTimezone(timezone) {
525
525
  return true;
526
526
  }
527
527
  catch (error) {
528
- logger_1.default.error('[setSystemTimezone失败]', error);
528
+ logger_1.default.error('[setSystemTimezone error]', error);
529
529
  return false;
530
530
  }
531
531
  }
@@ -6,6 +6,7 @@ class SockMessage {
6
6
  this.type = options.type;
7
7
  this.message = options.message;
8
8
  this.references = options.references;
9
+ this.status = options.status;
9
10
  }
10
11
  }
11
12
  exports.SockMessage = SockMessage;
@@ -11,6 +11,7 @@ const sshKey_1 = __importDefault(require("../services/sshKey"));
11
11
  const config_1 = __importDefault(require("../config"));
12
12
  const util_1 = require("../config/util");
13
13
  const path_1 = require("path");
14
+ const i18n_1 = require("../shared/i18n");
14
15
  exports.default = async () => {
15
16
  const systemService = typedi_1.Container.get(system_1.default);
16
17
  const scheduleService = typedi_1.Container.get(schedule_1.default);
@@ -24,7 +25,7 @@ exports.default = async () => {
24
25
  }
25
26
  const cron = {
26
27
  id: NaN,
27
- name: '生成token',
28
+ name: (0, i18n_1.t)('生成token'),
28
29
  command: tokenCommand,
29
30
  runOrigin: 'system',
30
31
  };
@@ -38,7 +39,7 @@ exports.default = async () => {
38
39
  if (data.info.logRemoveFrequency) {
39
40
  const rmlogCron = {
40
41
  id: data.id,
41
- name: '删除日志',
42
+ name: (0, i18n_1.t)('删除日志'),
42
43
  command: `ql rmlog ${data.info.logRemoveFrequency}`,
43
44
  runOrigin: 'system',
44
45
  };
@@ -588,21 +588,24 @@ let CronService = class CronService {
588
588
  async log(id) {
589
589
  const doc = await this.getDb({ id });
590
590
  if (!doc) {
591
- return '';
591
+ return { content: '', status: 'empty' };
592
592
  }
593
593
  if (doc.log_name === '/dev/null') {
594
- return '日志设置为忽略';
594
+ return { content: (0, i18n_1.t)('日志设置为忽略'), status: 'ignored' };
595
595
  }
596
596
  const absolutePath = path_1.default.resolve(config_1.default.logPath, `${doc.log_path}`);
597
597
  const logFileExist = doc.log_path && (await (0, util_1.fileExist)(absolutePath));
598
598
  if (logFileExist) {
599
- return await (0, util_1.getFileContentByName)(`${absolutePath}`);
599
+ const content = await (0, util_1.getFileContentByName)(`${absolutePath}`);
600
+ const isRunning = typeof doc.status === 'number' &&
601
+ [cron_1.CrontabStatus.running, cron_1.CrontabStatus.queued].includes(doc.status);
602
+ return { content, status: isRunning ? 'running' : 'completed' };
600
603
  }
601
604
  else {
602
605
  return typeof doc.status === 'number' &&
603
606
  [cron_1.CrontabStatus.queued, cron_1.CrontabStatus.running].includes(doc.status)
604
- ? '运行中...'
605
- : '日志不存在...';
607
+ ? { content: (0, i18n_1.t)('运行中...'), status: 'running' }
608
+ : { content: (0, i18n_1.t)('日志不存在...'), status: 'notFound' };
606
609
  }
607
610
  }
608
611
  async logs(id) {
@@ -38,6 +38,7 @@ const dayjs_1 = __importDefault(require("dayjs"));
38
38
  const pLimit_1 = __importDefault(require("../shared/pLimit"));
39
39
  const util_2 = require("../config/util");
40
40
  const const_1 = require("../config/const");
41
+ const i18n_1 = require("../shared/i18n");
41
42
  let DependenceService = class DependenceService {
42
43
  constructor(logger, sockService) {
43
44
  this.logger = logger;
@@ -183,7 +184,7 @@ let DependenceService = class DependenceService {
183
184
  }
184
185
  const depIds = [dependency.id];
185
186
  let depName = dependency.name.trim();
186
- const actionText = isInstall ? '安装' : '删除';
187
+ const actionText = isInstall ? (0, i18n_1.t)('安装') : (0, i18n_1.t)('删除');
187
188
  const socketMessageType = isInstall
188
189
  ? 'installDependence'
189
190
  : 'uninstallDependence';
@@ -197,11 +198,12 @@ let DependenceService = class DependenceService {
197
198
  if (!osType) {
198
199
  await dependence_1.DependenceModel.update({ status: dependence_1.DependenceStatus.installFailed }, { where: { id: depIds } });
199
200
  const startTime = (0, dayjs_1.default)();
200
- const message = `开始${actionText}依赖 ${depName},开始时间 ${startTime.format('YYYY-MM-DD HH:mm:ss')}\n\n当前系统不支持\n\n依赖${actionText}失败,结束时间 ${startTime.format('YYYY-MM-DD HH:mm:ss')},耗时 ${startTime.diff(startTime, 'second')} 秒`;
201
+ const message = (0, i18n_1.tf)('开始%s依赖 %s,开始时间 %s\n\n当前系统不支持\n\n依赖%s失败,结束时间 %s,耗时 %s 秒', actionText, depName, startTime.format('YYYY-MM-DD HH:mm:ss'), actionText, startTime.format('YYYY-MM-DD HH:mm:ss'), String(startTime.diff(startTime, 'second')));
201
202
  this.sockService.sendMessage({
202
203
  type: socketMessageType,
203
204
  message,
204
205
  references: depIds,
206
+ status: dependence_1.DependenceStatus.installFailed,
205
207
  });
206
208
  this.updateLog(depIds, message);
207
209
  return resolve(null);
@@ -221,11 +223,12 @@ let DependenceService = class DependenceService {
221
223
  : `${linuxCommand.uninstall} ${depName.trim()}`;
222
224
  }
223
225
  const startTime = (0, dayjs_1.default)();
224
- const message = `开始${actionText}依赖 ${depName},开始时间 ${startTime.format('YYYY-MM-DD HH:mm:ss')}\n\n`;
226
+ const message = (0, i18n_1.tf)('开始%s依赖 %s,开始时间 %s\n\n', actionText, depName, startTime.format('YYYY-MM-DD HH:mm:ss'));
225
227
  this.sockService.sendMessage({
226
228
  type: socketMessageType,
227
229
  message,
228
230
  references: depIds,
231
+ status,
229
232
  });
230
233
  this.updateLog(depIds, message);
231
234
  // 判断是否已经安装过依赖
@@ -254,11 +257,12 @@ let DependenceService = class DependenceService {
254
257
  isPythonDependence) &&
255
258
  (!depVersion || depInfo.includes(depVersion))) {
256
259
  const endTime = (0, dayjs_1.default)();
257
- const _message = `检测到已经安装 ${depName}\n\n${depInfo}\n\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format('YYYY-MM-DD HH:mm:ss')},耗时 ${endTime.diff(startTime, 'second')} 秒`;
260
+ const _message = (0, i18n_1.tf)('检测到已经安装 %s\n\n%s\n\n跳过安装\n\n依赖%s成功,结束时间 %s,耗时 %s 秒', depName, depInfo, actionText, endTime.format('YYYY-MM-DD HH:mm:ss'), String(endTime.diff(startTime, 'second')));
258
261
  this.sockService.sendMessage({
259
262
  type: socketMessageType,
260
263
  message: _message,
261
264
  references: depIds,
265
+ status: dependence_1.DependenceStatus.installed,
262
266
  });
263
267
  this.updateLog(depIds, _message);
264
268
  await dependence_1.DependenceModel.update({ status: dependence_1.DependenceStatus.installed }, { where: { id: depIds } });
@@ -277,6 +281,7 @@ let DependenceService = class DependenceService {
277
281
  type: socketMessageType,
278
282
  message: data.toString(),
279
283
  references: depIds,
284
+ status,
280
285
  });
281
286
  this.updateLog(depIds, data.toString());
282
287
  });
@@ -285,6 +290,7 @@ let DependenceService = class DependenceService {
285
290
  type: socketMessageType,
286
291
  message: data.toString(),
287
292
  references: depIds,
293
+ status,
288
294
  });
289
295
  this.updateLog(depIds, data.toString());
290
296
  });
@@ -293,37 +299,32 @@ let DependenceService = class DependenceService {
293
299
  type: socketMessageType,
294
300
  message: JSON.stringify(err),
295
301
  references: depIds,
302
+ status,
296
303
  });
297
304
  this.updateLog(depIds, JSON.stringify(err));
298
305
  });
299
306
  cp.on('exit', async (code) => {
300
307
  const endTime = (0, dayjs_1.default)();
301
308
  const isSucceed = code === 0;
302
- const resultText = isSucceed ? '成功' : '失败';
303
- const message = `\n依赖${actionText}${resultText},结束时间 ${endTime.format('YYYY-MM-DD HH:mm:ss')},耗时 ${endTime.diff(startTime, 'second')} 秒`;
309
+ const resultText = isSucceed ? (0, i18n_1.t)('成功') : (0, i18n_1.t)('失败');
310
+ const message = '\n' +
311
+ (0, i18n_1.tf)('依赖%s%s,结束时间 %s,耗时 %s 秒', actionText, resultText, endTime.format('YYYY-MM-DD HH:mm:ss'), String(endTime.diff(startTime, 'second')));
312
+ const exitStatus = isSucceed
313
+ ? (isInstall ? dependence_1.DependenceStatus.installed : dependence_1.DependenceStatus.removed)
314
+ : (isInstall ? dependence_1.DependenceStatus.installFailed : dependence_1.DependenceStatus.removeFailed);
304
315
  this.sockService.sendMessage({
305
316
  type: socketMessageType,
306
317
  message,
307
318
  references: depIds,
319
+ status: exitStatus,
308
320
  });
309
321
  this.updateLog(depIds, message);
310
- let status;
311
- if (isSucceed) {
312
- status = isInstall
313
- ? dependence_1.DependenceStatus.installed
314
- : dependence_1.DependenceStatus.removed;
315
- }
316
- else {
317
- status = isInstall
318
- ? dependence_1.DependenceStatus.installFailed
319
- : dependence_1.DependenceStatus.removeFailed;
320
- }
321
322
  const docs = await dependence_1.DependenceModel.findAll({ where: { id: depIds } });
322
323
  const _docIds = docs
323
324
  .filter((x) => x.status !== dependence_1.DependenceStatus.cancelled)
324
325
  .map((x) => x.id);
325
326
  if (_docIds.length > 0) {
326
- await dependence_1.DependenceModel.update({ status }, { where: { id: _docIds } });
327
+ await dependence_1.DependenceModel.update({ status: exitStatus }, { where: { id: _docIds } });
327
328
  }
328
329
  // 如果删除依赖成功或者强制删除
329
330
  if ((isSucceed || force) && !isInstall) {
@@ -306,7 +306,7 @@ let NotificationService = class NotificationService {
306
306
  {
307
307
  title: `${this.title}`,
308
308
  thumb_media_id,
309
- author: `智能助手`,
309
+ author: (0, i18n_1.t)('智能助手'),
310
310
  content_source_url: ``,
311
311
  content: `${this.content.replace(/\n/g, '<br/>')}`,
312
312
  digest: `${this.content}`,
@@ -322,7 +322,7 @@ let NotificationService = class NotificationService {
322
322
  title: `${this.title}`,
323
323
  description: `${this.content}`,
324
324
  url: 'https://github.com/whyour/qinglong',
325
- btntxt: '更多',
325
+ btntxt: (0, i18n_1.t)('更多'),
326
326
  },
327
327
  };
328
328
  break;
@@ -361,7 +361,7 @@ let NotificationService = class NotificationService {
361
361
  roomName: `${aibotkName}`,
362
362
  message: {
363
363
  type: 1,
364
- content: `【青龙快讯】\n\n${this.title}\n${this.content}`,
364
+ content: `【${(0, i18n_1.t)('青龙快讯')}】\n\n${this.title}\n${this.content}`,
365
365
  },
366
366
  };
367
367
  break;
@@ -372,7 +372,7 @@ let NotificationService = class NotificationService {
372
372
  name: `${aibotkName}`,
373
373
  message: {
374
374
  type: 1,
375
- content: `【青龙快讯】\n\n${this.title}\n${this.content}`,
375
+ content: `【${(0, i18n_1.t)('青龙快讯')}】\n\n${this.title}\n${this.content}`,
376
376
  },
377
377
  };
378
378
  break;
@@ -507,7 +507,7 @@ let NotificationService = class NotificationService {
507
507
  },
508
508
  });
509
509
  const info = await transporter.sendMail({
510
- from: `"青龙快讯" <${emailUser}>`,
510
+ from: `"${(0, i18n_1.t)('青龙快讯')}" <${emailUser}>`,
511
511
  to: recipients,
512
512
  subject: `${this.title}`,
513
513
  html: `${this.content.replace(/\n/g, '<br/>')}`,
@@ -72,7 +72,7 @@ let SystemService = class SystemService {
72
72
  }
73
73
  async updateNotificationMode(notificationInfo) {
74
74
  const code = Math.random().toString().slice(-6);
75
- const isSuccess = await this.notificationService.testNotify(notificationInfo, '青龙', `【蛟龙】测试通知 https://t.me/jiao_long`);
75
+ const isSuccess = await this.notificationService.testNotify(notificationInfo, (0, i18n_1.t)('青龙'), (0, i18n_1.t)('【蛟龙】测试通知 https://t.me/jiao_long'));
76
76
  if (isSuccess) {
77
77
  const result = await this.updateAuthDb({
78
78
  type: system_1.AuthDataType.notification,
@@ -90,7 +90,7 @@ let SystemService = class SystemService {
90
90
  const result = await this.updateAuthDb(Object.assign(Object.assign({}, oDoc), { info: Object.assign(Object.assign({}, oDoc.info), info) }));
91
91
  const cron = {
92
92
  id: result.id,
93
- name: '删除日志',
93
+ name: (0, i18n_1.t)('删除日志'),
94
94
  command: `ql rmlog ${info.logRemoveFrequency}`,
95
95
  runOrigin: 'system',
96
96
  };
@@ -149,6 +149,7 @@ let SystemService = class SystemService {
149
149
  this.sockService.sendMessage({
150
150
  type: 'updateNodeMirror',
151
151
  message: 'update node mirror end',
152
+ status: 'completed',
152
153
  });
153
154
  },
154
155
  onError: async (message) => {
@@ -189,6 +190,7 @@ let SystemService = class SystemService {
189
190
  this.sockService.sendMessage({
190
191
  type: 'updateLinuxMirror',
191
192
  message: 'update linux mirror end',
193
+ status: 'completed',
192
194
  });
193
195
  onEnd === null || onEnd === void 0 ? void 0 : onEnd();
194
196
  if (!hasError) {
@@ -277,6 +279,14 @@ let SystemService = class SystemService {
277
279
  this.sockService.sendMessage({
278
280
  type: 'updateSystemVersion',
279
281
  message: JSON.stringify(err),
282
+ status: 'failed',
283
+ });
284
+ });
285
+ cp.on('exit', (code) => {
286
+ this.sockService.sendMessage({
287
+ type: 'updateSystemVersion',
288
+ message: '',
289
+ status: code === 0 ? 'success' : 'failed',
280
290
  });
281
291
  });
282
292
  return { code: 200 };
@@ -49,7 +49,7 @@ let UserService = class UserService {
49
49
  const waitTime = Math.ceil((retriesTime - (timestamp - lastlogon)) / 1000);
50
50
  return {
51
51
  code: 410,
52
- message: `失败次数过多,请${waitTime}秒后重试`,
52
+ message: (0, i18n_1.tf)('失败次数过多,请%s秒后重试', waitTime),
53
53
  data: waitTime,
54
54
  };
55
55
  }
@@ -98,7 +98,18 @@ let UserService = class UserService {
98
98
  platform: req.platform,
99
99
  isTwoFactorChecking: false,
100
100
  });
101
- this.notificationService.notify('登录通知', `你于${(0, dayjs_1.default)(timestamp).format('YYYY-MM-DD HH:mm:ss')}在 ${address} ${req.platform}端 登录成功,ip地址 ${ip}`);
101
+ this.notificationService.notify((0, i18n_1.t)('登录通知'), (0, i18n_1.t)('你于') +
102
+ (0, dayjs_1.default)(timestamp).format('YYYY-MM-DD HH:mm:ss') +
103
+ (0, i18n_1.t)('在') +
104
+ address +
105
+ ' ' +
106
+ req.platform +
107
+ (0, i18n_1.t)('端') +
108
+ ' ' +
109
+ (0, i18n_1.t)('登录成功') +
110
+ (0, i18n_1.t)(',ip地址') +
111
+ ' ' +
112
+ ip);
102
113
  await this.insertDb({
103
114
  type: system_1.AuthDataType.loginLog,
104
115
  info: {
@@ -130,7 +141,18 @@ let UserService = class UserService {
130
141
  lastaddr: address,
131
142
  platform: req.platform,
132
143
  });
133
- this.notificationService.notify('登录通知', `你于${(0, dayjs_1.default)(timestamp).format('YYYY-MM-DD HH:mm:ss')}在 ${address} ${req.platform}端 登录失败,ip地址 ${ip}`);
144
+ this.notificationService.notify((0, i18n_1.t)('登录通知'), (0, i18n_1.t)('你于') +
145
+ (0, dayjs_1.default)(timestamp).format('YYYY-MM-DD HH:mm:ss') +
146
+ (0, i18n_1.t)('在') +
147
+ address +
148
+ ' ' +
149
+ req.platform +
150
+ (0, i18n_1.t)('端') +
151
+ ' ' +
152
+ (0, i18n_1.t)('登录失败') +
153
+ (0, i18n_1.t)(',ip地址') +
154
+ ' ' +
155
+ ip);
134
156
  await this.insertDb({
135
157
  type: system_1.AuthDataType.loginLog,
136
158
  info: {
@@ -146,12 +168,12 @@ let UserService = class UserService {
146
168
  const waitTime = Math.round(Math.pow(3, retries + 1));
147
169
  return {
148
170
  code: 410,
149
- message: `失败次数过多,请${waitTime}秒后重试`,
171
+ message: (0, i18n_1.tf)('失败次数过多,请%s秒后重试', waitTime),
150
172
  data: waitTime,
151
173
  };
152
174
  }
153
175
  else {
154
- return { code: 400, message: config_1.default.authError };
176
+ return { code: 400, message: (0, i18n_1.t)('错误的用户名密码,请重试') };
155
177
  }
156
178
  }
157
179
  }
@@ -308,7 +330,7 @@ let UserService = class UserService {
308
330
  }
309
331
  async updateNotificationMode(notificationInfo) {
310
332
  const code = Math.random().toString().slice(-6);
311
- const isSuccess = await this.notificationService.testNotify(notificationInfo, '青龙', `【蛟龙】测试通知 https://t.me/jiao_long`);
333
+ const isSuccess = await this.notificationService.testNotify(notificationInfo, (0, i18n_1.t)('青龙'), (0, i18n_1.t)('【蛟龙】测试通知 https://t.me/jiao_long'));
312
334
  if (isSuccess) {
313
335
  const result = await this.updateAuthDb({
314
336
  type: system_1.AuthDataType.notification,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.t = exports.getLang = exports.setLang = void 0;
3
+ exports.tf = exports.t = exports.getLang = exports.setLang = void 0;
4
4
  const messages = {
5
5
  zh: {},
6
6
  en: {
@@ -83,6 +83,42 @@ const messages = {
83
83
  '订阅执行完成': 'Subscription completed',
84
84
  'wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行': 'wxPusher requires at least one of TopicIds or Uids',
85
85
  'Url 或者 Body 中必须包含 $title': 'Url or Body must contain $title',
86
+ '绝对路径必须在日志目录内或使用 /dev/null': 'Absolute path must be within log directory or use /dev/null',
87
+ '请先登录!': 'Please login first!',
88
+ '运行中...': 'Running...',
89
+ '日志不存在...': 'Log does not exist...',
90
+ '未分类': 'Uncategorized',
91
+ '任务重复运行': 'Duplicate task execution',
92
+ '日志设置为忽略': 'Log set to ignore',
93
+ '定时规则不能为空': 'Schedule rule cannot be empty',
94
+ '无效的定时规则': 'Invalid schedule rule',
95
+ '日志名称只能包含字母、数字、下划线和连字符': 'Log name can only contain letters, numbers, underscores, and hyphens',
96
+ '日志名称不能超过100个字符': 'Log name cannot exceed 100 characters',
97
+ '错误的用户名密码,请重试': 'Incorrect username or password, please try again',
98
+ '青龙快讯': 'QingLong',
99
+ '登录通知': 'Login Notification',
100
+ '你于': 'You at ',
101
+ '在': ' in ',
102
+ 端: '',
103
+ 登录失败: 'login failed',
104
+ ',ip地址': ', IP: ',
105
+ '任务#%s': 'Task#%s',
106
+ 安装: 'Install',
107
+ 删除: 'Uninstall',
108
+ 成功: 'Succeeded',
109
+ 失败: 'Failed',
110
+ '失败次数过多,请%s秒后重试': 'Too many failed attempts, please retry in %s seconds',
111
+ 智能助手: 'Smart Assistant',
112
+ 更多: 'More',
113
+ '开始%s依赖 %s,开始时间 %s\n\n当前系统不支持\n\n依赖%s失败,结束时间 %s,耗时 %s 秒': 'Start %s dependency %s, start time %s\n\nCurrent system not supported\n\nDependency %s failed, end time %s, elapsed %s seconds',
114
+ '检测到已经安装 %s\n\n%s\n\n跳过安装\n\n依赖%s成功,结束时间 %s,耗时 %s 秒': 'Already installed %s\n\n%s\n\nSkipping install\n\nDependency %s succeeded, end time %s, elapsed %s seconds',
115
+ '开始%s依赖 %s,开始时间 %s\n\n': 'Start %s dependency %s, start time %s\n\n',
116
+ '依赖%s%s,结束时间 %s,耗时 %s 秒': 'Dependency %s%s, end time %s, elapsed %s seconds',
117
+ '任务:%s,命令:%s,定时:%s,处于运行中的超过 %d 个,请检查定时设置': 'Task: %s, command: %s, schedule: %s, more than %d instances running, please check schedule settings',
118
+ 青龙: 'QingLong',
119
+ '【蛟龙】测试通知 https://t.me/jiao_long': '[JiaoLong] Test notification https://t.me/jiao_long',
120
+ '生成token': 'Generate token',
121
+ '删除日志': 'Delete logs',
86
122
  },
87
123
  };
88
124
  let currentLang = 'zh';
@@ -102,4 +138,8 @@ function t(key, lang) {
102
138
  return key;
103
139
  }
104
140
  exports.t = t;
141
+ function tf(key, ...args) {
142
+ return args.reduce((str, arg) => str.replace(/%s|%d/, String(arg)), t(key));
143
+ }
144
+ exports.tf = tf;
105
145
  //# sourceMappingURL=i18n.js.map
@@ -8,6 +8,7 @@ const os_1 = __importDefault(require("os"));
8
8
  const system_1 = require("../data/system");
9
9
  const logger_1 = __importDefault(require("../loaders/logger"));
10
10
  const notify_1 = __importDefault(require("../services/notify"));
11
+ const i18n_1 = require("../shared/i18n");
11
12
  const config_1 = __importDefault(require("../config"));
12
13
  const grpc_js_1 = require("@grpc/grpc-js");
13
14
  const api_1 = require("../protos/api");
@@ -117,8 +118,8 @@ class TaskLimit {
117
118
  if (repeatTimes < 3) {
118
119
  this.repeatCronNotifyMap.set(cron.id, repeatTimes + 1);
119
120
  this.client.systemNotify({
120
- title: '任务重复运行',
121
- content: `任务:${cron.name},命令:${cron.command},定时:${cron.schedule},处于运行中的超过 5 个,请检查定时设置`,
121
+ title: (0, i18n_1.t)('任务重复运行'),
122
+ content: (0, i18n_1.tf)('任务:%s,命令:%s,定时:%s,处于运行中的超过 %d 个,请检查定时设置', cron.name || '', cron.command || '', cron.schedule || '', 5),
122
123
  }, (err, res) => {
123
124
  if (err) {
124
125
  logger_1.default.error(`[schedule][任务重复运行] 通知失败 ${JSON.stringify(err)}`);
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunk_whyour_qinglong=self.webpackChunk_whyour_qinglong||[]).push([[8826,7243],{8826:function(e,t,n){n.r(t);var a=n(48305),i=n.n(a),r=n(72317),o=n(75271),l=n(45520),s=n(93481),u=n(16314),c=n(3475),p=n(56958),g=n(44084),d=n(34014),h=n(78060),b=n.n(h),P=n(65814),v=n(57113),f=n(52676);t.default=function(e){var t=e.dependence,n=e.handleCancel,a=(0,o.useState)(""),h=i()(a,2),Z=h[0],m=h[1],k=(0,o.useState)(!0),y=i()(k,2),x=y[0],w=y[1],q=(0,o.useState)(!1),B=i()(q,2),S=B[0],T=B[1],C=(0,o.useState)(!0),U=i()(C,2),_=U[0],A=U[1],H=(0,o.useState)(!1),I=i()(H,2),E=I[0],K=I[1],j=(0,o.useState)(!1),L=i()(j,2),O=L[0],D=L[1],M=function(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];localStorage.removeItem("logDependence"),n(e)};(0,o.useEffect)((function(){t&&(A(!0),u.W.get("".concat(c.Z.apiPrefix,"dependencies/").concat(t.id)).then((function(e){var n=e.code,a=e.data;if(200===n&&localStorage.getItem("logDependence")===String(t.id)){var i=((null==a?void 0:a.log)||[]).join("");m(i);var r=null==a?void 0:a.status;w(r===v.Status.安装中||r===v.Status.删除中),K(r===v.Status.删除失败)}})).finally((function(){A(!1)})))}),[t]);var R=function(e){var n=e.message,a=e.references,i=e.status;null!=a&&a.length&&a.includes(t.id)&&("number"==typeof i&&(w(i===v.Status.安装中||i===v.Status.删除中),K(i===v.Status.删除失败)),n&&m((function(e){return"".concat(e).concat(n)})))};return(0,o.useEffect)((function(){var e=P.Z.getInstance();return e.subscribe("installDependence",R),e.subscribe("uninstallDependence",R),function(){e.unsubscribe("installDependence",R),e.unsubscribe("uninstallDependence",R)}}),[t]),(0,o.useEffect)((function(){T(document.body.clientWidth<768)}),[]),(0,f.jsx)(l.Z,{title:(0,f.jsxs)(f.Fragment,{children:[x&&(0,f.jsx)(p.Z,{spin:!0}),!x&&(0,f.jsx)(g.Z,{}),(0,f.jsxs)("span",{style:{marginLeft:5},children:[r.ZP.get("日志 -")," ",t&&t.name]})," "]}),open:!0,centered:!0,className:"log-modal",forceRender:!0,onOk:function(){return M()},onCancel:function(){return M()},footer:[(0,f.jsx)(s.Z,{type:"primary",onClick:function(){E?(D(!0),u.W.delete("".concat(c.Z.apiPrefix,"dependencies/force"),{data:[t.id]}).then((function(e){var t=e.code;e.data,200===t&&M(!0)})).finally((function(){D(!1)}))):M()},loading:O,children:E?r.ZP.get("强制删除"):r.ZP.get("知道了")})],children:(0,f.jsx)("div",{className:"log-container",children:_?(0,f.jsx)(d.Z,{}):(0,f.jsx)("pre",{style:S?{fontFamily:"Source Code Pro",zoom:.83}:{},children:(0,f.jsx)(b(),{children:Z})})})})}},57113:function(e,t,n){n.r(t),n.d(t,{DependenceStatus:function(){return a},Status:function(){return i}});var a=function(e){return e[e.installing=0]="installing",e[e.installed=1]="installed",e[e.installFailed=2]="installFailed",e[e.removing=3]="removing",e[e.removed=4]="removed",e[e.removeFailed=5]="removeFailed",e[e.queued=6]="queued",e[e.cancelled=7]="cancelled",e}({}),i=function(e){return e[e["安装中"]=0]="安装中",e[e["已安装"]=1]="已安装",e[e["安装失败"]=2]="安装失败",e[e["删除中"]=3]="删除中",e[e["已删除"]=4]="已删除",e[e["删除失败"]=5]="删除失败",e[e["队列中"]=6]="队列中",e[e["已取消"]=7]="已取消",e}({})},3475:function(e,t,n){var a=n(72317),i=window.__ENV__QlBaseUrl||"/";t.Z={siteName:a.ZP.get("青龙"),baseUrl:i,apiPrefix:"".concat(i,"api/"),authKey:"token",layouts:[{name:"primary",include:[/.*/],exclude:[/(\/(en|zh))*\/login/]}],scopes:[{name:a.ZP.get("定时任务"),value:"crons"},{name:a.ZP.get("环境变量"),value:"envs"},{name:a.ZP.get("订阅管理"),value:"subscriptions"},{name:a.ZP.get("配置文件"),value:"configs"},{name:a.ZP.get("脚本管理"),value:"scripts"},{name:a.ZP.get("日志管理"),value:"logs"},{name:a.ZP.get("依赖管理"),value:"dependencies"},{name:a.ZP.get("系统信息"),value:"system"}],scopesMap:{crons:a.ZP.get("定时任务"),envs:a.ZP.get("环境变量"),subscriptions:a.ZP.get("订阅管理"),configs:a.ZP.get("配置文件"),scripts:a.ZP.get("脚本管理"),logs:a.ZP.get("日志管理"),dependencies:a.ZP.get("依赖管理"),system:a.ZP.get("系统信息")},notificationModes:[{value:"gotify",label:"Gotify"},{value:"ntfy",label:"Ntfy"},{value:"goCqHttpBot",label:"GoCqHttpBot"},{value:"serverChan",label:a.ZP.get("Server酱")},{value:"pushDeer",label:"PushDeer"},{value:"bark",label:"Bark"},{value:"telegramBot",label:a.ZP.get("Telegram机器人")},{value:"dingtalkBot",label:a.ZP.get("钉钉机器人")},{value:"weWorkBot",label:a.ZP.get("企业微信机器人")},{value:"weWorkApp",label:a.ZP.get("企业微信应用")},{value:"aibotk",label:a.ZP.get("智能微秘书")},{value:"iGot",label:"IGot"},{value:"pushPlus",label:"PushPlus"},{value:"wePlusBot",label:a.ZP.get("微加机器人")},{value:"wxPusherBot",label:"wxPusher"},{value:"openiLink",label:"OpeniLink"},{value:"chat",label:a.ZP.get("群晖chat")},{value:"email",label:a.ZP.get("邮箱")},{value:"lark",label:a.ZP.get("飞书机器人")},{value:"pushMe",label:"PushMe"},{value:"chronocat",label:"Chronocat"},{value:"webhook",label:a.ZP.get("自定义通知")},{value:"closed",label:a.ZP.get("已关闭")}],notificationModeMap:{gotify:[{label:"gotifyUrl",tip:a.ZP.get("gotify的url地址,例如 https://push.example.de:8080"),required:!0},{label:"gotifyToken",tip:a.ZP.get("gotify的消息应用token码"),required:!0},{label:"gotifyPriority",tip:a.ZP.get("推送消息的优先级")}],ntfy:[{label:"ntfyUrl",tip:a.ZP.get("ntfy的url地址,例如 https://ntfy.sh"),required:!0},{label:"ntfyTopic",tip:a.ZP.get("ntfy应用topic"),required:!0},{label:"ntfyPriority",tip:a.ZP.get("推送消息的优先级")},{label:"ntfyToken",tip:a.ZP.get("ntfy应用token")},{label:"ntfyUsername",tip:a.ZP.get("ntfy应用用户名")},{label:"ntfyPassword",tip:a.ZP.get("ntfy应用密码")},{label:"ntfyActions",tip:a.ZP.get("ntfy用户动作")}],chat:[{label:"synologyChatUrl",tip:a.ZP.get("synologyChat的url地址"),required:!0}],goCqHttpBot:[{label:"goCqHttpBotUrl",tip:a.ZP.get("推送到个人QQ: http://127.0.0.1/send_private_msg,群:http://127.0.0.1/send_group_msg"),required:!0},{label:"goCqHttpBotToken",tip:a.ZP.get("访问密钥"),required:!0},{label:"goCqHttpBotQq",tip:a.ZP.get("如果GOBOT_URL设置 /send_private_msg 则需要填入 user_id=个人QQ 相反如果是 /send_group_msg 则需要填入 group_id=QQ群"),required:!0}],serverChan:[{label:"serverChanKey",tip:a.ZP.get("Server酱SENDKEY"),required:!0}],pushDeer:[{label:"pushDeerKey",tip:a.ZP.get("PushDeer的Key,https://github.com/easychen/pushdeer"),required:!0},{label:"pushDeerUrl",tip:a.ZP.get("PushDeer的自架API endpoint,默认是 https://api2.pushdeer.com/message/push")}],bark:[{label:"barkPush",tip:a.ZP.get("Bark的信息IP/设备码,例如:https://api.day.app/XXXXXXXX"),required:!0},{label:"barkIcon",tip:a.ZP.get("BARK推送图标,自定义推送图标 (需iOS15或以上才能显示)")},{label:"barkSound",tip:a.ZP.get("BARK推送铃声,铃声列表去APP查看复制填写")},{label:"barkGroup",tip:a.ZP.get("BARK推送消息的分组,默认为qinglong")},{label:"barkLevel",tip:a.ZP.get("BARK推送消息的时效性,默认为active")},{label:"barkUrl",tip:a.ZP.get("BARK推送消息的跳转URL")},{label:"barkArchive",tip:a.ZP.get("BARK是否保存推送消息")}],telegramBot:[{label:"telegramBotToken",tip:a.ZP.get("telegram机器人的token,例如:1077xxx4424:AAFjv0FcqxxxxxxgEMGfi22B4yh15R5uw"),required:!0},{label:"telegramBotUserId",tip:a.ZP.get("telegram用户的id,例如:129xxx206"),required:!0},{label:"telegramBotProxyHost",tip:a.ZP.get("代理IP")},{label:"telegramBotProxyPort",tip:a.ZP.get("代理端口")},{label:"telegramBotProxyAuth",tip:a.ZP.get("telegram代理配置认证参数,用户名与密码用英文冒号连接 user:password")},{label:"telegramBotApiHost",tip:a.ZP.get("telegram api自建的反向代理地址,默认tg官方api")}],dingtalkBot:[{label:"dingtalkBotToken",tip:a.ZP.get("钉钉机器人webhook token,例如:5a544165465465645d0f31dca676e7bd07415asdasd"),required:!0},{label:"dingtalkBotSecret",tip:a.ZP.get("密钥,机器人安全设置页面,加签一栏下面显示的SEC开头的字符串")}],weWorkBot:[{label:"weWorkBotKey",tip:a.ZP.get("企业微信机器人的webhook(详见文档 https://work.weixin.qq.com/api/doc/90000/90136/91770),例如:693a91f6-7xxx-4bc4-97a0-0ec2sifa5aaa"),required:!0},{label:"weWorkOrigin",tip:a.ZP.get("企业微信代理地址")}],weWorkApp:[{label:"weWorkAppKey",tip:a.ZP.get("corpid、corpsecret、touser(注:多个成员ID使用|隔开)、agentid、消息类型(选填,不填默认文本消息类型) 注意用,号隔开(英文输入法的逗号),例如:wwcfrs,B-76WERQ,qinglong,1000001,2COat"),required:!0},{label:"weWorkOrigin",tip:a.ZP.get("企业微信代理地址")}],aibotk:[{label:"aibotkKey",tip:a.ZP.get("密钥key,智能微秘书个人中心获取apikey,申请地址:https://wechat.aibotk.com/signup?from=ql"),required:!0},{label:"aibotkType",tip:a.ZP.get("发送的目标,群组或者好友"),required:!0,placeholder:a.ZP.get("请输入要发送的目标"),items:[{value:"room",label:a.ZP.get("群聊")},{value:"contact",label:a.ZP.get("好友")}]},{label:"aibotkName",tip:a.ZP.get("要发送的用户昵称或群名,如果目标是群,需要填群名,如果目标是好友,需要填好友昵称"),required:!0}],iGot:[{label:"iGotPushKey",tip:a.ZP.get("iGot的信息推送key,例如:https://push.hellyw.com/XXXXXXXX"),required:!0}],pushPlus:[{label:"pushPlusToken",tip:a.ZP.get("微信扫码登录后一对一推送或一对多推送下面的token(您的Token),不提供PUSH_PLUS_USER则默认为一对一推送,参考 https://www.pushplus.plus/"),required:!0},{label:"pushPlusUser",tip:a.ZP.get("一对多推送的“群组编码”(一对多推送下面->您的群组(如无则创建)->群组编码,如果您是创建群组人。也需点击“查看二维码”扫描绑定,否则不能接受群组消息推送)")},{label:"pushplusTemplate",tip:a.ZP.get("发送模板")},{label:"pushplusChannel",tip:a.ZP.get("发送渠道")},{label:"pushplusWebhook",tip:a.ZP.get("webhook编码")},{label:"pushplusCallbackUrl",tip:a.ZP.get("发送结果回调地址")},{label:"pushplusTo",tip:a.ZP.get("好友令牌")}],wePlusBot:[{label:"wePlusBotToken",tip:a.ZP.get("用户令牌,扫描登录后 我的—>设置->令牌 中获取,参考 https://www.weplusbot.com/"),required:!0},{label:"wePlusBotReceiver",tip:a.ZP.get("消息接收人")},{label:"wePlusBotVersion",tip:a.ZP.get("调用版本;专业版填写pro,个人版填写personal,为空默认使用专业版")}],wxPusherBot:[{label:"wxPusherBotAppToken",tip:a.ZP.get("wxPusherBot的appToken"),required:!0},{label:"wxPusherBotTopicIds",tip:a.ZP.get("wxPusherBot的topicIds"),required:!1},{label:"wxPusherBotUids",tip:a.ZP.get("wxPusherBot的uids"),required:!1}],openiLink:[{label:"openiLinkAppToken",tip:a.ZP.get("OpeniLink的app_token,在OpeniLink Hub后台安装App后获取,参考 https://openilink.com/docs/hub/apps"),required:!0},{label:"openiLinkHubUrl",tip:a.ZP.get("OpeniLink Hub地址,默认为 https://hub.openilink.com,自建Hub时填写自己的地址")},{label:"openiLinkContextToken",tip:a.ZP.get("OpeniLink的context_token,用于标识消息会话上下文,可从消息事件中获取")}],lark:[{label:"larkKey",tip:a.ZP.get("飞书群组机器人:https://www.feishu.cn/hc/zh-CN/articles/360024984973"),required:!0},{label:"larkSecret",tip:a.ZP.get("飞书群组机器人加签密钥,安全设置中开启签名校验后获得")}],email:[{label:"emailService",tip:a.ZP.get("邮箱服务名称,比如126、163、Gmail、QQ等,支持列表https://github.com/nodemailer/nodemailer/blob/master/lib/well-known/services.json"),required:!0},{label:"emailUser",tip:a.ZP.get("邮箱认证地址"),required:!0},{label:"emailPass",tip:a.ZP.get("SMTP 登录密码,也可能为特殊口令,视具体邮件服务商说明而定"),required:!0},{label:"emailTo",tip:a.ZP.get("收件邮箱地址,多个分号分隔,默认发送给发件邮箱地址")}],pushMe:[{label:"pushMeKey",tip:a.ZP.get("PushMe的Key,https://push.i-i.me/"),required:!0},{label:"pushMeUrl",tip:a.ZP.get("自建的PushMeServer消息接口地址,例如:http://127.0.0.1:3010,不填则使用官方消息接口"),required:!1}],chronocat:[{label:"chronocatURL",tip:a.ZP.get("Chronocat Red 服务的连接地址 https://chronocat.vercel.app/install/docker/official/"),required:!0},{label:"chronocatQQ",tip:a.ZP.get("个人:user_id=个人QQ 群则填入group_id=QQ群 多个用英文;隔开同时支持个人和群 如:user_id=xxx;group_id=xxxx;group_id=xxxxx"),required:!0},{label:"chronocatToken",tip:a.ZP.get("docker安装在持久化config目录下的chronocat.yml文件可找到"),required:!0}],webhook:[{label:"webhookMethod",tip:a.ZP.get("请求方法"),required:!0,items:[{value:"GET"},{value:"POST"},{value:"PUT"}]},{label:"webhookContentType",tip:a.ZP.get("请求头Content-Type"),required:!0,items:[{value:"text/plain"},{value:"application/json"},{value:"multipart/form-data"},{value:"application/x-www-form-urlencoded"}]},{label:"webhookUrl",tip:a.ZP.get("请求链接以http或者https开头。url或者body中必须包含$title,$content可选,对应api内容的位置"),required:!0,placeholder:"https://xxx.cn/api?content=$title\n"},{label:"webhookHeaders",tip:a.ZP.get("请求头格式Custom-Header1: Header1,多个换行分割"),placeholder:"Custom-Header1: Header1\nCustom-Header2: Header2"},{label:"webhookBody",tip:a.ZP.get("请求体格式key1: value1,多个换行分割。url或者body中必须包含$title,$content可选,对应api内容的位置"),placeholder:"key1: $title\nkey2: $content"}]},documentTitleMap:{"/login":a.ZP.get("登录"),"/initialization":a.ZP.get("初始化"),"/crontab":a.ZP.get("定时任务"),"/env":a.ZP.get("环境变量"),"/subscription":a.ZP.get("订阅管理"),"/config":a.ZP.get("配置文件"),"/script":a.ZP.get("脚本管理"),"/diff":a.ZP.get("对比工具"),"/log":a.ZP.get("日志管理"),"/setting":a.ZP.get("系统设置"),"/error":a.ZP.get("错误日志"),"/dependence":a.ZP.get("依赖管理"),"/dashboard":a.ZP.get("仪表盘")},dependenceTypes:["nodejs","python3","linux"]}},16314:function(e,t,n){n.d(t,{W:function(){return v}});var a=n(90228),i=n.n(a),r=n(87999),o=n.n(r),l=n(72317),s=n(61508),u=n(33839),c=n(3475),p=n(98783),g=n(69313),d=n(52676);s.ZP.config({duration:2});var h=Date.now(),b=g.Z.create({timeout:6e4,params:{t:h}}),P=["".concat(c.Z.baseUrl,"api/user/login"),"".concat(c.Z.baseUrl,"open/auth/token"),"".concat(c.Z.baseUrl,"api/user/two-factor/login"),"".concat(c.Z.baseUrl,"api/system"),"".concat(c.Z.baseUrl,"api/user/init"),"".concat(c.Z.baseUrl,"api/user/notification/init")];b.interceptors.request.use((function(e){var t=localStorage.getItem(c.Z.authKey);return t&&!P.includes(e.url)?(e.headers.Authorization="Bearer ".concat(t),e):e})),b.interceptors.response.use(function(){var e=o()(i()().mark((function e(t){var n,a,r;return i()().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(n=t.status,![502,504].includes(n)){e.next=5;break}p.history.push("/error"),e.next=18;break;case 5:if(401!==n){e.next=9;break}"/login"!==p.history.location.pathname&&(localStorage.removeItem(c.Z.authKey),p.history.push("/login")),e.next=18;break;case 9:return e.prev=9,200!==(a=t.data).code&&(r=a.message||a.data)&&u.Z.error({message:r,description:null!=a&&a.errors?(0,d.jsx)(d.Fragment,{children:null==a?void 0:a.errors.map((function(e){return(0,d.jsx)("div",{children:e.message})}))}):void 0}),e.abrupt("return",a);case 15:e.prev=15,e.t0=e.catch(9);case 17:case 18:return e.abrupt("return",t);case 19:case"end":return e.stop()}}),e,null,[[9,15]])})));return function(t){return e.apply(this,arguments)}}(),(function(e){if(e.response){var t=e.response.data?e.response.data.message||e.message:e.response.statusText,n=e.response.status;if([502,504].includes(n))p.history.push("/error");else if(401===n)"/login"!==p.history.location.pathname&&(s.ZP.error(l.ZP.get("登录已过期,请重新登录")),localStorage.removeItem(c.Z.authKey),p.history.push("/login"));else{var a,i,r,o;if("function"==typeof(null===(a=e.config)||void 0===a?void 0:a.onError))return null===(o=e.config)||void 0===o?void 0:o.onError(e.response);t&&u.Z.error({message:t,description:null!==(i=e.response)&&void 0!==i&&null!==(i=i.data)&&void 0!==i&&i.errors?(0,d.jsx)(d.Fragment,{children:null===(r=e.response)||void 0===r||null===(r=r.data)||void 0===r||null===(r=r.errors)||void 0===r?void 0:r.map((function(e){return(0,d.jsxs)("div",{children:[e.message," (",e.value,")"]})}))}):void 0})}}else console.log(e.message);return Promise.reject(e)}));var v=b},65814:function(e,t,n){var a=n(15558),i=n.n(a),r=n(67825),o=n.n(r),l=n(90228),s=n.n(l),u=n(87999),c=n.n(u),p=n(25298),g=n.n(p),d=n(17069),h=n.n(d),b=n(82092),P=n.n(b),v=n(78078),f=n.n(v),Z=["type"],m=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};g()(this,e),P()(this,"url",void 0),P()(this,"socket",null),P()(this,"subscriptions",new Map),P()(this,"options",void 0),P()(this,"reconnectAttempts",0),P()(this,"heartbeatTimeout",null),P()(this,"state","closed"),this.url=t,this.options={maxReconnectAttempts:n.maxReconnectAttempts||5,reconnectInterval:n.reconnectInterval||3e3,heartbeatInterval:n.heartbeatInterval||3e4},this.init()}var t,n;return h()(e,[{key:"init",value:(n=c()(s()().mark((function e(){var t=this;return s()().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:e.prev=0,this.state="connecting",this.emit("connecting");case 3:if(!(this.reconnectAttempts<this.options.maxReconnectAttempts)){e.next=16;break}return this.socket=new(f())(this.url),this.setupEventListeners(),this.startHeartbeat(),e.next=9,this.waitForClose();case 9:return this.stopHeartbeat(),this.socket=null,this.reconnectAttempts++,e.next=14,new Promise((function(e){return setTimeout(e,t.options.reconnectInterval)}));case 14:e.next=3;break;case 16:e.next=21;break;case 18:e.prev=18,e.t0=e.catch(0),this.handleError(e.t0);case 21:case"end":return e.stop()}}),e,this,[[0,18]])}))),function(){return n.apply(this,arguments)})},{key:"setupEventListeners",value:function(){var e=this;this.socket&&(this.socket.onopen=function(){e.state="open",e.emit("open")},this.socket.onmessage=function(t){var n=JSON.parse(t.data);e.dispatchMessage(n)},this.socket.onclose=function(){e.state="closed",e.emit("close")})}},{key:"waitForClose",value:(t=c()(s()().mark((function e(){var t;return s()().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if((null===(t=this.socket)||void 0===t?void 0:t.readyState)===f().CLOSED){e.next=5;break}return e.next=3,new Promise((function(e){return setTimeout(e,100)}));case 3:e.next=0;break;case 5:case"end":return e.stop()}}),e,this)}))),function(){return t.apply(this,arguments)})},{key:"subscribe",value:function(e,t){var n=this.subscriptions.get(e)||new Set;if(!n.has(t)){n.add(t),this.subscriptions.set(e,n);var a={action:"subscribe",topic:e};this.send(a)}}},{key:"unsubscribe",value:function(e,t){var n=this.subscriptions.get(e)||new Set;if(n.has(t)){n.delete(t);var a={action:"unsubscribe",topic:e};this.send(a)}}},{key:"send",value:function(e){var t;(null===(t=this.socket)||void 0===t?void 0:t.readyState)===f().OPEN&&this.socket.send(JSON.stringify(e))}},{key:"dispatchMessage",value:function(e){var t=e.type,n=o()(e,Z),a=this.subscriptions.get(t)||new Set;i()(a).forEach((function(e){return e(n)}))}},{key:"startHeartbeat",value:function(){var e=this;this.heartbeatTimeout=setInterval((function(){var t;(null===(t=e.socket)||void 0===t?void 0:t.readyState)===f().OPEN&&e.socket.send(JSON.stringify({type:"heartbeat"}))}),this.options.heartbeatInterval)}},{key:"stopHeartbeat",value:function(){this.heartbeatTimeout&&clearInterval(this.heartbeatTimeout)}},{key:"close",value:function(){this.socket&&(this.state="closed",this.stopHeartbeat(),this.socket.close(),this.emit("close"))}},{key:"handleError",value:function(e){console.error("WebSocket错误:",e),this.emit("error",e)}},{key:"on",value:function(e,t){}},{key:"emit",value:function(e,t){}}],[{key:"getInstance",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",n=arguments.length>1?arguments[1]:void 0;return e.instance||(e.instance=new e(t,n)),e.instance}}]),e}();P()(m,"instance",null),t.Z=m}}]);