mirror of
https://github.com/whyour/qinglong.git
synced 2026-08-13 04:02:56 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32eec68278 | ||
|
|
05ed8c9f4b | ||
|
|
bc281ee4d7 | ||
|
|
3e88314d0a | ||
|
|
141defd845 | ||
|
|
b9e49b181a | ||
|
|
102e447f78 | ||
|
|
f3de8435f1 | ||
|
|
06723407d2 | ||
|
|
db8dfb32cf | ||
|
|
a7117e4442 | ||
|
|
53414e5d70 | ||
|
|
7bbc776759 | ||
|
|
f123c0bfe1 | ||
|
|
830865ff77 | ||
|
|
15fc6f975c | ||
|
|
4582711867 | ||
|
|
1eb64720d1 |
@@ -14,7 +14,7 @@ export default defineConfig({
|
|||||||
dynamicImport: {
|
dynamicImport: {
|
||||||
loading: '@/components/pageLoading',
|
loading: '@/components/pageLoading',
|
||||||
},
|
},
|
||||||
favicon: '/images/g5.ico',
|
favicon: '/images/favicon.svg',
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api/public': {
|
'/api/public': {
|
||||||
target: 'http://127.0.0.1:5400/',
|
target: 'http://127.0.0.1:5400/',
|
||||||
|
|||||||
@@ -163,11 +163,11 @@ task <file_path> desi <env_name> <account_number>
|
|||||||
|
|
||||||
* file_url: 脚本地址
|
* file_url: 脚本地址
|
||||||
* repo_url: 仓库地址
|
* repo_url: 仓库地址
|
||||||
* whitelist: 拉取仓库时的白名单,即就是需要拉取的脚本的路径包含的字符串
|
* whitelist: 拉取仓库时的白名单,即就是需要拉取的脚本的路径包含的字符串,多个竖线分割
|
||||||
* blacklist: 拉取仓库时的黑名单,即就是需要拉取的脚本的路径不包含的字符串
|
* blacklist: 拉取仓库时的黑名单,即就是需要拉取的脚本的路径不包含的字符串,多个竖线分割
|
||||||
* dependence: 拉取仓库需要的依赖文件,会直接从仓库拷贝到scripts下的仓库目录,不受黑名单影响
|
* dependence: 拉取仓库需要的依赖文件,会直接从仓库拷贝到scripts下的仓库目录,不受黑名单影响,多个竖线分割
|
||||||
|
* extensions: 拉取仓库的文件后缀,多个竖线分割
|
||||||
* branch: 拉取仓库的分支
|
* branch: 拉取仓库的分支
|
||||||
* extensions: 拉取仓库的文件后缀
|
|
||||||
* days: 需要保留的日志的天数
|
* days: 需要保留的日志的天数
|
||||||
* file_path: 任务执行时的文件路径
|
* file_path: 任务执行时的文件路径
|
||||||
* env_name: 任务执行时需要并发或者指定时的环境变量名称
|
* env_name: 任务执行时需要并发或者指定时的环境变量名称
|
||||||
|
|||||||
+14
-3
@@ -9,17 +9,28 @@ const route = Router();
|
|||||||
export default (app: Router) => {
|
export default (app: Router) => {
|
||||||
app.use('/crons', route);
|
app.use('/crons', route);
|
||||||
|
|
||||||
route.get('/', async (req: Request, res: Response, next: NextFunction) => {
|
route.get(
|
||||||
|
'/',
|
||||||
|
celebrate({
|
||||||
|
query: Joi.object({
|
||||||
|
searchText: Joi.string().required().allow(''),
|
||||||
|
page: Joi.string().required(),
|
||||||
|
size: Joi.string().required(),
|
||||||
|
t: Joi.string().required(),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const logger: Logger = Container.get('logger');
|
const logger: Logger = Container.get('logger');
|
||||||
try {
|
try {
|
||||||
const cronService = Container.get(CronService);
|
const cronService = Container.get(CronService);
|
||||||
const data = await cronService.crontabs(req.query.searchValue as string);
|
const data = await cronService.crontabs(req.query as any);
|
||||||
return res.send({ code: 200, data });
|
return res.send({ code: 200, data });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error('🔥 error: %o', e);
|
logger.error('🔥 error: %o', e);
|
||||||
return next(e);
|
return next(e);
|
||||||
}
|
}
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
route.post(
|
route.post(
|
||||||
'/',
|
'/',
|
||||||
|
|||||||
@@ -3,12 +3,30 @@ import _ from 'lodash';
|
|||||||
import SystemService from '../services/system';
|
import SystemService from '../services/system';
|
||||||
import ScheduleService from '../services/schedule';
|
import ScheduleService from '../services/schedule';
|
||||||
import SubscriptionService from '../services/subscription';
|
import SubscriptionService from '../services/subscription';
|
||||||
|
import config from '../config';
|
||||||
|
import { fileExist } from '../config/util';
|
||||||
|
|
||||||
export default async () => {
|
export default async () => {
|
||||||
const systemService = Container.get(SystemService);
|
const systemService = Container.get(SystemService);
|
||||||
const scheduleService = Container.get(ScheduleService);
|
const scheduleService = Container.get(ScheduleService);
|
||||||
const subscriptionService = Container.get(SubscriptionService);
|
const subscriptionService = Container.get(SubscriptionService);
|
||||||
|
|
||||||
|
// 生成内置token
|
||||||
|
let tokenCommand = `ts-node-transpile-only ${config.rootPath}/back/token.ts`;
|
||||||
|
const tokenFile = `${config.rootPath}/static/build/token.js`;
|
||||||
|
if (await fileExist(tokenFile)) {
|
||||||
|
tokenCommand = `node ${tokenFile}`;
|
||||||
|
}
|
||||||
|
const cron = {
|
||||||
|
id: 'token',
|
||||||
|
name: '生成token',
|
||||||
|
command: tokenCommand,
|
||||||
|
};
|
||||||
|
scheduleService.createIntervalTask(cron as any, {
|
||||||
|
days: 28,
|
||||||
|
runImmediately: true,
|
||||||
|
});
|
||||||
|
|
||||||
// 运行删除日志任务
|
// 运行删除日志任务
|
||||||
const data = await systemService.getLogRemoveFrequency();
|
const data = await systemService.getLogRemoveFrequency();
|
||||||
if (data && data.info && data.info.frequency) {
|
if (data && data.info && data.info.frequency) {
|
||||||
@@ -17,7 +35,7 @@ export default async () => {
|
|||||||
name: '删除日志',
|
name: '删除日志',
|
||||||
command: `ql rmlog ${data.info.frequency}`,
|
command: `ql rmlog ${data.info.frequency}`,
|
||||||
};
|
};
|
||||||
await scheduleService.createIntervalTask(cron, {
|
scheduleService.createIntervalTask(cron, {
|
||||||
days: data.info.frequency,
|
days: data.info.frequency,
|
||||||
runImmediately: true,
|
runImmediately: true,
|
||||||
});
|
});
|
||||||
|
|||||||
+26
-7
@@ -113,7 +113,15 @@ export default class CronService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async crontabs(searchText?: string): Promise<Crontab[]> {
|
public async crontabs(params?: {
|
||||||
|
searchText: string;
|
||||||
|
page: string;
|
||||||
|
size: string;
|
||||||
|
}): Promise<{ data: Crontab[]; total: number }> {
|
||||||
|
const searchText = params?.searchText;
|
||||||
|
const page = Number(params?.page || '0');
|
||||||
|
const size = Number(params?.size || '0');
|
||||||
|
|
||||||
let query = {};
|
let query = {};
|
||||||
if (searchText) {
|
if (searchText) {
|
||||||
const textArray = searchText.split(':');
|
const textArray = searchText.split(':');
|
||||||
@@ -158,12 +166,23 @@ export default class CronService {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try {
|
let condition: any = {
|
||||||
const result = await CrontabModel.findAll({
|
|
||||||
where: query,
|
where: query,
|
||||||
order: [['createdAt', 'DESC']],
|
order: [
|
||||||
});
|
['isPinned', 'DESC'],
|
||||||
return result as any;
|
['isDisabled', 'ASC'],
|
||||||
|
['status', 'ASC'],
|
||||||
|
['createdAt', 'DESC'],
|
||||||
|
],
|
||||||
|
};
|
||||||
|
if (page && size) {
|
||||||
|
condition.offset = (page - 1) * size;
|
||||||
|
condition.limit = size;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const result = await CrontabModel.findAll(condition);
|
||||||
|
const count = await CrontabModel.count();
|
||||||
|
return { data: result, total: count };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -441,7 +460,7 @@ export default class CronService {
|
|||||||
private async set_crontab(needReloadSchedule: boolean = false) {
|
private async set_crontab(needReloadSchedule: boolean = false) {
|
||||||
const tabs = await this.crontabs();
|
const tabs = await this.crontabs();
|
||||||
var crontab_string = '';
|
var crontab_string = '';
|
||||||
tabs.forEach((tab) => {
|
tabs.data.forEach((tab) => {
|
||||||
const _schedule = tab.schedule && tab.schedule.split(/ +/);
|
const _schedule = tab.schedule && tab.schedule.split(/ +/);
|
||||||
if (tab.isDisabled === 1 || _schedule!.length !== 5) {
|
if (tab.isDisabled === 1 || _schedule!.length !== 5) {
|
||||||
crontab_string += '# ';
|
crontab_string += '# ';
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ export default class EnvService {
|
|||||||
.filter((x) => x.status !== EnvStatus.disabled)
|
.filter((x) => x.status !== EnvStatus.disabled)
|
||||||
.map('value')
|
.map('value')
|
||||||
.join('&')
|
.join('&')
|
||||||
.replace(/(\\)[^\n]/g, '\\\\')
|
.replace(/(\\)[^n]/g, '\\\\')
|
||||||
.replace(/(\\$)/, '\\\\')
|
.replace(/(\\$)/, '\\\\')
|
||||||
.replace(/"/g, '\\"')
|
.replace(/"/g, '\\"')
|
||||||
.trim();
|
.trim();
|
||||||
|
|||||||
+6
-15
@@ -145,7 +145,7 @@ export default class OpenService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async findSystemToken(): Promise<{
|
public async generateSystemToken(): Promise<{
|
||||||
value: string;
|
value: string;
|
||||||
expiration: number;
|
expiration: number;
|
||||||
}> {
|
}> {
|
||||||
@@ -158,22 +158,13 @@ export default class OpenService {
|
|||||||
scopes: ['crons', 'system'],
|
scopes: ['crons', 'system'],
|
||||||
} as App);
|
} as App);
|
||||||
}
|
}
|
||||||
const nowTime = Math.round(Date.now() / 1000);
|
const { data } = await this.authToken({
|
||||||
let token;
|
|
||||||
if (
|
|
||||||
!systemApp.tokens ||
|
|
||||||
!systemApp.tokens.length ||
|
|
||||||
nowTime > [...systemApp.tokens].pop()!.expiration
|
|
||||||
) {
|
|
||||||
const authToken = await this.authToken({
|
|
||||||
client_id: systemApp.client_id,
|
client_id: systemApp.client_id,
|
||||||
client_secret: systemApp.client_secret,
|
client_secret: systemApp.client_secret,
|
||||||
});
|
});
|
||||||
token = authToken.data;
|
return {
|
||||||
token.value = token.token;
|
...data,
|
||||||
} else {
|
value: data.token,
|
||||||
token = [...systemApp.tokens].pop();
|
};
|
||||||
}
|
|
||||||
return token;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ export default class ScheduleService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const job = new LongIntervalJob(
|
const job = new LongIntervalJob(
|
||||||
{ ...schedule, runImmediately: false },
|
{ runImmediately: false, ...schedule },
|
||||||
task,
|
task,
|
||||||
_id,
|
_id,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -42,23 +42,6 @@ export default class SubscriptionService {
|
|||||||
public async list(searchText?: string): Promise<Subscription[]> {
|
public async list(searchText?: string): Promise<Subscription[]> {
|
||||||
let query = {};
|
let query = {};
|
||||||
if (searchText) {
|
if (searchText) {
|
||||||
const textArray = searchText.split(':');
|
|
||||||
switch (textArray[0]) {
|
|
||||||
case 'name':
|
|
||||||
case 'command':
|
|
||||||
case 'schedule':
|
|
||||||
case 'label':
|
|
||||||
const column = textArray[0] === 'label' ? 'labels' : textArray[0];
|
|
||||||
query = {
|
|
||||||
[column]: {
|
|
||||||
[Op.or]: [
|
|
||||||
{ [Op.like]: `%${textArray[1]}%` },
|
|
||||||
{ [Op.like]: `%${encodeURIComponent(textArray[1])}%` },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
const reg = {
|
const reg = {
|
||||||
[Op.or]: [
|
[Op.or]: [
|
||||||
{ [Op.like]: `%${searchText}%` },
|
{ [Op.like]: `%${searchText}%` },
|
||||||
@@ -71,18 +54,10 @@ export default class SubscriptionService {
|
|||||||
name: reg,
|
name: reg,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
command: reg,
|
url: reg,
|
||||||
},
|
|
||||||
{
|
|
||||||
schedule: reg,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
labels: reg,
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const result = await SubscriptionModel.findAll({
|
const result = await SubscriptionModel.findAll({
|
||||||
|
|||||||
+1
-23
@@ -10,41 +10,19 @@ const tokenFile = path.join(config.configPath, 'token.json');
|
|||||||
|
|
||||||
async function getToken() {
|
async function getToken() {
|
||||||
try {
|
try {
|
||||||
const data = await readFile();
|
|
||||||
const nowTime = Math.round(Date.now() / 1000);
|
|
||||||
if (data.value && data.expiration > nowTime) {
|
|
||||||
console.log(data.value);
|
|
||||||
} else {
|
|
||||||
Container.set('logger', LoggerInstance);
|
Container.set('logger', LoggerInstance);
|
||||||
const openService = Container.get(OpenService);
|
const openService = Container.get(OpenService);
|
||||||
const appToken = await openService.findSystemToken();
|
const appToken = await openService.generateSystemToken();
|
||||||
console.log(appToken.value);
|
console.log(appToken.value);
|
||||||
await writeFile({
|
await writeFile({
|
||||||
value: appToken.value,
|
value: appToken.value,
|
||||||
expiration: appToken.expiration,
|
expiration: appToken.expiration,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function readFile() {
|
|
||||||
return new Promise<any>((resolve, reject) => {
|
|
||||||
fs.readFile(
|
|
||||||
path.join(config.configPath, 'token.json'),
|
|
||||||
{ encoding: 'utf8' },
|
|
||||||
(err, data) => {
|
|
||||||
if (err) {
|
|
||||||
resolve({});
|
|
||||||
} else {
|
|
||||||
resolve(JSON.parse(data));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function writeFile(data: any) {
|
async function writeFile(data: any) {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
fs.writeFile(tokenFile, JSON.stringify(data), { encoding: 'utf8' }, () => {
|
fs.writeFile(tokenFile, JSON.stringify(data), { encoding: 'utf8' }, () => {
|
||||||
|
|||||||
@@ -34,10 +34,12 @@ RUN set -x \
|
|||||||
openssh \
|
openssh \
|
||||||
py3-pip \
|
py3-pip \
|
||||||
&& rm -rf /var/cache/apk/* \
|
&& rm -rf /var/cache/apk/* \
|
||||||
|
&& apk update \
|
||||||
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
|
||||||
&& echo "Asia/Shanghai" > /etc/timezone \
|
&& echo "Asia/Shanghai" > /etc/timezone \
|
||||||
&& git config --global user.email "qinglong@@users.noreply.github.com" \
|
&& git config --global user.email "qinglong@@users.noreply.github.com" \
|
||||||
&& git config --global user.name "qinglong" \
|
&& git config --global user.name "qinglong" \
|
||||||
|
&& git config --global http.postBuffer 524288000 \
|
||||||
&& npm install -g pnpm \
|
&& npm install -g pnpm \
|
||||||
&& pnpm add -g pm2 ts-node typescript tslib \
|
&& pnpm add -g pm2 ts-node typescript tslib \
|
||||||
&& git clone -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} \
|
&& git clone -b ${QL_BRANCH} ${QL_URL} ${QL_DIR} \
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 91 KiB |
+10
-3
@@ -97,6 +97,13 @@ let IGOT_PUSH_KEY = '';
|
|||||||
let PUSH_PLUS_TOKEN = '';
|
let PUSH_PLUS_TOKEN = '';
|
||||||
let PUSH_PLUS_USER = '';
|
let PUSH_PLUS_USER = '';
|
||||||
|
|
||||||
|
// =======================================Cool Push设置区域=======================================
|
||||||
|
//官方文档:https://cp.xuthus.cc/docs
|
||||||
|
//QQ_SKEY: Cool Push登录授权后推送消息的调用代码Skey
|
||||||
|
//QQ_MODE: 推送模式详情请登录获取QQ_SKEY后见https://cp.xuthus.cc/feat
|
||||||
|
let QQ_SKEY = '';
|
||||||
|
let QQ_MODE = '';
|
||||||
|
|
||||||
//==========================云端环境变量的判断与接收=========================
|
//==========================云端环境变量的判断与接收=========================
|
||||||
if (process.env.GOTIFY_URL) {
|
if (process.env.GOTIFY_URL) {
|
||||||
GOTIFY_URL = process.env.GOTIFY_URL;
|
GOTIFY_URL = process.env.GOTIFY_URL;
|
||||||
@@ -723,9 +730,9 @@ function qywxamNotify(text, desp) {
|
|||||||
timeout,
|
timeout,
|
||||||
};
|
};
|
||||||
$.post(options_accesstoken, (err, resp, data) => {
|
$.post(options_accesstoken, (err, resp, data) => {
|
||||||
html = desp.replace(/\n/g, '<br/>');
|
let html = desp.replace(/\n/g, '<br/>');
|
||||||
var json = JSON.parse(data);
|
let json = JSON.parse(data);
|
||||||
accesstoken = json.access_token;
|
let accesstoken = json.access_token;
|
||||||
let options;
|
let options;
|
||||||
|
|
||||||
switch (QYWX_AM_AY[4]) {
|
switch (QYWX_AM_AY[4]) {
|
||||||
|
|||||||
+1
-6
@@ -1,12 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
get_token() {
|
get_token() {
|
||||||
local tokenFile="$dir_static/build/token.js"
|
token=$(cat $file_auth_token | jq -r .value)
|
||||||
if [[ ! -f "$tokenFile" ]]; then
|
|
||||||
token=$(ts-node-transpile-only "$dir_root/back/token.ts")
|
|
||||||
else
|
|
||||||
token=$(node "$tokenFile")
|
|
||||||
fi
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_cron_api() {
|
add_cron_api() {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ file_sharecode=$dir_config/sharecode.sh
|
|||||||
file_config_user=$dir_config/config.sh
|
file_config_user=$dir_config/config.sh
|
||||||
file_auth_sample=$dir_sample/auth.sample.json
|
file_auth_sample=$dir_sample/auth.sample.json
|
||||||
file_auth_user=$dir_config/auth.json
|
file_auth_user=$dir_config/auth.json
|
||||||
|
file_auth_token=$dir_config/token.json
|
||||||
file_extra_shell=$dir_config/extra.sh
|
file_extra_shell=$dir_config/extra.sh
|
||||||
file_task_before=$dir_config/task_before.sh
|
file_task_before=$dir_config/task_before.sh
|
||||||
file_task_after=$dir_config/task_after.sh
|
file_task_after=$dir_config/task_after.sh
|
||||||
|
|||||||
@@ -388,6 +388,9 @@ gen_list_repo() {
|
|||||||
local index=0
|
local index=0
|
||||||
if [[ $6 ]]; then
|
if [[ $6 ]]; then
|
||||||
file_extensions="$6"
|
file_extensions="$6"
|
||||||
|
if [[ $file_extensions =~ "|" ]]; then
|
||||||
|
file_extensions=$(echo $file_extensions | sed 's/|/ /g')
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
for extension in $file_extensions; do
|
for extension in $file_extensions; do
|
||||||
if [[ $index -eq 0 ]]; then
|
if [[ $index -eq 0 ]]; then
|
||||||
|
|||||||
@@ -101,3 +101,9 @@
|
|||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.crontab-view {
|
||||||
|
.ant-tabs-nav-wrap {
|
||||||
|
flex: unset !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+70
-60
@@ -12,6 +12,7 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
Input,
|
Input,
|
||||||
Popover,
|
Popover,
|
||||||
|
Tabs,
|
||||||
} from 'antd';
|
} from 'antd';
|
||||||
import {
|
import {
|
||||||
ClockCircleOutlined,
|
ClockCircleOutlined,
|
||||||
@@ -122,7 +123,7 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
sorter: {
|
sorter: {
|
||||||
compare: (a: any, b: any) => a.name.localeCompare(b.name),
|
compare: (a: any, b: any) => a?.name?.localeCompare(b?.name),
|
||||||
multiple: 2,
|
multiple: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -346,12 +347,14 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
const [isLogModalVisible, setIsLogModalVisible] = useState(false);
|
const [isLogModalVisible, setIsLogModalVisible] = useState(false);
|
||||||
const [logCron, setLogCron] = useState<any>();
|
const [logCron, setLogCron] = useState<any>();
|
||||||
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);
|
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
const [pageConf, setPageConf] = useState<{ page: number; size: number }>(
|
||||||
const [pageSize, setPageSize] = useState(20);
|
{} as any,
|
||||||
|
);
|
||||||
const [tableScrollHeight, setTableScrollHeight] = useState<number>();
|
const [tableScrollHeight, setTableScrollHeight] = useState<number>();
|
||||||
const [isDetailModalVisible, setIsDetailModalVisible] = useState(false);
|
const [isDetailModalVisible, setIsDetailModalVisible] = useState(false);
|
||||||
const [detailCron, setDetailCron] = useState<any>();
|
const [detailCron, setDetailCron] = useState<any>();
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
|
const [total, setTotal] = useState<number>();
|
||||||
|
|
||||||
const goToScriptManager = (record: any) => {
|
const goToScriptManager = (record: any) => {
|
||||||
const cmd = record.command.split(' ') as string[];
|
const cmd = record.command.split(' ') as string[];
|
||||||
@@ -374,26 +377,13 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
const getCrons = () => {
|
const getCrons = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
request
|
request
|
||||||
.get(`${config.apiPrefix}crons?searchValue=${searchText}`)
|
.get(
|
||||||
.then((data: any) => {
|
`${config.apiPrefix}crons?searchText=${searchText}&page=${pageConf.page}&size=${pageConf.size}`,
|
||||||
|
)
|
||||||
|
.then((_data: any) => {
|
||||||
|
const { data, total } = _data.data;
|
||||||
setValue(
|
setValue(
|
||||||
data.data
|
data.map((x) => {
|
||||||
.sort((a: any, b: any) => {
|
|
||||||
const sortA =
|
|
||||||
a.isPinned && a.status !== 0
|
|
||||||
? 5
|
|
||||||
: a.isDisabled && a.status !== 0
|
|
||||||
? 4
|
|
||||||
: a.status;
|
|
||||||
const sortB =
|
|
||||||
b.isPinned && b.status !== 0
|
|
||||||
? 5
|
|
||||||
: b.isDisabled && b.status !== 0
|
|
||||||
? 4
|
|
||||||
: b.status;
|
|
||||||
return CrontabSort[sortA] - CrontabSort[sortB];
|
|
||||||
})
|
|
||||||
.map((x) => {
|
|
||||||
return {
|
return {
|
||||||
...x,
|
...x,
|
||||||
nextRunTime: cron_parser
|
nextRunTime: cron_parser
|
||||||
@@ -403,7 +393,7 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
setCurrentPage(1);
|
setTotal(total);
|
||||||
})
|
})
|
||||||
.finally(() => setLoading(false));
|
.finally(() => setLoading(false));
|
||||||
};
|
};
|
||||||
@@ -743,11 +733,6 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
const rowSelection = {
|
const rowSelection = {
|
||||||
selectedRowIds,
|
selectedRowIds,
|
||||||
onChange: onSelectChange,
|
onChange: onSelectChange,
|
||||||
selections: [
|
|
||||||
Table.SELECTION_ALL,
|
|
||||||
Table.SELECTION_INVERT,
|
|
||||||
Table.SELECTION_NONE,
|
|
||||||
],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const delCrons = () => {
|
const delCrons = () => {
|
||||||
@@ -797,9 +782,8 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onPageChange = (page: number, pageSize: number | undefined) => {
|
const onPageChange = (page: number, pageSize: number | undefined) => {
|
||||||
setCurrentPage(page);
|
setPageConf({ page, size: pageSize as number });
|
||||||
setPageSize(pageSize as number);
|
localStorage.setItem('pageSize', String(pageSize));
|
||||||
localStorage.setItem('pageSize', pageSize + '');
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const getRowClassName = (record: any, index: number) => {
|
const getRowClassName = (record: any, index: number) => {
|
||||||
@@ -814,39 +798,27 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
}, [logCron]);
|
}, [logCron]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCrons();
|
setPageConf({ ...pageConf, page: 1 });
|
||||||
}, [searchText]);
|
}, [searchText]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPageSize(parseInt(localStorage.getItem('pageSize') || '20'));
|
if (pageConf.page && pageConf.size) {
|
||||||
|
getCrons();
|
||||||
|
}
|
||||||
|
}, [pageConf]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setPageConf({
|
||||||
|
page: 1,
|
||||||
|
size: parseInt(localStorage.getItem('pageSize') || '20'),
|
||||||
|
});
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setTableScrollHeight(getTableScroll());
|
setTableScrollHeight(getTableScroll());
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
const panelContent = (
|
||||||
<PageContainer
|
<>
|
||||||
className="ql-container-wrapper crontab-wrapper"
|
|
||||||
title="定时任务"
|
|
||||||
extra={[
|
|
||||||
<Search
|
|
||||||
placeholder="请输入名称或者关键词"
|
|
||||||
style={{ width: 'auto' }}
|
|
||||||
enterButton
|
|
||||||
allowClear
|
|
||||||
loading={loading}
|
|
||||||
value={searchValue}
|
|
||||||
onChange={(e) => setSearchValue(e.target.value)}
|
|
||||||
onSearch={onSearch}
|
|
||||||
/>,
|
|
||||||
<Button key="2" type="primary" onClick={() => addCron()}>
|
|
||||||
新建任务
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
header={{
|
|
||||||
style: headerStyle,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{selectedRowIds.length > 0 && (
|
{selectedRowIds.length > 0 && (
|
||||||
<div style={{ marginBottom: 16 }}>
|
<div style={{ marginBottom: 16 }}>
|
||||||
<Button type="primary" style={{ marginBottom: 5 }} onClick={delCrons}>
|
<Button type="primary" style={{ marginBottom: 5 }} onClick={delCrons}>
|
||||||
@@ -906,15 +878,17 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
<Table
|
<Table
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={{
|
pagination={{
|
||||||
current: currentPage,
|
current: pageConf.page,
|
||||||
onChange: onPageChange,
|
onChange: onPageChange,
|
||||||
pageSize: pageSize,
|
pageSize: pageConf.size,
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
simple: isPhone,
|
simple: isPhone,
|
||||||
defaultPageSize: 20,
|
total,
|
||||||
showTotal: (total: number, range: number[]) =>
|
showTotal: (total: number, range: number[]) =>
|
||||||
`第 ${range[0]}-${range[1]} 条/总共 ${total} 条`,
|
`第 ${range[0]}-${range[1]} 条/总共 ${total} 条`,
|
||||||
pageSizeOptions: [20, 100, 500, 1000] as any,
|
pageSizeOptions: [10, 20, 50, 100, 200, 500, total || 10000].sort(
|
||||||
|
(a, b) => a - b,
|
||||||
|
),
|
||||||
}}
|
}}
|
||||||
onRow={(record) => {
|
onRow={(record) => {
|
||||||
return {
|
return {
|
||||||
@@ -932,6 +906,42 @@ const Crontab = ({ headerStyle, isPhone, theme }: any) => {
|
|||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
rowClassName={getRowClassName}
|
rowClassName={getRowClassName}
|
||||||
/>
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer
|
||||||
|
className="ql-container-wrapper crontab-wrapper"
|
||||||
|
title="定时任务"
|
||||||
|
extra={[
|
||||||
|
<Search
|
||||||
|
placeholder="请输入名称或者关键词"
|
||||||
|
style={{ width: 'auto' }}
|
||||||
|
enterButton
|
||||||
|
allowClear
|
||||||
|
loading={loading}
|
||||||
|
value={searchValue}
|
||||||
|
onChange={(e) => setSearchValue(e.target.value)}
|
||||||
|
onSearch={onSearch}
|
||||||
|
/>,
|
||||||
|
<Button key="2" type="primary" onClick={() => addCron()}>
|
||||||
|
新建任务
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
header={{
|
||||||
|
style: headerStyle,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tabs
|
||||||
|
defaultActiveKey="all"
|
||||||
|
size="small"
|
||||||
|
tabPosition="top"
|
||||||
|
className="crontab-view"
|
||||||
|
>
|
||||||
|
<Tabs.TabPane tab="全部任务" key="all">
|
||||||
|
{panelContent}
|
||||||
|
</Tabs.TabPane>
|
||||||
|
</Tabs>
|
||||||
<CronLogModal
|
<CronLogModal
|
||||||
visible={isLogModalVisible}
|
visible={isLogModalVisible}
|
||||||
handleCancel={() => {
|
handleCancel={() => {
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ const Login = ({ reloadUser }: any) => {
|
|||||||
message: '验证码为6位数字',
|
message: '验证码为6位数字',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
validateTrigger="onBlur"
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
placeholder="6位数字"
|
placeholder="6位数字"
|
||||||
|
|||||||
+6
-4
@@ -1,5 +1,7 @@
|
|||||||
export const version = '2.13.6';
|
export const version = '2.13.9';
|
||||||
export const changeLogLink = 'https://t.me/jiao_long/321';
|
export const changeLogLink = 'https://t.me/jiao_long/324';
|
||||||
export const changeLog = `2.13.6 版本说明
|
export const changeLog = `2.13.9 版本说明
|
||||||
1. 修复 cant't find .env
|
1. 修改定时任务分页功能,加快每页数据获取
|
||||||
|
2. 定时任务增加每页数据可设置为最大,使任务一页展示(数据获取速度也会变慢)
|
||||||
|
3. favicon修改😀😀
|
||||||
`;
|
`;
|
||||||
|
|||||||
Reference in New Issue
Block a user