Browse Source

(*) 数据源增加备份数据源 资源检索展示优化

master
peng.peng 2 years ago
parent
commit
de03a0681c
  1. 13
      api/app/lib/models/data_source.js
  2. 9
      scripts/0.0.7/02_alter_t_data_source.sql
  3. 111
      web/client/src/sections/metadataAcquisition/components/steps/postgre/stepOne.js
  4. 2
      web/client/src/sections/metadataAcquisition/components/steps/postgre/stepThree.js
  5. 1
      web/client/src/sections/metadataAcquisition/containers/adapter.js
  6. 1
      web/client/src/sections/metadataAcquisition/containers/dataSourceManagement.js
  7. 6
      web/client/src/sections/resourceRetrieval/components/keyModal.js
  8. 54
      web/client/src/sections/resourceRetrieval/containers/retrieval.js
  9. 7
      web/client/src/sections/resourceRetrieval/utils/index.js

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

@ -49,7 +49,7 @@ module.exports = dc => {
}, },
mountPath: { mountPath: {
type: DataTypes.INTEGER, type: DataTypes.INTEGER,
allowNull: false, allowNull: true,
defaultValue: null, defaultValue: null,
comment: "数据源挂载路径", comment: "数据源挂载路径",
primaryKey: false, primaryKey: false,
@ -95,7 +95,16 @@ module.exports = dc => {
primaryKey: false, primaryKey: false,
field: "catalogKey", field: "catalogKey",
autoIncrement: false autoIncrement: false
} },
type: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: null,
comment: "元数据类型",
primaryKey: false,
field: "type",
autoIncrement: false
},
}, { }, {
tableName: "t_data_source", tableName: "t_data_source",
comment: "", comment: "",

9
scripts/0.0.7/02_alter_t_data_source.sql

@ -0,0 +1,9 @@
create type enum_datasource_type as enum ('原数据库', '备份数据库');
alter table t_data_source
alter column mount_path drop not null;
alter table t_data_source
add type enum_datasource_type;
comment on column t_data_source.type is '数据源类型';

111
web/client/src/sections/metadataAcquisition/components/steps/postgre/stepOne.js

@ -5,7 +5,8 @@ import {
ProFormSelect, ProFormSelect,
ProFormTextArea, ProFormTextArea,
ProFormText, ProFormText,
ProFormTreeSelect ProFormTreeSelect,
ProFormDependency
} from '@ant-design/pro-form'; } from '@ant-design/pro-form';
import { push } from 'react-router-redux'; import { push } from 'react-router-redux';
@ -16,6 +17,7 @@ function StepOne(props) {
adapterName: 'PostgreSQL采集适配器', adapterName: 'PostgreSQL采集适配器',
adapterVersion: '9.x', adapterVersion: '9.x',
mode: '数据库连接', mode: '数据库连接',
type: '原数据库'
// mountPath: 1, // mountPath: 1,
} }
@ -67,7 +69,7 @@ function StepOne(props) {
onCancel: () => { }, onCancel: () => { },
}} }}
onFinish={async (values) => { onFinish={async (values) => {
values.mountPath = values.catalogKey.split('-')[values.catalogKey.split('-')?.length - 1] if (values.catalogKey) values.mountPath = values.catalogKey.split('-')[values.catalogKey.split('-')?.length - 1]
next() next()
stepOneValuesFinish(values) stepOneValuesFinish(values)
return true; return true;
@ -117,54 +119,65 @@ function StepOne(props) {
label="采集模式" label="采集模式"
disabled={readOnly} disabled={readOnly}
/> />
{/* <ProFormSelect <ProFormSelect
rules={[{ required: true, message: '请选择输入控件' }]}
options={[
{ label: '库表/目录1', value: 1 },
]}
name="mountPath"
label="数据源挂载路径"
// disabled={true}
/> */}
{treeDataFilter.length > 0 ? <ProFormTreeSelect
key={JSON.stringify(treeDataFilter)}
// width={'md'}
name="catalogKey"
label="数据源挂载路径"
placeholder="请选择数据源挂载路径"
rules={[{ required: true, message: '请选择数据源挂载路径' }]}
allowClear
width={480}
secondary
request={async () => {
return treeDataFilter || [];
}}
// tree-select args
fieldProps={{
showArrow: false,
filterTreeNode: true,
showSearch: true,
dropdownMatchSelectWidth: false,
labelInValue: false,
autoClearSearchValue: true,
multiple: false,
treeNodeFilterProp: 'title',
fieldNames: {
label: 'title',
},
}}
addonAfter={renderAddonAfter()}
disabled={editData}
/> : <ProFormSelect
width={480}
rules={[{ required: true, message: '请选择' }]} rules={[{ required: true, message: '请选择' }]}
options={[]} options={
name="catalogKey" [
label="数据源挂载路径" { label: '原数据库', value: '原数据库' },
addonAfter={renderAddonAfter()} { label: '备份数据库', value: '备份数据库' }
placeholder="请选择数据源挂载路径" ]
disabled={editData} }
/>} name="type"
label="数据源属性"
disabled={readOnly}
/>
<ProFormDependency name={['type']}>
{({ type }) => {
return (
type == '备份数据库' ? null : treeDataFilter.length > 0 ? <ProFormTreeSelect
key={JSON.stringify(treeDataFilter)}
// width={'md'}
name="catalogKey"
label="数据源挂载路径"
placeholder="请选择数据源挂载路径"
rules={[{ required: true, message: '请选择数据源挂载路径' }]}
allowClear
width={480}
secondary
request={async () => {
return treeDataFilter || [];
}}
// tree-select args
fieldProps={{
showArrow: false,
filterTreeNode: true,
showSearch: true,
dropdownMatchSelectWidth: false,
labelInValue: false,
autoClearSearchValue: true,
multiple: false,
treeNodeFilterProp: 'title',
fieldNames: {
label: 'title',
},
}}
addonAfter={renderAddonAfter()}
disabled={editData}
/> : <ProFormSelect
width={480}
rules={[{ required: true, message: '请选择' }]}
options={[]}
name="catalogKey"
label="数据源挂载路径"
addonAfter={renderAddonAfter()}
placeholder="请选择数据源挂载路径"
disabled={editData}
/>
);
}}
</ProFormDependency>
<ProFormTextArea <ProFormTextArea
name="description" name="description"

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

@ -67,7 +67,7 @@ function StepThree(props) {
{dataSourceFilter && <ProFormSelect {dataSourceFilter && <ProFormSelect
width={'md'} width={'md'}
rules={[{ required: true, message: '请选择数据源' }]} rules={[{ required: true, message: '请选择数据源' }]}
options={dataSourceFilter?.map(s => { options={dataSourceFilter?.filter(x => x?.type != '备份数据库')?.map(s => {
return { label: s?.name, value: s?.id, disabled: s?.disabled } return { label: s?.name, value: s?.id, disabled: s?.disabled }
})} })}
disabled={editData} disabled={editData}

1
web/client/src/sections/metadataAcquisition/containers/adapter.js

@ -57,6 +57,7 @@ const Adapter = (props) => {
mountPath: stepOneValues?.mountPath, mountPath: stepOneValues?.mountPath,
catalogKey: stepOneValues?.catalogKey, catalogKey: stepOneValues?.catalogKey,
description: stepOneValues?.description, description: stepOneValues?.description,
type: stepOneValues?.type,
config: stepTwoValues, config: stepTwoValues,
time: moment() time: moment()
}, '')).then(res => { }, '')).then(res => {

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

@ -124,6 +124,7 @@ function DataSourceManagement(props) {
mountPath: stepOneValues?.mountPath, mountPath: stepOneValues?.mountPath,
catalogKey: stepOneValues?.catalogKey, catalogKey: stepOneValues?.catalogKey,
description: stepOneValues?.description, description: stepOneValues?.description,
type: stepOneValues?.type,
config: stepTwoValues, config: stepTwoValues,
time: moment() time: moment()
} }

6
web/client/src/sections/resourceRetrieval/components/keyModal.js

@ -6,20 +6,22 @@ import {
import { Form, message } from 'antd'; import { Form, message } from 'antd';
export default (props) => { export default (props) => {
const { resourceId, onFinish, approveList } = props; const { resourceId, onFinish, approveList, } = props;
const [form] = Form.useForm(); const [form] = Form.useForm();
return ( return (
<ModalForm <ModalForm
title="输入令牌" title="输入令牌"
trigger={ trigger={
<a>下载</a> <a></a>
} }
visible={true}
form={form} form={form}
layout='horizontal' layout='horizontal'
autoFocusFirstInput autoFocusFirstInput
modalProps={{ modalProps={{
destroyOnClose: true, destroyOnClose: true,
onCancel: () => { props.onCancel() }
}} }}
onFinish={async (values) => { onFinish={async (values) => {
console.log(values.name); console.log(values.name);

54
web/client/src/sections/resourceRetrieval/containers/retrieval.js

@ -1,9 +1,9 @@
import React, { useEffect, useState } from 'react' import React, { useEffect, useState } from 'react'
import { Input, Tooltip, Empty, Pagination, Modal, Form } from 'antd' import { Input, Tooltip, Empty, Pagination, Popover, message } from 'antd'
import { InsertRowBelowOutlined, DatabaseOutlined, FileOutlined, PullRequestOutlined, KeyOutlined } from '@ant-design/icons'; import { InsertRowBelowOutlined, DatabaseOutlined, FileOutlined, PullRequestOutlined, KeyOutlined } from '@ant-design/icons';
import { useFsRequest, ApiTable } from '$utils'; import { useFsRequest, ApiTable } from '$utils';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { downloadImg } from '../utils/index' import { downloadImg, markRedKeywords } from '../utils/index'
import KeyModal from '../components/keyModal'; import KeyModal from '../components/keyModal';
const METADTA_TYPE = { const METADTA_TYPE = {
'库': 'databases', '库': 'databases',
@ -11,12 +11,21 @@ const METADTA_TYPE = {
'文件': 'files', '文件': 'files',
'接口': 'restapis', '接口': 'restapis',
} }
const METADTA_TYPE_NAMES = {
'库': '库表/库(Schema)',
'表': '库表/表(Table)',
'文件': '文件(File)',
'接口': '接口(Api)',
}
import './style.less'; import './style.less';
function Retrieval(props) { function Retrieval(props) {
const { user, catalogs, dispatch, actions } = props; const { user, catalogs, dispatch, actions } = props;
const [keywords, setKeywords] = useState() const [keywords, setKeywords] = useState()
const [firstInput, setFirstInput] = useState() const [firstInput, setFirstInput] = useState()
const [page, setPage] = useState(1) const [page, setPage] = useState(1)
const [currentData, setCurrentData] = useState(null)
const formRef = React.createRef(); const formRef = React.createRef();
// const { data: catalogs = [] } = useFsRequest({ // const { data: catalogs = [] } = useFsRequest({
// url: ApiTable.getResourceCatalog, // url: ApiTable.getResourceCatalog,
@ -77,6 +86,17 @@ function Retrieval(props) {
</Tooltip> : text </Tooltip> : text
} }
const renderName = (text) => {
function createMarkup(textFilter) {
return { __html: textFilter.length == text.length ? markRedKeywords(textFilter, keywords) : markRedKeywords(textFilter, keywords) + '...' };
}
return text?.length > 16 ?
<Popover placement="topRight" title={null} content={<span dangerouslySetInnerHTML={createMarkup(text)} />}>
<span dangerouslySetInnerHTML={createMarkup(text.substring(0, 16))} />
</Popover>
: <span dangerouslySetInnerHTML={createMarkup(text)} />
}
const downloadData = (s) => { const downloadData = (s) => {
if (s?.type == '文件') { if (s?.type == '文件') {
const suffix = s?.fileName?.substring(s?.fileName?.length - 3, s?.fileName?.length) const suffix = s?.fileName?.substring(s?.fileName?.length - 3, s?.fileName?.length)
@ -109,21 +129,23 @@ function Retrieval(props) {
<div className='column1'> <div className='column1'>
{renderIcon(s?.type)} {renderIcon(s?.type)}
{s?.code && <span> 代码{renderText(s?.code)}</span>} {s?.code && <span> 代码{renderText(s?.code)}</span>}
<span> 名称{renderText(s?.name)}</span> <span> 名称{renderName(s?.name)}</span>
<span> 类型{s?.type}</span> <span> 类型{METADTA_TYPE_NAMES[s?.type]}</span>
<span> 路径{renderText(catalogText)}</span> <span> 路径{renderText(catalogText)}</span>
<span> 标签{renderText(tagText)}</span> <span> 标签{renderText(tagText)}</span>
</div> </div>
<div className='column2'>相关操作<a onClick={() => { window.open(`/metadataManagement/latestMetadata?type=${METADTA_TYPE[s.type]}&treeId=${s?.catalog}&resourceId=${s.id}&catalogKey=${s.catalogKey}`) }}>定位</a> <div className='column2'>相关操作<a onClick={() => { window.open(`/metadataManagement/latestMetadata?type=${METADTA_TYPE[s.type]}&treeId=${s?.catalog}&resourceId=${s.id}&catalogKey=${s.catalogKey}`) }}>定位</a>
{s?.type == '表' || s?.type == '文件' ? {s?.type == '表' || s?.type == '文件' ?
user?.role == '数据消费者' ? user?.role == '数据消费者' ?
<KeyModal <a onClick={() => {
resourceId={s.id} const token = approveList?.rows?.find(x => x.resourceId == s.id)?.token
approveList={approveList} if (!token) {
onFinish={() => { message.warning('您暂未申请该数据资源,请先申请该数据资源')
downloadData(s) } else {
}} setCurrentData(s)
/> : }
}}>下载</a> :
<a onClick={() => { downloadData(s) }}>下载</a> : ''} <a onClick={() => { downloadData(s) }}>下载</a> : ''}
</div> </div>
</div> </div>
@ -137,6 +159,16 @@ function Retrieval(props) {
}} }}
/>} />}
{!result?.rows?.length > 0 && <Empty />} {!result?.rows?.length > 0 && <Empty />}
{currentData && <KeyModal
resourceId={currentData?.id}
approveList={approveList}
onFinish={() => {
downloadData(currentData)
setCurrentData(null)
}}
onCancel={() => { setCurrentData(null) }}
/>}
</> </>
} }

7
web/client/src/sections/resourceRetrieval/utils/index.js

@ -28,3 +28,10 @@ export const downloadImg = (fileName) => {
} }
} }
export const markRedKeywords = (str, key) => {
var reg = new RegExp((`(${key})`), "gi");
var replace = '<span style="color:#FD463E;font-weight:bold;margin-right:0px;">$1</span>';
return str.replace(reg, replace);
}
Loading…
Cancel
Save