Compare commits

..
18 Commits
Author SHA1 Message Date
whyour 32eec68278 更新版本 v2.13.9 2022-08-26 00:04:59 +08:00
whyour 05ed8c9f4b 修改定时任务列表布局 2022-08-25 23:58:20 +08:00
whyour bc281ee4d7 修改定时任务pageSize,增加全部展示为一页 2022-08-25 23:12:12 +08:00
whyour 3e88314d0a 修改二次验证交互 2022-08-23 22:38:03 +08:00
whyour 141defd845 修复定时任务默认pageSize 2022-08-20 23:21:31 +08:00
whyour b9e49b181a 修改定时任务排序 2022-08-20 20:27:19 +08:00
whyour 102e447f78 修改定时任务分页数据 2022-08-20 20:05:35 +08:00
whyour f3de8435f1 修改 favicon 2022-08-20 17:31:01 +08:00
whyour 06723407d2 更新版本 v2.13.8 2022-08-11 19:41:59 +08:00
whyour db8dfb32cf 修改生成系统token逻辑 2022-08-11 19:37:14 +08:00
whyour a7117e4442 修改内置token获取方式 2022-08-11 13:13:37 +08:00
whyour 53414e5d70 更新版本 v2.13.7 2022-07-31 15:58:34 +08:00
whyour 7bbc776759 修复环境变量转义 2022-07-31 15:35:13 +08:00
whyour f123c0bfe1 更新dockerfile 2022-07-31 15:26:08 +08:00
whyour 830865ff77 修改dockerfile 2022-07-31 15:22:17 +08:00
whyour 15fc6f975c repo命令后缀参数竖线分割 2022-07-31 15:09:32 +08:00
whyour 4582711867 修复搜索订阅 2022-07-31 15:00:27 +08:00
迷人的幽幽andGitHub 1eb64720d1 fix: 🐛 修复ts运行环境下发送企业微信通知错误问题 (#1553) 2022-07-24 13:33:44 +08:00
21 changed files with 216 additions and 196 deletions
+1 -1
View File
@@ -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/',
+4 -4
View File
@@ -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
View File
@@ -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(
'/', '/',
+19 -1
View File
@@ -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
View File
@@ -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 += '# ';
+1 -1
View File
@@ -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
View File
@@ -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;
} }
} }
+1 -1
View File
@@ -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,
); );
+1 -26
View File
@@ -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
View File
@@ -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' }, () => {
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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() {
+1
View File
@@ -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
+3
View File
@@ -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
+6
View File
@@ -101,3 +101,9 @@
background: #fafafa; background: #fafafa;
} }
} }
.crontab-view {
.ant-tabs-nav-wrap {
flex: unset !important;
}
}
+70 -60
View File
@@ -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={() => {
+1
View File
@@ -154,6 +154,7 @@ const Login = ({ reloadUser }: any) => {
message: '验证码为6位数字', message: '验证码为6位数字',
}, },
]} ]}
validateTrigger="onBlur"
> >
<Input <Input
placeholder="6位数字" placeholder="6位数字"
+6 -4
View File
@@ -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修改😀😀
`; `;