Compare commits

...
29 Commits
Author SHA1 Message Date
whyour 88cf671465 更新版本v2.14.6 2022-09-29 23:06:31 +08:00
whyour 29f082dea2 增加config资源配置 2022-09-29 23:03:22 +08:00
whyour 9a55968ed6 修改资源异常推送 2022-09-29 13:29:22 +08:00
whyour 6ec6e25855 修改资源提示 2022-09-29 00:59:27 +08:00
whyour af48bc378b 修复获取cpu占用 2022-09-29 00:57:31 +08:00
whyour 3f5ae4bcb9 修复 echo 2022-09-29 00:44:07 +08:00
whyour c6624e9001 增加资源占用提示 2022-09-29 00:43:07 +08:00
whyour 5530ce76e3 添加系统资源消耗提示 2022-09-29 00:32:17 +08:00
whyour 654b51e476 修复脚本和日志搜索逻辑 2022-09-25 21:03:11 +08:00
whyour 6428ac3624 修复SplitPane类型错误 2022-09-25 14:02:27 +08:00
whyour c36450f436 修复ant-tree高度获取 2022-09-25 13:38:10 +08:00
whyour dcea231249 更新版本 v2.14.5 2022-09-24 21:00:47 +08:00
whyour f236119bd6 修改输入框自动填充样式 2022-09-24 14:40:13 +08:00
whyour cb870fad85 修改检查更新逻辑 2022-09-24 14:20:35 +08:00
whyour 44e2caedfc 修改更新日志清除评率 2022-09-24 13:59:56 +08:00
whyour c0b5192296 修改移动端脚本高亮 2022-09-24 11:27:16 +08:00
whyour ba43882c0b 修复脚本管理删除 2022-09-23 23:16:57 +08:00
whyour dfc706e16d 日志管理支持删除日志文件和目录 2022-09-23 20:09:10 +08:00
whyour 25b03d4345 脚本管理支持删除文件夹 2022-09-23 19:12:51 +08:00
whyour 4e8f36d9a4 修复登录错误提示 2022-09-23 17:44:48 +08:00
whyour 8f4d67ffa7 修改task命令ID获取 2022-09-23 14:37:56 +08:00
whyour ad47277149 修复登录验证 2022-09-23 12:15:15 +08:00
whyour 98c2a37ab6 修复初始化逻辑 2022-09-23 00:17:53 +08:00
whyour f2fea47336 重构前端错误提示 2022-09-22 23:59:23 +08:00
whyour e274d3e2f9 sentry增加版本号 2022-09-22 12:14:42 +08:00
whyour 36f4c3c02c 修改任务启动参数 2022-09-21 21:28:31 +08:00
whyour ae891f8e55 修复docker启动逻辑 2022-09-21 17:42:13 +08:00
whyour c874dc9705 更新readme 2022-09-21 16:03:53 +08:00
whyour 23bfbeb995 修改新建订阅提示 2022-09-21 14:54:45 +08:00
62 changed files with 1971 additions and 1799 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
<p align="center"> <p align="center">
<a href="https://github.com/whyour/qinglong"> <a href="https://github.com/whyour/qinglong">
<img width="150" src="https://z3.ax1x.com/2021/11/18/I7MpAe.png"> <img width="150" src="https://user-images.githubusercontent.com/22700758/191449379-f9f56204-0e31-4a16-be5a-331f52696a73.png">
</a> </a>
</p> </p>
@@ -183,7 +183,7 @@ task <file_path> desi <env_name> <account_number>
- [crontab-ui](https://github.com/alseambusher/crontab-ui) - [crontab-ui](https://github.com/alseambusher/crontab-ui)
- [Ant Design](https://ant.design) - [Ant Design](https://ant.design)
- [Ant Design Pro](https://pro.ant.design/) - [Ant Design Pro](https://pro.ant.design/)
- [Umijs3.0](https://umijs.org) - [Umijs](https://umijs.org)
- [darkreader](https://github.com/darkreader/darkreader) - [darkreader](https://github.com/darkreader/darkreader)
- [admin-server](https://github.com/sunpu007/admin-server) - [admin-server](https://github.com/sunpu007/admin-server)
+2 -2
View File
@@ -1,6 +1,6 @@
<p align="center"> <p align="center">
<a href="https://github.com/whyour/qinglong"> <a href="https://github.com/whyour/qinglong">
<img width="150" src="https://z3.ax1x.com/2021/11/18/I7MpAe.png"> <img width="150" src="https://user-images.githubusercontent.com/22700758/191449379-f9f56204-0e31-4a16-be5a-331f52696a73.png">
</a> </a>
</p> </p>
@@ -183,7 +183,7 @@ task <file_path> desi <env_name> <account_number>
- [crontab-ui](https://github.com/alseambusher/crontab-ui) - [crontab-ui](https://github.com/alseambusher/crontab-ui)
- [Ant Design](https://ant.design) - [Ant Design](https://ant.design)
- [Ant Design Pro](https://pro.ant.design/) - [Ant Design Pro](https://pro.ant.design/)
- [Umijs3.0](https://umijs.org) - [Umijs](https://umijs.org)
- [darkreader](https://github.com/darkreader/darkreader) - [darkreader](https://github.com/darkreader/darkreader)
- [admin-server](https://github.com/sunpu007/admin-server) - [admin-server](https://github.com/sunpu007/admin-server)
+32 -1
View File
@@ -3,8 +3,9 @@ import { Container } from 'typedi';
import { Logger } from 'winston'; import { Logger } from 'winston';
import * as fs from 'fs'; import * as fs from 'fs';
import config from '../config'; import config from '../config';
import { getFileContentByName, readDirs } from '../config/util'; import { emptyDir, getFileContentByName, readDirs } from '../config/util';
import { join } from 'path'; import { join } from 'path';
import { celebrate, Joi } from 'celebrate';
const route = Router(); const route = Router();
const blacklist = ['.tmp']; const blacklist = ['.tmp'];
@@ -45,4 +46,34 @@ export default (app: Router) => {
} }
}, },
); );
route.delete(
'/',
celebrate({
body: Joi.object({
filename: Joi.string().required(),
path: Joi.string().allow(''),
type: Joi.string().optional()
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
try {
let { filename, path, type } = req.body as {
filename: string;
path: string;
type: string;
};
const filePath = join(config.logPath, path, filename);
if (type === 'directory') {
emptyDir(filePath);
} else {
fs.unlinkSync(filePath);
}
res.send({ code: 200 });
} catch (e) {
return next(e);
}
},
);
}; };
+8 -1
View File
@@ -4,6 +4,7 @@ import {
readDirs, readDirs,
getLastModifyFilePath, getLastModifyFilePath,
readDir, readDir,
emptyDir,
} from '../config/util'; } from '../config/util';
import { Router, Request, Response, NextFunction } from 'express'; import { Router, Request, Response, NextFunction } from 'express';
import { Container } from 'typedi'; import { Container } from 'typedi';
@@ -169,17 +170,23 @@ export default (app: Router) => {
body: Joi.object({ body: Joi.object({
filename: Joi.string().required(), filename: Joi.string().required(),
path: Joi.string().allow(''), path: Joi.string().allow(''),
type: Joi.string().optional()
}), }),
}), }),
async (req: Request, res: Response, next: NextFunction) => { async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger'); const logger: Logger = Container.get('logger');
try { try {
let { filename, path } = req.body as { let { filename, path, type } = req.body as {
filename: string; filename: string;
path: string; path: string;
type: string;
}; };
const filePath = join(config.scriptPath, path, filename); const filePath = join(config.scriptPath, path, filename);
if (type === 'directory') {
emptyDir(filePath);
} else {
fs.unlinkSync(filePath); fs.unlinkSync(filePath);
}
res.send({ code: 200 }); res.send({ code: 200 });
} catch (e) { } catch (e) {
return next(e); return next(e);
+1 -1
View File
@@ -17,7 +17,7 @@ async function startServer() {
const server = app const server = app
.listen(config.port, () => { .listen(config.port, () => {
Logger.debug(`✌️ Back server launched on port ${config.port}`); Logger.debug(`✌️ 后端服务启动成功!`);
}) })
.on('error', (err) => { .on('error', (err) => {
Logger.error(err); Logger.error(err);
+1 -1
View File
@@ -11,7 +11,7 @@ if (!process.env.QL_DIR) {
if (qlHomePath.endsWith('/static/')) { if (qlHomePath.endsWith('/static/')) {
qlHomePath = path.join(qlHomePath, '../'); qlHomePath = path.join(qlHomePath, '../');
} }
process.env.QL_DIR = qlHomePath; process.env.QL_DIR = qlHomePath.replace(/\/$/g, '');
} }
const lastVersionFile = `http://qn.whyour.cn/version.ts?v=${Date.now()}`; const lastVersionFile = `http://qn.whyour.cn/version.ts?v=${Date.now()}`;
+29 -7
View File
@@ -302,7 +302,6 @@ export function readDirs(
title: file, title: file,
key, key,
type: 'directory', type: 'directory',
disabled: true,
parent: relativePath, parent: relativePath,
children: readDirs(subPath, baseDir).sort( children: readDirs(subPath, baseDir).sort(
(a: any, b: any) => (a: any, b: any) =>
@@ -313,6 +312,7 @@ export function readDirs(
return { return {
title: file, title: file,
type: 'file', type: 'file',
isLeaf: true,
key, key,
parent: relativePath, parent: relativePath,
}; };
@@ -345,6 +345,20 @@ export function readDir(
return result; return result;
} }
export function emptyDir(path: string) {
const files = fs.readdirSync(path);
files.forEach((file) => {
const filePath = `${path}/${file}`;
const stats = fs.statSync(filePath);
if (stats.isDirectory()) {
emptyDir(filePath);
} else {
fs.unlinkSync(filePath);
}
});
fs.rmdirSync(path);
}
export function promiseExec(command: string): Promise<string> { export function promiseExec(command: string): Promise<string> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
exec( exec(
@@ -365,7 +379,8 @@ export function parseHeaders(headers: string) {
let val; let val;
let i; let i;
headers && headers.split('\n').forEach(function parser(line) { headers &&
headers.split('\n').forEach(function parser(line) {
i = line.indexOf(':'); i = line.indexOf(':');
key = line.substring(0, i).trim().toLowerCase(); key = line.substring(0, i).trim().toLowerCase();
val = line.substring(i + 1).trim(); val = line.substring(i + 1).trim();
@@ -378,9 +393,15 @@ export function parseHeaders(headers: string) {
}); });
return parsed; return parsed;
}; }
export function parseBody(body: string, contentType: 'application/json' | 'multipart/form-data' | 'application/x-www-form-urlencoded') { export function parseBody(
body: string,
contentType:
| 'application/json'
| 'multipart/form-data'
| 'application/x-www-form-urlencoded',
) {
if (!body) return ''; if (!body) return '';
const parsed: any = {}; const parsed: any = {};
@@ -388,7 +409,8 @@ export function parseBody(body: string, contentType: 'application/json' | 'multi
let val; let val;
let i; let i;
body && body.split('\n').forEach(function parser(line) { body &&
body.split('\n').forEach(function parser(line) {
i = line.indexOf(':'); i = line.indexOf(':');
key = line.substring(0, i).trim().toLowerCase(); key = line.substring(0, i).trim().toLowerCase();
val = line.substring(i + 1).trim(); val = line.substring(i + 1).trim();
@@ -403,7 +425,7 @@ export function parseBody(body: string, contentType: 'application/json' | 'multi
switch (contentType) { switch (contentType) {
case 'multipart/form-data': case 'multipart/form-data':
return Object.keys(parsed).reduce((p, c) => { return Object.keys(parsed).reduce((p, c) => {
p.append(c, parsed[c]) p.append(c, parsed[c]);
return p; return p;
}, new FormData()); }, new FormData());
case 'application/x-www-form-urlencoded': case 'application/x-www-form-urlencoded':
@@ -413,4 +435,4 @@ export function parseBody(body: string, contentType: 'application/json' | 'multi
} }
return parsed; return parsed;
}; }
+2 -4
View File
@@ -18,13 +18,12 @@ export default async () => {
tokenCommand = `node ${tokenFile}`; tokenCommand = `node ${tokenFile}`;
} }
const cron = { const cron = {
id: 'token', id: NaN,
name: '生成token', name: '生成token',
command: tokenCommand, command: tokenCommand,
}; };
scheduleService.createIntervalTask(cron as any, { scheduleService.createIntervalTask(cron, {
days: 28, days: 28,
runImmediately: true,
}); });
// 运行删除日志任务 // 运行删除日志任务
@@ -37,7 +36,6 @@ export default async () => {
}; };
scheduleService.createIntervalTask(cron, { scheduleService.createIntervalTask(cron, {
days: data.info.frequency, days: data.info.frequency,
runImmediately: true,
}); });
} }
+9 -2
View File
@@ -2,16 +2,23 @@ import { Application } from 'express';
import * as Sentry from '@sentry/node'; import * as Sentry from '@sentry/node';
import * as Tracing from '@sentry/tracing'; import * as Tracing from '@sentry/tracing';
import Logger from './logger'; import Logger from './logger';
import config from '../config';
import fs from 'fs';
export default ({ expressApp }: { expressApp: Application }) => { export default ({ expressApp }: { expressApp: Application }) => {
const versionRegx = /.*export const version = \'(.*)\'\;/;
const currentVersionFile = fs.readFileSync(config.versionFile, 'utf8');
const currentVersion = currentVersionFile.match(versionRegx)![1];
Sentry.init({ Sentry.init({
dsn: 'https://f4b5b55fb3c645b29a5dc2d70a1a4ef4@o1098464.ingest.sentry.io/6122819', dsn: 'https://f4b5b55fb3c645b29a5dc2d70a1a4ef4@o1098464.ingest.sentry.io/6122819',
integrations: [ integrations: [
new Sentry.Integrations.Http({ tracing: true }), new Sentry.Integrations.Http({ tracing: true }),
new Tracing.Integrations.Express({ app: expressApp }), new Tracing.Integrations.Express({ app: expressApp }),
], ],
tracesSampleRate: 0.1,
tracesSampleRate: 1.0, release: currentVersion,
}); });
expressApp.use(Sentry.Handlers.requestHandler()); expressApp.use(Sentry.Handlers.requestHandler());
+1 -1
View File
@@ -22,7 +22,7 @@ app
await require('./loaders/sentry').default({ expressApp: app }); await require('./loaders/sentry').default({ expressApp: app });
await require('./loaders/db').default(); await require('./loaders/db').default();
Logger.debug(`✌️ Back server launched on port ${config.publicPort}`); Logger.debug(`✌️ 公共服务启动成功!`);
}) })
.on('error', (err) => { .on('error', (err) => {
Logger.error(err); Logger.error(err);
+1 -5
View File
@@ -44,11 +44,7 @@ app
await require('./loaders/db').default(); await require('./loaders/db').default();
await run(); await run();
Logger.info(` Logger.debug('定时任务服务启动成功!');
################################################
🛡️ Schedule listening on port: ${config.cronPort} 🛡️
################################################
`);
}) })
.on('error', (err) => { .on('error', (err) => {
Logger.error(err); Logger.error(err);
+1 -2
View File
@@ -70,9 +70,8 @@ export default class SystemService {
}; };
await this.scheduleService.cancelIntervalTask(cron); await this.scheduleService.cancelIntervalTask(cron);
if (frequency > 0) { if (frequency > 0) {
await this.scheduleService.createIntervalTask(cron, { this.scheduleService.createIntervalTask(cron, {
days: frequency, days: frequency,
runImmediately: true,
}); });
} }
return { code: 200, data: { ...cron } }; return { code: 200, data: { ...cron } };
+18 -13
View File
@@ -65,15 +65,13 @@ export default class UserService {
return this.initAuthInfo(); return this.initAuthInfo();
} }
if (retries > 2 && Date.now() - lastlogon < Math.pow(3, retries) * 1000) { const retriesTime = Math.pow(3, retries) * 1000;
if (retries > 2 && timestamp - lastlogon < retriesTime) {
const waitTime = Math.ceil((retriesTime - (timestamp - lastlogon)) / 1000);
return { return {
code: 410, code: 410,
message: `失败次数过多,请${Math.round( message: `失败次数过多,请${waitTime}秒后重试`,
(Math.pow(3, retries) * 1000 - Date.now() + lastlogon) / 1000, data: waitTime,
)}秒后重试`,
data: Math.round(
(Math.pow(3, retries) * 1000 - Date.now() + lastlogon) / 1000,
),
}; };
} }
@@ -85,12 +83,12 @@ export default class UserService {
}); });
return { return {
code: 420, code: 420,
message: '请输入两步验证token', message: '',
}; };
} }
const data = createRandomString(50, 100); const data = createRandomString(50, 100);
const expiration = twoFactorActivated ? 30 : 3; const expiration = twoFactorActivated ? 60 : 20;
let token = jwt.sign({ data }, config.secret as any, { let token = jwt.sign({ data }, config.secret as any, {
expiresIn: 60 * 60 * 24 * expiration, expiresIn: 60 * 60 * 24 * expiration,
algorithm: 'HS384', algorithm: 'HS384',
@@ -111,8 +109,7 @@ export default class UserService {
}); });
await this.notificationService.notify( await this.notificationService.notify(
'登录通知', '登录通知',
`你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}${address} ${ `你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}${address} ${req.platform
req.platform
}端 登录成功,ip地址 ${ip}`, }端 登录成功,ip地址 ${ip}`,
); );
await this.getLoginLog(); await this.getLoginLog();
@@ -140,8 +137,7 @@ export default class UserService {
}); });
await this.notificationService.notify( await this.notificationService.notify(
'登录通知', '登录通知',
`你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}${address} ${ `你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}${address} ${req.platform
req.platform
}端 登录失败,ip地址 ${ip}`, }端 登录失败,ip地址 ${ip}`,
); );
await this.getLoginLog(); await this.getLoginLog();
@@ -155,8 +151,17 @@ export default class UserService {
status: LoginStatus.fail, status: LoginStatus.fail,
}, },
}); });
if (retries > 2) {
const waitTime = Math.round(Math.pow(3, retries + 1));
return {
code: 410,
message: `失败次数过多,请${waitTime}秒后重试`,
data: waitTime,
};
} else {
return { code: 400, message: config.authError }; return { code: 400, message: config.authError };
} }
}
} else { } else {
return this.initAuthInfo(); return this.initAuthInfo();
} }
+3 -8
View File
@@ -14,12 +14,7 @@ cp -fv $nginx_app_conf /etc/nginx/conf.d/front.conf
sed -i "s,QL_BASE_URL,${qlBaseUrl},g" /etc/nginx/conf.d/front.conf sed -i "s,QL_BASE_URL,${qlBaseUrl},g" /etc/nginx/conf.d/front.conf
pm2 l &>/dev/null pm2 l &>/dev/null
if [[ $PipMirror ]]; then patch_version &>/dev/null
pip3 config set global.index-url $PipMirror
fi
if [[ $NpmMirror ]]; then
npm config set registry $NpmMirror
fi
echo echo
echo -e "======================2. 安装依赖========================\n" echo -e "======================2. 安装依赖========================\n"
@@ -47,13 +42,13 @@ echo -e "定时任务启动成功...\n"
if [[ $AutoStartBot == true ]]; then if [[ $AutoStartBot == true ]]; then
echo -e "======================7. 启动bot========================\n" echo -e "======================7. 启动bot========================\n"
nohup ql bot >>$dir_log/start.log 2>&1 & nohup ql bot >$dir_log/bot.log 2>&1 &
echo -e "bot后台启动中...\n" echo -e "bot后台启动中...\n"
fi fi
if [[ $EnableExtraShell == true ]]; then if [[ $EnableExtraShell == true ]]; then
echo -e "======================8. 执行自定义脚本========================\n" echo -e "======================8. 执行自定义脚本========================\n"
nohup ql extra >>$dir_log/start.log 2>&1 & nohup ql extra >$dir_log/extra.log 2>&1 &
echo -e "自定义脚本后台执行中...\n" echo -e "自定义脚本后台执行中...\n"
fi fi
+2 -2
View File
@@ -125,12 +125,12 @@
"qrcode.react": "^1.0.1", "qrcode.react": "^1.0.1",
"query-string": "^7.1.1", "query-string": "^7.1.1",
"rc-tween-one": "^3.0.6", "rc-tween-one": "^3.0.6",
"react": "18.x", "react": "18.2.0",
"react-codemirror2": "^7.2.1", "react-codemirror2": "^7.2.1",
"react-diff-viewer": "^3.1.1", "react-diff-viewer": "^3.1.1",
"react-dnd": "^14.0.2", "react-dnd": "^14.0.2",
"react-dnd-html5-backend": "^14.0.0", "react-dnd-html5-backend": "^14.0.0",
"react-dom": "18.x", "react-dom": "18.2.0",
"react-split-pane": "^0.1.92", "react-split-pane": "^0.1.92",
"sockjs-client": "^1.6.0", "sockjs-client": "^1.6.0",
"ts-node": "^10.6.0", "ts-node": "^10.6.0",
+5
View File
@@ -19,6 +19,11 @@ RepoFileExtensions="js py"
## 代理地址,支持http/https/socks,例如 http://127.0.0.1:7890 ## 代理地址,支持http/https/socks,例如 http://127.0.0.1:7890
ProxyUrl="" ProxyUrl=""
## 资源告警阙值,默认CPU 80%、内存80%、磁盘90%
CpuWarn=80
MemoryWarn=80
DiskWarn=90
## 设置定时任务执行的超时时间,默认1h,后缀"s"代表秒(默认值), "m"代表分, "h"代表小时, "d"代表天 ## 设置定时任务执行的超时时间,默认1h,后缀"s"代表秒(默认值), "m"代表分, "h"代表小时, "d"代表天
CommandTimeoutTime="1h" CommandTimeoutTime="1h"
+1 -2
View File
@@ -35,8 +35,7 @@ fi
cp -f "$repo_path/jbot/requirements.txt" "$dir_data" cp -f "$repo_path/jbot/requirements.txt" "$dir_data"
cd $dir_data cd $dir_data
cat requirements.txt | while read LREAD cat requirements.txt | while read LREAD; do
do
if [[ ! $(pip3 show "${LREAD%%=*}" 2>/dev/null) ]]; then if [[ ! $(pip3 show "${LREAD%%=*}" 2>/dev/null) ]]; then
pip3 --default-timeout=100 install ${LREAD} pip3 --default-timeout=100 install ${LREAD}
fi fi
+59 -2
View File
@@ -78,6 +78,10 @@ import_config() {
else else
default_cron="$(random_range 0 59) $(random_range 0 23) * * *" default_cron="$(random_range 0 59) $(random_range 0 23) * * *"
fi fi
cpu_warn=${CpuWarn:-80}
mem_warn=${MemoryWarn:-80}
disk_warn=${DiskWarn:-90}
} }
set_proxy() { set_proxy() {
@@ -349,8 +353,8 @@ reset_branch() {
local branch="$1" local branch="$1"
if [[ $branch ]]; then if [[ $branch ]]; then
part_cmd="origin/${branch}" part_cmd="origin/${branch}"
git checkout -B "$branch" git checkout -B "$branch" &>/dev/null
git branch --set-upstream-to=$part_cmd $branch git branch --set-upstream-to=$part_cmd $branch &>/dev/null
fi fi
git reset --hard $part_cmd &>/dev/null git reset --hard $part_cmd &>/dev/null
} }
@@ -423,6 +427,59 @@ format_timestamp() {
fi fi
} }
patch_version() {
if [[ $PipMirror ]]; then
pip3 config set global.index-url $PipMirror
fi
if [[ $NpmMirror ]]; then
npm config set registry $NpmMirror
fi
# 兼容pnpm@7
pnpm setup &>/dev/null
source ~/.bashrc
pnpm install -g &>/dev/null
if [[ -f "$dir_root/db/cookie.db" ]]; then
echo -e "检测到旧的db文件,拷贝为新db...\n"
mv $dir_root/db/cookie.db $dir_root/db/env.db
rm -rf $dir_root/db/cookie.db
echo
fi
if ! type ts-node &>/dev/null; then
pnpm add -g ts-node typescript tslib
fi
git config --global pull.rebase false
cp -f $dir_root/.env.example $dir_root/.env
if [[ -d "$dir_root/db" ]]; then
echo -e "检测到旧的db目录,拷贝到data目录...\n"
cp -rf $dir_root/config $dir_root/data
echo
fi
if [[ -d "$dir_root/scripts" ]]; then
echo -e "检测到旧的scripts目录,拷贝到data目录...\n"
cp -rf $dir_root/scripts $dir_root/data
echo
fi
if [[ -d "$dir_root/log" ]]; then
echo -e "检测到旧的log目录,拷贝到data目录...\n"
cp -rf $dir_root/log $dir_root/data
echo
fi
if [[ -d "$dir_root/config" ]]; then
echo -e "检测到旧的config目录,拷贝到data目录...\n"
cp -rf $dir_root/config $dir_root/data
echo
fi
}
init_env init_env
detect_termux detect_termux
detect_macos detect_macos
+48 -51
View File
@@ -118,6 +118,44 @@ handle_log_path() {
make_dir "$dir_log/$log_dir" make_dir "$dir_log/$log_dir"
} }
check_server() {
cpu_use=$(top -b -n 1 | grep CPU | grep -v -E 'grep|PID' | awk '{print $2}' | cut -f 1 -d "%")
mem_free=$(free -m | grep "Mem" | awk '{print $3}')
mem_total=$(free -m | grep "Mem" | awk '{print $2}')
mem_use=$(printf "%d%%" $((mem_free * 100 / mem_total)) | cut -f 1 -d "%")
disk_use=$(df -P | grep /dev | grep -v -E '(tmp|boot|shm)' | awk '{print $5}' | cut -f 1 -d "%")
eval echo -e "\#\# 当前CPU占用 $cpu_use% 内存占用 $mem_use% 磁盘占用 $disk_use% \\\n" $cmd
if [[ $cpu_use -gt $cpu_warn ]] || [[ $mem_free -lt $mem_warn ]] || [[ $disk_use -gt $disk_warn ]]; then
echo -e "\#\# 服务器资源占用异常,本次任务跳过执行" $cmd
notify_api "服务器资源异常警告" "当前CPU占用 $cpu_use% 内存占用 $mem_use% 磁盘占用 $disk_use%"
end_time=$(date '+%Y-%m-%d %H:%M:%S')
diff_time=$(($end_timestamp - $begin_timestamp))
[[ $ID ]] && update_cron "\"$ID\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time"
eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd
exit 1
fi
}
handle_task_before() {
handle_log_path
begin_time=$(format_time "$time_format" "$time")
begin_timestamp=$(format_timestamp "$time_format" "$time")
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
[[ $is_macos -eq 0 ]] && check_server
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
[[ $ID ]] && update_cron "\"$ID\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
}
## 正常运行单个脚本,$1:传入参数 ## 正常运行单个脚本,$1:传入参数
run_normal() { run_normal() {
local file_param=$1 local file_param=$1
@@ -125,17 +163,7 @@ run_normal() {
random_delay "$file_param" random_delay "$file_param"
fi fi
handle_log_path handle_task_before
local begin_time=$(format_time "$time_format" "$time")
local begin_timestamp=$(format_timestamp "$time_format" "$time")
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
local id=$(cat $list_crontab_user | grep -E "$cmd_task $file_param" | perl -pe "s|.*ID=(.*) $cmd_task $file_param\.*|\1|" | head -1 | awk -F " " '{print $1}')
[[ $id ]] && update_cron "\"$id\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
cd $dir_scripts cd $dir_scripts
local relative_path="${file_param%/*}" local relative_path="${file_param%/*}"
@@ -150,7 +178,7 @@ run_normal() {
local end_time=$(date '+%Y-%m-%d %H:%M:%S') local end_time=$(date '+%Y-%m-%d %H:%M:%S')
local end_timestamp=$(date "+%s") local end_timestamp=$(date "+%s")
local diff_time=$(expr $end_timestamp - $begin_timestamp) local diff_time=$(expr $end_timestamp - $begin_timestamp)
[[ $id ]] && update_cron "\"$id\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time" [[ $ID ]] && update_cron "\"$ID\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time"
eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd
} }
@@ -164,6 +192,8 @@ run_concurrent() {
exit 1 exit 1
fi fi
handle_task_before
local envs=$(eval echo "\$${env_param}") local envs=$(eval echo "\$${env_param}")
local array=($(echo $envs | sed 's/&/ /g')) local array=($(echo $envs | sed 's/&/ /g'))
local tempArr=$(echo $num_param | perl -pe "s|(\d+)(-\|~\|_)(\d+)|{\1..\3}|g") local tempArr=$(echo $num_param | perl -pe "s|(\d+)(-\|~\|_)(\d+)|{\1..\3}|g")
@@ -179,18 +209,6 @@ run_concurrent() {
local cookieStr=$(echo ${array_run[*]} | sed 's/\ /\&/g') local cookieStr=$(echo ${array_run[*]} | sed 's/\ /\&/g')
[[ ! -z $cookieStr ]] && export ${env_param}=${cookieStr} [[ ! -z $cookieStr ]] && export ${env_param}=${cookieStr}
handle_log_path
local begin_time=$(format_time "$time_format" "$time")
local begin_timestamp=$(format_timestamp "$time_format" "$time")
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
local id=$(cat $list_crontab_user | grep -E "$cmd_task $file_param" | perl -pe "s|.*ID=(.*) $cmd_task $file_param\.*|\1|" | head -1 | awk -F " " '{print $1}')
[[ $id ]] && update_cron "\"$id\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
local envs=$(eval echo "\$${env_param}") local envs=$(eval echo "\$${env_param}")
local array=($(echo $envs | sed 's/&/ /g')) local array=($(echo $envs | sed 's/&/ /g'))
single_log_time=$(date "+%Y-%m-%d-%H-%M-%S.%N") single_log_time=$(date "+%Y-%m-%d-%H-%M-%S.%N")
@@ -218,7 +236,7 @@ run_concurrent() {
local end_time=$(date '+%Y-%m-%d %H:%M:%S') local end_time=$(date '+%Y-%m-%d %H:%M:%S')
local end_timestamp=$(date "+%s") local end_timestamp=$(date "+%s")
local diff_time=$(($end_timestamp - $begin_timestamp)) local diff_time=$(($end_timestamp - $begin_timestamp))
[[ $id ]] && update_cron "\"$id\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time" [[ $ID ]] && update_cron "\"$ID\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time"
eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd
} }
@@ -231,10 +249,7 @@ run_designated() {
exit 1 exit 1
fi fi
handle_log_path handle_task_before
local begin_time=$(format_time "$time_format" "$time")
local begin_timestamp=$(format_timestamp "$time_format" "$time")
local envs=$(eval echo "\$${env_param}") local envs=$(eval echo "\$${env_param}")
local array=($(echo $envs | sed 's/&/ /g')) local array=($(echo $envs | sed 's/&/ /g'))
@@ -251,13 +266,6 @@ run_designated() {
local cookieStr=$(echo ${array_run[*]} | sed 's/\ /\&/g') local cookieStr=$(echo ${array_run[*]} | sed 's/\ /\&/g')
[[ ! -z $cookieStr ]] && export ${env_param}=${cookieStr} [[ ! -z $cookieStr ]] && export ${env_param}=${cookieStr}
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
local id=$(cat $list_crontab_user | grep -E "$cmd_task $file_param" | perl -pe "s|.*ID=(.*) $cmd_task $file_param\.*|\1|" | head -1 | awk -F " " '{print $1}')
[[ $id ]] && update_cron "\"$id\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
cd $dir_scripts cd $dir_scripts
local relative_path="${file_param%/*}" local relative_path="${file_param%/*}"
if [[ ! -z ${relative_path} ]] && [[ ${file_param} =~ "/" ]]; then if [[ ! -z ${relative_path} ]] && [[ ${file_param} =~ "/" ]]; then
@@ -270,7 +278,7 @@ run_designated() {
local end_time=$(date '+%Y-%m-%d %H:%M:%S') local end_time=$(date '+%Y-%m-%d %H:%M:%S')
local end_timestamp=$(date "+%s") local end_timestamp=$(date "+%s")
local diff_time=$(($end_timestamp - $begin_timestamp)) local diff_time=$(($end_timestamp - $begin_timestamp))
[[ $id ]] && update_cron "\"$id\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time" [[ $ID ]] && update_cron "\"$ID\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time"
eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd
} }
@@ -278,17 +286,7 @@ run_designated() {
run_else() { run_else() {
local file_param="$1" local file_param="$1"
handle_log_path handle_task_before
local begin_time=$(format_time "$time_format" "$time")
local begin_timestamp=$(format_timestamp "$time_format" "$time")
eval echo -e "\#\# 开始执行... $begin_time\\\n" $cmd
[[ -f $task_error_log_path ]] && eval cat $task_error_log_path $cmd
local id=$(cat $list_crontab_user | grep -E "$cmd_task $@" | perl -pe "s|.*ID=(.*) $cmd_task $@\.*|\1|" | head -1 | awk -F " " '{print $1}')
[[ $id ]] && update_cron "\"$id\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
cd $dir_scripts cd $dir_scripts
local relative_path="${file_param%/*}" local relative_path="${file_param%/*}"
@@ -304,15 +302,14 @@ run_else() {
local end_time=$(date '+%Y-%m-%d %H:%M:%S') local end_time=$(date '+%Y-%m-%d %H:%M:%S')
local end_timestamp=$(date "+%s") local end_timestamp=$(date "+%s")
local diff_time=$(($end_timestamp - $begin_timestamp)) local diff_time=$(($end_timestamp - $begin_timestamp))
[[ $id ]] && update_cron "\"$id\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time" [[ $ID ]] && update_cron "\"$ID\"" "1" "" "$log_path" "$begin_timestamp" "$diff_time"
eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd eval echo -e "\\\n\#\# 执行结束... $end_time 耗时 $diff_time" $cmd
} }
## 命令检测 ## 命令检测
main() { main() {
show_log="false" show_log="false"
while getopts ":l" opt while getopts ":l" opt; do
do
case $opt in case $opt in
l) l)
show_log="true" show_log="true"
+12 -63
View File
@@ -244,11 +244,10 @@ usage() {
## 更新qinglong ## 更新qinglong
update_qinglong() { update_qinglong() {
patch_version patch_version &>/dev/null
export isFirstStartServer=false export isFirstStartServer=false
local no_restart="$1"
local all_branch=$(git branch -a) local all_branch=$(git branch -a)
local primary_branch="master" local primary_branch="master"
if [[ "${all_branch}" =~ "${current_branch}" ]]; then if [[ "${all_branch}" =~ "${current_branch}" ]]; then
@@ -266,10 +265,16 @@ update_qinglong() {
[[ -f $dir_root/package.json ]] && ql_depend_new=$(cat $dir_root/package.json) [[ -f $dir_root/package.json ]] && ql_depend_new=$(cat $dir_root/package.json)
[[ "$ql_depend_old" != "$ql_depend_new" ]] && npm_install_2 $dir_root [[ "$ql_depend_old" != "$ql_depend_new" ]] && npm_install_2 $dir_root
else
echo -e "\n更新青龙源文件失败,请检查原因...\n"
fi
update_qinglong_static "$1" "$primary_branch"
else
echo -e "\n更新青龙源文件失败,请检查网络...\n"
fi
}
update_qinglong_static() {
local no_restart="$1"
local primary_branch="$2"
local url="https://github.com/whyour/qinglong-static.git" local url="https://github.com/whyour/qinglong-static.git"
if [[ -d ${ql_static_repo}/.git ]]; then if [[ -d ${ql_static_repo}/.git ]]; then
reset_romote_url ${ql_static_repo} ${url} ${primary_branch} reset_romote_url ${ql_static_repo} ${url} ${primary_branch}
@@ -291,63 +296,8 @@ update_qinglong() {
reload_pm2 reload_pm2
fi fi
else else
echo -e "\n更新青龙静态资源失败,请检查原因...\n" echo -e "\n更新青龙静态资源失败,请检查网络...\n"
fi fi
}
patch_version() {
# 兼容pnpm@7
pnpm setup &>/dev/null
source ~/.bashrc
pnpm install -g &>/dev/null
if [[ -f "$dir_root/db/cookie.db" ]]; then
echo -e "检测到旧的db文件,拷贝为新db...\n"
mv $dir_root/db/cookie.db $dir_root/db/env.db
rm -rf $dir_root/db/cookie.db
echo
fi
if ! type ts-node &>/dev/null; then
pnpm add -g ts-node typescript tslib
fi
git config --global pull.rebase false
cp -f $dir_root/.env.example $dir_root/.env
if [[ -d "$dir_root/db" ]]; then
echo -e "检测到旧的db目录,拷贝到data目录...\n"
cp -rf $dir_root/config $dir_root/data
echo
fi
if [[ -d "$dir_root/scripts" ]]; then
echo -e "检测到旧的scripts目录,拷贝到data目录...\n"
cp -rf $dir_root/scripts $dir_root/data
echo
fi
if [[ -d "$dir_root/log" ]]; then
echo -e "检测到旧的log目录,拷贝到data目录...\n"
cp -rf $dir_root/log $dir_root/data
echo
fi
if [[ -d "$dir_root/config" ]]; then
echo -e "检测到旧的config目录,拷贝到data目录...\n"
cp -rf $dir_root/config $dir_root/data
echo
fi
if [[ $PipMirror ]]; then
pip3 config set global.index-url $PipMirror
fi
if [[ $NpmMirror ]]; then
npm config set registry $NpmMirror
fi
} }
## 对比脚本 ## 对比脚本
@@ -466,8 +416,7 @@ get_uniq_path() {
main() { main() {
## for ql update ## for ql update
show_log="false" show_log="false"
while getopts ":l" opt while getopts ":l" opt; do
do
case $opt in case $opt in
l) l)
show_log="true" show_log="true"
+48
View File
@@ -0,0 +1,48 @@
import { useMemo, useState } from 'react';
export default (
treeData: any[],
searchValue: string,
{
treeNodeFilterProp,
}: {
treeNodeFilterProp: string;
},
) => {
return useMemo(() => {
const keys: string[] = [];
if (!searchValue) {
return { treeData, keys };
}
const upperStr = searchValue.toUpperCase();
function filterOptionFunc(_: string, dataNode: any[]) {
const value = dataNode[treeNodeFilterProp as any];
return String(value).toUpperCase().includes(upperStr);
}
function dig(list: any[], keepAll: boolean = false): any[] {
return list
.map((dataNode) => {
const children = dataNode.children;
const match = keepAll || filterOptionFunc!(searchValue, dataNode);
const childList = dig(children || [], match);
if (match || childList.length) {
childList.length && keys.push(dataNode.key);
return {
...dataNode,
children: childList,
};
}
return null;
})
.filter((node) => node);
}
return { treeData: dig(treeData), keys };
}, [treeData, searchValue, treeNodeFilterProp]);
};
+6 -6
View File
@@ -68,18 +68,18 @@ export default {
icon: <IconFont type="ql-icon-dependence" />, icon: <IconFont type="ql-icon-dependence" />,
component: '@/pages/dependence/index', component: '@/pages/dependence/index',
}, },
{
path: '/log',
name: '日志管理',
icon: <IconFont type="ql-icon-log" />,
component: '@/pages/log/index',
},
{ {
path: '/diff', path: '/diff',
name: '对比工具', name: '对比工具',
icon: <IconFont type="ql-icon-diff" />, icon: <IconFont type="ql-icon-diff" />,
component: '@/pages/diff/index', component: '@/pages/diff/index',
}, },
{
path: '/log',
name: '任务日志',
icon: <IconFont type="ql-icon-log" />,
component: '@/pages/log/index',
},
{ {
path: '/setting', path: '/setting',
name: '系统设置', name: '系统设置',
+2 -5
View File
@@ -161,7 +161,7 @@
&.env-wrapper, &.env-wrapper,
&.config-wrapper { &.config-wrapper {
.CodeMirror { .CodeMirror {
width: calc(100vw - 80px); width: calc(100vw - 24px);
} }
} }
} }
@@ -243,7 +243,6 @@
font-size: 13px; font-size: 13px;
} }
[data-dark='true'] {
/* Change autocomplete styles in WebKit */ /* Change autocomplete styles in WebKit */
input:-webkit-autofill, input:-webkit-autofill,
input:-webkit-autofill:hover, input:-webkit-autofill:hover,
@@ -254,11 +253,10 @@
select:-webkit-autofill, select:-webkit-autofill,
select:-webkit-autofill:hover, select:-webkit-autofill:hover,
select:-webkit-autofill:focus { select:-webkit-autofill:focus {
border: 1px solid @border-color-base; border: none;
box-shadow: none; box-shadow: none;
transition: background-color 5000s ease-in-out 0s; transition: background-color 5000s ease-in-out 0s;
-webkit-text-fill-color: @text-color; -webkit-text-fill-color: @text-color;
caret-color: #e8e6f3 !important;
} }
::placeholder { ::placeholder {
@@ -268,7 +266,6 @@
.ant-select-selection-placeholder { .ant-select-selection-placeholder {
opacity: 0.5 !important; opacity: 0.5 !important;
} }
}
.ant-pro-basicLayout-content { .ant-pro-basicLayout-content {
margin: 12px; margin: 12px;
+10 -6
View File
@@ -20,6 +20,9 @@ import { message, Badge, Modal, Avatar, Dropdown, Menu, Image } from 'antd';
import SockJS from 'sockjs-client'; import SockJS from 'sockjs-client';
import * as Sentry from '@sentry/react'; import * as Sentry from '@sentry/react';
import { init } from '../utils/init'; import { init } from '../utils/init';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/python/python';
import 'codemirror/mode/shell/shell';
export interface SharedContext { export interface SharedContext {
headerStyle: React.CSSProperties; headerStyle: React.CSSProperties;
@@ -41,6 +44,7 @@ export default function () {
const ws = useRef<any>(null); const ws = useRef<any>(null);
const [socketMessage, setSocketMessage] = useState<any>(); const [socketMessage, setSocketMessage] = useState<any>();
const [collapsed, setCollapsed] = useState(false); const [collapsed, setCollapsed] = useState(false);
const [initLoading, setInitLoading] = useState<boolean>(true);
const { const {
enable: enableDarkMode, enable: enableDarkMode,
disable: disableDarkMode, disable: disableDarkMode,
@@ -64,17 +68,15 @@ export default function () {
setSystemInfo(data); setSystemInfo(data);
if (!data.isInitialized) { if (!data.isInitialized) {
history.push('/initialization'); history.push('/initialization');
setLoading(false);
} else { } else {
getUser(); getUser();
} }
} else {
message.error(data);
} }
}) })
.catch((error) => { .catch((error) => {
console.log(error); console.log(error);
}); })
.finally(() => setInitLoading(false));
}; };
const getUser = (needLoading = true) => { const getUser = (needLoading = true) => {
@@ -87,8 +89,6 @@ export default function () {
if (location.pathname === '/') { if (location.pathname === '/') {
history.push('/crontab'); history.push('/crontab');
} }
} else {
message.error(data);
} }
needLoading && setLoading(false); needLoading && setLoading(false);
}) })
@@ -196,6 +196,10 @@ export default function () {
}; };
}, []); }, []);
if (initLoading) {
return <PageLoading />;
}
if (['/login', '/initialization', '/error'].includes(location.pathname)) { if (['/login', '/initialization', '/error'].includes(location.pathname)) {
document.title = `${ document.title = `${
(config.documentTitleMap as any)[location.pathname] (config.documentTitleMap as any)[location.pathname]
+12 -6
View File
@@ -25,8 +25,10 @@ const Config = () => {
const [confirmLoading, setConfirmLoading] = useState(false); const [confirmLoading, setConfirmLoading] = useState(false);
const getConfig = (name: string) => { const getConfig = (name: string) => {
request.get(`${config.apiPrefix}configs/${name}`).then((data: any) => { request.get(`${config.apiPrefix}configs/${name}`).then(({ code, data }) => {
setValue(data.data); if (code === 200) {
setValue(data);
}
}); });
}; };
@@ -34,8 +36,10 @@ const Config = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}configs/files`) .get(`${config.apiPrefix}configs/files`)
.then((data: any) => { .then(({ code, data }) => {
setData(data.data); if (code === 200) {
setData(data);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -50,8 +54,10 @@ const Config = () => {
.post(`${config.apiPrefix}configs/save`, { .post(`${config.apiPrefix}configs/save`, {
data: { content, name: select }, data: { content, name: select },
}) })
.then((data: any) => { .then(({ code, data }) => {
message.success(data.message); if (code === 200) {
message.success('保存成功');
}
setConfirmLoading(false); setConfirmLoading(false);
}); });
}; };
+21 -28
View File
@@ -103,7 +103,6 @@ const CronDetailModal = ({
fontSize: 12, fontSize: 12,
lineNumbersMinChars: 3, lineNumbersMinChars: 3,
fontFamily: 'Source Code Pro', fontFamily: 'Source Code Pro',
folding: false,
glyphMargin: false, glyphMargin: false,
wordWrap: 'on', wordWrap: 'on',
}} }}
@@ -123,9 +122,11 @@ const CronDetailModal = ({
.get( .get(
`${config.apiPrefix}logs/${item.filename}?path=${item.directory || ''}`, `${config.apiPrefix}logs/${item.filename}?path=${item.directory || ''}`,
) )
.then((data) => { .then(({ code, data }) => {
setLog(data.data); if (code === 200) {
setLog(data);
setIsLogModalVisible(true); setIsLogModalVisible(true);
}
}); });
}; };
@@ -137,9 +138,9 @@ const CronDetailModal = ({
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}crons/${cron.id}/logs`) .get(`${config.apiPrefix}crons/${cron.id}/logs`)
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
setLogs(data.data); setLogs(data);
} }
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
@@ -165,8 +166,10 @@ const CronDetailModal = ({
setScriptInfo({ parent: p, filename: s }); setScriptInfo({ parent: p, filename: s });
request request
.get(`${config.apiPrefix}scripts/${s}?path=${p || ''}`) .get(`${config.apiPrefix}scripts/${s}?path=${p || ''}`)
.then((data) => { .then(({ code, data }) => {
setValue(data.data); if (code === 200) {
setValue(data);
}
}); });
} else { } else {
setValidTabs([validTabs[0]]); setValidTabs([validTabs[0]]);
@@ -198,12 +201,10 @@ const CronDetailModal = ({
content, content,
}, },
}) })
.then((_data: any) => { .then(({ code, data }) => {
if (_data.code === 200) { if (code === 200) {
setValue(content); setValue(content);
message.success(`保存成功`); message.success(`保存成功`);
} else {
message.error(_data);
} }
resolve(null); resolve(null);
}) })
@@ -231,14 +232,12 @@ const CronDetailModal = ({
onOk() { onOk() {
request request
.put(`${config.apiPrefix}crons/run`, { data: [currentCron.id] }) .put(`${config.apiPrefix}crons/run`, { data: [currentCron.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
setCurrentCron({ ...currentCron, status: CrontabStatus.running }); setCurrentCron({ ...currentCron, status: CrontabStatus.running });
setTimeout(() => { setTimeout(() => {
getLogs(); getLogs();
}, 1000); }, 1000);
} else {
message.error(data);
} }
}); });
}, },
@@ -263,11 +262,9 @@ const CronDetailModal = ({
onOk() { onOk() {
request request
.put(`${config.apiPrefix}crons/stop`, { data: [currentCron.id] }) .put(`${config.apiPrefix}crons/stop`, { data: [currentCron.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
setCurrentCron({ ...currentCron, status: CrontabStatus.idle }); setCurrentCron({ ...currentCron, status: CrontabStatus.idle });
} else {
message.error(data);
} }
}); });
}, },
@@ -300,14 +297,12 @@ const CronDetailModal = ({
data: [currentCron.id], data: [currentCron.id],
}, },
) )
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
setCurrentCron({ setCurrentCron({
...currentCron, ...currentCron,
isDisabled: currentCron.isDisabled === 1 ? 0 : 1, isDisabled: currentCron.isDisabled === 1 ? 0 : 1,
}); });
} else {
message.error(data);
} }
}); });
}, },
@@ -340,14 +335,12 @@ const CronDetailModal = ({
data: [currentCron.id], data: [currentCron.id],
}, },
) )
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
setCurrentCron({ setCurrentCron({
...currentCron, ...currentCron,
isPinned: currentCron.isPinned === 1 ? 0 : 1, isPinned: currentCron.isPinned === 1 ? 0 : 1,
}); });
} else {
message.error(data);
} }
}); });
}, },
+29 -37
View File
@@ -433,8 +433,9 @@ const Crontab = () => {
} }
request request
.get(url) .get(url)
.then((_data: any) => { .then(({ code, data: _data }) => {
const { data, total } = _data.data; if (code === 200) {
const { data, total } = _data;
setValue( setValue(
data.map((x) => { data.map((x) => {
return { return {
@@ -447,6 +448,7 @@ const Crontab = () => {
}), }),
); );
setTotal(total); setTotal(total);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -476,8 +478,8 @@ const Crontab = () => {
onOk() { onOk() {
request request
.delete(`${config.apiPrefix}crons`, { data: [record.id] }) .delete(`${config.apiPrefix}crons`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success('删除成功'); message.success('删除成功');
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
@@ -485,8 +487,6 @@ const Crontab = () => {
result.splice(i, 1); result.splice(i, 1);
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
@@ -511,8 +511,8 @@ const Crontab = () => {
onOk() { onOk() {
request request
.put(`${config.apiPrefix}crons/run`, { data: [record.id] }) .put(`${config.apiPrefix}crons/run`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
if (i !== -1) { if (i !== -1) {
@@ -522,8 +522,6 @@ const Crontab = () => {
}); });
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
@@ -548,8 +546,8 @@ const Crontab = () => {
onOk() { onOk() {
request request
.put(`${config.apiPrefix}crons/stop`, { data: [record.id] }) .put(`${config.apiPrefix}crons/stop`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
if (i !== -1) { if (i !== -1) {
@@ -560,8 +558,6 @@ const Crontab = () => {
}); });
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
@@ -594,8 +590,8 @@ const Crontab = () => {
data: [record.id], data: [record.id],
}, },
) )
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const newStatus = record.isDisabled === 1 ? 0 : 1; const newStatus = record.isDisabled === 1 ? 0 : 1;
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
@@ -606,8 +602,6 @@ const Crontab = () => {
}); });
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
@@ -640,8 +634,8 @@ const Crontab = () => {
data: [record.id], data: [record.id],
}, },
) )
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const newStatus = record.isPinned === 1 ? 0 : 1; const newStatus = record.isPinned === 1 ? 0 : 1;
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
@@ -652,8 +646,6 @@ const Crontab = () => {
}); });
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
@@ -755,20 +747,22 @@ const Crontab = () => {
const getCronDetail = (cron: any) => { const getCronDetail = (cron: any) => {
request request
.get(`${config.apiPrefix}crons/${cron.id}`) .get(`${config.apiPrefix}crons/${cron.id}`)
.then((data: any) => { .then(({ code, data }) => {
if (code === 200) {
const index = value.findIndex((x) => x.id === cron.id); const index = value.findIndex((x) => x.id === cron.id);
const result = [...value]; const result = [...value];
data.data.nextRunTime = cron_parser data.nextRunTime = cron_parser
.parseExpression(data.data.schedule) .parseExpression(data.schedule)
.next() .next()
.toDate(); .toDate();
if (index !== -1) { if (index !== -1) {
result.splice(index, 1, { result.splice(index, 1, {
...cron, ...cron,
...data.data, ...data,
}); });
setValue(result); setValue(result);
} }
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -795,13 +789,11 @@ const Crontab = () => {
onOk() { onOk() {
request request
.delete(`${config.apiPrefix}crons`, { data: selectedRowIds }) .delete(`${config.apiPrefix}crons`, { data: selectedRowIds })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success('批量删除成功'); message.success('批量删除成功');
setSelectedRowIds([]); setSelectedRowIds([]);
getCrons(); getCrons();
} else {
message.error(data);
} }
}); });
}, },
@@ -820,11 +812,9 @@ const Crontab = () => {
.put(`${config.apiPrefix}crons/${OperationPath[operationStatus]}`, { .put(`${config.apiPrefix}crons/${OperationPath[operationStatus]}`, {
data: selectedRowIds, data: selectedRowIds,
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
getCrons(); getCrons();
} else {
message.error(data);
} }
}); });
}, },
@@ -1029,9 +1019,11 @@ const Crontab = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}crons/views`) .get(`${config.apiPrefix}crons/views`)
.then((data: any) => { .then(({ code, data }) => {
setCronViews(data.data); if (code === 200) {
setEnabledCronViews(data.data.filter((x) => !x.isDisabled)); setCronViews(data);
setEnabledCronViews(data.filter((x) => !x.isDisabled));
}
}) })
.finally(() => { .finally(() => {
setLoading(false); setLoading(false);
+6 -3
View File
@@ -41,9 +41,12 @@ const CronLogModal = ({
} }
request request
.get(logUrl ? logUrl : `${config.apiPrefix}crons/${cron.id}/log`) .get(logUrl ? logUrl : `${config.apiPrefix}crons/${cron.id}/log`)
.then((data: any) => { .then(({ code, data }) => {
if (localStorage.getItem('logCron') === String(cron.id)) { if (
const log = data.data as string; code === 200 &&
localStorage.getItem('logCron') === String(cron.id)
) {
const log = data as string;
setValue(log || '暂无日志'); setValue(log || '暂无日志');
setExecuting( setExecuting(
log && !log.includes('执行结束') && !log.includes('重启面板'), log && !log.includes('执行结束') && !log.includes('重启面板'),
-4
View File
@@ -32,8 +32,6 @@ const CronModal = ({
if (code === 200) { if (code === 200) {
message.success(cron ? '更新Cron成功' : '新建Cron成功'); message.success(cron ? '更新Cron成功' : '新建Cron成功');
handleCancel(data); handleCancel(data);
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
} catch (error: any) { } catch (error: any) {
@@ -142,8 +140,6 @@ const CronLabelModal = ({
action === 'post' ? '添加Labels成功' : '删除Labels成功', action === 'post' ? '添加Labels成功' : '删除Labels成功',
); );
handleCancel(true); handleCancel(true);
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
} catch (error) { } catch (error) {
+1 -3
View File
@@ -66,9 +66,7 @@ const ViewCreateModal = ({
}, },
); );
if (code !== 200) { if (code === 200) {
message.error(data);
} else {
handleCancel(data); handleCancel(data);
} }
setLoading(false); setLoading(false);
+7 -13
View File
@@ -141,12 +141,10 @@ const ViewManageModal = ({
onOk() { onOk() {
request request
.delete(`${config.apiPrefix}crons/views`, { data: [record.id] }) .delete(`${config.apiPrefix}crons/views`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success('删除成功'); message.success('删除成功');
cronViewChange(); cronViewChange();
} else {
message.error(data);
} }
}); });
}, },
@@ -162,14 +160,12 @@ const ViewManageModal = ({
.put(`${config.apiPrefix}crons/views/${checked ? 'enable' : 'disable'}`, { .put(`${config.apiPrefix}crons/views/${checked ? 'enable' : 'disable'}`, {
data: [record.id], data: [record.id],
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const _list = [...list]; const _list = [...list];
_list.splice(index, 1, { ...list[index], isDisabled: !checked }); _list.splice(index, 1, { ...list[index], isDisabled: !checked });
setList(_list); setList(_list);
cronViewChange(); cronViewChange();
} else {
message.error(data);
} }
}); });
}; };
@@ -190,15 +186,13 @@ const ViewManageModal = ({
.put(`${config.apiPrefix}crons/views/move`, { .put(`${config.apiPrefix}crons/views/move`, {
data: { fromIndex: dragIndex, toIndex: hoverIndex, id: dragRow.id }, data: { fromIndex: dragIndex, toIndex: hoverIndex, id: dragRow.id },
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const newData = [...list]; const newData = [...list];
newData.splice(dragIndex, 1); newData.splice(dragIndex, 1);
newData.splice(hoverIndex, 0, { ...dragRow, ...data.data }); newData.splice(hoverIndex, 0, { ...dragRow, ...data });
setList(newData); setList(newData);
cronViewChange(); cronViewChange();
} else {
message.error(data);
} }
}); });
}, },
+17 -23
View File
@@ -175,8 +175,10 @@ const Dependence = () => {
.get( .get(
`${config.apiPrefix}dependencies?searchValue=${searchText}&type=${type}`, `${config.apiPrefix}dependencies?searchValue=${searchText}&type=${type}`,
) )
.then((data: any) => { .then(({ code, data }) => {
setValue(data.data); if (code === 200) {
setValue(data);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -212,9 +214,8 @@ const Dependence = () => {
.delete(`${config.apiPrefix}dependencies${force ? '/force' : ''}`, { .delete(`${config.apiPrefix}dependencies${force ? '/force' : ''}`, {
data: [record.id], data: [record.id],
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200 && force) {
if (force) {
const i = value.findIndex((x) => x.id === data.data[0].id); const i = value.findIndex((x) => x.id === data.data[0].id);
if (i !== -1) { if (i !== -1) {
const result = [...value]; const result = [...value];
@@ -222,9 +223,6 @@ const Dependence = () => {
setValue(result); setValue(result);
} }
} }
} else {
message.error(data);
}
}); });
}, },
onCancel() { onCancel() {
@@ -250,11 +248,9 @@ const Dependence = () => {
.put(`${config.apiPrefix}dependencies/reinstall`, { .put(`${config.apiPrefix}dependencies/reinstall`, {
data: [record.id], data: [record.id],
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
handleDependence(data.data[0]); handleDependence(data[0]);
} else {
message.error(data);
} }
}); });
}, },
@@ -309,12 +305,10 @@ const Dependence = () => {
.delete(`${config.apiPrefix}dependencies${forceUrl}`, { .delete(`${config.apiPrefix}dependencies${forceUrl}`, {
data: selectedRowIds, data: selectedRowIds,
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
setSelectedRowIds([]); setSelectedRowIds([]);
getDependencies(); getDependencies();
} else {
message.error(data);
} }
}); });
}, },
@@ -333,12 +327,10 @@ const Dependence = () => {
.put(`${config.apiPrefix}dependencies/reinstall`, { .put(`${config.apiPrefix}dependencies/reinstall`, {
data: selectedRowIds, data: selectedRowIds,
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
setSelectedRowIds([]); setSelectedRowIds([]);
getDependencies(); getDependencies();
} else {
message.error(data);
} }
}); });
}, },
@@ -351,16 +343,18 @@ const Dependence = () => {
const getDependenceDetail = (dependence: any) => { const getDependenceDetail = (dependence: any) => {
request request
.get(`${config.apiPrefix}dependencies/${dependence.id}`) .get(`${config.apiPrefix}dependencies/${dependence.id}`)
.then((data: any) => { .then(({ code, data }) => {
if (code === 200) {
const index = value.findIndex((x) => x.id === dependence.id); const index = value.findIndex((x) => x.id === dependence.id);
const result = [...value]; const result = [...value];
if (index !== -1) { if (index !== -1) {
result.splice(index, 1, { result.splice(index, 1, {
...dependence, ...dependence,
...data.data, ...data,
}); });
setValue(result); setValue(result);
} }
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
+9 -4
View File
@@ -48,9 +48,12 @@ const DependenceLogModal = ({
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}dependencies/${dependence.id}`) .get(`${config.apiPrefix}dependencies/${dependence.id}`)
.then((data: any) => { .then(({ code, data }) => {
if (localStorage.getItem('logDependence') === String(dependence.id)) { if (
const log = (data.data.log || []).join('') as string; code === 200 &&
localStorage.getItem('logDependence') === String(dependence.id)
) {
const log = (data.log || []).join('') as string;
setValue(log); setValue(log);
setExecuting(!log.includes('结束时间')); setExecuting(!log.includes('结束时间'));
setIsRemoveFailed(log.includes('删除失败')); setIsRemoveFailed(log.includes('删除失败'));
@@ -67,8 +70,10 @@ const DependenceLogModal = ({
.delete(`${config.apiPrefix}dependencies/force`, { .delete(`${config.apiPrefix}dependencies/force`, {
data: [dependence.id], data: [dependence.id],
}) })
.then((data: any) => { .then(({ code, data }) => {
if (code === 200) {
cancel(true); cancel(true);
}
}) })
.finally(() => { .finally(() => {
setRemoveLoading(false); setRemoveLoading(false);
+1 -3
View File
@@ -53,9 +53,7 @@ const DependenceModal = ({
}, },
); );
if (code !== 200) { if (code === 200) {
message.error(data);
} else {
handleCancel(data); handleCancel(data);
} }
setLoading(false); setLoading(false);
+20 -8
View File
@@ -22,14 +22,22 @@ const Diff = () => {
const editorRef = useRef<any>(null); const editorRef = useRef<any>(null);
const getConfig = () => { const getConfig = () => {
request.get(`${config.apiPrefix}configs/${current}`).then((data) => { request
setCurrentValue(data.data); .get(`${config.apiPrefix}configs/${current}`)
.then(({ code, data }) => {
if (code === 200) {
setCurrentValue(data);
}
}); });
}; };
const getSample = () => { const getSample = () => {
request.get(`${config.apiPrefix}configs/${origin}`).then((data) => { request
setOriginValue(data.data); .get(`${config.apiPrefix}configs/${origin}`)
.then(({ code, data }) => {
if (code === 200) {
setOriginValue(data);
}
}); });
}; };
@@ -42,8 +50,10 @@ const Diff = () => {
.post(`${config.apiPrefix}configs/save`, { .post(`${config.apiPrefix}configs/save`, {
data: { content, name: current }, data: { content, name: current },
}) })
.then((data: any) => { .then(({ code, data }) => {
message.success(data.message); if (code === 200) {
message.success('保存成功');
}
}); });
}; };
@@ -51,8 +61,10 @@ const Diff = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}configs/files`) .get(`${config.apiPrefix}configs/files`)
.then((data: any) => { .then(({ code, data }) => {
setFiles(data.data); if (code === 200) {
setFiles(data);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
-2
View File
@@ -28,8 +28,6 @@ const EditNameModal = ({
if (code === 200) { if (code === 200) {
message.success('更新环境变量名称成功'); message.success('更新环境变量名称成功');
handleCancel(); handleCancel();
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
} catch (error) { } catch (error) {
+14 -22
View File
@@ -255,8 +255,10 @@ const Env = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}envs?searchValue=${searchText}`) .get(`${config.apiPrefix}envs?searchValue=${searchText}`)
.then((data: any) => { .then(({ code, data }) => {
setValue(data.data); if (code === 200) {
setValue(data);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -284,8 +286,8 @@ const Env = () => {
data: [record.id], data: [record.id],
}, },
) )
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success( message.success(
`${record.status === Status. ? '启用' : '禁用'}成功`, `${record.status === Status. ? '启用' : '禁用'}成功`,
); );
@@ -297,8 +299,6 @@ const Env = () => {
status: newStatus, status: newStatus,
}); });
setValue(result); setValue(result);
} else {
message.error(data);
} }
}); });
}, },
@@ -333,14 +333,12 @@ const Env = () => {
onOk() { onOk() {
request request
.delete(`${config.apiPrefix}envs`, { data: [record.id] }) .delete(`${config.apiPrefix}envs`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success('删除成功'); message.success('删除成功');
const result = [...value]; const result = [...value];
result.splice(index, 1); result.splice(index, 1);
setValue(result); setValue(result);
} else {
message.error(data);
} }
}); });
}, },
@@ -390,14 +388,12 @@ const Env = () => {
.put(`${config.apiPrefix}envs/${dragRow.id}/move`, { .put(`${config.apiPrefix}envs/${dragRow.id}/move`, {
data: { fromIndex: dragIndex, toIndex: hoverIndex }, data: { fromIndex: dragIndex, toIndex: hoverIndex },
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const newData = [...value]; const newData = [...value];
newData.splice(dragIndex, 1); newData.splice(dragIndex, 1);
newData.splice(hoverIndex, 0, { ...dragRow, ...data.data }); newData.splice(hoverIndex, 0, { ...dragRow, ...data.data });
setValue([...newData]); setValue([...newData]);
} else {
message.error(data);
} }
}); });
}, },
@@ -426,13 +422,11 @@ const Env = () => {
onOk() { onOk() {
request request
.delete(`${config.apiPrefix}envs`, { data: selectedRowIds }) .delete(`${config.apiPrefix}envs`, { data: selectedRowIds })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success('批量删除成功'); message.success('批量删除成功');
setSelectedRowIds([]); setSelectedRowIds([]);
getEnvs(); getEnvs();
} else {
message.error(data);
} }
}); });
}, },
@@ -451,11 +445,9 @@ const Env = () => {
.put(`${config.apiPrefix}envs/${OperationPath[operationStatus]}`, { .put(`${config.apiPrefix}envs/${OperationPath[operationStatus]}`, {
data: selectedRowIds, data: selectedRowIds,
}) })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
getEnvs(); getEnvs();
} else {
message.error(data);
} }
}); });
}, },
-2
View File
@@ -44,8 +44,6 @@ const EnvModal = ({
if (code === 200) { if (code === 200) {
message.success(env ? '更新变量成功' : '新建变量成功'); message.success(env ? '更新变量成功' : '新建变量成功');
handleCancel(data); handleCancel(data);
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
} catch (error: any) { } catch (error: any) {
+4 -2
View File
@@ -17,8 +17,10 @@ const Error = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}public/panel/log`) .get(`${config.apiPrefix}public/panel/log`)
.then((data: any) => { .then(({ code, data }) => {
setData(data.data); if (code === 200) {
setData(data);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
+4 -8
View File
@@ -41,11 +41,9 @@ const Initialization = () => {
password: values.password, password: values.password,
}, },
}) })
.then((data) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
next(); next();
} else {
message.error(data.message);
} }
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
@@ -59,11 +57,9 @@ const Initialization = () => {
...values, ...values,
}, },
}) })
.then((_data: any) => { .then(({ code, data }) => {
if (_data && _data.code === 200) { if (code === 200) {
next(); next();
} else {
message.error(_data.message);
} }
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
+140 -50
View File
@@ -1,5 +1,15 @@
import { useState, useEffect, useCallback, Key, useRef } from 'react'; import { useState, useEffect, useCallback, Key, useRef } from 'react';
import { TreeSelect, Tree, Input, Empty } from 'antd'; import {
TreeSelect,
Tree,
Input,
Empty,
Button,
message,
Modal,
Tooltip,
Typography,
} from 'antd';
import config from '@/utils/config'; import config from '@/utils/config';
import { PageContainer } from '@ant-design/pro-layout'; import { PageContainer } from '@ant-design/pro-layout';
import Editor from '@monaco-editor/react'; import Editor from '@monaco-editor/react';
@@ -9,54 +19,33 @@ import { Controlled as CodeMirror } from 'react-codemirror2';
import SplitPane from 'react-split-pane'; import SplitPane from 'react-split-pane';
import { useOutletContext } from '@umijs/max'; import { useOutletContext } from '@umijs/max';
import { SharedContext } from '@/layouts'; import { SharedContext } from '@/layouts';
import { DeleteOutlined } from '@ant-design/icons';
import { depthFirstSearch } from '@/utils';
import { debounce, uniq } from 'lodash';
import useFilterTreeData from '@/hooks/useFilterTreeData';
function getFilterData(keyword: string, data: any) { const { Text } = Typography;
const expandedKeys: string[] = [];
if (keyword) {
const tree: any = [];
data.forEach((item: any) => {
if (item.title.toLocaleLowerCase().includes(keyword)) {
tree.push(item);
} else {
const children: any[] = [];
(item.children || []).forEach((subItem: any) => {
if (subItem.title.toLocaleLowerCase().includes(keyword)) {
children.push(subItem);
}
});
if (children.length > 0) {
tree.push({
...item,
children,
});
expandedKeys.push(item.key);
}
}
});
return { tree, expandedKeys };
}
return { tree: data, expandedKeys };
}
const Log = () => { const Log = () => {
const { headerStyle, isPhone, theme } = useOutletContext<SharedContext>(); const { headerStyle, isPhone, theme } = useOutletContext<SharedContext>();
const [title, setTitle] = useState('请选择日志文件');
const [value, setValue] = useState('请选择日志文件'); const [value, setValue] = useState('请选择日志文件');
const [select, setSelect] = useState<any>(); const [select, setSelect] = useState<string>('');
const [data, setData] = useState<any[]>([]); const [data, setData] = useState<any[]>([]);
const [filterData, setFilterData] = useState<any[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [height, setHeight] = useState<number>(); const [height, setHeight] = useState<number>();
const treeDom = useRef<any>(); const treeDom = useRef<any>();
const [expandedKeys, setExpandedKeys] = useState<string[]>([]); const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
const [currentNode, setCurrentNode] = useState<any>();
const [searchValue, setSearchValue] = useState('');
const getLogs = () => { const getLogs = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}logs`) .get(`${config.apiPrefix}logs`)
.then((data) => { .then(({ code, data }) => {
setData(data.data); if (code === 200) {
setFilterData(data.data); setData(data);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -64,18 +53,27 @@ const Log = () => {
const getLog = (node: any) => { const getLog = (node: any) => {
request request
.get(`${config.apiPrefix}logs/${node.title}?path=${node.parent || ''}`) .get(`${config.apiPrefix}logs/${node.title}?path=${node.parent || ''}`)
.then((data) => { .then(({ code, data }) => {
setValue(data.data); if (code === 200) {
setValue(data);
}
}); });
}; };
const onSelect = (value: any, node: any) => { const onSelect = (value: any, node: any) => {
setCurrentNode(node);
setSelect(value);
if (node.key === select || !value) { if (node.key === select || !value) {
return; return;
} }
if (node.type === 'directory') {
setValue('请选择日志文件');
return;
}
setValue('加载中...'); setValue('加载中...');
setSelect(value);
setTitle(node.key);
getLog(node); getLog(node);
}; };
@@ -86,41 +84,129 @@ const Log = () => {
const onSearch = useCallback( const onSearch = useCallback(
(e) => { (e) => {
const keyword = e.target.value; const keyword = e.target.value;
const { tree, expandedKeys } = getFilterData( debounceSearch(keyword);
keyword.toLocaleLowerCase(),
data,
);
setFilterData(tree);
setExpandedKeys(expandedKeys);
}, },
[data, setFilterData], [data],
);
const debounceSearch = useCallback(
debounce((keyword) => {
setSearchValue(keyword);
}, 300),
[data],
);
const { treeData: filterData, keys: searchExpandedKeys } = useFilterTreeData(
data,
searchValue,
{ treeNodeFilterProp: 'title' },
); );
useEffect(() => {
setExpandedKeys(uniq([...expandedKeys, ...searchExpandedKeys]));
}, [searchExpandedKeys]);
const deleteFile = () => {
Modal.confirm({
title: `确认删除`,
content: (
<>
<Text style={{ wordBreak: 'break-all' }} type="warning">
{select}
</Text>
{currentNode.type === 'directory' ? '夹下所以日志' : ''}
</>
),
onOk() {
request
.delete(`${config.apiPrefix}logs`, {
data: {
filename: currentNode.title,
path: currentNode.parent || '',
type: currentNode.type,
},
})
.then(({ code }) => {
if (code === 200) {
message.success(`删除成功`);
let newData = [...data];
if (currentNode.parent) {
newData = depthFirstSearch(
newData,
(c) => c.key === currentNode.key,
);
} else {
const index = newData.findIndex(
(x) => x.key === currentNode.key,
);
if (index !== -1) {
newData.splice(index, 1);
}
}
setData(newData);
initState();
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const initState = () => {
setSelect('');
setCurrentNode(null);
setValue('请选择脚本文件');
};
const onExpand = (expKeys: any) => {
setExpandedKeys(expKeys);
};
useEffect(() => { useEffect(() => {
getLogs(); getLogs();
if (treeDom && treeDom.current) { }, []);
useEffect(() => {
if (treeDom.current) {
setHeight(treeDom.current.clientHeight); setHeight(treeDom.current.clientHeight);
} }
}, []); }, [treeDom.current, data]);
return ( return (
<PageContainer <PageContainer
className="ql-container-wrapper log-wrapper" className="ql-container-wrapper log-wrapper"
title={title} title={select}
loading={loading} loading={loading}
extra={ extra={
isPhone && [ isPhone
? [
<TreeSelect <TreeSelect
className="log-select" className="log-select"
value={select} value={select}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={data} treeData={data}
placeholder="请选择日志" placeholder="请选择日志"
fieldNames={{ value: 'key', label: 'title' }} fieldNames={{ value: 'key' }}
treeNodeFilterProp="title"
showSearch showSearch
allowClear
onSelect={onSelect} onSelect={onSelect}
/>, />,
] ]
: [
<Tooltip title="删除">
<Button
type="primary"
disabled={!select}
onClick={deleteFile}
icon={<DeleteOutlined />}
/>
</Tooltip>,
]
} }
header={{ header={{
style: headerStyle, style: headerStyle,
@@ -128,6 +214,7 @@ const Log = () => {
> >
<div className={`${styles['log-container']} log-container`}> <div className={`${styles['log-container']} log-container`}>
{!isPhone && ( {!isPhone && (
/*// @ts-ignore*/
<SplitPane split="vertical" size={200} maxSize={-100}> <SplitPane split="vertical" size={200} maxSize={-100}>
<div className={styles['left-tree-container']}> <div className={styles['left-tree-container']}>
{data.length > 0 ? ( {data.length > 0 ? (
@@ -140,6 +227,7 @@ const Log = () => {
></Input.Search> ></Input.Search>
<div className={styles['left-tree-scroller']} ref={treeDom}> <div className={styles['left-tree-scroller']} ref={treeDom}>
<Tree <Tree
expandAction="click"
className={styles['left-tree']} className={styles['left-tree']}
treeData={filterData} treeData={filterData}
showIcon={true} showIcon={true}
@@ -147,6 +235,8 @@ const Log = () => {
selectedKeys={[select]} selectedKeys={[select]}
showLine={{ showLeafIcon: true }} showLine={{ showLeafIcon: true }}
onSelect={onTreeSelect} onSelect={onTreeSelect}
expandedKeys={expandedKeys}
onExpand={onExpand}
></Tree> ></Tree>
</div> </div>
</> </>
+15 -23
View File
@@ -40,15 +40,7 @@ const Login = () => {
}, },
}) })
.then((data) => { .then((data) => {
if (data.code === 420) { checkResponse(data, values);
setLoginInfo({
username: values.username,
password: values.password,
});
setTwoFactor(true);
} else {
checkResponse(data);
}
setLoading(false); setLoading(false);
}) })
.catch(function (error) { .catch(function (error) {
@@ -64,11 +56,7 @@ const Login = () => {
data: { ...loginInfo, code: values.code }, data: { ...loginInfo, code: values.code },
}) })
.then((data: any) => { .then((data: any) => {
if (data.code === 430) {
message.error(data.message);
} else {
checkResponse(data); checkResponse(data);
}
setVerifying(false); setVerifying(false);
}) })
.catch((error: any) => { .catch((error: any) => {
@@ -77,8 +65,11 @@ const Login = () => {
}); });
}; };
const checkResponse = (data: any) => { const checkResponse = (
if (data.code === 200) { { code, data, message: _message }: any,
values?: any,
) => {
if (code === 200) {
const { const {
token, token,
lastip, lastip,
@@ -86,7 +77,7 @@ const Login = () => {
lastlogon, lastlogon,
retries = 0, retries = 0,
platform, platform,
} = data.data; } = data;
localStorage.setItem(config.authKey, token); localStorage.setItem(config.authKey, token);
notification.success({ notification.success({
message: '登录成功!', message: '登录成功!',
@@ -105,13 +96,14 @@ const Login = () => {
}); });
reloadUser(true); reloadUser(true);
history.push('/crontab'); history.push('/crontab');
} else if (data.code === 100) { } else if (code === 410) {
message.warn(data.message); setWaitTime(data);
} else if (data.code === 410) { } else if (code === 420) {
message.error(data.message); setLoginInfo({
setWaitTime(data.data); username: values.username,
} else { password: values.password,
message.error(data.message); });
setTwoFactor(true);
} }
}; };
+11 -4
View File
@@ -67,8 +67,10 @@ const EditModal = ({
const getDetail = (node: any) => { const getDetail = (node: any) => {
request request
.get(`${config.apiPrefix}scripts/${node.title}?path=${node.parent || ''}`) .get(`${config.apiPrefix}scripts/${node.title}?path=${node.parent || ''}`)
.then((data) => { .then(({ code, data }) => {
setValue(data.data); if (code === 200) {
setValue(data);
}
}); });
}; };
@@ -83,8 +85,10 @@ const EditModal = ({
content, content,
}, },
}) })
.then((data) => { .then(({ code, data }) => {
if (code === 200) {
setIsRunning(true); setIsRunning(true);
}
}); });
}; };
@@ -101,8 +105,10 @@ const EditModal = ({
content, content,
}, },
}) })
.then((data) => { .then(({ code, data }) => {
if (code === 200) {
setIsRunning(false); setIsRunning(false);
}
}); });
}; };
@@ -216,6 +222,7 @@ const EditModal = ({
onClose={cancel} onClose={cancel}
open={visible} open={visible}
> >
{/* @ts-ignore */}
<SplitPane <SplitPane
split="vertical" split="vertical"
minSize={200} minSize={200}
-2
View File
@@ -57,8 +57,6 @@ const EditScriptNameModal = ({
path, path,
key: `${key}${filename}`, key: `${key}${filename}`,
}); });
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
}) })
+70 -84
View File
@@ -37,37 +37,11 @@ import { history, useOutletContext, useLocation } from '@umijs/max';
import { parse } from 'query-string'; import { parse } from 'query-string';
import { depthFirstSearch } from '@/utils'; import { depthFirstSearch } from '@/utils';
import { SharedContext } from '@/layouts'; import { SharedContext } from '@/layouts';
import useFilterTreeData from '@/hooks/useFilterTreeData';
import { uniq } from 'lodash';
const { Text } = Typography; const { Text } = Typography;
function getFilterData(keyword: string, data: any) {
const expandedKeys: string[] = [];
if (keyword) {
const tree: any = [];
data.forEach((item: any) => {
if (item.title.toLocaleLowerCase().includes(keyword)) {
tree.push(item);
} else {
const children: any[] = [];
(item.children || []).forEach((subItem: any) => {
if (subItem.title.toLocaleLowerCase().includes(keyword)) {
children.push(subItem);
}
});
if (children.length > 0) {
tree.push({
...item,
children,
});
expandedKeys.push(item.key);
}
}
});
return { tree, expandedKeys };
}
return { tree: data, expandedKeys };
}
const LangMap: any = { const LangMap: any = {
'.py': 'python', '.py': 'python',
'.js': 'javascript', '.js': 'javascript',
@@ -78,11 +52,9 @@ const LangMap: any = {
const Script = () => { const Script = () => {
const { headerStyle, isPhone, theme, socketMessage } = const { headerStyle, isPhone, theme, socketMessage } =
useOutletContext<SharedContext>(); useOutletContext<SharedContext>();
const [title, setTitle] = useState('请选择脚本文件');
const [value, setValue] = useState('请选择脚本文件'); const [value, setValue] = useState('请选择脚本文件');
const [select, setSelect] = useState<any>(); const [select, setSelect] = useState<string>('');
const [data, setData] = useState<any[]>([]); const [data, setData] = useState<any[]>([]);
const [filterData, setFilterData] = useState<any[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [mode, setMode] = useState(''); const [mode, setMode] = useState('');
const [height, setHeight] = useState<number>(); const [height, setHeight] = useState<number>();
@@ -99,10 +71,11 @@ const Script = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}scripts`) .get(`${config.apiPrefix}scripts`)
.then((data) => { .then(({ code, data }) => {
setData(data.data); if (code === 200) {
setFilterData(data.data); setData(data);
initGetScript(); initGetScript();
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -110,8 +83,10 @@ const Script = () => {
const getDetail = (node: any) => { const getDetail = (node: any) => {
request request
.get(`${config.apiPrefix}scripts/${node.title}?path=${node.parent || ''}`) .get(`${config.apiPrefix}scripts/${node.title}?path=${node.parent || ''}`)
.then((data) => { .then(({ code, data }) => {
setValue(data.data); if (code === 200) {
setValue(data);
}
}); });
}; };
@@ -132,22 +107,24 @@ const Script = () => {
}; };
const onSelect = (value: any, node: any) => { const onSelect = (value: any, node: any) => {
setSelect(node.key);
setCurrentNode(node);
if (node.key === select || !value) { if (node.key === select || !value) {
return; return;
} }
setValue('加载中...');
if (node.type === 'directory') {
setValue('请选择脚本文件');
return;
}
const newMode = value ? LangMap[value.slice(-3)] : ''; const newMode = value ? LangMap[value.slice(-3)] : '';
setMode(isPhone && newMode === 'typescript' ? 'javascript' : newMode); setMode(isPhone && newMode === 'typescript' ? 'javascript' : newMode);
setSelect(node.key); setValue('加载中...');
setTitle(node.key);
setCurrentNode(node);
getDetail(node); getDetail(node);
}; };
const onExpand = (expKeys: any) => {
setExpandedKeys(expKeys);
};
const onTreeSelect = useCallback( const onTreeSelect = useCallback(
(keys: Key[], e: any) => { (keys: Key[], e: any) => {
const content = editorRef.current const content = editorRef.current
@@ -178,22 +155,30 @@ const Script = () => {
const keyword = e.target.value; const keyword = e.target.value;
debounceSearch(keyword); debounceSearch(keyword);
}, },
[data, setFilterData], [data],
); );
const debounceSearch = useCallback( const debounceSearch = useCallback(
debounce((keyword) => { debounce((keyword) => {
setSearchValue(keyword); setSearchValue(keyword);
const { tree, expandedKeys } = getFilterData(
keyword.toLocaleLowerCase(),
data,
);
setExpandedKeys(expandedKeys);
setFilterData(tree);
}, 300), }, 300),
[data, setFilterData], [data],
); );
const { treeData: filterData, keys: searchExpandedKeys } = useFilterTreeData(
data,
searchValue,
{ treeNodeFilterProp: 'title' },
);
useEffect(() => {
setExpandedKeys(uniq([...expandedKeys, ...searchExpandedKeys]));
}, [searchExpandedKeys]);
const onExpand = (expKeys: any) => {
setExpandedKeys(expKeys);
};
const editFile = () => { const editFile = () => {
setTimeout(() => { setTimeout(() => {
setIsEditing(true); setIsEditing(true);
@@ -231,13 +216,11 @@ const Script = () => {
content, content,
}, },
}) })
.then((_data: any) => { .then(({ code, data }) => {
if (_data.code === 200) { if (code === 200) {
message.success(`保存成功`); message.success(`保存成功`);
setValue(content); setValue(content);
setIsEditing(false); setIsEditing(false);
} else {
message.error(_data);
} }
resolve(null); resolve(null);
}) })
@@ -255,10 +238,11 @@ const Script = () => {
title: `确认删除`, title: `确认删除`,
content: ( content: (
<> <>
<Text style={{ wordBreak: 'break-all' }} type="warning"> <Text style={{ wordBreak: 'break-all' }} type="warning">
{select} {select}
</Text>{' '} </Text>
{currentNode.type === 'directory' ? '夹及其子文件' : ''}
</> </>
), ),
@@ -268,24 +252,18 @@ const Script = () => {
data: { data: {
filename: currentNode.title, filename: currentNode.title,
path: currentNode.parent || '', path: currentNode.parent || '',
type: currentNode.type,
}, },
}) })
.then((_data: any) => { .then(({ code }) => {
if (_data.code === 200) { if (code === 200) {
message.success(`删除成功`); message.success(`删除成功`);
let newData = [...data]; let newData = [...data];
if (currentNode.parent) { if (currentNode.parent) {
const parentNodeIndex = newData.findIndex( newData = depthFirstSearch(
(x) => x.key === currentNode.parent, newData,
(c) => c.key === currentNode.key,
); );
const parentNode = newData[parentNodeIndex];
const index = parentNode.children.findIndex(
(y) => y.key === currentNode.key,
);
if (index !== -1 && parentNodeIndex !== -1) {
parentNode.children.splice(index, 1);
newData.splice(parentNodeIndex, 1, { ...parentNode });
}
} else { } else {
const index = newData.findIndex( const index = newData.findIndex(
(x) => x.key === currentNode.key, (x) => x.key === currentNode.key,
@@ -295,8 +273,7 @@ const Script = () => {
} }
} }
setData(newData); setData(newData);
} else { initState();
message.error(_data);
} }
}); });
}, },
@@ -346,8 +323,9 @@ const Script = () => {
filename: currentNode.title, filename: currentNode.title,
}, },
}) })
.then((_data: any) => { .then(({ code, data }) => {
const blob = new Blob([_data], { type: 'application/json' }); if (code === 200) {
const blob = new Blob([data], { type: 'application/json' });
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const a = document.createElement('a'); const a = document.createElement('a');
a.href = url; a.href = url;
@@ -355,21 +333,25 @@ const Script = () => {
document.documentElement.appendChild(a); document.documentElement.appendChild(a);
a.click(); a.click();
document.documentElement.removeChild(a); document.documentElement.removeChild(a);
}
}); });
}; };
useEffect(() => { const initState = () => {
const word = searchValue || ''; setSelect('');
const { tree } = getFilterData(word.toLocaleLowerCase(), data); setCurrentNode(null);
setFilterData(tree); setValue('请选择脚本文件');
}, [data]); };
useEffect(() => { useEffect(() => {
getScripts(); getScripts();
if (treeDom && treeDom.current) { }, []);
useEffect(() => {
if (treeDom.current) {
setHeight(treeDom.current.clientHeight); setHeight(treeDom.current.clientHeight);
} }
}, []); }, [treeDom.current, data]);
const action = (key: string | number) => { const action = (key: string | number) => {
switch (key) { switch (key) {
@@ -438,19 +420,22 @@ const Script = () => {
return ( return (
<PageContainer <PageContainer
className="ql-container-wrapper log-wrapper" className="ql-container-wrapper log-wrapper"
title={title} title={select}
loading={loading} loading={loading}
extra={ extra={
isPhone isPhone
? [ ? [
<TreeSelect <TreeSelect
treeExpandAction="click"
className="log-select" className="log-select"
value={select} value={select}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={data} treeData={data}
placeholder="请选择脚本" placeholder="请选择脚本"
fieldNames={{ value: 'key', label: 'title' }} fieldNames={{ value: 'key' }}
treeNodeFilterProp="title"
showSearch showSearch
allowClear
onSelect={onSelect} onSelect={onSelect}
/>, />,
<Dropdown overlay={menu} trigger={['click']}> <Dropdown overlay={menu} trigger={['click']}>
@@ -506,6 +491,7 @@ const Script = () => {
> >
<div className={`${styles['log-container']} log-container`}> <div className={`${styles['log-container']} log-container`}>
{!isPhone && ( {!isPhone && (
/*// @ts-ignore*/
<SplitPane split="vertical" size={200} maxSize={-100}> <SplitPane split="vertical" size={200} maxSize={-100}>
<div className={styles['left-tree-container']}> <div className={styles['left-tree-container']}>
{data.length > 0 ? ( {data.length > 0 ? (
@@ -518,6 +504,7 @@ const Script = () => {
></Input.Search> ></Input.Search>
<div className={styles['left-tree-scroller']} ref={treeDom}> <div className={styles['left-tree-scroller']} ref={treeDom}>
<Tree <Tree
expandAction="click"
className={styles['left-tree']} className={styles['left-tree']}
treeData={filterData} treeData={filterData}
showIcon={true} showIcon={true}
@@ -554,7 +541,6 @@ const Script = () => {
readOnly: !isEditing, readOnly: !isEditing,
fontSize: 12, fontSize: 12,
lineNumbersMinChars: 3, lineNumbersMinChars: 3,
folding: false,
glyphMargin: false, glyphMargin: false,
}} }}
onMount={(editor) => { onMount={(editor) => {
-2
View File
@@ -26,8 +26,6 @@ const SaveModal = ({
if (code === 200) { if (code === 200) {
message.success('保存文件成功'); message.success('保存文件成功');
handleCancel(data); handleCancel(data);
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
}); });
-2
View File
@@ -26,8 +26,6 @@ const SettingModal = ({
if (code === 200) { if (code === 200) {
message.success('保存文件成功'); message.success('保存文件成功');
handleCancel(data); handleCancel(data);
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
}); });
-2
View File
@@ -30,8 +30,6 @@ const AppModal = ({
if (code === 200) { if (code === 200) {
message.success(app ? '更新应用成功' : '新建应用成功'); message.success(app ? '更新应用成功' : '新建应用成功');
handleCancel(data); handleCancel(data);
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
} catch (error) { } catch (error) {
+12 -4
View File
@@ -17,17 +17,14 @@ const CheckUpdate = ({ socketMessage }: any) => {
message.loading('检查更新中...', 0); message.loading('检查更新中...', 0);
request request
.put(`${config.apiPrefix}system/update-check`) .put(`${config.apiPrefix}system/update-check`)
.then((_data: any) => { .then(({ code, data }) => {
message.destroy(); message.destroy();
const { code, data } = _data;
if (code === 200) { if (code === 200) {
if (data.hasNewVersion) { if (data.hasNewVersion) {
showConfirmUpdateModal(data); showConfirmUpdateModal(data);
} else { } else {
showForceUpdateModal(); showForceUpdateModal();
} }
} else {
message.error(data);
} }
}) })
.catch((error: any) => { .catch((error: any) => {
@@ -105,6 +102,7 @@ const CheckUpdate = ({ socketMessage }: any) => {
}; };
const showUpdatingModal = () => { const showUpdatingModal = () => {
setValue('');
modalRef.current = Modal.info({ modalRef.current = Modal.info({
width: 600, width: 600,
maskClosable: false, maskClosable: false,
@@ -140,7 +138,12 @@ const CheckUpdate = ({ socketMessage }: any) => {
} }
const newMessage = `${value}${_message}`; const newMessage = `${value}${_message}`;
const updateFailed = newMessage.includes('失败,请检查');
modalRef.current.update({ modalRef.current.update({
maskClosable: updateFailed,
closable: updateFailed,
okButtonProps: { disabled: !updateFailed },
content: ( content: (
<div style={{ height: '60vh', overflowY: 'auto' }}> <div style={{ height: '60vh', overflowY: 'auto' }}>
<pre <pre
@@ -157,6 +160,11 @@ const CheckUpdate = ({ socketMessage }: any) => {
</div> </div>
), ),
}); });
if (updateFailed && !value.includes('失败,请检查')) {
message.error('更新失败,请检查网络及日志或稍后再试');
}
setValue(newMessage); setValue(newMessage);
document.getElementById('log-identifier') && document.getElementById('log-identifier') &&
+23 -19
View File
@@ -144,8 +144,10 @@ const Setting = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}apps`) .get(`${config.apiPrefix}apps`)
.then((data: any) => { .then(({ code, data }) => {
setDataSource(data.data); if (code === 200) {
setDataSource(data);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -175,14 +177,12 @@ const Setting = () => {
onOk() { onOk() {
request request
.delete(`${config.apiPrefix}apps`, { data: [record.id] }) .delete(`${config.apiPrefix}apps`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success('删除成功'); message.success('删除成功');
const result = [...dataSource]; const result = [...dataSource];
result.splice(index, 1); result.splice(index, 1);
setDataSource(result); setDataSource(result);
} else {
message.error(data);
} }
}); });
}, },
@@ -209,12 +209,10 @@ const Setting = () => {
onOk() { onOk() {
request request
.put(`${config.apiPrefix}apps/${record.id}/reset-secret`) .put(`${config.apiPrefix}apps/${record.id}/reset-secret`)
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success('重置成功'); message.success('重置成功');
handleApp(data.data); handleApp(data);
} else {
message.error(data);
} }
}); });
}, },
@@ -247,8 +245,10 @@ const Setting = () => {
const getLoginLog = () => { const getLoginLog = () => {
request request
.get(`${config.apiPrefix}user/login-log`) .get(`${config.apiPrefix}user/login-log`)
.then((data: any) => { .then(({ code, data }) => {
setLoginLogData(data.data); if (code === 200) {
setLoginLogData(data);
}
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(error); console.log(error);
@@ -271,8 +271,10 @@ const Setting = () => {
const getNotification = () => { const getNotification = () => {
request request
.get(`${config.apiPrefix}user/notification`) .get(`${config.apiPrefix}user/notification`)
.then((data: any) => { .then(({ code, data }) => {
setNotificationInfo(data.data); if (code === 200) {
setNotificationInfo(data);
}
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(error); console.log(error);
@@ -282,9 +284,9 @@ const Setting = () => {
const getLogRemoveFrequency = () => { const getLogRemoveFrequency = () => {
request request
.get(`${config.apiPrefix}system/log/remove`) .get(`${config.apiPrefix}system/log/remove`)
.then((data: any) => { .then(({ code, data }) => {
if (data.data.info) { if (code === 200 && data.info) {
const { frequency } = data.data.info; const { frequency } = data.info;
setLogRemoveFrequency(frequency); setLogRemoveFrequency(frequency);
} }
}) })
@@ -299,8 +301,10 @@ const Setting = () => {
.put(`${config.apiPrefix}system/log/remove`, { .put(`${config.apiPrefix}system/log/remove`, {
data: { frequency: logRemoveFrequency }, data: { frequency: logRemoveFrequency },
}) })
.then((data: any) => { .then(({ code, data }) => {
if (code === 200) {
message.success('更新成功'); message.success('更新成功');
}
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(error); console.log(error);
+4 -8
View File
@@ -23,11 +23,9 @@ const NotificationSetting = ({ data }: any) => {
...values, ...values,
}, },
}) })
.then((_data: any) => { .then(({ code, data }) => {
if (_data && _data.code === 200) { if (code === 200) {
message.success(values.type ? '通知发送成功' : '通知关闭成功'); message.success(values.type ? '通知发送成功' : '通知关闭成功');
} else {
message.error(_data.message);
} }
}) })
.catch((error: any) => { .catch((error: any) => {
@@ -75,8 +73,7 @@ const NotificationSetting = ({ data }: any) => {
rules={[{ required: x.required }]} rules={[{ required: x.required }]}
style={{ maxWidth: 400 }} style={{ maxWidth: 400 }}
> >
{ {x.items ? (
x.items ? (
<Select placeholder={x.placeholder || `请选择${x.label}`}> <Select placeholder={x.placeholder || `请选择${x.label}`}>
{x.items.map((y) => ( {x.items.map((y) => (
<Option key={y.value} value={y.value}> <Option key={y.value} value={y.value}>
@@ -89,8 +86,7 @@ const NotificationSetting = ({ data }: any) => {
autoSize={true} autoSize={true}
placeholder={x.placeholder || `请输入${x.label}`} placeholder={x.placeholder || `请输入${x.label}`}
/> />
) )}
}
</Form.Item> </Form.Item>
))} ))}
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">
+13 -7
View File
@@ -27,9 +27,11 @@ const SecuritySettings = ({ user, userChange }: any) => {
password: values.password, password: values.password,
}, },
}) })
.then((data: any) => { .then(({ code, data }) => {
if (code === 200) {
localStorage.removeItem(config.authKey); localStorage.removeItem(config.authKey);
history.push('/login'); history.push('/login');
}
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(error); console.log(error);
@@ -48,8 +50,8 @@ const SecuritySettings = ({ user, userChange }: any) => {
const deactiveTowFactor = () => { const deactiveTowFactor = () => {
request request
.put(`${config.apiPrefix}user/two-factor/deactive`) .put(`${config.apiPrefix}user/two-factor/deactive`)
.then((data: any) => { .then(({ code, data }) => {
if (data.data) { if (code === 200 && data) {
setTwoFactorActivated(false); setTwoFactorActivated(false);
userChange(); userChange();
} }
@@ -63,8 +65,9 @@ const SecuritySettings = ({ user, userChange }: any) => {
setLoading(true); setLoading(true);
request request
.put(`${config.apiPrefix}user/two-factor/active`, { data: { code } }) .put(`${config.apiPrefix}user/two-factor/active`, { data: { code } })
.then((data: any) => { .then(({ code, data }) => {
if (data.data) { if (code === 200) {
if (data) {
message.success('激活成功'); message.success('激活成功');
setTwoFactoring(false); setTwoFactoring(false);
setTwoFactorActivated(true); setTwoFactorActivated(true);
@@ -72,6 +75,7 @@ const SecuritySettings = ({ user, userChange }: any) => {
} else { } else {
message.success('验证失败'); message.success('验证失败');
} }
}
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(error); console.log(error);
@@ -82,8 +86,10 @@ const SecuritySettings = ({ user, userChange }: any) => {
const getTwoFactorInfo = () => { const getTwoFactorInfo = () => {
request request
.get(`${config.apiPrefix}user/two-factor/init`) .get(`${config.apiPrefix}user/two-factor/init`)
.then((data: any) => { .then(({ code, data }) => {
setTwoFactorInfo(data.data); if (code === 200) {
setTwoFactorInfo(data);
}
}) })
.catch((error: any) => { .catch((error: any) => {
console.log(error); console.log(error);
+12 -18
View File
@@ -263,8 +263,8 @@ const Subscription = () => {
onOk() { onOk() {
request request
.put(`${config.apiPrefix}subscriptions/run`, { data: [record.id] }) .put(`${config.apiPrefix}subscriptions/run`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
if (i !== -1) { if (i !== -1) {
@@ -274,8 +274,6 @@ const Subscription = () => {
}); });
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
@@ -300,8 +298,8 @@ const Subscription = () => {
onOk() { onOk() {
request request
.put(`${config.apiPrefix}subscriptions/stop`, { data: [record.id] }) .put(`${config.apiPrefix}subscriptions/stop`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
if (i !== -1) { if (i !== -1) {
@@ -312,8 +310,6 @@ const Subscription = () => {
}); });
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
@@ -327,9 +323,11 @@ const Subscription = () => {
setLoading(true); setLoading(true);
request request
.get(`${config.apiPrefix}subscriptions?searchValue=${searchText}`) .get(`${config.apiPrefix}subscriptions?searchValue=${searchText}`)
.then((data: any) => { .then(({ code, data }) => {
setValue(data.data); if (code === 200) {
setValue(data);
setCurrentPage(1); setCurrentPage(1);
}
}) })
.finally(() => setLoading(false)); .finally(() => setLoading(false));
}; };
@@ -359,8 +357,8 @@ const Subscription = () => {
onOk() { onOk() {
request request
.delete(`${config.apiPrefix}subscriptions`, { data: [record.id] }) .delete(`${config.apiPrefix}subscriptions`, { data: [record.id] })
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
message.success('删除成功'); message.success('删除成功');
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
@@ -368,8 +366,6 @@ const Subscription = () => {
result.splice(i, 1); result.splice(i, 1);
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
@@ -402,8 +398,8 @@ const Subscription = () => {
data: [record.id], data: [record.id],
}, },
) )
.then((data: any) => { .then(({ code, data }) => {
if (data.code === 200) { if (code === 200) {
const newStatus = record.is_disabled === 1 ? 0 : 1; const newStatus = record.is_disabled === 1 ? 0 : 1;
const result = [...value]; const result = [...value];
const i = result.findIndex((x) => x.id === record.id); const i = result.findIndex((x) => x.id === record.id);
@@ -414,8 +410,6 @@ const Subscription = () => {
}); });
setValue(result); setValue(result);
} }
} else {
message.error(data);
} }
}); });
}, },
+3 -2
View File
@@ -36,11 +36,12 @@ const SubscriptionLogModal = ({
? logUrl ? logUrl
: `${config.apiPrefix}subscriptions/${subscription.id}/log`, : `${config.apiPrefix}subscriptions/${subscription.id}/log`,
) )
.then((data: any) => { .then(({ code, data }) => {
if ( if (
code === 200 &&
localStorage.getItem('logSubscription') === String(subscription.id) localStorage.getItem('logSubscription') === String(subscription.id)
) { ) {
const log = data.data as string; const log = data as string;
setValue(log || '暂无日志'); setValue(log || '暂无日志');
setExecuting(log && !log.includes('执行结束')); setExecuting(log && !log.includes('执行结束'));
if (log && !log.includes('执行结束')) { if (log && !log.includes('执行结束')) {
+14 -32
View File
@@ -40,8 +40,6 @@ const SubscriptionModal = ({
if (code === 200) { if (code === 200) {
message.success(subscription ? '更新订阅成功' : '新建订阅成功'); message.success(subscription ? '更新订阅成功' : '新建订阅成功');
handleCancel(data); handleCancel(data);
} else {
message.error(data);
} }
setLoading(false); setLoading(false);
} catch (error: any) { } catch (error: any) {
@@ -190,8 +188,8 @@ const SubscriptionModal = ({
}; };
const onPaste = useCallback((e: any) => { const onPaste = useCallback((e: any) => {
const text = e.clipboardData.getData('text'); const text = e.clipboardData.getData('text') as string;
if (!subscription && text.includes('ql ')) { if (text.startsWith('ql ')) {
const [ const [
, ,
type, type,
@@ -225,6 +223,13 @@ const SubscriptionModal = ({
} }
}, []); }, []);
const onNamePaste = useCallback((e) => {
const text = e.clipboardData.getData('text') as string;
if (text.startsWith('ql ')) {
e.preventDefault();
}
}, []);
useEffect(() => { useEffect(() => {
if (visible) { if (visible) {
window.addEventListener('paste', onPaste); window.addEventListener('paste', onPaste);
@@ -243,35 +248,9 @@ const SubscriptionModal = ({
} }
}, [subscription, visible]); }, [subscription, visible]);
const isFirefox = navigator.userAgent.includes('Firefox');
const isSafari =
navigator.userAgent.includes('Safari') &&
!navigator.userAgent.includes('Chrome');
const isQQBrowser = navigator.userAgent.includes('QQBrowser');
return ( return (
<Modal <Modal
title={ title={subscription ? '编辑订阅' : '新建订阅'}
subscription ? (
'编辑订阅'
) : (
<span>
<small
style={{
color: '#999',
fontWeight: 400,
fontSize: isFirefox ? 9 : 12,
marginLeft: 2,
zoom: isSafari ? 0.66 : 0.8,
letterSpacing: isQQBrowser ? -2 : 0,
}}
>
repo/raw命令
</small>
</span>
)
}
open={visible} open={visible}
forceRender forceRender
centered centered
@@ -291,7 +270,10 @@ const SubscriptionModal = ({
> >
<Form form={form} name="form_in_modal" layout="vertical"> <Form form={form} name="form_in_modal" layout="vertical">
<Form.Item name="name" label="名称"> <Form.Item name="name" label="名称">
<Input placeholder="请输入订阅名" /> <Input
placeholder="支持拷贝ql repo/raw命令,粘贴导入"
onPaste={onNamePaste}
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="type" name="type"
+3 -3
View File
@@ -56,7 +56,7 @@ export default {
value: 'scripts', value: 'scripts',
}, },
{ {
name: '任务日志', name: '日志管理',
value: 'logs', value: 'logs',
}, },
{ {
@@ -74,7 +74,7 @@ export default {
subscriptions: '订阅管理', subscriptions: '订阅管理',
configs: '配置文件', configs: '配置文件',
scripts: '脚本管理', scripts: '脚本管理',
logs: '任务日志', logs: '日志管理',
dependencies: '依赖管理', dependencies: '依赖管理',
system: '系统信息', system: '系统信息',
}, },
@@ -263,7 +263,7 @@ export default {
'/config': '配置文件', '/config': '配置文件',
'/script': '脚本管理', '/script': '脚本管理',
'/diff': '对比工具', '/diff': '对比工具',
'/log': '任务日志', '/log': '日志管理',
'/setting': '系统设置', '/setting': '系统设置',
'/error': '错误日志', '/error': '错误日志',
}, },
+17 -1
View File
@@ -54,7 +54,23 @@ _request.interceptors.request.use((url, options) => {
}); });
_request.interceptors.response.use(async (response) => { _request.interceptors.response.use(async (response) => {
const res = await response.clone(); const responseStatus = response.status;
if ([502, 504].includes(responseStatus)) {
message.error('服务异常,请稍后刷新!');
history.push('/error');
} else if (responseStatus === 401) {
if (history.location.pathname !== '/login') {
localStorage.removeItem(config.authKey);
history.push('/login');
}
} else {
const res = await response.clone().json();
if (res.code !== 200) {
const msg = res.message || res.data;
msg && message.error(msg);
}
return res;
}
return response; return response;
}); });
+6 -1
View File
@@ -244,7 +244,7 @@ export function exportJson(name: string, data: string) {
export function depthFirstSearch< export function depthFirstSearch<
T extends Record<string, any> & { children?: T[] }, T extends Record<string, any> & { children?: T[] },
>(children: T[], condition: (column: T) => boolean, item: T) { >(children: T[], condition: (column: T) => boolean, item?: T) {
const c = [...children]; const c = [...children];
const keys = []; const keys = [];
@@ -252,6 +252,11 @@ export function depthFirstSearch<
if (!cls) return; if (!cls) return;
for (let i = 0; i < cls?.length; i++) { for (let i = 0; i < cls?.length; i++) {
if (condition(cls[i])) { if (condition(cls[i])) {
if (!item) {
cls.splice(i, 1);
return;
}
if (cls[i].children) { if (cls[i].children) {
cls[i].children!.unshift(item); cls[i].children!.unshift(item);
} else { } else {
+7 -7
View File
@@ -1,8 +1,8 @@
export const version = '2.14.4'; export const version = '2.14.6';
export const changeLogLink = 'https://t.me/jiao_long/331'; export const changeLogLink = 'https://t.me/jiao_long/333';
export const changeLog = `2.14.4 版本说明 export const changeLog = `2.14.6 版本说明
1. 通知设置新增自定义通知 1. 任务执行日志增加资源占用说明
2. 脚本管理支持新建文件夹 2. 配置文件config.sh增加资源配置参数CpuWarn/MemoryWarn/DiskWarn
3. 依赖管理增加批量重新安装 3. 修复脚本管理和日志管理搜索
4. 修复创建应用错误 4. 其他bug修复
`; `;