完成计划任务功能

This commit is contained in:
dushixiang
2021-03-05 15:14:37 +08:00
parent 2d06cd373f
commit f81aedcac0
11 changed files with 375 additions and 112 deletions

View File

@ -1,6 +1,6 @@
{
"name": "next-terminal",
"version": "0.2.7",
"version": "0.3.0",
"private": true,
"dependencies": {
"@ant-design/icons": "^4.3.0",

View File

@ -490,7 +490,7 @@ class Asset extends Component {
if (tags[i] === '-') {
continue;
}
tagDocuments.push(<Tag>{tagArr[i]}</Tag>)
tagDocuments.push(<Tag key={tagArr[i]}>{tagArr[i]}</Tag>)
}
return tagDocuments;
}

View File

@ -12,10 +12,10 @@ import {
PageHeader,
Row,
Space,
Spin,
Switch,
Table,
Tag,
Timeline,
Tooltip,
Typography
} from "antd";
@ -68,6 +68,7 @@ class Job extends Component {
modalConfirmLoading: false,
selectedRow: undefined,
selectedRowKeys: [],
logPending: false,
logs: []
};
@ -159,11 +160,19 @@ class Job extends Component {
});
};
showModal(title, assets = null) {
showModal(title, obj = null) {
if (obj['func'] === 'shell-job') {
obj['shell'] = JSON.parse(obj['metadata'])['shell'];
}
if (obj['mode'] === 'custom') {
obj['resourceIds'] = obj['resourceIds'].split(',');
}
this.setState({
modalTitle: title,
modalVisible: true,
model: assets
model: obj
});
};
@ -180,6 +189,19 @@ class Job extends Component {
modalConfirmLoading: true
});
console.log(formData)
if (formData['func'] === 'shell-job') {
console.log(formData['shell'], JSON.stringify({'shell': formData['shell']}))
formData['metadata'] = JSON.stringify({'shell': formData['shell']});
formData['shell'] = undefined;
}
if (formData['mode'] === 'custom') {
let resourceIds = formData['resourceIds'];
formData['resourceIds'] = resourceIds.join(',');
}
if (formData.id) {
// 向后台提交数据
const result = await request.put('/jobs/' + formData.id, formData);
@ -284,7 +306,9 @@ class Job extends Component {
render: (func, record) => {
switch (func) {
case "check-asset-status-job":
return <Tag color="green">资产状态检测</Tag>
return <Tag color="green">资产状态检测</Tag>;
case "shell-job":
return <Tag color="volcano">Shell脚本</Tag>
}
}
}, {
@ -307,6 +331,9 @@ class Job extends Component {
dataIndex: 'updated',
key: 'updated',
render: (text, record) => {
if (text === '0001-01-01 00:00:00') {
return '';
}
return (
<Tooltip title={text}>
{dayjs(text).fromNow()}
@ -330,7 +357,7 @@ class Job extends Component {
onClick={async () => {
this.setState({
logVisible: true,
logPending: '正在加载...'
logPending: true
})
let result = await request.get(`/jobs/${record['id']}/logs`);
@ -401,7 +428,7 @@ class Job extends Component {
<>
<PageHeader
className="site-page-header-ghost-wrapper page-herder"
title="定时任务"
title="计划任务"
breadcrumb={{
routes: routes,
itemRender: itemRender
@ -409,7 +436,7 @@ class Job extends Component {
extra={[
<Logout key='logout'/>
]}
subTitle="定时任务"
subTitle="计划任务"
>
</PageHeader>
@ -444,7 +471,7 @@ class Job extends Component {
<Tooltip title="新增">
<Button type="dashed" icon={<PlusOutlined/>}
onClick={() => this.showModal('新增任务', {})}>
onClick={() => this.showModal('新增计划任务', {})}>
</Button>
</Tooltip>
@ -548,7 +575,7 @@ class Job extends Component {
okType={'danger'}
cancelText='取消'
>
<Timeline pending={this.state.logPending} mode={'left'}>
<Spin tip='加载中...' spinning={this.state.logPending}>
<pre className='cron-log'>
{
this.state.logs.map(item => {
@ -559,8 +586,7 @@ class Job extends Component {
})
}
</pre>
</Timeline>
</Spin>
</Modal> : undefined
}
</Content>

View File

@ -1,9 +1,41 @@
import React from 'react';
import {Form, Input, Modal, Radio, Select} from "antd/lib/index";
import React, {useEffect, useState} from 'react';
import {Form, Input, Modal, Radio, Select, Spin} from "antd/lib/index";
import TextArea from "antd/es/input/TextArea";
import request from "../../common/request";
import {message} from "antd";
const JobModal = ({title, visible, handleOk, handleCancel, confirmLoading, model}) => {
const [form] = Form.useForm();
if (model.func === undefined) {
model.func = 'shell-job';
}
if (model.mode === undefined) {
model.mode = 'all';
}
let [func, setFunc] = useState(model.func);
let [mode, setMode] = useState(model.mode);
let [resources, setResources] = useState([]);
useEffect(() => {
const fetchData = async () => {
setResourcesLoading(true);
let result = await request.get('/assets?protocol=ssh');
if (result['code'] === 1) {
setResources(result['data']);
} else {
message.error(result['message'], 10);
}
setResourcesLoading(false);
};
fetchData();
}, []);
let [resourcesLoading, setResourcesLoading] = useState(false);
const formItemLayout = {
labelCol: {span: 6},
@ -39,9 +71,9 @@ const JobModal = ({title, visible, handleOk, handleCancel, confirmLoading, model
<Form.Item label="任务类型" name='func' rules={[{required: true, message: '请选择任务类型'}]}>
<Select onChange={(value) => {
setFunc(value);
}}>
<Select.Option value="shell">Shell脚本</Select.Option>
<Select.Option value="shell-job">Shell脚本</Select.Option>
<Select.Option value="check-asset-status-job">资产状态检测</Select.Option>
</Select>
</Form.Item>
@ -50,10 +82,45 @@ const JobModal = ({title, visible, handleOk, handleCancel, confirmLoading, model
<Input autoComplete="off" placeholder="请输入任务名称"/>
</Form.Item>
{
func === 'shell-job' ?
<Form.Item label="Shell脚本" name='shell' rules={[{required: true, message: '请输入Shell脚本'}]}>
<TextArea autoSize={{minRows: 5, maxRows: 10}} placeholder="在此处填写Shell脚本内容"/>
</Form.Item> : undefined
}
<Form.Item label="cron表达式" name='cron' rules={[{required: true, message: '请输入cron表达式'}]}>
<Input placeholder="请输入cron表达式"/>
</Form.Item>
<Form.Item label="资产选择" name='mode' rules={[{required: true, message: '请选择资产'}]}>
<Radio.Group onChange={async (e) => {
setMode(e.target.value);
}}>
<Radio value={'all'}>全部资产</Radio>
<Radio value={'custom'}>自定义</Radio>
</Radio.Group>
</Form.Item>
{
mode === 'custom' ?
<Spin tip='加载中...' spinning={resourcesLoading}>
<Form.Item label="已选择资产" name='resourceIds' rules={[{required: true}]}>
<Select
mode="multiple"
allowClear
placeholder="请选择资产"
>
{
resources.map(item => {
return <Select.Option key={item['id']}>{item['name']}</Select.Option>
})
}
</Select>
</Form.Item>
</Spin>
: undefined
}
</Form>
</Modal>
)