Compare commits

...
18 Commits
Author SHA1 Message Date
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
55 changed files with 741 additions and 593 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
<p align="center">
<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>
</p>
@@ -183,7 +183,7 @@ task <file_path> desi <env_name> <account_number>
- [crontab-ui](https://github.com/alseambusher/crontab-ui)
- [Ant Design](https://ant.design)
- [Ant Design Pro](https://pro.ant.design/)
- [Umijs3.0](https://umijs.org)
- [Umijs](https://umijs.org)
- [darkreader](https://github.com/darkreader/darkreader)
- [admin-server](https://github.com/sunpu007/admin-server)
+2 -2
View File
@@ -1,6 +1,6 @@
<p align="center">
<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>
</p>
@@ -183,7 +183,7 @@ task <file_path> desi <env_name> <account_number>
- [crontab-ui](https://github.com/alseambusher/crontab-ui)
- [Ant Design](https://ant.design)
- [Ant Design Pro](https://pro.ant.design/)
- [Umijs3.0](https://umijs.org)
- [Umijs](https://umijs.org)
- [darkreader](https://github.com/darkreader/darkreader)
- [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 * as fs from 'fs';
import config from '../config';
import { getFileContentByName, readDirs } from '../config/util';
import { emptyDir, getFileContentByName, readDirs } from '../config/util';
import { join } from 'path';
import { celebrate, Joi } from 'celebrate';
const route = Router();
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);
}
},
);
};
+9 -2
View File
@@ -4,6 +4,7 @@ import {
readDirs,
getLastModifyFilePath,
readDir,
emptyDir,
} from '../config/util';
import { Router, Request, Response, NextFunction } from 'express';
import { Container } from 'typedi';
@@ -169,17 +170,23 @@ export default (app: Router) => {
body: Joi.object({
filename: Joi.string().required(),
path: Joi.string().allow(''),
type: Joi.string().optional()
}),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
let { filename, path } = req.body as {
let { filename, path, type } = req.body as {
filename: string;
path: string;
type: string;
};
const filePath = join(config.scriptPath, path, filename);
fs.unlinkSync(filePath);
if (type === 'directory') {
emptyDir(filePath);
} else {
fs.unlinkSync(filePath);
}
res.send({ code: 200 });
} catch (e) {
return next(e);
+1 -1
View File
@@ -17,7 +17,7 @@ async function startServer() {
const server = app
.listen(config.port, () => {
Logger.debug(`✌️ Back server launched on port ${config.port}`);
Logger.debug(`✌️ 后端服务启动成功!`);
})
.on('error', (err) => {
Logger.error(err);
+1 -1
View File
@@ -11,7 +11,7 @@ if (!process.env.QL_DIR) {
if (qlHomePath.endsWith('/static/')) {
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()}`;
+15 -1
View File
@@ -302,7 +302,6 @@ export function readDirs(
title: file,
key,
type: 'directory',
disabled: true,
parent: relativePath,
children: readDirs(subPath, baseDir).sort(
(a: any, b: any) =>
@@ -345,6 +344,21 @@ export function readDir(
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> {
return new Promise((resolve, reject) => {
exec(
+2 -4
View File
@@ -18,13 +18,12 @@ export default async () => {
tokenCommand = `node ${tokenFile}`;
}
const cron = {
id: 'token',
id: NaN,
name: '生成token',
command: tokenCommand,
};
scheduleService.createIntervalTask(cron as any, {
scheduleService.createIntervalTask(cron, {
days: 28,
runImmediately: true,
});
// 运行删除日志任务
@@ -37,7 +36,6 @@ export default async () => {
};
scheduleService.createIntervalTask(cron, {
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 Tracing from '@sentry/tracing';
import Logger from './logger';
import config from '../config';
import fs from 'fs';
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({
dsn: 'https://f4b5b55fb3c645b29a5dc2d70a1a4ef4@o1098464.ingest.sentry.io/6122819',
integrations: [
new Sentry.Integrations.Http({ tracing: true }),
new Tracing.Integrations.Express({ app: expressApp }),
],
tracesSampleRate: 1.0,
tracesSampleRate: 0.1,
release: currentVersion,
});
expressApp.use(Sentry.Handlers.requestHandler());
+1 -1
View File
@@ -22,7 +22,7 @@ app
await require('./loaders/sentry').default({ expressApp: app });
await require('./loaders/db').default();
Logger.debug(`✌️ Back server launched on port ${config.publicPort}`);
Logger.debug(`✌️ 公共服务启动成功!`);
})
.on('error', (err) => {
Logger.error(err);
+1 -5
View File
@@ -44,11 +44,7 @@ app
await require('./loaders/db').default();
await run();
Logger.info(`
################################################
🛡️ Schedule listening on port: ${config.cronPort} 🛡️
################################################
`);
Logger.debug('定时任务服务启动成功!');
})
.on('error', (err) => {
Logger.error(err);
+1 -2
View File
@@ -70,9 +70,8 @@ export default class SystemService {
};
await this.scheduleService.cancelIntervalTask(cron);
if (frequency > 0) {
await this.scheduleService.createIntervalTask(cron, {
this.scheduleService.createIntervalTask(cron, {
days: frequency,
runImmediately: true,
});
}
return { code: 200, data: { ...cron } };
+20 -15
View File
@@ -24,7 +24,7 @@ export default class UserService {
@Inject('logger') private logger: winston.Logger,
private scheduleService: ScheduleService,
private sockService: SockService,
) {}
) { }
public async login(
payloads: {
@@ -65,15 +65,13 @@ export default class UserService {
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 {
code: 410,
message: `失败次数过多,请${Math.round(
(Math.pow(3, retries) * 1000 - Date.now() + lastlogon) / 1000,
)}秒后重试`,
data: Math.round(
(Math.pow(3, retries) * 1000 - Date.now() + lastlogon) / 1000,
),
message: `失败次数过多,请${waitTime}秒后重试`,
data: waitTime,
};
}
@@ -85,12 +83,12 @@ export default class UserService {
});
return {
code: 420,
message: '请输入两步验证token',
message: '',
};
}
const data = createRandomString(50, 100);
const expiration = twoFactorActivated ? 30 : 3;
const expiration = twoFactorActivated ? 60 : 20;
let token = jwt.sign({ data }, config.secret as any, {
expiresIn: 60 * 60 * 24 * expiration,
algorithm: 'HS384',
@@ -111,8 +109,7 @@ export default class UserService {
});
await this.notificationService.notify(
'登录通知',
`你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}${address} ${
req.platform
`你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}${address} ${req.platform
}端 登录成功,ip地址 ${ip}`,
);
await this.getLoginLog();
@@ -140,8 +137,7 @@ export default class UserService {
});
await this.notificationService.notify(
'登录通知',
`你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}${address} ${
req.platform
`你于${dayjs(timestamp).format('YYYY-MM-DD HH:mm:ss')}${address} ${req.platform
}端 登录失败,ip地址 ${ip}`,
);
await this.getLoginLog();
@@ -155,7 +151,16 @@ export default class UserService {
status: LoginStatus.fail,
},
});
return { code: 400, message: config.authError };
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 };
}
}
} else {
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
pm2 l &>/dev/null
if [[ $PipMirror ]]; then
pip3 config set global.index-url $PipMirror
fi
if [[ $NpmMirror ]]; then
npm config set registry $NpmMirror
fi
patch_version &>/dev/null
echo
echo -e "======================2. 安装依赖========================\n"
@@ -47,13 +42,13 @@ echo -e "定时任务启动成功...\n"
if [[ $AutoStartBot == true ]]; then
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"
fi
if [[ $EnableExtraShell == true ]]; then
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"
fi
+55 -2
View File
@@ -349,8 +349,8 @@ reset_branch() {
local branch="$1"
if [[ $branch ]]; then
part_cmd="origin/${branch}"
git checkout -B "$branch"
git branch --set-upstream-to=$part_cmd $branch
git checkout -B "$branch" &>/dev/null
git branch --set-upstream-to=$part_cmd $branch &>/dev/null
fi
git reset --hard $part_cmd &>/dev/null
}
@@ -423,6 +423,59 @@ format_timestamp() {
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
detect_termux
detect_macos
+8 -13
View File
@@ -133,8 +133,7 @@ run_normal() {
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"
[[ $ID ]] && update_cron "\"$ID\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
cd $dir_scripts
@@ -150,7 +149,7 @@ run_normal() {
local end_time=$(date '+%Y-%m-%d %H:%M:%S')
local end_timestamp=$(date "+%s")
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
}
@@ -187,8 +186,7 @@ run_concurrent() {
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"
[[ $ID ]] && update_cron "\"$ID\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
local envs=$(eval echo "\$${env_param}")
@@ -218,7 +216,7 @@ run_concurrent() {
local end_time=$(date '+%Y-%m-%d %H:%M:%S')
local end_timestamp=$(date "+%s")
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
}
@@ -254,8 +252,7 @@ run_designated() {
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"
[[ $ID ]] && update_cron "\"$ID\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
cd $dir_scripts
@@ -270,7 +267,7 @@ run_designated() {
local end_time=$(date '+%Y-%m-%d %H:%M:%S')
local end_timestamp=$(date "+%s")
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
}
@@ -285,9 +282,7 @@ run_else() {
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"
[[ $ID ]] && update_cron "\"$ID\"" "0" "$$" "$log_path" "$begin_timestamp"
eval . $file_task_before "$@" $cmd
cd $dir_scripts
@@ -304,7 +299,7 @@ run_else() {
local end_time=$(date '+%Y-%m-%d %H:%M:%S')
local end_timestamp=$(date "+%s")
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
}
+11 -61
View File
@@ -244,11 +244,10 @@ usage() {
## 更新qinglong
update_qinglong() {
patch_version
patch_version &>/dev/null
export isFirstStartServer=false
local no_restart="$1"
local all_branch=$(git branch -a)
local primary_branch="master"
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)
[[ "$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"
if [[ -d ${ql_static_repo}/.git ]]; then
reset_romote_url ${ql_static_repo} ${url} ${primary_branch}
@@ -291,63 +296,8 @@ update_qinglong() {
reload_pm2
fi
else
echo -e "\n更新青龙静态资源失败,请检查原因...\n"
echo -e "\n更新青龙静态资源失败,请检查网络...\n"
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
}
## 对比脚本
+6 -6
View File
@@ -68,18 +68,18 @@ export default {
icon: <IconFont type="ql-icon-dependence" />,
component: '@/pages/dependence/index',
},
{
path: '/log',
name: '日志管理',
icon: <IconFont type="ql-icon-log" />,
component: '@/pages/log/index',
},
{
path: '/diff',
name: '对比工具',
icon: <IconFont type="ql-icon-diff" />,
component: '@/pages/diff/index',
},
{
path: '/log',
name: '任务日志',
icon: <IconFont type="ql-icon-log" />,
component: '@/pages/log/index',
},
{
path: '/setting',
name: '系统设置',
+21 -24
View File
@@ -161,7 +161,7 @@
&.env-wrapper,
&.config-wrapper {
.CodeMirror {
width: calc(100vw - 80px);
width: calc(100vw - 24px);
}
}
}
@@ -243,31 +243,28 @@
font-size: 13px;
}
[data-dark='true'] {
/* Change autocomplete styles in WebKit */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus,
select:-webkit-autofill,
select:-webkit-autofill:hover,
select:-webkit-autofill:focus {
border: 1px solid @border-color-base;
box-shadow: none;
transition: background-color 5000s ease-in-out 0s;
-webkit-text-fill-color: @text-color;
caret-color: #e8e6f3 !important;
}
/* Change autocomplete styles in WebKit */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
textarea:-webkit-autofill:hover,
textarea:-webkit-autofill:focus,
select:-webkit-autofill,
select:-webkit-autofill:hover,
select:-webkit-autofill:focus {
border: none;
box-shadow: none;
transition: background-color 5000s ease-in-out 0s;
-webkit-text-fill-color: @text-color;
}
::placeholder {
opacity: 0.5 !important;
}
::placeholder {
opacity: 0.5 !important;
}
.ant-select-selection-placeholder {
opacity: 0.5 !important;
}
.ant-select-selection-placeholder {
opacity: 0.5 !important;
}
.ant-pro-basicLayout-content {
+10 -6
View File
@@ -20,6 +20,9 @@ import { message, Badge, Modal, Avatar, Dropdown, Menu, Image } from 'antd';
import SockJS from 'sockjs-client';
import * as Sentry from '@sentry/react';
import { init } from '../utils/init';
import 'codemirror/mode/javascript/javascript';
import 'codemirror/mode/python/python';
import 'codemirror/mode/shell/shell';
export interface SharedContext {
headerStyle: React.CSSProperties;
@@ -41,6 +44,7 @@ export default function () {
const ws = useRef<any>(null);
const [socketMessage, setSocketMessage] = useState<any>();
const [collapsed, setCollapsed] = useState(false);
const [initLoading, setInitLoading] = useState<boolean>(true);
const {
enable: enableDarkMode,
disable: disableDarkMode,
@@ -64,17 +68,15 @@ export default function () {
setSystemInfo(data);
if (!data.isInitialized) {
history.push('/initialization');
setLoading(false);
} else {
getUser();
}
} else {
message.error(data);
}
})
.catch((error) => {
console.log(error);
});
})
.finally(() => setInitLoading(false));
};
const getUser = (needLoading = true) => {
@@ -87,8 +89,6 @@ export default function () {
if (location.pathname === '/') {
history.push('/crontab');
}
} else {
message.error(data);
}
needLoading && setLoading(false);
})
@@ -196,6 +196,10 @@ export default function () {
};
}, []);
if (initLoading) {
return <PageLoading />;
}
if (['/login', '/initialization', '/error'].includes(location.pathname)) {
document.title = `${
(config.documentTitleMap as any)[location.pathname]
+12 -6
View File
@@ -25,8 +25,10 @@ const Config = () => {
const [confirmLoading, setConfirmLoading] = useState(false);
const getConfig = (name: string) => {
request.get(`${config.apiPrefix}configs/${name}`).then((data: any) => {
setValue(data.data);
request.get(`${config.apiPrefix}configs/${name}`).then(({ code, data }) => {
if (code === 200) {
setValue(data);
}
});
};
@@ -34,8 +36,10 @@ const Config = () => {
setLoading(true);
request
.get(`${config.apiPrefix}configs/files`)
.then((data: any) => {
setData(data.data);
.then(({ code, data }) => {
if (code === 200) {
setData(data);
}
})
.finally(() => setLoading(false));
};
@@ -50,8 +54,10 @@ const Config = () => {
.post(`${config.apiPrefix}configs/save`, {
data: { content, name: select },
})
.then((data: any) => {
message.success(data.message);
.then(({ code, data }) => {
if (code === 200) {
message.success('保存成功');
}
setConfirmLoading(false);
});
};
+22 -29
View File
@@ -103,7 +103,6 @@ const CronDetailModal = ({
fontSize: 12,
lineNumbersMinChars: 3,
fontFamily: 'Source Code Pro',
folding: false,
glyphMargin: false,
wordWrap: 'on',
}}
@@ -123,9 +122,11 @@ const CronDetailModal = ({
.get(
`${config.apiPrefix}logs/${item.filename}?path=${item.directory || ''}`,
)
.then((data) => {
setLog(data.data);
setIsLogModalVisible(true);
.then(({ code, data }) => {
if (code === 200) {
setLog(data);
setIsLogModalVisible(true);
}
});
};
@@ -137,9 +138,9 @@ const CronDetailModal = ({
setLoading(true);
request
.get(`${config.apiPrefix}crons/${cron.id}/logs`)
.then((data: any) => {
if (data.code === 200) {
setLogs(data.data);
.then(({ code, data }) => {
if (code === 200) {
setLogs(data);
}
})
.finally(() => setLoading(false));
@@ -165,8 +166,10 @@ const CronDetailModal = ({
setScriptInfo({ parent: p, filename: s });
request
.get(`${config.apiPrefix}scripts/${s}?path=${p || ''}`)
.then((data) => {
setValue(data.data);
.then(({ code, data }) => {
if (code === 200) {
setValue(data);
}
});
} else {
setValidTabs([validTabs[0]]);
@@ -198,12 +201,10 @@ const CronDetailModal = ({
content,
},
})
.then((_data: any) => {
if (_data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
setValue(content);
message.success(`保存成功`);
} else {
message.error(_data);
}
resolve(null);
})
@@ -231,14 +232,12 @@ const CronDetailModal = ({
onOk() {
request
.put(`${config.apiPrefix}crons/run`, { data: [currentCron.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
setCurrentCron({ ...currentCron, status: CrontabStatus.running });
setTimeout(() => {
getLogs();
}, 1000);
} else {
message.error(data);
}
});
},
@@ -263,11 +262,9 @@ const CronDetailModal = ({
onOk() {
request
.put(`${config.apiPrefix}crons/stop`, { data: [currentCron.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
setCurrentCron({ ...currentCron, status: CrontabStatus.idle });
} else {
message.error(data);
}
});
},
@@ -300,14 +297,12 @@ const CronDetailModal = ({
data: [currentCron.id],
},
)
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
setCurrentCron({
...currentCron,
isDisabled: currentCron.isDisabled === 1 ? 0 : 1,
});
} else {
message.error(data);
}
});
},
@@ -340,14 +335,12 @@ const CronDetailModal = ({
data: [currentCron.id],
},
)
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
setCurrentCron({
...currentCron,
isPinned: currentCron.isPinned === 1 ? 0 : 1,
});
} else {
message.error(data);
}
});
},
+50 -58
View File
@@ -433,20 +433,22 @@ const Crontab = () => {
}
request
.get(url)
.then((_data: any) => {
const { data, total } = _data.data;
setValue(
data.map((x) => {
return {
...x,
nextRunTime: cron_parser
.parseExpression(x.schedule)
.next()
.toDate(),
};
}),
);
setTotal(total);
.then(({ code, data: _data }) => {
if (code === 200) {
const { data, total } = _data;
setValue(
data.map((x) => {
return {
...x,
nextRunTime: cron_parser
.parseExpression(x.schedule)
.next()
.toDate(),
};
}),
);
setTotal(total);
}
})
.finally(() => setLoading(false));
};
@@ -476,8 +478,8 @@ const Crontab = () => {
onOk() {
request
.delete(`${config.apiPrefix}crons`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success('删除成功');
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
@@ -485,8 +487,6 @@ const Crontab = () => {
result.splice(i, 1);
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -511,8 +511,8 @@ const Crontab = () => {
onOk() {
request
.put(`${config.apiPrefix}crons/run`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
if (i !== -1) {
@@ -522,8 +522,6 @@ const Crontab = () => {
});
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -548,8 +546,8 @@ const Crontab = () => {
onOk() {
request
.put(`${config.apiPrefix}crons/stop`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
if (i !== -1) {
@@ -560,8 +558,6 @@ const Crontab = () => {
});
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -594,8 +590,8 @@ const Crontab = () => {
data: [record.id],
},
)
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const newStatus = record.isDisabled === 1 ? 0 : 1;
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
@@ -606,8 +602,6 @@ const Crontab = () => {
});
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -640,8 +634,8 @@ const Crontab = () => {
data: [record.id],
},
)
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const newStatus = record.isPinned === 1 ? 0 : 1;
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
@@ -652,8 +646,6 @@ const Crontab = () => {
});
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -755,19 +747,21 @@ const Crontab = () => {
const getCronDetail = (cron: any) => {
request
.get(`${config.apiPrefix}crons/${cron.id}`)
.then((data: any) => {
const index = value.findIndex((x) => x.id === cron.id);
const result = [...value];
data.data.nextRunTime = cron_parser
.parseExpression(data.data.schedule)
.next()
.toDate();
if (index !== -1) {
result.splice(index, 1, {
...cron,
...data.data,
});
setValue(result);
.then(({ code, data }) => {
if (code === 200) {
const index = value.findIndex((x) => x.id === cron.id);
const result = [...value];
data.nextRunTime = cron_parser
.parseExpression(data.schedule)
.next()
.toDate();
if (index !== -1) {
result.splice(index, 1, {
...cron,
...data,
});
setValue(result);
}
}
})
.finally(() => setLoading(false));
@@ -795,13 +789,11 @@ const Crontab = () => {
onOk() {
request
.delete(`${config.apiPrefix}crons`, { data: selectedRowIds })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success('批量删除成功');
setSelectedRowIds([]);
getCrons();
} else {
message.error(data);
}
});
},
@@ -820,11 +812,9 @@ const Crontab = () => {
.put(`${config.apiPrefix}crons/${OperationPath[operationStatus]}`, {
data: selectedRowIds,
})
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
getCrons();
} else {
message.error(data);
}
});
},
@@ -1029,9 +1019,11 @@ const Crontab = () => {
setLoading(true);
request
.get(`${config.apiPrefix}crons/views`)
.then((data: any) => {
setCronViews(data.data);
setEnabledCronViews(data.data.filter((x) => !x.isDisabled));
.then(({ code, data }) => {
if (code === 200) {
setCronViews(data);
setEnabledCronViews(data.filter((x) => !x.isDisabled));
}
})
.finally(() => {
setLoading(false);
+6 -3
View File
@@ -41,9 +41,12 @@ const CronLogModal = ({
}
request
.get(logUrl ? logUrl : `${config.apiPrefix}crons/${cron.id}/log`)
.then((data: any) => {
if (localStorage.getItem('logCron') === String(cron.id)) {
const log = data.data as string;
.then(({ code, data }) => {
if (
code === 200 &&
localStorage.getItem('logCron') === String(cron.id)
) {
const log = data as string;
setValue(log || '暂无日志');
setExecuting(
log && !log.includes('执行结束') && !log.includes('重启面板'),
-4
View File
@@ -32,8 +32,6 @@ const CronModal = ({
if (code === 200) {
message.success(cron ? '更新Cron成功' : '新建Cron成功');
handleCancel(data);
} else {
message.error(data);
}
setLoading(false);
} catch (error: any) {
@@ -142,8 +140,6 @@ const CronLabelModal = ({
action === 'post' ? '添加Labels成功' : '删除Labels成功',
);
handleCancel(true);
} else {
message.error(data);
}
setLoading(false);
} catch (error) {
+1 -3
View File
@@ -66,9 +66,7 @@ const ViewCreateModal = ({
},
);
if (code !== 200) {
message.error(data);
} else {
if (code === 200) {
handleCancel(data);
}
setLoading(false);
+7 -13
View File
@@ -141,12 +141,10 @@ const ViewManageModal = ({
onOk() {
request
.delete(`${config.apiPrefix}crons/views`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success('删除成功');
cronViewChange();
} else {
message.error(data);
}
});
},
@@ -162,14 +160,12 @@ const ViewManageModal = ({
.put(`${config.apiPrefix}crons/views/${checked ? 'enable' : 'disable'}`, {
data: [record.id],
})
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const _list = [...list];
_list.splice(index, 1, { ...list[index], isDisabled: !checked });
setList(_list);
cronViewChange();
} else {
message.error(data);
}
});
};
@@ -190,15 +186,13 @@ const ViewManageModal = ({
.put(`${config.apiPrefix}crons/views/move`, {
data: { fromIndex: dragIndex, toIndex: hoverIndex, id: dragRow.id },
})
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const newData = [...list];
newData.splice(dragIndex, 1);
newData.splice(hoverIndex, 0, { ...dragRow, ...data.data });
newData.splice(hoverIndex, 0, { ...dragRow, ...data });
setList(newData);
cronViewChange();
} else {
message.error(data);
}
});
},
+29 -35
View File
@@ -175,8 +175,10 @@ const Dependence = () => {
.get(
`${config.apiPrefix}dependencies?searchValue=${searchText}&type=${type}`,
)
.then((data: any) => {
setValue(data.data);
.then(({ code, data }) => {
if (code === 200) {
setValue(data);
}
})
.finally(() => setLoading(false));
};
@@ -212,18 +214,14 @@ const Dependence = () => {
.delete(`${config.apiPrefix}dependencies${force ? '/force' : ''}`, {
data: [record.id],
})
.then((data: any) => {
if (data.code === 200) {
if (force) {
const i = value.findIndex((x) => x.id === data.data[0].id);
if (i !== -1) {
const result = [...value];
result.splice(i, 1);
setValue(result);
}
.then(({ code, data }) => {
if (code === 200 && force) {
const i = value.findIndex((x) => x.id === data.data[0].id);
if (i !== -1) {
const result = [...value];
result.splice(i, 1);
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -250,11 +248,9 @@ const Dependence = () => {
.put(`${config.apiPrefix}dependencies/reinstall`, {
data: [record.id],
})
.then((data: any) => {
if (data.code === 200) {
handleDependence(data.data[0]);
} else {
message.error(data);
.then(({ code, data }) => {
if (code === 200) {
handleDependence(data[0]);
}
});
},
@@ -309,12 +305,10 @@ const Dependence = () => {
.delete(`${config.apiPrefix}dependencies${forceUrl}`, {
data: selectedRowIds,
})
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
setSelectedRowIds([]);
getDependencies();
} else {
message.error(data);
}
});
},
@@ -333,12 +327,10 @@ const Dependence = () => {
.put(`${config.apiPrefix}dependencies/reinstall`, {
data: selectedRowIds,
})
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
setSelectedRowIds([]);
getDependencies();
} else {
message.error(data);
}
});
},
@@ -351,15 +343,17 @@ const Dependence = () => {
const getDependenceDetail = (dependence: any) => {
request
.get(`${config.apiPrefix}dependencies/${dependence.id}`)
.then((data: any) => {
const index = value.findIndex((x) => x.id === dependence.id);
const result = [...value];
if (index !== -1) {
result.splice(index, 1, {
...dependence,
...data.data,
});
setValue(result);
.then(({ code, data }) => {
if (code === 200) {
const index = value.findIndex((x) => x.id === dependence.id);
const result = [...value];
if (index !== -1) {
result.splice(index, 1, {
...dependence,
...data,
});
setValue(result);
}
}
})
.finally(() => setLoading(false));
+10 -5
View File
@@ -48,9 +48,12 @@ const DependenceLogModal = ({
setLoading(true);
request
.get(`${config.apiPrefix}dependencies/${dependence.id}`)
.then((data: any) => {
if (localStorage.getItem('logDependence') === String(dependence.id)) {
const log = (data.data.log || []).join('') as string;
.then(({ code, data }) => {
if (
code === 200 &&
localStorage.getItem('logDependence') === String(dependence.id)
) {
const log = (data.log || []).join('') as string;
setValue(log);
setExecuting(!log.includes('结束时间'));
setIsRemoveFailed(log.includes('删除失败'));
@@ -67,8 +70,10 @@ const DependenceLogModal = ({
.delete(`${config.apiPrefix}dependencies/force`, {
data: [dependence.id],
})
.then((data: any) => {
cancel(true);
.then(({ code, data }) => {
if (code === 200) {
cancel(true);
}
})
.finally(() => {
setRemoveLoading(false);
+1 -3
View File
@@ -53,9 +53,7 @@ const DependenceModal = ({
},
);
if (code !== 200) {
message.error(data);
} else {
if (code === 200) {
handleCancel(data);
}
setLoading(false);
+22 -10
View File
@@ -22,15 +22,23 @@ const Diff = () => {
const editorRef = useRef<any>(null);
const getConfig = () => {
request.get(`${config.apiPrefix}configs/${current}`).then((data) => {
setCurrentValue(data.data);
});
request
.get(`${config.apiPrefix}configs/${current}`)
.then(({ code, data }) => {
if (code === 200) {
setCurrentValue(data);
}
});
};
const getSample = () => {
request.get(`${config.apiPrefix}configs/${origin}`).then((data) => {
setOriginValue(data.data);
});
request
.get(`${config.apiPrefix}configs/${origin}`)
.then(({ code, data }) => {
if (code === 200) {
setOriginValue(data);
}
});
};
const updateConfig = () => {
@@ -42,8 +50,10 @@ const Diff = () => {
.post(`${config.apiPrefix}configs/save`, {
data: { content, name: current },
})
.then((data: any) => {
message.success(data.message);
.then(({ code, data }) => {
if (code === 200) {
message.success('保存成功');
}
});
};
@@ -51,8 +61,10 @@ const Diff = () => {
setLoading(true);
request
.get(`${config.apiPrefix}configs/files`)
.then((data: any) => {
setFiles(data.data);
.then(({ code, data }) => {
if (code === 200) {
setFiles(data);
}
})
.finally(() => setLoading(false));
};
-2
View File
@@ -28,8 +28,6 @@ const EditNameModal = ({
if (code === 200) {
message.success('更新环境变量名称成功');
handleCancel();
} else {
message.error(data);
}
setLoading(false);
} catch (error) {
+14 -22
View File
@@ -255,8 +255,10 @@ const Env = () => {
setLoading(true);
request
.get(`${config.apiPrefix}envs?searchValue=${searchText}`)
.then((data: any) => {
setValue(data.data);
.then(({ code, data }) => {
if (code === 200) {
setValue(data);
}
})
.finally(() => setLoading(false));
};
@@ -284,8 +286,8 @@ const Env = () => {
data: [record.id],
},
)
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success(
`${record.status === Status. ? '启用' : '禁用'}成功`,
);
@@ -297,8 +299,6 @@ const Env = () => {
status: newStatus,
});
setValue(result);
} else {
message.error(data);
}
});
},
@@ -333,14 +333,12 @@ const Env = () => {
onOk() {
request
.delete(`${config.apiPrefix}envs`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success('删除成功');
const result = [...value];
result.splice(index, 1);
setValue(result);
} else {
message.error(data);
}
});
},
@@ -390,14 +388,12 @@ const Env = () => {
.put(`${config.apiPrefix}envs/${dragRow.id}/move`, {
data: { fromIndex: dragIndex, toIndex: hoverIndex },
})
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const newData = [...value];
newData.splice(dragIndex, 1);
newData.splice(hoverIndex, 0, { ...dragRow, ...data.data });
setValue([...newData]);
} else {
message.error(data);
}
});
},
@@ -426,13 +422,11 @@ const Env = () => {
onOk() {
request
.delete(`${config.apiPrefix}envs`, { data: selectedRowIds })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success('批量删除成功');
setSelectedRowIds([]);
getEnvs();
} else {
message.error(data);
}
});
},
@@ -451,11 +445,9 @@ const Env = () => {
.put(`${config.apiPrefix}envs/${OperationPath[operationStatus]}`, {
data: selectedRowIds,
})
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
getEnvs();
} else {
message.error(data);
}
});
},
-2
View File
@@ -44,8 +44,6 @@ const EnvModal = ({
if (code === 200) {
message.success(env ? '更新变量成功' : '新建变量成功');
handleCancel(data);
} else {
message.error(data);
}
setLoading(false);
} catch (error: any) {
+4 -2
View File
@@ -17,8 +17,10 @@ const Error = () => {
setLoading(true);
request
.get(`${config.apiPrefix}public/panel/log`)
.then((data: any) => {
setData(data.data);
.then(({ code, data }) => {
if (code === 200) {
setData(data);
}
})
.finally(() => setLoading(false));
};
+4 -8
View File
@@ -41,11 +41,9 @@ const Initialization = () => {
password: values.password,
},
})
.then((data) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
next();
} else {
message.error(data.message);
}
})
.finally(() => setLoading(false));
@@ -59,11 +57,9 @@ const Initialization = () => {
...values,
},
})
.then((_data: any) => {
if (_data && _data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
next();
} else {
message.error(_data.message);
}
})
.finally(() => setLoading(false));
+133 -24
View File
@@ -1,5 +1,15 @@
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 { PageContainer } from '@ant-design/pro-layout';
import Editor from '@monaco-editor/react';
@@ -9,6 +19,11 @@ import { Controlled as CodeMirror } from 'react-codemirror2';
import SplitPane from 'react-split-pane';
import { useOutletContext } from '@umijs/max';
import { SharedContext } from '@/layouts';
import { DeleteOutlined } from '@ant-design/icons';
import { depthFirstSearch } from '@/utils';
import { debounce } from 'lodash';
const { Text } = Typography;
function getFilterData(keyword: string, data: any) {
const expandedKeys: string[] = [];
@@ -40,23 +55,26 @@ function getFilterData(keyword: string, data: any) {
const Log = () => {
const { headerStyle, isPhone, theme } = useOutletContext<SharedContext>();
const [title, setTitle] = useState('请选择日志文件');
const [value, setValue] = useState('请选择日志文件');
const [select, setSelect] = useState<any>();
const [select, setSelect] = useState<string>('');
const [data, setData] = useState<any[]>([]);
const [filterData, setFilterData] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
const [height, setHeight] = useState<number>();
const treeDom = useRef<any>();
const [expandedKeys, setExpandedKeys] = useState<string[]>([]);
const [currentNode, setCurrentNode] = useState<any>();
const [searchValue, setSearchValue] = useState('');
const getLogs = () => {
setLoading(true);
request
.get(`${config.apiPrefix}logs`)
.then((data) => {
setData(data.data);
setFilterData(data.data);
.then(({ code, data }) => {
if (code === 200) {
setData(data);
setFilterData(data);
}
})
.finally(() => setLoading(false));
};
@@ -64,18 +82,27 @@ const Log = () => {
const getLog = (node: any) => {
request
.get(`${config.apiPrefix}logs/${node.title}?path=${node.parent || ''}`)
.then((data) => {
setValue(data.data);
.then(({ code, data }) => {
if (code === 200) {
setValue(data);
}
});
};
const onSelect = (value: any, node: any) => {
setCurrentNode(node);
setSelect(value);
if (node.key === select || !value) {
return;
}
if (node.type === 'directory') {
setValue('请选择日志文件');
return;
}
setValue('加载中...');
setSelect(value);
setTitle(node.key);
getLog(node);
};
@@ -86,16 +113,86 @@ const Log = () => {
const onSearch = useCallback(
(e) => {
const keyword = e.target.value;
debounceSearch(keyword);
},
[data, setFilterData],
);
const debounceSearch = useCallback(
debounce((keyword) => {
setSearchValue(keyword);
const { tree, expandedKeys } = getFilterData(
keyword.toLocaleLowerCase(),
data,
);
setFilterData(tree);
setExpandedKeys(expandedKeys);
},
}, 300),
[data, setFilterData],
);
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('请选择脚本文件');
};
useEffect(() => {
const word = searchValue || '';
const { tree } = getFilterData(word.toLocaleLowerCase(), data);
setFilterData(tree);
}, [data]);
useEffect(() => {
getLogs();
if (treeDom && treeDom.current) {
@@ -106,21 +203,32 @@ const Log = () => {
return (
<PageContainer
className="ql-container-wrapper log-wrapper"
title={title}
title={select}
loading={loading}
extra={
isPhone && [
<TreeSelect
className="log-select"
value={select}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={data}
placeholder="请选择日志"
fieldNames={{ value: 'key', label: 'title' }}
showSearch
onSelect={onSelect}
/>,
]
isPhone
? [
<TreeSelect
className="log-select"
value={select}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
treeData={data}
placeholder="请选择日志"
fieldNames={{ value: 'key', label: 'title' }}
showSearch
onSelect={onSelect}
/>,
]
: [
<Tooltip title="删除">
<Button
type="primary"
disabled={!select}
onClick={deleteFile}
icon={<DeleteOutlined />}
/>
</Tooltip>,
]
}
header={{
style: headerStyle,
@@ -140,6 +248,7 @@ const Log = () => {
></Input.Search>
<div className={styles['left-tree-scroller']} ref={treeDom}>
<Tree
expandAction="click"
className={styles['left-tree']}
treeData={filterData}
showIcon={true}
+16 -24
View File
@@ -40,15 +40,7 @@ const Login = () => {
},
})
.then((data) => {
if (data.code === 420) {
setLoginInfo({
username: values.username,
password: values.password,
});
setTwoFactor(true);
} else {
checkResponse(data);
}
checkResponse(data, values);
setLoading(false);
})
.catch(function (error) {
@@ -64,11 +56,7 @@ const Login = () => {
data: { ...loginInfo, code: values.code },
})
.then((data: any) => {
if (data.code === 430) {
message.error(data.message);
} else {
checkResponse(data);
}
checkResponse(data);
setVerifying(false);
})
.catch((error: any) => {
@@ -77,8 +65,11 @@ const Login = () => {
});
};
const checkResponse = (data: any) => {
if (data.code === 200) {
const checkResponse = (
{ code, data, message: _message }: any,
values?: any,
) => {
if (code === 200) {
const {
token,
lastip,
@@ -86,7 +77,7 @@ const Login = () => {
lastlogon,
retries = 0,
platform,
} = data.data;
} = data;
localStorage.setItem(config.authKey, token);
notification.success({
message: '登录成功!',
@@ -105,13 +96,14 @@ const Login = () => {
});
reloadUser(true);
history.push('/crontab');
} else if (data.code === 100) {
message.warn(data.message);
} else if (data.code === 410) {
message.error(data.message);
setWaitTime(data.data);
} else {
message.error(data.message);
} else if (code === 410) {
setWaitTime(data);
} else if (code === 420) {
setLoginInfo({
username: values.username,
password: values.password,
});
setTwoFactor(true);
}
};
+12 -6
View File
@@ -67,8 +67,10 @@ const EditModal = ({
const getDetail = (node: any) => {
request
.get(`${config.apiPrefix}scripts/${node.title}?path=${node.parent || ''}`)
.then((data) => {
setValue(data.data);
.then(({ code, data }) => {
if (code === 200) {
setValue(data);
}
});
};
@@ -83,8 +85,10 @@ const EditModal = ({
content,
},
})
.then((data) => {
setIsRunning(true);
.then(({ code, data }) => {
if (code === 200) {
setIsRunning(true);
}
});
};
@@ -101,8 +105,10 @@ const EditModal = ({
content,
},
})
.then((data) => {
setIsRunning(false);
.then(({ code, data }) => {
if (code === 200) {
setIsRunning(false);
}
});
};
-2
View File
@@ -57,8 +57,6 @@ const EditScriptNameModal = ({
path,
key: `${key}${filename}`,
});
} else {
message.error(data);
}
setLoading(false);
})
+53 -43
View File
@@ -78,9 +78,8 @@ const LangMap: any = {
const Script = () => {
const { headerStyle, isPhone, theme, socketMessage } =
useOutletContext<SharedContext>();
const [title, setTitle] = useState('请选择脚本文件');
const [value, setValue] = useState('请选择脚本文件');
const [select, setSelect] = useState<any>();
const [select, setSelect] = useState<string>('');
const [data, setData] = useState<any[]>([]);
const [filterData, setFilterData] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
@@ -99,10 +98,12 @@ const Script = () => {
setLoading(true);
request
.get(`${config.apiPrefix}scripts`)
.then((data) => {
setData(data.data);
setFilterData(data.data);
initGetScript();
.then(({ code, data }) => {
if (code === 200) {
setData(data);
setFilterData(data);
initGetScript();
}
})
.finally(() => setLoading(false));
};
@@ -110,8 +111,10 @@ const Script = () => {
const getDetail = (node: any) => {
request
.get(`${config.apiPrefix}scripts/${node.title}?path=${node.parent || ''}`)
.then((data) => {
setValue(data.data);
.then(({ code, data }) => {
if (code === 200) {
setValue(data);
}
});
};
@@ -132,15 +135,21 @@ const Script = () => {
};
const onSelect = (value: any, node: any) => {
setSelect(node.key);
setCurrentNode(node);
if (node.key === select || !value) {
return;
}
setValue('加载中...');
if (node.type === 'directory') {
setValue('请选择脚本文件');
return;
}
const newMode = value ? LangMap[value.slice(-3)] : '';
setMode(isPhone && newMode === 'typescript' ? 'javascript' : newMode);
setSelect(node.key);
setTitle(node.key);
setCurrentNode(node);
setValue('加载中...');
getDetail(node);
};
@@ -231,13 +240,11 @@ const Script = () => {
content,
},
})
.then((_data: any) => {
if (_data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success(`保存成功`);
setValue(content);
setIsEditing(false);
} else {
message.error(_data);
}
resolve(null);
})
@@ -255,10 +262,11 @@ const Script = () => {
title: `确认删除`,
content: (
<>
<Text style={{ wordBreak: 'break-all' }} type="warning">
{select}
</Text>{' '}
</Text>
{currentNode.type === 'directory' ? '夹及其子文件' : ''}
</>
),
@@ -268,24 +276,18 @@ const Script = () => {
data: {
filename: currentNode.title,
path: currentNode.parent || '',
type: currentNode.type,
},
})
.then((_data: any) => {
if (_data.code === 200) {
.then(({ code }) => {
if (code === 200) {
message.success(`删除成功`);
let newData = [...data];
if (currentNode.parent) {
const parentNodeIndex = newData.findIndex(
(x) => x.key === currentNode.parent,
newData = depthFirstSearch(
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 {
const index = newData.findIndex(
(x) => x.key === currentNode.key,
@@ -295,8 +297,7 @@ const Script = () => {
}
}
setData(newData);
} else {
message.error(_data);
initState();
}
});
},
@@ -346,18 +347,26 @@ const Script = () => {
filename: currentNode.title,
},
})
.then((_data: any) => {
const blob = new Blob([_data], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = currentNode.title;
document.documentElement.appendChild(a);
a.click();
document.documentElement.removeChild(a);
.then(({ code, data }) => {
if (code === 200) {
const blob = new Blob([data], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = currentNode.title;
document.documentElement.appendChild(a);
a.click();
document.documentElement.removeChild(a);
}
});
};
const initState = () => {
setSelect('');
setCurrentNode(null);
setValue('请选择脚本文件');
};
useEffect(() => {
const word = searchValue || '';
const { tree } = getFilterData(word.toLocaleLowerCase(), data);
@@ -438,12 +447,13 @@ const Script = () => {
return (
<PageContainer
className="ql-container-wrapper log-wrapper"
title={title}
title={select}
loading={loading}
extra={
isPhone
? [
<TreeSelect
treeExpandAction="click"
className="log-select"
value={select}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
@@ -518,6 +528,7 @@ const Script = () => {
></Input.Search>
<div className={styles['left-tree-scroller']} ref={treeDom}>
<Tree
expandAction="click"
className={styles['left-tree']}
treeData={filterData}
showIcon={true}
@@ -554,7 +565,6 @@ const Script = () => {
readOnly: !isEditing,
fontSize: 12,
lineNumbersMinChars: 3,
folding: false,
glyphMargin: false,
}}
onMount={(editor) => {
-2
View File
@@ -26,8 +26,6 @@ const SaveModal = ({
if (code === 200) {
message.success('保存文件成功');
handleCancel(data);
} else {
message.error(data);
}
setLoading(false);
});
-2
View File
@@ -26,8 +26,6 @@ const SettingModal = ({
if (code === 200) {
message.success('保存文件成功');
handleCancel(data);
} else {
message.error(data);
}
setLoading(false);
});
-2
View File
@@ -30,8 +30,6 @@ const AppModal = ({
if (code === 200) {
message.success(app ? '更新应用成功' : '新建应用成功');
handleCancel(data);
} else {
message.error(data);
}
setLoading(false);
} catch (error) {
+10 -4
View File
@@ -17,17 +17,14 @@ const CheckUpdate = ({ socketMessage }: any) => {
message.loading('检查更新中...', 0);
request
.put(`${config.apiPrefix}system/update-check`)
.then((_data: any) => {
.then(({ code, data }) => {
message.destroy();
const { code, data } = _data;
if (code === 200) {
if (data.hasNewVersion) {
showConfirmUpdateModal(data);
} else {
showForceUpdateModal();
}
} else {
message.error(data);
}
})
.catch((error: any) => {
@@ -140,7 +137,12 @@ const CheckUpdate = ({ socketMessage }: any) => {
}
const newMessage = `${value}${_message}`;
const updateFailed = newMessage.includes('失败,请检查');
modalRef.current.update({
maskClosable: updateFailed,
closable: updateFailed,
okButtonProps: { disabled: !updateFailed },
content: (
<div style={{ height: '60vh', overflowY: 'auto' }}>
<pre
@@ -159,6 +161,10 @@ const CheckUpdate = ({ socketMessage }: any) => {
});
setValue(newMessage);
if (updateFailed) {
message.error('更新失败,请检查网络及日志或稍后再试');
}
document.getElementById('log-identifier') &&
document
.getElementById('log-identifier')!
+24 -20
View File
@@ -144,8 +144,10 @@ const Setting = () => {
setLoading(true);
request
.get(`${config.apiPrefix}apps`)
.then((data: any) => {
setDataSource(data.data);
.then(({ code, data }) => {
if (code === 200) {
setDataSource(data);
}
})
.finally(() => setLoading(false));
};
@@ -175,14 +177,12 @@ const Setting = () => {
onOk() {
request
.delete(`${config.apiPrefix}apps`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success('删除成功');
const result = [...dataSource];
result.splice(index, 1);
setDataSource(result);
} else {
message.error(data);
}
});
},
@@ -209,12 +209,10 @@ const Setting = () => {
onOk() {
request
.put(`${config.apiPrefix}apps/${record.id}/reset-secret`)
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success('重置成功');
handleApp(data.data);
} else {
message.error(data);
handleApp(data);
}
});
},
@@ -247,8 +245,10 @@ const Setting = () => {
const getLoginLog = () => {
request
.get(`${config.apiPrefix}user/login-log`)
.then((data: any) => {
setLoginLogData(data.data);
.then(({ code, data }) => {
if (code === 200) {
setLoginLogData(data);
}
})
.catch((error: any) => {
console.log(error);
@@ -271,8 +271,10 @@ const Setting = () => {
const getNotification = () => {
request
.get(`${config.apiPrefix}user/notification`)
.then((data: any) => {
setNotificationInfo(data.data);
.then(({ code, data }) => {
if (code === 200) {
setNotificationInfo(data);
}
})
.catch((error: any) => {
console.log(error);
@@ -282,9 +284,9 @@ const Setting = () => {
const getLogRemoveFrequency = () => {
request
.get(`${config.apiPrefix}system/log/remove`)
.then((data: any) => {
if (data.data.info) {
const { frequency } = data.data.info;
.then(({ code, data }) => {
if (code === 200 && data.info) {
const { frequency } = data.info;
setLogRemoveFrequency(frequency);
}
})
@@ -299,8 +301,10 @@ const Setting = () => {
.put(`${config.apiPrefix}system/log/remove`, {
data: { frequency: logRemoveFrequency },
})
.then((data: any) => {
message.success('更新成功');
.then(({ code, data }) => {
if (code === 200) {
message.success('更新成功');
}
})
.catch((error: any) => {
console.log(error);
+16 -20
View File
@@ -23,11 +23,9 @@ const NotificationSetting = ({ data }: any) => {
...values,
},
})
.then((_data: any) => {
if (_data && _data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success(values.type ? '通知发送成功' : '通知关闭成功');
} else {
message.error(_data.message);
}
})
.catch((error: any) => {
@@ -75,22 +73,20 @@ const NotificationSetting = ({ data }: any) => {
rules={[{ required: x.required }]}
style={{ maxWidth: 400 }}
>
{
x.items ? (
<Select placeholder={x.placeholder || `请选择${x.label}`}>
{x.items.map((y) => (
<Option key={y.value} value={y.value}>
{y.label || y.value}
</Option>
))}
</Select>
) : (
<Input.TextArea
autoSize={true}
placeholder={x.placeholder || `请输入${x.label}`}
/>
)
}
{x.items ? (
<Select placeholder={x.placeholder || `请选择${x.label}`}>
{x.items.map((y) => (
<Option key={y.value} value={y.value}>
{y.label || y.value}
</Option>
))}
</Select>
) : (
<Input.TextArea
autoSize={true}
placeholder={x.placeholder || `请输入${x.label}`}
/>
)}
</Form.Item>
))}
<Button type="primary" htmlType="submit">
+21 -15
View File
@@ -27,9 +27,11 @@ const SecuritySettings = ({ user, userChange }: any) => {
password: values.password,
},
})
.then((data: any) => {
localStorage.removeItem(config.authKey);
history.push('/login');
.then(({ code, data }) => {
if (code === 200) {
localStorage.removeItem(config.authKey);
history.push('/login');
}
})
.catch((error: any) => {
console.log(error);
@@ -48,8 +50,8 @@ const SecuritySettings = ({ user, userChange }: any) => {
const deactiveTowFactor = () => {
request
.put(`${config.apiPrefix}user/two-factor/deactive`)
.then((data: any) => {
if (data.data) {
.then(({ code, data }) => {
if (code === 200 && data) {
setTwoFactorActivated(false);
userChange();
}
@@ -63,14 +65,16 @@ const SecuritySettings = ({ user, userChange }: any) => {
setLoading(true);
request
.put(`${config.apiPrefix}user/two-factor/active`, { data: { code } })
.then((data: any) => {
if (data.data) {
message.success('激活成功');
setTwoFactoring(false);
setTwoFactorActivated(true);
userChange();
} else {
message.success('验证失败');
.then(({ code, data }) => {
if (code === 200) {
if (data) {
message.success('激活成功');
setTwoFactoring(false);
setTwoFactorActivated(true);
userChange();
} else {
message.success('验证失败');
}
}
})
.catch((error: any) => {
@@ -82,8 +86,10 @@ const SecuritySettings = ({ user, userChange }: any) => {
const getTwoFactorInfo = () => {
request
.get(`${config.apiPrefix}user/two-factor/init`)
.then((data: any) => {
setTwoFactorInfo(data.data);
.then(({ code, data }) => {
if (code === 200) {
setTwoFactorInfo(data);
}
})
.catch((error: any) => {
console.log(error);
+13 -19
View File
@@ -263,8 +263,8 @@ const Subscription = () => {
onOk() {
request
.put(`${config.apiPrefix}subscriptions/run`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
if (i !== -1) {
@@ -274,8 +274,6 @@ const Subscription = () => {
});
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -300,8 +298,8 @@ const Subscription = () => {
onOk() {
request
.put(`${config.apiPrefix}subscriptions/stop`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
if (i !== -1) {
@@ -312,8 +310,6 @@ const Subscription = () => {
});
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -327,9 +323,11 @@ const Subscription = () => {
setLoading(true);
request
.get(`${config.apiPrefix}subscriptions?searchValue=${searchText}`)
.then((data: any) => {
setValue(data.data);
setCurrentPage(1);
.then(({ code, data }) => {
if (code === 200) {
setValue(data);
setCurrentPage(1);
}
})
.finally(() => setLoading(false));
};
@@ -359,8 +357,8 @@ const Subscription = () => {
onOk() {
request
.delete(`${config.apiPrefix}subscriptions`, { data: [record.id] })
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
message.success('删除成功');
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
@@ -368,8 +366,6 @@ const Subscription = () => {
result.splice(i, 1);
setValue(result);
}
} else {
message.error(data);
}
});
},
@@ -402,8 +398,8 @@ const Subscription = () => {
data: [record.id],
},
)
.then((data: any) => {
if (data.code === 200) {
.then(({ code, data }) => {
if (code === 200) {
const newStatus = record.is_disabled === 1 ? 0 : 1;
const result = [...value];
const i = result.findIndex((x) => x.id === record.id);
@@ -414,8 +410,6 @@ const Subscription = () => {
});
setValue(result);
}
} else {
message.error(data);
}
});
},
+3 -2
View File
@@ -36,11 +36,12 @@ const SubscriptionLogModal = ({
? logUrl
: `${config.apiPrefix}subscriptions/${subscription.id}/log`,
)
.then((data: any) => {
.then(({ code, data }) => {
if (
code === 200 &&
localStorage.getItem('logSubscription') === String(subscription.id)
) {
const log = data.data as string;
const log = data as string;
setValue(log || '暂无日志');
setExecuting(log && !log.includes('执行结束'));
if (log && !log.includes('执行结束')) {
+14 -32
View File
@@ -40,8 +40,6 @@ const SubscriptionModal = ({
if (code === 200) {
message.success(subscription ? '更新订阅成功' : '新建订阅成功');
handleCancel(data);
} else {
message.error(data);
}
setLoading(false);
} catch (error: any) {
@@ -190,8 +188,8 @@ const SubscriptionModal = ({
};
const onPaste = useCallback((e: any) => {
const text = e.clipboardData.getData('text');
if (!subscription && text.includes('ql ')) {
const text = e.clipboardData.getData('text') as string;
if (text.startsWith('ql ')) {
const [
,
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(() => {
if (visible) {
window.addEventListener('paste', onPaste);
@@ -243,35 +248,9 @@ const SubscriptionModal = ({
}
}, [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 (
<Modal
title={
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>
)
}
title={subscription ? '编辑订阅' : '新建订阅'}
open={visible}
forceRender
centered
@@ -291,7 +270,10 @@ const SubscriptionModal = ({
>
<Form form={form} name="form_in_modal" layout="vertical">
<Form.Item name="name" label="名称">
<Input placeholder="请输入订阅名" />
<Input
placeholder="支持拷贝ql repo/raw命令,粘贴导入"
onPaste={onNamePaste}
/>
</Form.Item>
<Form.Item
name="type"
+3 -3
View File
@@ -56,7 +56,7 @@ export default {
value: 'scripts',
},
{
name: '任务日志',
name: '日志管理',
value: 'logs',
},
{
@@ -74,7 +74,7 @@ export default {
subscriptions: '订阅管理',
configs: '配置文件',
scripts: '脚本管理',
logs: '任务日志',
logs: '日志管理',
dependencies: '依赖管理',
system: '系统信息',
},
@@ -263,7 +263,7 @@ export default {
'/config': '配置文件',
'/script': '脚本管理',
'/diff': '对比工具',
'/log': '任务日志',
'/log': '日志管理',
'/setting': '系统设置',
'/error': '错误日志',
},
+17 -1
View File
@@ -54,7 +54,23 @@ _request.interceptors.request.use((url, options) => {
});
_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;
});
+6 -1
View File
@@ -244,7 +244,7 @@ export function exportJson(name: string, data: string) {
export function depthFirstSearch<
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 keys = [];
@@ -252,6 +252,11 @@ export function depthFirstSearch<
if (!cls) return;
for (let i = 0; i < cls?.length; i++) {
if (condition(cls[i])) {
if (!item) {
cls.splice(i, 1);
return;
}
if (cls[i].children) {
cls[i].children!.unshift(item);
} else {
+8 -7
View File
@@ -1,8 +1,9 @@
export const version = '2.14.4';
export const changeLogLink = 'https://t.me/jiao_long/331';
export const changeLog = `2.14.4 版本说明
1.
2.
3.
4.
export const version = '2.14.5';
export const changeLogLink = 'https://t.me/jiao_long/333';
export const changeLog = `2.14.5 版本说明
1.
2.
3.
4.
5. Node依赖提示ERR_PNPM_REGISTRIES_MISMATCH
`;