mirror of
https://github.com/whyour/qinglong.git
synced 2026-06-28 02:45:08 +08:00
修复国际化文案
This commit is contained in:
parent
369dd13212
commit
3044f63f03
|
|
@ -312,8 +312,8 @@ export default (app: Router) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cronService = Container.get(CronService);
|
const cronService = Container.get(CronService);
|
||||||
const data = await cronService.log(req.params.id);
|
const result = await cronService.log(req.params.id);
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data: result.content, logStatus: result.status });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return next(e);
|
return next(e);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import {
|
||||||
} from '../data/runningInstance';
|
} from '../data/runningInstance';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
import { t, tf } from '../shared/i18n';
|
||||||
|
|
||||||
const route = Router();
|
const route = Router();
|
||||||
|
|
||||||
|
|
@ -181,7 +183,7 @@ export default (app: Router) => {
|
||||||
|
|
||||||
const data = rows.map((r: any, i) => ({
|
const data = rows.map((r: any, i) => ({
|
||||||
rank: i + 1,
|
rank: i + 1,
|
||||||
name: nameMap[Number(r.ref_id)] || `任务#${r.ref_id}`,
|
name: nameMap[Number(r.ref_id)] || tf('任务#%s', r.ref_id),
|
||||||
avgTime: Math.round(Number(r.total_time) / Number(r.run_count)),
|
avgTime: Math.round(Number(r.total_time) / Number(r.run_count)),
|
||||||
maxTime: Number(r.max_time),
|
maxTime: Number(r.max_time),
|
||||||
}));
|
}));
|
||||||
|
|
@ -223,7 +225,7 @@ export default (app: Router) => {
|
||||||
|
|
||||||
const data = rows.map((r: any, i) => ({
|
const data = rows.map((r: any, i) => ({
|
||||||
rank: i + 1,
|
rank: i + 1,
|
||||||
name: nameMap[Number(r.ref_id)] || `任务#${r.ref_id}`,
|
name: nameMap[Number(r.ref_id)] || tf('任务#%s', r.ref_id),
|
||||||
runCount: Number(r.run_count),
|
runCount: Number(r.run_count),
|
||||||
avgTime: Math.round(Number(r.total_time) / Number(r.run_count)),
|
avgTime: Math.round(Number(r.total_time) / Number(r.run_count)),
|
||||||
successRate:
|
successRate:
|
||||||
|
|
@ -264,9 +266,9 @@ export default (app: Router) => {
|
||||||
const crons =
|
const crons =
|
||||||
cronIds.length > 0
|
cronIds.length > 0
|
||||||
? await CrontabModel.findAll({
|
? await CrontabModel.findAll({
|
||||||
where: { id: cronIds },
|
where: { id: cronIds },
|
||||||
raw: true,
|
raw: true,
|
||||||
})
|
})
|
||||||
: [];
|
: [];
|
||||||
const cronMap = new Map(crons.map((c: any) => [c.id, c]));
|
const cronMap = new Map(crons.map((c: any) => [c.id, c]));
|
||||||
|
|
||||||
|
|
@ -276,7 +278,7 @@ export default (app: Router) => {
|
||||||
return {
|
return {
|
||||||
instanceId: inst.id,
|
instanceId: inst.id,
|
||||||
id: inst.cron_id,
|
id: inst.cron_id,
|
||||||
name: cron?.name || cron?.command || `任务#${inst.cron_id}`,
|
name: cron?.name || cron?.command || tf('任务#%s', inst.cron_id),
|
||||||
pid: inst.pid,
|
pid: inst.pid,
|
||||||
elapsed: inst.started_at ? now - inst.started_at : 0,
|
elapsed: inst.started_at ? now - inst.started_at : 0,
|
||||||
logPath: inst.log_path,
|
logPath: inst.log_path,
|
||||||
|
|
@ -303,7 +305,7 @@ export default (app: Router) => {
|
||||||
running,
|
running,
|
||||||
idleTasks: idleTasks.map((c: any) => ({
|
idleTasks: idleTasks.map((c: any) => ({
|
||||||
id: c.id,
|
id: c.id,
|
||||||
name: c.name || c.command || `任务#${c.id}`,
|
name: c.name || c.command || tf('任务#%s', c.id),
|
||||||
lastRun: c.last_execution_time
|
lastRun: c.last_execution_time
|
||||||
? dayjs.unix(c.last_execution_time).format('MM-DD HH:mm')
|
? dayjs.unix(c.last_execution_time).format('MM-DD HH:mm')
|
||||||
: '-',
|
: '-',
|
||||||
|
|
@ -324,17 +326,22 @@ export default (app: Router) => {
|
||||||
const [crons, stats] = (await Promise.all([
|
const [crons, stats] = (await Promise.all([
|
||||||
CrontabModel.findAll({ where: { isDisabled: 0 }, raw: true }),
|
CrontabModel.findAll({ where: { isDisabled: 0 }, raw: true }),
|
||||||
CrontabStatModel.findAll({ where: { date: today }, raw: true }),
|
CrontabStatModel.findAll({ where: { date: today }, raw: true }),
|
||||||
])) as any[];
|
]));
|
||||||
|
|
||||||
const statMap: Record<number, any> = {};
|
const statMap: Record<number, any> = {};
|
||||||
stats.forEach((s: any) => { statMap[s.ref_id] = s; });
|
stats.forEach((s: any) => { statMap[s.ref_id] = s; });
|
||||||
|
|
||||||
const labelMap: Record<string, { count: number; runs: number; success: number; totalTime: number }> = {};
|
const labelMap: Record<string, { count: number; runs: number; success: number; totalTime: number }> = {};
|
||||||
crons.forEach((c: any) => {
|
crons.forEach((c) => {
|
||||||
let rawLabels = c.labels;
|
let rawLabels = c.labels;
|
||||||
if (typeof rawLabels === 'string') rawLabels = JSON.parse(rawLabels);
|
if (typeof rawLabels === 'string') rawLabels = JSON.parse(rawLabels);
|
||||||
const labels: string[] = Array.isArray(rawLabels) && rawLabels.length > 0 ? rawLabels : ['未分类'];
|
const labels: string[] = Array.isArray(rawLabels)
|
||||||
const st = statMap[c.id];
|
? [...new Set((rawLabels as string[]).filter((l: string) => !isEmpty(l)))]
|
||||||
|
: [];
|
||||||
|
if (labels.length === 0) {
|
||||||
|
labels.push(t('未分类'));
|
||||||
|
}
|
||||||
|
const st = statMap[c.id!];
|
||||||
labels.forEach((label: string) => {
|
labels.forEach((label: string) => {
|
||||||
if (!labelMap[label]) labelMap[label] = { count: 0, runs: 0, success: 0, totalTime: 0 };
|
if (!labelMap[label]) labelMap[label] = { count: 0, runs: 0, success: 0, totalTime: 0 };
|
||||||
labelMap[label].count += 1;
|
labelMap[label].count += 1;
|
||||||
|
|
@ -372,7 +379,7 @@ export default (app: Router) => {
|
||||||
code: 200,
|
code: 200,
|
||||||
data: {
|
data: {
|
||||||
platform: os.platform(),
|
platform: os.platform(),
|
||||||
uptime: Math.floor(os.uptime()),
|
uptime: Math.floor(process.uptime()),
|
||||||
memTotal: os.totalmem(),
|
memTotal: os.totalmem(),
|
||||||
memFree: os.freemem(),
|
memFree: os.freemem(),
|
||||||
memUsagePercent: ((1 - os.freemem() / os.totalmem()) * 100).toFixed(1),
|
memUsagePercent: ((1 - os.freemem() / os.totalmem()) * 100).toFixed(1),
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { createRandomString } from './share';
|
|
||||||
|
|
||||||
dotenv.config({
|
dotenv.config({
|
||||||
path: path.join(__dirname, '../../.env'),
|
path: path.join(__dirname, '../../.env'),
|
||||||
|
|
@ -119,8 +118,6 @@ const confBakDir = path.join(dataPath, 'config/bak/');
|
||||||
const sampleFile = path.join(samplePath, 'config.sample.sh');
|
const sampleFile = path.join(samplePath, 'config.sample.sh');
|
||||||
const sqliteFile = path.join(samplePath, 'database.sqlite');
|
const sqliteFile = path.join(samplePath, 'database.sqlite');
|
||||||
|
|
||||||
const authError = '错误的用户名密码,请重试';
|
|
||||||
const loginFaild = '请先登录!';
|
|
||||||
const configString = 'config sample crontab shareCode diy';
|
const configString = 'config sample crontab shareCode diy';
|
||||||
const versionFile = path.join(rootPath, 'version.yaml');
|
const versionFile = path.join(rootPath, 'version.yaml');
|
||||||
const dataTgzFile = path.join(tmpPath, 'data.tgz');
|
const dataTgzFile = path.join(tmpPath, 'data.tgz');
|
||||||
|
|
@ -142,8 +139,6 @@ export default {
|
||||||
shareShellFile,
|
shareShellFile,
|
||||||
dependenceProxyFile,
|
dependenceProxyFile,
|
||||||
configString,
|
configString,
|
||||||
loginFaild,
|
|
||||||
authError,
|
|
||||||
logPath,
|
logPath,
|
||||||
extraFile,
|
extraFile,
|
||||||
authConfigFile,
|
authConfigFile,
|
||||||
|
|
|
||||||
|
|
@ -536,7 +536,7 @@ export function safeJSONParse(value?: string) {
|
||||||
try {
|
try {
|
||||||
return JSON.parse(value);
|
return JSON.parse(value);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error('[safeJSONParse失败]', error);
|
Logger.error('[safeJSONParse error]', error);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -548,7 +548,7 @@ export async function rmPath(path: string) {
|
||||||
await fs.rm(path, { force: true, recursive: true, maxRetries: 5 });
|
await fs.rm(path, { force: true, recursive: true, maxRetries: 5 });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error('[rmPath失败]', error);
|
Logger.error('[rmPath error]', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -563,7 +563,7 @@ export async function setSystemTimezone(timezone: string): Promise<boolean> {
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.error('[setSystemTimezone失败]', error);
|
Logger.error('[setSystemTimezone error]', error);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,13 @@ export class SockMessage {
|
||||||
message?: string;
|
message?: string;
|
||||||
type?: SockMessageType;
|
type?: SockMessageType;
|
||||||
references?: number[];
|
references?: number[];
|
||||||
|
status?: number | string;
|
||||||
|
|
||||||
constructor(options: SockMessage) {
|
constructor(options: SockMessage) {
|
||||||
this.type = options.type;
|
this.type = options.type;
|
||||||
this.message = options.message;
|
this.message = options.message;
|
||||||
this.references = options.references;
|
this.references = options.references;
|
||||||
|
this.status = options.status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import SshKeyService from '../services/sshKey';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { fileExist } from '../config/util';
|
import { fileExist } from '../config/util';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
import { t } from '../shared/i18n';
|
||||||
|
|
||||||
export default async () => {
|
export default async () => {
|
||||||
const systemService = Container.get(SystemService);
|
const systemService = Container.get(SystemService);
|
||||||
|
|
@ -25,7 +26,7 @@ export default async () => {
|
||||||
}
|
}
|
||||||
const cron = {
|
const cron = {
|
||||||
id: NaN,
|
id: NaN,
|
||||||
name: '生成token',
|
name: t('生成token'),
|
||||||
command: tokenCommand,
|
command: tokenCommand,
|
||||||
runOrigin: 'system',
|
runOrigin: 'system',
|
||||||
} as ScheduleTaskType;
|
} as ScheduleTaskType;
|
||||||
|
|
@ -44,7 +45,7 @@ export default async () => {
|
||||||
if (data.info.logRemoveFrequency) {
|
if (data.info.logRemoveFrequency) {
|
||||||
const rmlogCron = {
|
const rmlogCron = {
|
||||||
id: data.id as number,
|
id: data.id as number,
|
||||||
name: '删除日志',
|
name: t('删除日志'),
|
||||||
command: `ql rmlog ${data.info.logRemoveFrequency}`,
|
command: `ql rmlog ${data.info.logRemoveFrequency}`,
|
||||||
runOrigin: 'system' as const,
|
runOrigin: 'system' as const,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -712,23 +712,27 @@ export default class CronService {
|
||||||
await this.setCrontab();
|
await this.setCrontab();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async log(id: number) {
|
public async log(id: number): Promise<{ content: string; status: string }> {
|
||||||
const doc = await this.getDb({ id });
|
const doc = await this.getDb({ id });
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
return '';
|
return { content: '', status: 'empty' };
|
||||||
}
|
}
|
||||||
if (doc.log_name === '/dev/null') {
|
if (doc.log_name === '/dev/null') {
|
||||||
return '日志设置为忽略';
|
return { content: t('日志设置为忽略'), status: 'ignored' };
|
||||||
}
|
}
|
||||||
const absolutePath = path.resolve(config.logPath, `${doc.log_path}`);
|
const absolutePath = path.resolve(config.logPath, `${doc.log_path}`);
|
||||||
const logFileExist = doc.log_path && (await fileExist(absolutePath));
|
const logFileExist = doc.log_path && (await fileExist(absolutePath));
|
||||||
if (logFileExist) {
|
if (logFileExist) {
|
||||||
return await getFileContentByName(`${absolutePath}`);
|
const content = await getFileContentByName(`${absolutePath}`);
|
||||||
|
const isRunning =
|
||||||
|
typeof doc.status === 'number' &&
|
||||||
|
[CrontabStatus.running, CrontabStatus.queued].includes(doc.status);
|
||||||
|
return { content, status: isRunning ? 'running' : 'completed' };
|
||||||
} else {
|
} else {
|
||||||
return typeof doc.status === 'number' &&
|
return typeof doc.status === 'number' &&
|
||||||
[CrontabStatus.queued, CrontabStatus.running].includes(doc.status)
|
[CrontabStatus.queued, CrontabStatus.running].includes(doc.status)
|
||||||
? '运行中...'
|
? { content: t('运行中...'), status: 'running' }
|
||||||
: '日志不存在...';
|
: { content: t('日志不存在...'), status: 'notFound' };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import dayjs from 'dayjs';
|
||||||
import taskLimit from '../shared/pLimit';
|
import taskLimit from '../shared/pLimit';
|
||||||
import { detectOS } from '../config/util';
|
import { detectOS } from '../config/util';
|
||||||
import { LINUX_DEPENDENCE_COMMAND } from '../config/const';
|
import { LINUX_DEPENDENCE_COMMAND } from '../config/const';
|
||||||
|
import { t, tf } from '../shared/i18n';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class DependenceService {
|
export default class DependenceService {
|
||||||
|
|
@ -232,7 +233,7 @@ export default class DependenceService {
|
||||||
}
|
}
|
||||||
const depIds = [dependency.id!];
|
const depIds = [dependency.id!];
|
||||||
let depName = dependency.name.trim();
|
let depName = dependency.name.trim();
|
||||||
const actionText = isInstall ? '安装' : '删除';
|
const actionText = isInstall ? t('安装') : t('删除');
|
||||||
const socketMessageType = isInstall
|
const socketMessageType = isInstall
|
||||||
? 'installDependence'
|
? 'installDependence'
|
||||||
: 'uninstallDependence';
|
: 'uninstallDependence';
|
||||||
|
|
@ -249,15 +250,20 @@ export default class DependenceService {
|
||||||
{ where: { id: depIds } },
|
{ where: { id: depIds } },
|
||||||
);
|
);
|
||||||
const startTime = dayjs();
|
const startTime = dayjs();
|
||||||
const message = `开始${actionText}依赖 ${depName},开始时间 ${startTime.format(
|
const message = tf(
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
'开始%s依赖 %s,开始时间 %s\n\n当前系统不支持\n\n依赖%s失败,结束时间 %s,耗时 %s 秒',
|
||||||
)}\n\n当前系统不支持\n\n依赖${actionText}失败,结束时间 ${startTime.format(
|
actionText,
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
depName,
|
||||||
)},耗时 ${startTime.diff(startTime, 'second')} 秒`;
|
startTime.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
actionText,
|
||||||
|
startTime.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
String(startTime.diff(startTime, 'second')),
|
||||||
|
);
|
||||||
this.sockService.sendMessage({
|
this.sockService.sendMessage({
|
||||||
type: socketMessageType,
|
type: socketMessageType,
|
||||||
message,
|
message,
|
||||||
references: depIds,
|
references: depIds,
|
||||||
|
status: DependenceStatus.installFailed,
|
||||||
});
|
});
|
||||||
this.updateLog(depIds, message);
|
this.updateLog(depIds, message);
|
||||||
return resolve(null);
|
return resolve(null);
|
||||||
|
|
@ -280,13 +286,17 @@ export default class DependenceService {
|
||||||
}
|
}
|
||||||
const startTime = dayjs();
|
const startTime = dayjs();
|
||||||
|
|
||||||
const message = `开始${actionText}依赖 ${depName},开始时间 ${startTime.format(
|
const message = tf(
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
'开始%s依赖 %s,开始时间 %s\n\n',
|
||||||
)}\n\n`;
|
actionText,
|
||||||
|
depName,
|
||||||
|
startTime.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
);
|
||||||
this.sockService.sendMessage({
|
this.sockService.sendMessage({
|
||||||
type: socketMessageType,
|
type: socketMessageType,
|
||||||
message,
|
message,
|
||||||
references: depIds,
|
references: depIds,
|
||||||
|
status,
|
||||||
});
|
});
|
||||||
this.updateLog(depIds, message);
|
this.updateLog(depIds, message);
|
||||||
|
|
||||||
|
|
@ -322,13 +332,19 @@ export default class DependenceService {
|
||||||
(!depVersion || depInfo.includes(depVersion))
|
(!depVersion || depInfo.includes(depVersion))
|
||||||
) {
|
) {
|
||||||
const endTime = dayjs();
|
const endTime = dayjs();
|
||||||
const _message = `检测到已经安装 ${depName}\n\n${depInfo}\n\n跳过安装\n\n依赖${actionText}成功,结束时间 ${endTime.format(
|
const _message = tf(
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
'检测到已经安装 %s\n\n%s\n\n跳过安装\n\n依赖%s成功,结束时间 %s,耗时 %s 秒',
|
||||||
)},耗时 ${endTime.diff(startTime, 'second')} 秒`;
|
depName,
|
||||||
|
depInfo,
|
||||||
|
actionText,
|
||||||
|
endTime.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
String(endTime.diff(startTime, 'second')),
|
||||||
|
);
|
||||||
this.sockService.sendMessage({
|
this.sockService.sendMessage({
|
||||||
type: socketMessageType,
|
type: socketMessageType,
|
||||||
message: _message,
|
message: _message,
|
||||||
references: depIds,
|
references: depIds,
|
||||||
|
status: DependenceStatus.installed,
|
||||||
});
|
});
|
||||||
this.updateLog(depIds, _message);
|
this.updateLog(depIds, _message);
|
||||||
await DependenceModel.update(
|
await DependenceModel.update(
|
||||||
|
|
@ -353,6 +369,7 @@ export default class DependenceService {
|
||||||
type: socketMessageType,
|
type: socketMessageType,
|
||||||
message: data.toString(),
|
message: data.toString(),
|
||||||
references: depIds,
|
references: depIds,
|
||||||
|
status,
|
||||||
});
|
});
|
||||||
this.updateLog(depIds, data.toString());
|
this.updateLog(depIds, data.toString());
|
||||||
});
|
});
|
||||||
|
|
@ -362,6 +379,7 @@ export default class DependenceService {
|
||||||
type: socketMessageType,
|
type: socketMessageType,
|
||||||
message: data.toString(),
|
message: data.toString(),
|
||||||
references: depIds,
|
references: depIds,
|
||||||
|
status,
|
||||||
});
|
});
|
||||||
this.updateLog(depIds, data.toString());
|
this.updateLog(depIds, data.toString());
|
||||||
});
|
});
|
||||||
|
|
@ -371,6 +389,7 @@ export default class DependenceService {
|
||||||
type: socketMessageType,
|
type: socketMessageType,
|
||||||
message: JSON.stringify(err),
|
message: JSON.stringify(err),
|
||||||
references: depIds,
|
references: depIds,
|
||||||
|
status,
|
||||||
});
|
});
|
||||||
this.updateLog(depIds, JSON.stringify(err));
|
this.updateLog(depIds, JSON.stringify(err));
|
||||||
});
|
});
|
||||||
|
|
@ -378,28 +397,27 @@ export default class DependenceService {
|
||||||
cp.on('exit', async (code) => {
|
cp.on('exit', async (code) => {
|
||||||
const endTime = dayjs();
|
const endTime = dayjs();
|
||||||
const isSucceed = code === 0;
|
const isSucceed = code === 0;
|
||||||
const resultText = isSucceed ? '成功' : '失败';
|
const resultText = isSucceed ? t('成功') : t('失败');
|
||||||
|
|
||||||
const message = `\n依赖${actionText}${resultText},结束时间 ${endTime.format(
|
const message =
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
'\n' +
|
||||||
)},耗时 ${endTime.diff(startTime, 'second')} 秒`;
|
tf('依赖%s%s,结束时间 %s,耗时 %s 秒',
|
||||||
|
actionText,
|
||||||
|
resultText,
|
||||||
|
endTime.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
String(endTime.diff(startTime, 'second')),
|
||||||
|
);
|
||||||
|
const exitStatus = isSucceed
|
||||||
|
? (isInstall ? DependenceStatus.installed : DependenceStatus.removed)
|
||||||
|
: (isInstall ? DependenceStatus.installFailed : DependenceStatus.removeFailed);
|
||||||
this.sockService.sendMessage({
|
this.sockService.sendMessage({
|
||||||
type: socketMessageType,
|
type: socketMessageType,
|
||||||
message,
|
message,
|
||||||
references: depIds,
|
references: depIds,
|
||||||
|
status: exitStatus,
|
||||||
});
|
});
|
||||||
this.updateLog(depIds, message);
|
this.updateLog(depIds, message);
|
||||||
|
|
||||||
let status: number;
|
|
||||||
if (isSucceed) {
|
|
||||||
status = isInstall
|
|
||||||
? DependenceStatus.installed
|
|
||||||
: DependenceStatus.removed;
|
|
||||||
} else {
|
|
||||||
status = isInstall
|
|
||||||
? DependenceStatus.installFailed
|
|
||||||
: DependenceStatus.removeFailed;
|
|
||||||
}
|
|
||||||
const docs = await DependenceModel.findAll({ where: { id: depIds } });
|
const docs = await DependenceModel.findAll({ where: { id: depIds } });
|
||||||
const _docIds = docs
|
const _docIds = docs
|
||||||
.filter((x) => x.status !== DependenceStatus.cancelled)
|
.filter((x) => x.status !== DependenceStatus.cancelled)
|
||||||
|
|
@ -407,7 +425,7 @@ export default class DependenceService {
|
||||||
|
|
||||||
if (_docIds.length > 0) {
|
if (_docIds.length > 0) {
|
||||||
await DependenceModel.update(
|
await DependenceModel.update(
|
||||||
{ status },
|
{ status: exitStatus },
|
||||||
{ where: { id: _docIds } },
|
{ where: { id: _docIds } },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -365,7 +365,7 @@ export default class NotificationService {
|
||||||
{
|
{
|
||||||
title: `${this.title}`,
|
title: `${this.title}`,
|
||||||
thumb_media_id,
|
thumb_media_id,
|
||||||
author: `智能助手`,
|
author: t('智能助手'),
|
||||||
content_source_url: ``,
|
content_source_url: ``,
|
||||||
content: `${this.content.replace(/\n/g, '<br/>')}`,
|
content: `${this.content.replace(/\n/g, '<br/>')}`,
|
||||||
digest: `${this.content}`,
|
digest: `${this.content}`,
|
||||||
|
|
@ -381,7 +381,7 @@ export default class NotificationService {
|
||||||
title: `${this.title}`,
|
title: `${this.title}`,
|
||||||
description: `${this.content}`,
|
description: `${this.content}`,
|
||||||
url: 'https://github.com/whyour/qinglong',
|
url: 'https://github.com/whyour/qinglong',
|
||||||
btntxt: '更多',
|
btntxt: t('更多'),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
|
@ -432,7 +432,7 @@ export default class NotificationService {
|
||||||
roomName: `${aibotkName}`,
|
roomName: `${aibotkName}`,
|
||||||
message: {
|
message: {
|
||||||
type: 1,
|
type: 1,
|
||||||
content: `【青龙快讯】\n\n${this.title}\n${this.content}`,
|
content: `【${t('青龙快讯')}】\n\n${this.title}\n${this.content}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
|
@ -443,7 +443,7 @@ export default class NotificationService {
|
||||||
name: `${aibotkName}`,
|
name: `${aibotkName}`,
|
||||||
message: {
|
message: {
|
||||||
type: 1,
|
type: 1,
|
||||||
content: `【青龙快讯】\n\n${this.title}\n${this.content}`,
|
content: `【${t('青龙快讯')}】\n\n${this.title}\n${this.content}`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
|
@ -613,7 +613,7 @@ export default class NotificationService {
|
||||||
});
|
});
|
||||||
|
|
||||||
const info = await transporter.sendMail({
|
const info = await transporter.sendMail({
|
||||||
from: `"青龙快讯" <${emailUser}>`,
|
from: `"${t('青龙快讯')}" <${emailUser}>`,
|
||||||
to: recipients,
|
to: recipients,
|
||||||
subject: `${this.title}`,
|
subject: `${this.title}`,
|
||||||
html: `${this.content.replace(/\n/g, '<br/>')}`,
|
html: `${this.content.replace(/\n/g, '<br/>')}`,
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import path, { join } from 'path';
|
||||||
import ScheduleService, { TaskCallbacks } from './schedule';
|
import ScheduleService, { TaskCallbacks } from './schedule';
|
||||||
import { SimpleIntervalSchedule } from 'toad-scheduler';
|
import { SimpleIntervalSchedule } from 'toad-scheduler';
|
||||||
import SockService from './sock';
|
import SockService from './sock';
|
||||||
import { t } from '../shared/i18n';
|
import { t, tf } from '../shared/i18n';
|
||||||
import SshKeyService from './sshKey';
|
import SshKeyService from './sshKey';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { LOG_END_SYMBOL } from '../config/const';
|
import { LOG_END_SYMBOL } from '../config/const';
|
||||||
|
|
@ -131,14 +131,14 @@ export default class SubscriptionService {
|
||||||
);
|
);
|
||||||
const absolutePath = await handleLogPath(
|
const absolutePath = await handleLogPath(
|
||||||
logPath as string,
|
logPath as string,
|
||||||
`## 开始执行... ${startTime.format('YYYY-MM-DD HH:mm:ss')}\n`,
|
tf('## 开始执行... %s\n', startTime.format('YYYY-MM-DD HH:mm:ss')),
|
||||||
);
|
);
|
||||||
|
|
||||||
// 执行sub_before
|
// 执行sub_before
|
||||||
let beforeStr = '';
|
let beforeStr = '';
|
||||||
try {
|
try {
|
||||||
if (doc.sub_before) {
|
if (doc.sub_before) {
|
||||||
await logStreamManager.write(absolutePath, `\n## 执行before命令...\n\n`);
|
await logStreamManager.write(absolutePath, `\n## ${t('执行before命令...')}\n\n`);
|
||||||
beforeStr = await promiseExec(doc.sub_before);
|
beforeStr = await promiseExec(doc.sub_before);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|
@ -165,7 +165,7 @@ export default class SubscriptionService {
|
||||||
let afterStr = '';
|
let afterStr = '';
|
||||||
try {
|
try {
|
||||||
if (sub.sub_after) {
|
if (sub.sub_after) {
|
||||||
await logStreamManager.write(absolutePath, `\n\n## 执行after命令...\n\n`);
|
await logStreamManager.write(absolutePath, `\n\n## ${t('执行after命令...')}\n\n`);
|
||||||
afterStr = await promiseExec(sub.sub_after);
|
afterStr = await promiseExec(sub.sub_after);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
|
|
@ -178,9 +178,13 @@ export default class SubscriptionService {
|
||||||
|
|
||||||
await logStreamManager.write(
|
await logStreamManager.write(
|
||||||
absolutePath,
|
absolutePath,
|
||||||
`\n## 执行结束... ${endTime.format(
|
'\n' +
|
||||||
'YYYY-MM-DD HH:mm:ss',
|
tf(
|
||||||
)} 耗时 ${diff} 秒${LOG_END_SYMBOL}`,
|
'## 执行结束... %s 耗时 %s 秒',
|
||||||
|
endTime.format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
String(diff),
|
||||||
|
) +
|
||||||
|
LOG_END_SYMBOL,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Close the stream after task completion
|
// Close the stream after task completion
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ export default class SystemService {
|
||||||
const code = Math.random().toString().slice(-6);
|
const code = Math.random().toString().slice(-6);
|
||||||
const isSuccess = await this.notificationService.testNotify(
|
const isSuccess = await this.notificationService.testNotify(
|
||||||
notificationInfo,
|
notificationInfo,
|
||||||
'青龙',
|
t('青龙'),
|
||||||
`【蛟龙】测试通知 https://t.me/jiao_long`,
|
t('【蛟龙】测试通知 https://t.me/jiao_long'),
|
||||||
);
|
);
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
const result = await this.updateAuthDb({
|
const result = await this.updateAuthDb({
|
||||||
|
|
@ -100,7 +100,7 @@ export default class SystemService {
|
||||||
});
|
});
|
||||||
const cron = {
|
const cron = {
|
||||||
id: result.id as number,
|
id: result.id as number,
|
||||||
name: '删除日志',
|
name: t('删除日志'),
|
||||||
command: `ql rmlog ${info.logRemoveFrequency}`,
|
command: `ql rmlog ${info.logRemoveFrequency}`,
|
||||||
runOrigin: 'system' as const,
|
runOrigin: 'system' as const,
|
||||||
};
|
};
|
||||||
|
|
@ -179,6 +179,7 @@ export default class SystemService {
|
||||||
this.sockService.sendMessage({
|
this.sockService.sendMessage({
|
||||||
type: 'updateNodeMirror',
|
type: 'updateNodeMirror',
|
||||||
message: 'update node mirror end',
|
message: 'update node mirror end',
|
||||||
|
status: 'completed',
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onError: async (message: string) => {
|
onError: async (message: string) => {
|
||||||
|
|
@ -232,6 +233,7 @@ export default class SystemService {
|
||||||
this.sockService.sendMessage({
|
this.sockService.sendMessage({
|
||||||
type: 'updateLinuxMirror',
|
type: 'updateLinuxMirror',
|
||||||
message: 'update linux mirror end',
|
message: 'update linux mirror end',
|
||||||
|
status: 'completed',
|
||||||
});
|
});
|
||||||
onEnd?.();
|
onEnd?.();
|
||||||
if (!hasError) {
|
if (!hasError) {
|
||||||
|
|
@ -340,6 +342,15 @@ export default class SystemService {
|
||||||
this.sockService.sendMessage({
|
this.sockService.sendMessage({
|
||||||
type: 'updateSystemVersion',
|
type: 'updateSystemVersion',
|
||||||
message: JSON.stringify(err),
|
message: JSON.stringify(err),
|
||||||
|
status: 'failed',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
cp.on('exit', (code) => {
|
||||||
|
this.sockService.sendMessage({
|
||||||
|
type: 'updateSystemVersion',
|
||||||
|
message: '',
|
||||||
|
status: code === 0 ? 'success' : 'failed',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ import uniq from 'lodash/uniq';
|
||||||
import pickBy from 'lodash/pickBy';
|
import pickBy from 'lodash/pickBy';
|
||||||
import isNil from 'lodash/isNil';
|
import isNil from 'lodash/isNil';
|
||||||
import { shareStore } from '../shared/store';
|
import { shareStore } from '../shared/store';
|
||||||
import { t } from '../shared/i18n';
|
import { t, tf } from '../shared/i18n';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export default class UserService {
|
export default class UserService {
|
||||||
|
|
@ -67,7 +67,7 @@ export default class UserService {
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
code: 410,
|
code: 410,
|
||||||
message: `失败次数过多,请${waitTime}秒后重试`,
|
message: tf('失败次数过多,请%s秒后重试', waitTime),
|
||||||
data: waitTime,
|
data: waitTime,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -128,10 +128,19 @@ export default class UserService {
|
||||||
isTwoFactorChecking: false,
|
isTwoFactorChecking: false,
|
||||||
});
|
});
|
||||||
this.notificationService.notify(
|
this.notificationService.notify(
|
||||||
'登录通知',
|
t('登录通知'),
|
||||||
`你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}在 ${address} ${
|
t('你于') +
|
||||||
req.platform
|
dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss') +
|
||||||
}端 登录成功,ip地址 ${ip}`,
|
t('在') +
|
||||||
|
address +
|
||||||
|
' ' +
|
||||||
|
req.platform +
|
||||||
|
t('端') +
|
||||||
|
' ' +
|
||||||
|
t('登录成功') +
|
||||||
|
t(',ip地址') +
|
||||||
|
' ' +
|
||||||
|
ip,
|
||||||
);
|
);
|
||||||
await this.insertDb({
|
await this.insertDb({
|
||||||
type: AuthDataType.loginLog,
|
type: AuthDataType.loginLog,
|
||||||
|
|
@ -164,10 +173,19 @@ export default class UserService {
|
||||||
platform: req.platform,
|
platform: req.platform,
|
||||||
});
|
});
|
||||||
this.notificationService.notify(
|
this.notificationService.notify(
|
||||||
'登录通知',
|
t('登录通知'),
|
||||||
`你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}在 ${address} ${
|
t('你于') +
|
||||||
req.platform
|
dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss') +
|
||||||
}端 登录失败,ip地址 ${ip}`,
|
t('在') +
|
||||||
|
address +
|
||||||
|
' ' +
|
||||||
|
req.platform +
|
||||||
|
t('端') +
|
||||||
|
' ' +
|
||||||
|
t('登录失败') +
|
||||||
|
t(',ip地址') +
|
||||||
|
' ' +
|
||||||
|
ip,
|
||||||
);
|
);
|
||||||
await this.insertDb({
|
await this.insertDb({
|
||||||
type: AuthDataType.loginLog,
|
type: AuthDataType.loginLog,
|
||||||
|
|
@ -184,11 +202,11 @@ export default class UserService {
|
||||||
const waitTime = Math.round(Math.pow(3, retries + 1));
|
const waitTime = Math.round(Math.pow(3, retries + 1));
|
||||||
return {
|
return {
|
||||||
code: 410,
|
code: 410,
|
||||||
message: `失败次数过多,请${waitTime}秒后重试`,
|
message: tf('失败次数过多,请%s秒后重试', waitTime),
|
||||||
data: waitTime,
|
data: waitTime,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return { code: 400, message: config.authError };
|
return { code: 400, message: t('错误的用户名密码,请重试') };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -389,8 +407,8 @@ export default class UserService {
|
||||||
const code = Math.random().toString().slice(-6);
|
const code = Math.random().toString().slice(-6);
|
||||||
const isSuccess = await this.notificationService.testNotify(
|
const isSuccess = await this.notificationService.testNotify(
|
||||||
notificationInfo,
|
notificationInfo,
|
||||||
'青龙',
|
t('青龙'),
|
||||||
`【蛟龙】测试通知 https://t.me/jiao_long`,
|
t('【蛟龙】测试通知 https://t.me/jiao_long'),
|
||||||
);
|
);
|
||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
const result = await this.updateAuthDb({
|
const result = await this.updateAuthDb({
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,55 @@ const messages: Record<string, Record<string, string>> = {
|
||||||
'订阅执行完成': 'Subscription completed',
|
'订阅执行完成': 'Subscription completed',
|
||||||
'wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行': 'wxPusher requires at least one of TopicIds or Uids',
|
'wxPusher 服务的 TopicIds 和 Uids 至少配置一个才行': 'wxPusher requires at least one of TopicIds or Uids',
|
||||||
'Url 或者 Body 中必须包含 $title': 'Url or Body must contain $title',
|
'Url 或者 Body 中必须包含 $title': 'Url or Body must contain $title',
|
||||||
|
'绝对路径必须在日志目录内或使用 /dev/null':
|
||||||
|
'Absolute path must be within log directory or use /dev/null',
|
||||||
|
'请先登录!': 'Please login first!',
|
||||||
|
'运行中...': 'Running...',
|
||||||
|
'日志不存在...': 'Log does not exist...',
|
||||||
|
'未分类': 'Uncategorized',
|
||||||
|
'任务重复运行': 'Duplicate task execution',
|
||||||
|
'日志设置为忽略': 'Log set to ignore',
|
||||||
|
'定时规则不能为空': 'Schedule rule cannot be empty',
|
||||||
|
'无效的定时规则': 'Invalid schedule rule',
|
||||||
|
'日志名称只能包含字母、数字、下划线和连字符':
|
||||||
|
'Log name can only contain letters, numbers, underscores, and hyphens',
|
||||||
|
'日志名称不能超过100个字符': 'Log name cannot exceed 100 characters',
|
||||||
|
'错误的用户名密码,请重试': 'Incorrect username or password, please try again',
|
||||||
|
'青龙快讯': 'QingLong',
|
||||||
|
'登录通知': 'Login Notification',
|
||||||
|
'你于': 'You at ',
|
||||||
|
'在': ' in ',
|
||||||
|
端: '',
|
||||||
|
登录失败: 'login failed',
|
||||||
|
',ip地址': ', IP: ',
|
||||||
|
'任务#%s': 'Task#%s',
|
||||||
|
安装: 'Install',
|
||||||
|
删除: 'Uninstall',
|
||||||
|
成功: 'Succeeded',
|
||||||
|
失败: 'Failed',
|
||||||
|
'失败次数过多,请%s秒后重试':
|
||||||
|
'Too many failed attempts, please retry in %s seconds',
|
||||||
|
智能助手: 'Smart Assistant',
|
||||||
|
更多: 'More',
|
||||||
|
'开始%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',
|
||||||
|
'检测到已经安装 %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',
|
||||||
|
'开始%s依赖 %s,开始时间 %s\n\n':
|
||||||
|
'Start %s dependency %s, start time %s\n\n',
|
||||||
|
'依赖%s%s,结束时间 %s,耗时 %s 秒':
|
||||||
|
'Dependency %s%s, end time %s, elapsed %s seconds',
|
||||||
|
'任务:%s,命令:%s,定时:%s,处于运行中的超过 %d 个,请检查定时设置':
|
||||||
|
'Task: %s, command: %s, schedule: %s, more than %d instances running, please check schedule settings',
|
||||||
|
青龙: 'QingLong',
|
||||||
|
'【蛟龙】测试通知 https://t.me/jiao_long':
|
||||||
|
'[JiaoLong] Test notification https://t.me/jiao_long',
|
||||||
|
'生成token': 'Generate token',
|
||||||
|
'删除日志': 'Delete logs',
|
||||||
|
'## 开始执行... %s\n': '## Start executing... %s\n',
|
||||||
|
'执行before命令...': 'Execute before command...',
|
||||||
|
'执行after命令...': 'Execute after command...',
|
||||||
|
'## 执行结束... %s 耗时 %s 秒': '## Execution finished... %s elapsed %s seconds',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -100,3 +149,10 @@ export function t(key: string, lang?: string): string {
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tf(key: string, ...args: (string | number)[]): string {
|
||||||
|
return args.reduce<string>(
|
||||||
|
(str, arg) => str.replace(/%s|%d/, String(arg)),
|
||||||
|
t(key),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import { AuthDataType, SystemModel } from '../data/system';
|
||||||
import Logger from '../loaders/logger';
|
import Logger from '../loaders/logger';
|
||||||
import { Dependence } from '../data/dependence';
|
import { Dependence } from '../data/dependence';
|
||||||
import NotificationService from '../services/notify';
|
import NotificationService from '../services/notify';
|
||||||
|
import { t, tf } from '../shared/i18n';
|
||||||
import {
|
import {
|
||||||
ICronFn,
|
ICronFn,
|
||||||
IDependencyFn,
|
IDependencyFn,
|
||||||
|
|
@ -152,8 +153,14 @@ class TaskLimit {
|
||||||
this.repeatCronNotifyMap.set(cron.id, repeatTimes + 1);
|
this.repeatCronNotifyMap.set(cron.id, repeatTimes + 1);
|
||||||
this.client.systemNotify(
|
this.client.systemNotify(
|
||||||
{
|
{
|
||||||
title: '任务重复运行',
|
title: t('任务重复运行'),
|
||||||
content: `任务:${cron.name},命令:${cron.command},定时:${cron.schedule},处于运行中的超过 5 个,请检查定时设置`,
|
content: tf(
|
||||||
|
'任务:%s,命令:%s,定时:%s,处于运行中的超过 %d 个,请检查定时设置',
|
||||||
|
cron.name || '',
|
||||||
|
cron.command || '',
|
||||||
|
cron.schedule || '',
|
||||||
|
5,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
(err, res) => {
|
(err, res) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
|
|
|
||||||
|
|
@ -594,5 +594,11 @@
|
||||||
"黑名单": "Blacklist",
|
"黑名单": "Blacklist",
|
||||||
"默认为 CPU 个数": "Default is the number of CPUs",
|
"默认为 CPU 个数": "Default is the number of CPUs",
|
||||||
",保存后不可恢复": ", it can't be recovered after saving.",
|
",保存后不可恢复": ", it can't be recovered after saving.",
|
||||||
",删除后不可恢复": ", it can't be recovered after deletion"
|
",删除后不可恢复": ", it can't be recovered after deletion",
|
||||||
|
"日志不存在": "Log does not exist",
|
||||||
|
"日志设置为忽略": "Log set to ignore",
|
||||||
|
"确认保存": "Confirm to save",
|
||||||
|
"上传失败": "Upload failed",
|
||||||
|
"成功上传": "Successfully uploaded",
|
||||||
|
"个环境变量": " environment variables"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -594,5 +594,11 @@
|
||||||
"黑名单": "黑名单",
|
"黑名单": "黑名单",
|
||||||
"默认为 CPU 个数": "默认为 CPU 个数",
|
"默认为 CPU 个数": "默认为 CPU 个数",
|
||||||
",保存后不可恢复": ",保存后不可恢复",
|
",保存后不可恢复": ",保存后不可恢复",
|
||||||
",删除后不可恢复": ",删除后不可恢复"
|
",删除后不可恢复": ",删除后不可恢复",
|
||||||
|
"日志不存在": "日志不存在",
|
||||||
|
"日志设置为忽略": "日志设置为忽略",
|
||||||
|
"确认保存": "确认保存",
|
||||||
|
"上传失败": "上传失败",
|
||||||
|
"成功上传": "成功上传",
|
||||||
|
"个环境变量": "个环境变量"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ const CronDetailModal = ({
|
||||||
|
|
||||||
const saveFile = () => {
|
const saveFile = () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: `确认保存`,
|
title: intl.get('确认保存'),
|
||||||
content: (
|
content: (
|
||||||
<>
|
<>
|
||||||
{intl.get('确认保存文件')}
|
{intl.get('确认保存文件')}
|
||||||
|
|
@ -323,7 +323,7 @@ const CronDetailModal = ({
|
||||||
.then(({ code, data }) => {
|
.then(({ code, data }) => {
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
setValue(content);
|
setValue(content);
|
||||||
message.success(`保存成功`);
|
message.success(intl.get('保存成功'));
|
||||||
}
|
}
|
||||||
resolve(null);
|
resolve(null);
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -46,17 +46,15 @@ const CronLogModal = ({
|
||||||
}
|
}
|
||||||
request
|
request
|
||||||
.get(logUrl ? logUrl : `${config.apiPrefix}crons/${cron.id}/log`)
|
.get(logUrl ? logUrl : `${config.apiPrefix}crons/${cron.id}/log`)
|
||||||
.then(({ code, data }) => {
|
.then(({ code, data, logStatus }) => {
|
||||||
if (
|
if (
|
||||||
code === 200 &&
|
code === 200 &&
|
||||||
localStorage.getItem("logCron") === uniqPath &&
|
localStorage.getItem("logCron") === uniqPath &&
|
||||||
data !== value
|
data !== value
|
||||||
) {
|
) {
|
||||||
const log = data as string;
|
const log = (data as string) || intl.get("暂无日志");
|
||||||
setValue(log || intl.get("暂无日志"));
|
setValue(log);
|
||||||
const hasNext = Boolean(
|
const hasNext = logStatus === 'running';
|
||||||
log && !logEnded(log) && !log.includes("日志不存在") && !log.includes("日志设置为忽略"),
|
|
||||||
);
|
|
||||||
if (!hasNext && !logEnded(value) && value !== intl.get("启动中...")) {
|
if (!hasNext && !logEnded(value) && value !== intl.get("启动中...")) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
autoScroll();
|
autoScroll();
|
||||||
|
|
|
||||||
|
|
@ -465,49 +465,33 @@ const Dependence = () => {
|
||||||
}, [logDependence]);
|
}, [logDependence]);
|
||||||
|
|
||||||
const handleMessage = useCallback((payload: any) => {
|
const handleMessage = useCallback((payload: any) => {
|
||||||
const { message, references } = payload;
|
const { references, status } = payload;
|
||||||
let status: number | undefined = undefined;
|
if (typeof status !== 'number' || !references?.length) return;
|
||||||
if (message.includes('开始时间') && references.length > 0) {
|
|
||||||
status = message.includes('安装') ? Status.安装中 : Status.删除中;
|
|
||||||
}
|
|
||||||
if (message.includes('结束时间') && references.length > 0) {
|
|
||||||
if (message.includes('安装')) {
|
|
||||||
status = message.includes('成功') ? Status.已安装 : Status.安装失败;
|
|
||||||
} else {
|
|
||||||
status = message.includes('成功') ? Status.已删除 : Status.删除失败;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status === Status.已删除) {
|
if (status === Status.已删除) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setValue((p) => {
|
setValue((p) => {
|
||||||
const _result = [...p];
|
const _result = [...p];
|
||||||
for (let i = 0; i < references.length; i++) {
|
for (const refId of references) {
|
||||||
const index = p.findIndex((x) => x.id === references[i]);
|
const index = p.findIndex((x) => x.id === refId);
|
||||||
if (index !== -1) {
|
if (index !== -1) _result.splice(index, 1);
|
||||||
_result.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return _result;
|
|
||||||
});
|
|
||||||
}, 300);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (typeof status === 'number') {
|
|
||||||
setValue((p) => {
|
|
||||||
const result = [...p];
|
|
||||||
for (let i = 0; i < references.length; i++) {
|
|
||||||
const index = p.findIndex((x) => x.id === references[i]);
|
|
||||||
if (index !== -1) {
|
|
||||||
result.splice(index, 1, {
|
|
||||||
...p[index],
|
|
||||||
status,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
return _result;
|
||||||
return result;
|
});
|
||||||
});
|
}, 300);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setValue((p) => {
|
||||||
|
const result = [...p];
|
||||||
|
for (const refId of references) {
|
||||||
|
const index = p.findIndex((x) => x.id === refId);
|
||||||
|
if (index !== -1) {
|
||||||
|
result.splice(index, 1, { ...p[index], status });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,11 @@ const DependenceLogModal = ({
|
||||||
) {
|
) {
|
||||||
const log = (data?.log || []).join('') as string;
|
const log = (data?.log || []).join('') as string;
|
||||||
setValue(log);
|
setValue(log);
|
||||||
setExecuting(!log.includes('结束时间'));
|
const dbStatus = data?.status as number | undefined;
|
||||||
setIsRemoveFailed(log.includes('删除失败'));
|
setExecuting(
|
||||||
|
dbStatus === Status.安装中 || dbStatus === Status.删除中,
|
||||||
|
);
|
||||||
|
setIsRemoveFailed(dbStatus === Status.删除失败);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
|
@ -94,16 +97,17 @@ const DependenceLogModal = ({
|
||||||
}, [dependence]);
|
}, [dependence]);
|
||||||
|
|
||||||
const handleMessage = (payload: any) => {
|
const handleMessage = (payload: any) => {
|
||||||
const { message, references } = payload;
|
const { message, references, status } = payload;
|
||||||
if (
|
if (
|
||||||
references.length > 0 &&
|
!references?.length ||
|
||||||
references.includes(dependence.id) &&
|
!references.includes(dependence.id)
|
||||||
[Status.删除中, Status.安装中].includes(dependence.status)
|
) return;
|
||||||
) {
|
|
||||||
if (message.includes('结束时间')) {
|
if (typeof status === 'number') {
|
||||||
setExecuting(false);
|
setExecuting(status === Status.安装中 || status === Status.删除中);
|
||||||
setIsRemoveFailed(message.includes('删除失败'));
|
setIsRemoveFailed(status === Status.删除失败);
|
||||||
}
|
}
|
||||||
|
if (message) {
|
||||||
setValue((p) => `${p}${message}`);
|
setValue((p) => `${p}${message}`);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
2
src/pages/env/index.tsx
vendored
2
src/pages/env/index.tsx
vendored
|
|
@ -603,7 +603,7 @@ const Env = () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
message.success(`成功上传${data.length}个环境变量`);
|
message.success(`${intl.get('成功上传')}${data.length}${intl.get('个环境变量')}`);
|
||||||
getEnvs();
|
getEnvs();
|
||||||
}
|
}
|
||||||
setImportLoading(false);
|
setImportLoading(false);
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ const Log = () => {
|
||||||
|
|
||||||
const deleteFile = () => {
|
const deleteFile = () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: `确认删除`,
|
title: intl.get('确认删除'),
|
||||||
content: (
|
content: (
|
||||||
<>
|
<>
|
||||||
{intl.get('确认删除')}
|
{intl.get('确认删除')}
|
||||||
|
|
@ -155,7 +155,7 @@ const Log = () => {
|
||||||
})
|
})
|
||||||
.then(({ code }) => {
|
.then(({ code }) => {
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
message.success(`删除成功`);
|
message.success(intl.get('删除成功'));
|
||||||
let newData = [...data];
|
let newData = [...data];
|
||||||
if (currentNode.parent) {
|
if (currentNode.parent) {
|
||||||
newData = depthFirstSearch(
|
newData = depthFirstSearch(
|
||||||
|
|
|
||||||
|
|
@ -249,7 +249,7 @@ const Script = () => {
|
||||||
|
|
||||||
const saveFile = () => {
|
const saveFile = () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: `确认保存`,
|
title: intl.get('确认保存'),
|
||||||
content: (
|
content: (
|
||||||
<>
|
<>
|
||||||
{intl.get('确认保存文件')}
|
{intl.get('确认保存文件')}
|
||||||
|
|
@ -273,7 +273,7 @@ const Script = () => {
|
||||||
})
|
})
|
||||||
.then(({ code, data }) => {
|
.then(({ code, data }) => {
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
message.success(`保存成功`);
|
message.success(intl.get('保存成功'));
|
||||||
setValue(content);
|
setValue(content);
|
||||||
handleIsEditing(currentNode.title, false);
|
handleIsEditing(currentNode.title, false);
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +287,7 @@ const Script = () => {
|
||||||
|
|
||||||
const deleteFile = () => {
|
const deleteFile = () => {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: `确认删除`,
|
title: intl.get('确认删除'),
|
||||||
content: (
|
content: (
|
||||||
<>
|
<>
|
||||||
{intl.get('确认删除')}
|
{intl.get('确认删除')}
|
||||||
|
|
@ -311,7 +311,7 @@ const Script = () => {
|
||||||
})
|
})
|
||||||
.then(({ code }) => {
|
.then(({ code }) => {
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
message.success(`删除成功`);
|
message.success(intl.get('删除成功'));
|
||||||
let newData = [...data];
|
let newData = [...data];
|
||||||
if (currentNode.parent) {
|
if (currentNode.parent) {
|
||||||
newData = depthFirstSearch(
|
newData = depthFirstSearch(
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
||||||
const [updateLoading, setUpdateLoading] = useState(false);
|
const [updateLoading, setUpdateLoading] = useState(false);
|
||||||
const [value, setValue] = useState("");
|
const [value, setValue] = useState("");
|
||||||
const modalRef = useRef<any>();
|
const modalRef = useRef<any>();
|
||||||
|
const lastStatusRef = useRef<string | undefined>();
|
||||||
|
|
||||||
const checkUpgrade = () => {
|
const checkUpgrade = () => {
|
||||||
if (updateLoading) return;
|
if (updateLoading) return;
|
||||||
|
|
@ -166,7 +167,7 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!value) return;
|
if (!value) return;
|
||||||
const updateFailed = value.includes("失败,请检查");
|
const updateFailed = lastStatusRef.current === 'failed';
|
||||||
|
|
||||||
modalRef.current.update({
|
modalRef.current.update({
|
||||||
maskClosable: updateFailed,
|
maskClosable: updateFailed,
|
||||||
|
|
@ -184,26 +185,29 @@ const CheckUpdate = ({ systemInfo }: any) => {
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
const handleMessage = useCallback((payload: any) => {
|
const handleMessage = useCallback((payload: any) => {
|
||||||
let { message: _message } = payload;
|
const { message: _message, status } = payload;
|
||||||
const updateFailed = _message.includes("失败,请检查");
|
|
||||||
|
|
||||||
if (updateFailed) {
|
if (status === 'failed') {
|
||||||
|
lastStatusRef.current = 'failed';
|
||||||
message.error(intl.get("更新失败,请检查网络及日志或稍后再试"));
|
message.error(intl.get("更新失败,请检查网络及日志或稍后再试"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (status === 'success') {
|
||||||
|
lastStatusRef.current = 'success';
|
||||||
|
setTimeout(() => {
|
||||||
|
showReloadModal();
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
document
|
document
|
||||||
.querySelector("#log-identifier")
|
.querySelector("#log-identifier")
|
||||||
?.scrollIntoView({ behavior: "smooth" });
|
?.scrollIntoView({ behavior: "smooth" });
|
||||||
}, 600);
|
}, 600);
|
||||||
|
|
||||||
if (_message.includes("更新包下载成功")) {
|
if (_message) {
|
||||||
setTimeout(() => {
|
setValue((p) => `${p}${_message}`);
|
||||||
showReloadModal();
|
|
||||||
}, 1000);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setValue((p) => `${p}${_message}`);
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
|
||||||
|
|
@ -75,12 +75,9 @@ const Dependence = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleMessage = (payload: any) => {
|
const handleMessage = (payload: any) => {
|
||||||
const { message } = payload;
|
const { message, status } = payload;
|
||||||
setLog((p) => `${p}${message}`);
|
if (message) setLog((p) => `${p}${message}`);
|
||||||
if (
|
if (status === 'completed') {
|
||||||
message.includes('update node mirror end') ||
|
|
||||||
message.includes('update linux mirror end')
|
|
||||||
) {
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -109,7 +106,7 @@ const Dependence = () => {
|
||||||
ws.subscribe('updateLinuxMirror', handleMessage);
|
ws.subscribe('updateLinuxMirror', handleMessage);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
ws.subscribe('updateNodeMirror', handleMessage);
|
ws.unsubscribe('updateNodeMirror', handleMessage);
|
||||||
ws.unsubscribe('updateLinuxMirror', handleMessage);
|
ws.unsubscribe('updateLinuxMirror', handleMessage);
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
|
||||||
|
|
@ -379,7 +379,7 @@ const Other = ({
|
||||||
showReloadModal();
|
showReloadModal();
|
||||||
}
|
}
|
||||||
if (file.status === 'error') {
|
if (file.status === 'error') {
|
||||||
message.error('上传失败');
|
message.error(intl.get('上传失败'));
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
name="data"
|
name="data"
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ const SystemLog = ({ height, theme }: any) => {
|
||||||
|
|
||||||
const deleteLog = () => {
|
const deleteLog = () => {
|
||||||
request.delete(`${config.apiPrefix}system/log`).then((x) => {
|
request.delete(`${config.apiPrefix}system/log`).then((x) => {
|
||||||
message.success('删除成功');
|
message.success(intl.get('删除成功'));
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -205,21 +205,47 @@ const SubscriptionModal = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const parseArgs = (text: string): string[] => {
|
||||||
|
const args: string[] = [];
|
||||||
|
let current = '';
|
||||||
|
let inDouble = false;
|
||||||
|
let inSingle = false;
|
||||||
|
let justClosed = false;
|
||||||
|
for (const ch of text) {
|
||||||
|
if (inDouble) {
|
||||||
|
if (ch === '"') { inDouble = false; justClosed = true; continue; }
|
||||||
|
current += ch;
|
||||||
|
} else if (inSingle) {
|
||||||
|
if (ch === "'") { inSingle = false; justClosed = true; continue; }
|
||||||
|
current += ch;
|
||||||
|
} else if (ch === '"') {
|
||||||
|
inDouble = true;
|
||||||
|
justClosed = false;
|
||||||
|
} else if (ch === "'") {
|
||||||
|
inSingle = true;
|
||||||
|
justClosed = false;
|
||||||
|
} else if (ch === ' ' || ch === '\t') {
|
||||||
|
if (current || justClosed) { args.push(current); current = ''; justClosed = false; }
|
||||||
|
} else {
|
||||||
|
current += ch;
|
||||||
|
justClosed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (current || justClosed) args.push(current);
|
||||||
|
return args;
|
||||||
|
};
|
||||||
|
|
||||||
const onPaste = useCallback((e: any) => {
|
const onPaste = useCallback((e: any) => {
|
||||||
const text = e.clipboardData.getData('text') as string;
|
const text = e.clipboardData.getData('text') as string;
|
||||||
if (text.startsWith('ql ')) {
|
if (text.startsWith('ql ')) {
|
||||||
const [
|
const args = parseArgs(text);
|
||||||
,
|
const type = args[1];
|
||||||
type,
|
const url = args[2] || '';
|
||||||
url,
|
const whitelist = args[3] || '';
|
||||||
whitelist,
|
const blacklist = args[4] || '';
|
||||||
blacklist,
|
const dependences = args[5] || '';
|
||||||
dependences,
|
const branch = args[6] || '';
|
||||||
branch,
|
const extensions = args[7] || '';
|
||||||
extensions,
|
|
||||||
] = text
|
|
||||||
.split(' ')
|
|
||||||
.map((x) => x.trim().replace(/\"/g, '').replace(/\'/, ''));
|
|
||||||
const _type =
|
const _type =
|
||||||
type === 'raw'
|
type === 'raw'
|
||||||
? 'file'
|
? 'file'
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user