定时任务支持批量启用禁用删除运行

This commit is contained in:
whyour 2021-05-08 14:28:05 +08:00
parent 2092e93dc2
commit 5d43add6eb
5 changed files with 211 additions and 97 deletions

View File

@ -51,18 +51,16 @@ export default (app: Router) => {
},
);
route.get(
'/crons/:id/run',
route.put(
'/crons/run',
celebrate({
params: Joi.object({
id: Joi.string().required(),
}),
body: Joi.array().items(Joi.string().required()),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
const cronService = Container.get(CronService);
const data = await cronService.run(req.params.id);
const data = await cronService.run(req.body);
return res.send({ code: 200, data });
} catch (e) {
logger.error('🔥 error: %o', e);
@ -71,18 +69,16 @@ export default (app: Router) => {
},
);
route.get(
'/crons/:id/disable',
route.put(
'/crons/disable',
celebrate({
params: Joi.object({
id: Joi.string().required(),
}),
body: Joi.array().items(Joi.string().required()),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
const cronService = Container.get(CronService);
const data = await cronService.disabled(req.params.id);
const data = await cronService.disabled(req.body);
return res.send({ code: 200, data });
} catch (e) {
logger.error('🔥 error: %o', e);
@ -91,18 +87,16 @@ export default (app: Router) => {
},
);
route.get(
'/crons/:id/enable',
route.put(
'/crons/enable',
celebrate({
params: Joi.object({
id: Joi.string().required(),
}),
body: Joi.array().items(Joi.string().required()),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
const cronService = Container.get(CronService);
const data = await cronService.enabled(req.params.id);
const data = await cronService.enabled(req.body);
return res.send({ code: 200, data });
} catch (e) {
logger.error('🔥 error: %o', e);
@ -159,17 +153,15 @@ export default (app: Router) => {
);
route.delete(
'/crons/:id',
'/crons',
celebrate({
params: Joi.object({
id: Joi.string().required(),
}),
body: Joi.array().items(Joi.string().required()),
}),
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
const cronService = Container.get(CronService);
const data = await cronService.remove(req.params.id);
const data = await cronService.remove(req.body);
return res.send({ code: 200, data });
} catch (e) {
logger.error('🔥 error: %o', e);

View File

@ -33,7 +33,7 @@ const run = async () => {
) {
schedule.scheduleJob(task.schedule, function () {
let command = task.command as string;
if (!command.startsWith('task ') && !command.startsWith('ql ')) {
if (!command.includes('task ') && !command.includes('ql ')) {
command = `task ${command}`;
}
exec(command);

View File

@ -74,8 +74,8 @@ export default class CronService {
this.cronDb.update({ _id }, { $set: { stopped, saved: false } });
}
public async remove(_id: string) {
this.cronDb.remove({ _id }, {});
public async remove(ids: string[]) {
this.cronDb.remove({ _id: { $in: ids } }, { multi: true });
await this.set_crontab();
}
@ -112,19 +112,27 @@ export default class CronService {
});
}
public async run(_id: string) {
this.cronDb.find({ _id }).exec((err, docs: Crontab[]) => {
let res = docs[0];
public async run(ids: string[]) {
this.cronDb.find({ _id: { $in: ids } }).exec((err, docs: Crontab[]) => {
for (let i = 0; i < docs.length; i++) {
const doc = docs[i];
this.runSingle(doc);
}
});
}
private async runSingle(cron: Crontab) {
let { _id, command } = cron;
this.logger.silly('Running job');
this.logger.silly('ID: ' + _id);
this.logger.silly('Original command: ' + res.command);
this.logger.silly('Original command: ' + command);
let logFile = `${config.manualLogPath}${res._id}.log`;
let logFile = `${config.manualLogPath}${_id}.log`;
fs.writeFileSync(logFile, `开始执行...\n\n${new Date().toString()}\n`);
let cmdStr = res.command;
if (!cmdStr.startsWith('task') && !cmdStr.startsWith('ql ')) {
let cmdStr = command;
if (!cmdStr.includes('task ') && !cmdStr.includes('ql ')) {
cmdStr = `task ${cmdStr}`;
}
if (cmdStr.endsWith('.js')) {
@ -165,16 +173,23 @@ export default class CronService {
this.cronDb.update({ _id }, { $set: { status: CrontabStatus.idle } });
fs.appendFileSync(logFile, `\n\n连接断开...`);
});
});
}
public async disabled(_id: string) {
this.cronDb.update({ _id }, { $set: { status: CrontabStatus.disabled } });
public async disabled(ids: string[]) {
this.cronDb.update(
{ _id: { $in: ids } },
{ $set: { status: CrontabStatus.disabled } },
{ multi: true },
);
await this.set_crontab();
}
public async enabled(_id: string) {
this.cronDb.update({ _id }, { $set: { status: CrontabStatus.idle } });
public async enabled(ids: string[]) {
this.cronDb.update(
{ _id: { $in: ids } },
{ $set: { status: CrontabStatus.idle } },
{ multi: true },
);
}
public async log(_id: string) {

View File

@ -434,7 +434,6 @@ const Config = () => {
<PageContainer
className="cookie-wrapper"
title="Cookie管理"
loading={loading}
extra={[
<Button key="2" type="primary" onClick={() => addCookie()}>
Cookie
@ -463,9 +462,9 @@ const Config = () => {
dataSource={value}
rowKey="value"
size="middle"
bordered
scroll={{ x: 768 }}
components={components}
loading={loading}
onRow={(record, index) => {
return {
index,

View File

@ -39,6 +39,18 @@ enum CrontabStatus {
'disabled',
}
enum OperationName {
'启用',
'禁用',
'运行',
}
enum OperationPath {
'enable',
'disable',
'run',
}
const Crontab = () => {
const columns = [
{
@ -142,6 +154,7 @@ const Crontab = () => {
const [searchText, setSearchText] = useState('');
const [isLogModalVisible, setIsLogModalVisible] = useState(false);
const [logCron, setLogCron] = useState<any>();
const [selectedRowIds, setSelectedRowIds] = useState<string[]>([]);
const getCrons = () => {
setLoading(true);
@ -177,7 +190,7 @@ const Crontab = () => {
),
onOk() {
request
.delete(`${config.apiPrefix}crons/${record._id}`)
.delete(`${config.apiPrefix}crons`, { data: [record._id] })
.then((data: any) => {
if (data.code === 200) {
notification.success({
@ -213,7 +226,7 @@ const Crontab = () => {
),
onOk() {
request
.get(`${config.apiPrefix}crons/${record._id}/run`)
.put(`${config.apiPrefix}crons/run`, { data: [record._id] })
.then((data: any) => {
if (data.code === 200) {
const result = [...value];
@ -252,21 +265,16 @@ const Crontab = () => {
),
onOk() {
request
.get(
`${config.apiPrefix}crons/${record._id}/${
.put(
`${config.apiPrefix}crons/${
record.status === CrontabStatus.disabled ? 'enable' : 'disable'
}`,
{
data: { _id: record._id },
data: [record._id],
},
)
.then((data: any) => {
if (data.code === 200) {
notification.success({
message: `${
record.status === CrontabStatus.disabled ? '启用' : '禁用'
}`,
});
const newStatus =
record.status === CrontabStatus.disabled
? CrontabStatus.idle
@ -296,7 +304,7 @@ const Crontab = () => {
}> = ({ record, index }) => (
<Dropdown
arrow
trigger={['click', 'hover']}
trigger={['click']}
overlay={
<Menu onClick={({ key }) => action(key, record, index)}>
<Menu.Item key="edit" icon={<EditOutlined />}>
@ -383,6 +391,74 @@ const Crontab = () => {
.finally(() => setLoading(false));
};
const onSelectChange = (selectedIds: any[]) => {
setSelectedRowIds(selectedIds);
};
const rowSelection = {
selectedRowIds,
onChange: onSelectChange,
selections: [
Table.SELECTION_ALL,
Table.SELECTION_INVERT,
Table.SELECTION_NONE,
],
};
const delCrons = () => {
Modal.confirm({
title: '确认删除',
content: <></>,
onOk() {
request
.delete(`${config.apiPrefix}crons`, { data: selectedRowIds })
.then((data: any) => {
if (data.code === 200) {
notification.success({
message: '批量删除成功',
});
getCrons();
} else {
notification.error({
message: data,
});
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
const operateCrons = (operationStatus: number) => {
Modal.confirm({
title: `确认${OperationName[operationStatus]}`,
content: <>{OperationName[operationStatus]}</>,
onOk() {
request
.put(`${config.apiPrefix}crons/${OperationPath[operationStatus]}`, {
data: selectedRowIds,
})
.then((data: any) => {
if (data.code === 200) {
notification.success({
message: `批量${OperationName[operationStatus]}成功`,
});
getCrons();
} else {
notification.error({
message: data,
});
}
});
},
onCancel() {
console.log('Cancel');
},
});
};
useEffect(() => {
if (logCron) {
localStorage.setItem('logCron', logCron._id);
@ -410,7 +486,6 @@ const Crontab = () => {
<PageContainer
className="code-mirror-wrapper"
title="定时任务"
loading={loading}
extra={[
<Search
placeholder="请输入名称或者关键词"
@ -439,6 +514,38 @@ const Crontab = () => {
height: '100vh',
}}
>
{selectedRowIds.length > 0 && (
<div style={{ marginBottom: 16 }}>
<Button type="primary" onClick={delCrons}>
</Button>
<Button
type="primary"
onClick={() => operateCrons(0)}
style={{ marginLeft: 8 }}
>
</Button>
<Button
type="primary"
onClick={() => operateCrons(1)}
style={{ marginLeft: 8 }}
>
</Button>
<Button
type="primary"
onClick={() => operateCrons(2)}
style={{ marginLeft: 8 }}
>
</Button>
<span style={{ marginLeft: 8 }}>
<a>{selectedRowIds?.length}</a>
</span>
</div>
)}
<Table
columns={columns}
pagination={{
@ -449,8 +556,9 @@ const Crontab = () => {
dataSource={value}
rowKey="_id"
size="middle"
bordered
scroll={{ x: 768 }}
loading={loading}
rowSelection={rowSelection}
/>
<CronLogModal
visible={isLogModalVisible}