Browse Source

(*)采集任务配置接口完善

master
peng.peng 2 years ago
parent
commit
40596340c6
  1. 1
      api/app/lib/controllers/metadataAcquisition/dataSource.js
  2. 1
      api/app/lib/controllers/metadataAcquisition/task.js
  3. 11
      api/app/lib/index.js
  4. 2
      api/app/lib/models/acquisition_task.js
  5. 2
      api/app/lib/models/data_source.js
  6. 6
      web/client/src/sections/metadataAcquisition/components/dataSourceManagementModal.js
  7. 119
      web/client/src/sections/metadataAcquisition/components/steps/postgre/stepThree.js
  8. 25
      web/client/src/sections/metadataAcquisition/components/taskModal.js
  9. 228
      web/client/src/sections/metadataAcquisition/containers/acquisitionTask.js
  10. 6
      web/client/src/sections/metadataAcquisition/containers/dataSourceManagement.js

1
api/app/lib/controllers/metadataAcquisition/dataSource.js

@ -38,6 +38,7 @@ function getDataSource(opts) {
let option = {
where: searchWhere,
order: [["id", "desc"]],
include: [{ model: models.Adapter }]
}
if (name) {

1
api/app/lib/controllers/metadataAcquisition/task.js

@ -38,6 +38,7 @@ function getAcquisitionTask(opts) {
let option = {
where: searchWhere,
order: [["id", "desc"]],
include: [{ model: models.DataSource }]
}
if (taskName) {

11
api/app/lib/index.js

@ -54,6 +54,15 @@ module.exports.models = function (dc) {
require(`./models/${filename}`)(dc)
});
const { } = dc.models;
const {
DataSource, AcquisitionTask, Adapter
} = dc.models;
AcquisitionTask.belongsTo(DataSource, { foreignKey: 'dataSourceId', targetKey: 'id' });
DataSource.hasMany(AcquisitionTask, { foreignKey: 'dataSourceId', sourceKey: 'id' });
DataSource.belongsTo(Adapter, { foreignKey: 'adapterId', targetKey: 'id' });
Adapter.hasMany(DataSource, { foreignKey: 'adapterId', sourceKey: 'id' });
};

2
api/app/lib/models/acquisition_task.js

@ -25,7 +25,7 @@ module.exports = dc => {
field: "task_name",
autoIncrement: false
},
dataSource: {
dataSourceId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,

2
api/app/lib/models/data_source.js

@ -34,7 +34,7 @@ module.exports = dc => {
field: "audited",
autoIncrement: false
},
adapter: {
adapterId: {
type: DataTypes.INTEGER,
allowNull: false,
defaultValue: null,

6
web/client/src/sections/metadataAcquisition/components/dataSourceManagementModal.js

@ -4,7 +4,9 @@ import AdapterStep from './adapterStep';
import { BellOutlined } from '@ant-design/icons'
function DataSourceModal(props) {
const { visible, editData, onFinish, onCancel, adapterInfo } = props;
const { visible, editData, onFinish, onCancel, adapterInfo,
type = 'postgre',//当前卡片的key (目前只有postgre,支持后续扩展)
} = props;
const [current, setCurrent] = useState(0);
// const onFinish = () => { }
return <>
@ -18,7 +20,7 @@ function DataSourceModal(props) {
>
<div style={{ fontSize: 17 }}><BellOutlined style={{ marginRight: 15 }} />{current == 0 ? '数据源基本信息' : '数据源参数配置'}</div>
<AdapterStep
type={'postgre'} //当前卡片的key (目前只有postgre,支持后续扩展)
type={type} //当前卡片的key (目前只有postgre,支持后续扩展)
onFinish={onFinish}
stepProps={2}
currentChange={c => { setCurrent(c) }}

119
web/client/src/sections/metadataAcquisition/components/steps/postgre/stepThree.js

@ -9,6 +9,7 @@ import {
ProFormCheckbox,
ProFormDependency
} from '@ant-design/pro-form';
import { BellOutlined } from '@ant-design/icons'
import '../../style.less';
function StepThree(props) {
@ -17,8 +18,10 @@ function StepThree(props) {
const initialValues = {
}
const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 10 } };
const formItemLayout = { labelCol: { span: 4 }, wrapperCol: { span: 16 } };
return <>
<div style={{ fontSize: 17 }}><BellOutlined style={{ marginRight: 15 }} />请输入该计划任务执行时间</div>
<ProForm
title={''}
initialValues={initialValues}
@ -31,7 +34,7 @@ function StepThree(props) {
}}
onFinish={async (values) => {
next()
return true;
// return true;
}}
style={{ marginTop: 20 }}
submitter={{
@ -40,73 +43,69 @@ function StepThree(props) {
},
}}
>
<ProForm.Group title="请输入该计划任务执行时间">
<ProFormText
width="md"
rules={[{ required: true, message: '请输入数据源名称' },
{ max: 255, message: '数据源名称长度不能大于255个字符' },
]}
name="taskName"
label="名称"
style={{
minWidth: 140,
}}
/>
<ProFormText
rules={[{ required: true, message: '请输入cron表达式' },
{ max: 255, message: 'cron表达式长度不能大于255个字符' },
]}
name="cron"
label="请输入cron表达式"
style={{
minWidth: 140,
}}
addonAfter={<Button>测试</Button>}
/>
<ProFormCheckbox
// rules={[{ required: true, message: '请选择重试次数' }]}
name="retried"
label="重试"
/>
<ProFormText
width={'md'}
rules={[{ required: true, message: '请输入数据源名称' },
{ max: 255, message: '数据源名称长度不能大于255个字符' },
]}
name="taskName"
label="名称"
addonAfter={' '}
/>
<ProFormDependency name={['retried']}>
{({ retried }) => {
<ProFormText
width={'md'}
rules={[{ required: true, message: '请输入cron表达式' },
{ max: 255, message: 'cron表达式长度不能大于255个字符' },
]}
name="cron"
label="请输入cron表达式"
addonAfter={<Button type='primary'>测试</Button>}
/>
return retried ?
<>
<ProFormDigit
rules={[
// { required: true, message: '请输入重试次数' },
// { max: 10, message: '重试次数不能大于10个字符' },
]}
name="retryCount"
label="重试次数"
fieldProps={{ precision: 0, max: 10, }}
addonAfter={' '}
/>
<ProFormCheckbox
width={'md'}
// rules={[{ required: true, message: '请选择重试次数' }]}
name="retried"
label="重试"
/>
<ProFormDigit
rules={[
// { required: true, message: '请输入时间间隔' },
// { max: 255, message: '时间间隔长度不能大于255个字符' },
]}
name="retryTime"
label="时间间隔"
addonAfter={'分钟'}
/>
<ProFormDependency name={['retried']}>
{({ retried }) => {
</>
: null
}}
</ProFormDependency>
return retried ?
<>
<ProFormDigit
width={'md'}
rules={[
// { required: true, message: '请输入重试次数' },
// { max: 10, message: '重试次数不能大于10个字符' },
]}
name="retryCount"
label="重试次数"
fieldProps={{ precision: 0, max: 10, }}
addonAfter={' '}
/>
<ProFormDigit
width={'md'}
rules={[
// { required: true, message: '请输入时间间隔' },
// { max: 255, message: '时间间隔长度不能大于255个字符' },
]}
name="retryTime"
label="时间间隔"
addonAfter={<span>分钟</span>}
/>
</ProForm.Group>
</>
: null
}}
</ProFormDependency>
<div className='step-footer'>
<Button style={{ margin: '0 8px', }} onClick={() => prev()}>上一步</Button>
{prev && <Button style={{ margin: '0 8px', }} onClick={() => prev()}>上一步</Button>}
<Button type="primary" htmlType="submit">
完成
</Button>

25
web/client/src/sections/metadataAcquisition/components/taskModal.js

@ -0,0 +1,25 @@
import React, { useEffect, useState } from 'react'
import { Tabs, Card, Modal } from 'antd'
import AdapterStep from './adapterStep';
import { STEP_CONFIG } from './steps/index'
function DataSourceModal(props) {
const { visible, editData, onFinish, onCancel,
type = 'postgre',//当前卡片的key (目前只有postgre,支持后续扩展)
} = props;
const { StepThree } = STEP_CONFIG[type];
// const onFinish = () => { }
return <>
<Modal
title={editData ? '编辑数据源' : "新建数据源"}
onCancel={() => { onCancel() }}
open={visible}
footer={null}
width={1200}
destroyOnClose={true}
>
<StepThree next={onFinish} />
</Modal>
</>
}
export default DataSourceModal

228
web/client/src/sections/metadataAcquisition/containers/acquisitionTask.js

@ -1,7 +1,229 @@
import React, { useEffect, useState } from 'react'
import { Spin, Popconfirm, Tree, Row, Col, Button, Input, Table } from 'antd';
import { connect } from 'react-redux';
import ProTable from '@ant-design/pro-table';
import moment from 'moment';
import TaskModal from '../components/taskModal';
import { RELATION_DATABASE_TOOL_CONFIG } from '../constants/adapter';
function AcquisitionTask (props) {
return <>采集任务配置</>
import './style.less';
function AcquisitionTask(props) {
const { loading, clientHeight, actions, dispatch, dataSources, adapters, tasks } = props;
const [pageSize, setPageSize] = useState(10);
const [currentPage, setCurrentPage] = useState(1);
const [searchValue, setSearchValue] = useState('')
const [visible, setVisible] = useState(false);//是否展示新增编辑模态框
const [editData, setEditData] = useState(null);//模态框编辑数据
const queryData = (search) => {
const query = {
limit: search ? 10 : pageSize || 10,
page: search ? 1 : currentPage || 1,
taskName: searchValue
}
dispatch(actions.metadataAcquisition.getTasks(query));
}
useEffect(() => {
dispatch(actions.metadataAcquisition.getDataSources());
dispatch(actions.metadataAcquisition.getAdapters())
queryData();
}, [pageSize, currentPage]);
const handleDelete = (id) => {
dispatch(actions.metadataAcquisition.deleteDataSource(id)).then(() => {
queryData();
});
};
const columns = [
{
title: '数据源名称',
dataIndex: 'taskName',
},
{
title: '数据源名称',
dataIndex: 'name',
},
{
title: '挂载点',
dataIndex: 'mountPath',
},
{
title: '适配器类型',
dataIndex: 'adapter',
render: (text, record) => {
const adapterInfo = adapters?.find(s => s.id == record?.adapter)
return adapterInfo?.adapterName
}
},
{
title: '采集方式',
dataIndex: 'control',
render: (text, record) => {
const adapterInfo = adapters?.find(s => s.id == record?.adapter)
return adapterInfo?.mode
}
},
{
title: '工具版本',
dataIndex: 'length',
render: (text, record) => {
const adapterInfo = adapters?.find(s => s.id == record?.adapter)
return adapterInfo?.adapterVersion
}
},
{
title: '修改时间',
dataIndex: 'time',
render: (text, record) => moment(record?.time).format('YYYY-MM-DD HH:mm:ss')
},
{
title: '描述',
dataIndex: 'description',
ellipsis: true,
search: false,
},
{
title: '操作',
width: 160,
key: 'option',
valueType: 'option',
render: (text, record) => {
const options = [];
options.push(<a onClick={() => {
const adapterInfo = adapters?.find(x => x.id == record?.adapter)
setVisible(true)
record.adapterInfo = adapterInfo
setEditData(record)
}} style={{ marginRight: 8 }}>编辑</a>)
options.push(
<Popconfirm
key="del"
placement="top"
title="是否确认删除该数据源?"
onConfirm={() => handleDelete(record.id)}
okText="是"
cancelText="否"
>
<a>删除</a>
</Popconfirm>)
return options;
},
},
];
const onFinish = (values) => {
const { stepOneValues, stepTwoValues } = values;
const adapterInfo = adapters?.find(x => x.adapterName == stepOneValues?.adapterName)
if (adapterInfo) {
const dataToSave = {
name: stepOneValues?.name,
audited: true,
adapter: adapterInfo?.id,
mountPath: 1,
description: stepOneValues?.description,
config: stepTwoValues,
time: moment()
}
if (editData) {
dispatch(actions.metadataAcquisition.modifyTask(editData?.id, dataToSave)).then(res => {
if (res.success) {
setVisible(false);
setEditData(null);
queryData();
}
})
} else {
dispatch(actions.metadataAcquisition.addTask(dataToSave)).then(res => {
if (res.success) {
setVisible(false);
setEditData(null);
queryData();
}
})
}
}
}
return <Spin spinning={loading}>
<Row className='protable-title'>
<Col span={12}><Button type='primary' onClick={() => { setVisible(true) }}>新建</Button></Col>
<Col span={12} style={{ textAlign: 'right' }}><Input
value={searchValue} onChange={e => { setSearchValue(e.target.value) }}
style={{ width: 220, marginRight: 15 }} placeholder="数据源或任务名称" /><Button onClick={() => { queryData() }} type='primary'>查询</Button></Col>
</Row>
<ProTable
columns={columns}
dateFormatter="string"
search={false}
scroll={
{
scrollToFirstRowOnChange: true,
y: clientHeight - 260
}
}
pagination={{
size: 'large',
total: tasks?.count,
showSizeChanger: true,
// showQuickJumper: true,
current: currentPage,
pageSize: pageSize || 10,
pageSizeOptions: [10, 20, 50],
showTotal: (total) => {
return <span style={{ fontSize: 15 }}>{`${Math.ceil(total / pageSize)}页,${total}`}</span>
},
onShowSizeChange: (currentPage, pageSize) => {
setCurrentPage(currentPage);
setPageSize(pageSize);
},
onChange: (page, pageSize) => {
setCurrentPage(page);
setPageSize(pageSize);
}
}}
dataSource={tasks?.rows || []}
options={false}
/>
{
visible && <TaskModal
onCancel={
() => {
setVisible(false)
setEditData(null)
}
}
editData={editData}
visible={visible}
onFinish={onFinish}
{...props}
/>
}
</Spin>
}
function mapStateToProps(state) {
const {
auth, global, datasources, adapters, tasks
} = state;
return {
loading: datasources.isRequesting || adapters?.isRequesting,
clientHeight: global.clientHeight,
actions: global.actions,
dataSources: datasources?.data || {},
adapters: adapters?.data || [],
tasks: tasks?.data || [],
};
}
export default AcquisitionTask
export default connect(mapStateToProps)(AcquisitionTask);

6
web/client/src/sections/metadataAcquisition/containers/dataSourceManagement.js

@ -48,7 +48,7 @@ function DataSourceManagement(props) {
title: '适配器类型',
dataIndex: 'adapter',
render: (text, record) => {
const adapterInfo = adapters?.find(s => s.id == record?.adapter)
const adapterInfo = record?.adapter
return adapterInfo?.adapterName
}
},
@ -56,7 +56,7 @@ function DataSourceManagement(props) {
title: '采集方式',
dataIndex: 'control',
render: (text, record) => {
const adapterInfo = adapters?.find(s => s.id == record?.adapter)
const adapterInfo = record?.adapter
return adapterInfo?.mode
}
},
@ -64,7 +64,7 @@ function DataSourceManagement(props) {
title: '工具版本',
dataIndex: 'length',
render: (text, record) => {
const adapterInfo = adapters?.find(s => s.id == record?.adapter)
const adapterInfo = record?.adapter
return adapterInfo?.adapterVersion
}
},

Loading…
Cancel
Save