完成计划任务功能
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "next-terminal",
|
||||
"version": "0.2.7",
|
||||
"version": "0.3.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.3.0",
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
)
|
||||
|
Reference in New Issue
Block a user