Commit 814265af by zhaochengxiang

资产详情

parent 96dc5d96
import React, { useEffect, useState } from 'react';
import { Form, Spin, Input, Descriptions, Space, Button } from 'antd';
import { DownOutlined, UpOutlined } from '@ant-design/icons';
import MetadataInfo from './MetadataInfo';
import { dispatch } from '../../../../model';
import { highlightSearchContentByTerms, showMessage } from '../../../../util';
import { unfoldedElements } from '../util';
const AssetAction = (props) => {
const { id, dirId, action, terms } = props;
const [ currentAction, setCurrentAction ] = useState(action);
const [ assetParams, setAssetParams ] = useState({ assets: [], attributes: [], attributesFoldMap: {} });
const [ elements, setElements ] = useState([]);
const [ metadataId, setMetadataId ] = useState('');
const [ loading, setLoading ] = useState(false);
const [ confirmLoading, setConfirmLoading ] = useState(false);
const { assets, attributes, attributesFoldMap } = assetParams;
const [ form ] = Form.useForm();
useEffect(() => {
if (action === 'add') {
getElements();
} else if ((id||'')!=='') {
setCurrentAction('detail');
getElements(() => {
getAsset();
});
}
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [id])
const getElements = ( cb = null ) => {
setLoading(true);
dispatch({
type: 'assetmanage.listElements',
callback: data => {
setLoading(false);
setElements(data||[]);
if (action === 'add') {
const _attributes = [];
(data||[]).forEach(element => {
if (_attributes.indexOf(element.type) === -1) {
_attributes.push(element.type);
}
})
let newAttributesFoldMap = {...attributesFoldMap};
(_attributes||[]).forEach(attribute => {
if (newAttributesFoldMap[attribute]===undefined || newAttributesFoldMap[attribute]===null) {
newAttributesFoldMap[attribute] = true;
}
})
setAssetParams({ assets: [], attributes: _attributes, attributesFoldMap: newAttributesFoldMap });
form?.resetFields();
}
cb && cb();
},
error: () => {
setLoading(false);
}
})
}
const getAsset = () => {
setLoading(true);
dispatch({
type: 'assetmanage.getDataAssetDetail',
payload: {
dataAssetId: id
},
callback: data => {
setLoading(false);
setMetadataId(data?.mid||'');
const _attributes = [];
(data?.elements||[]).forEach(element => {
if (_attributes.indexOf(element.type) === -1) {
_attributes.push(element.type||'');
}
})
let newAttributesFoldMap = {...attributesFoldMap};
(_attributes||[]).forEach(attribute => {
if (newAttributesFoldMap[attribute]===undefined || newAttributesFoldMap[attribute]===null) {
newAttributesFoldMap[attribute] = true;
}
})
setAssetParams({ assets: data, attributes: _attributes, attributesFoldMap: newAttributesFoldMap });
let _fieldsValue = {};
(data.elements||[]).forEach(element => {
_fieldsValue[element.name] = element.value||'';
})
form?.setFieldsValue(_fieldsValue);
},
error: () => {
setLoading(false);
}
})
}
const onActionButtonClick = () => {
if (currentAction === 'detail') {
setCurrentAction('edit');
} else if (currentAction === 'edit') {
onOk();
}
}
const onOk = async() => {
try {
const row = await form.validateFields();
const newElements = [...elements];
(newElements||[]).forEach(element => {
if (row.hasOwnProperty(element.name)) {
element.value = row[element.name];
}
});
const params = {
dirId,
}
if ((metadataId||'')!=='') {
params.metadataId = metadataId;
}
setConfirmLoading(true);
dispatch({
type: 'assetmanage.addOrUpdateDataAsset',
payload: {
params,
data: action==='add' ? { elements: newElements } : { ...assets, elements: newElements }
},
callback: () => {
setConfirmLoading(false);
setCurrentAction('detail');
getAsset();
showMessage("success",(action==='add')?"新增成功":"修改成功");
},
error: () => {
setConfirmLoading(false);
}
})
} catch (errInfo) {
console.log('Validate Failed:', errInfo);
setConfirmLoading(false);
}
}
const onFoldButtonClick = (attribute, fold) => {
let newAttributesFoldMap = {...attributesFoldMap};
newAttributesFoldMap[attribute] = fold;
setAssetParams({...assetParams, attributesFoldMap: newAttributesFoldMap});
}
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 17 },
},
};
return (
<div
className='flex'
style={{
height: '100%',
flexDirection: 'column'
}}
>
<div
className='flex px-3'
style={{
height: 52,
alignItems: 'center',
justifyContent: 'space-between',
borderBottom: '1px solid #f0f0f0',
}}
>
<div style={{ color: 'rgba(0,0,0,0.75)' }}>资产详情</div>
<Space>
<Button loading={confirmLoading} onClick={onActionButtonClick}>{ currentAction==='detail'?'编辑':'保存'}</Button>
</Space>
</div>
<div
className='p-3'
style={{
flex: 1,
overflow: 'auto'
}}
>
<Spin
spinning={loading}
>
{
(attributes||[]).map((attribute, index) => {
let sameAttributeElements = [];
if (currentAction==='add' || currentAction==='edit') {
sameAttributeElements = (elements||[]).filter(element => element.type===attribute);
} else {
sameAttributeElements = (assets?.elements||[]).filter(element => element.type===attribute);
}
if (attributesFoldMap[attribute]) {
sameAttributeElements = (sameAttributeElements||[]).filter(element => unfoldedElements.indexOf(element?.name||'')!==-1);
}
return (
<div key={index}>
<div className='flex'>
<div style={{ color: 'rgba(0,0,0,0.75)' }}>{attribute||''}</div>
{
attributesFoldMap[attribute] ? <Button type='text' style={{ padding: 0, color: '#0069AC' }} onClick={() => { onFoldButtonClick(attribute, false) }}>展开<DownOutlined /></Button> : <Button type='text' style={{ padding: 0, color: '#0069AC' }} onClick={() => { onFoldButtonClick(attribute, true) }}>收起<UpOutlined /></Button>
}
</div>
{
(currentAction==='add'||currentAction==='edit') ? <Form {...formItemLayout} form={form}>
{
(sameAttributeElements||[]).map((element, _index) => {
return (
<Form.Item
label={element.name}
name={element.name}
key={_index}
>
{ (element.name==='资产项') ? <MetadataInfo /> : <Input disabled={element.manualMaintain==='否'} /> }
</Form.Item>
);
})
}
</Form> : <Descriptions column={1}>
{
(sameAttributeElements||[]).map((item, index) => {
return (
<Descriptions.Item label={item.name||''} key={index}>
{
item.name==='资产项' ? <MetadataInfo config={false} value={item.value||''} /> : <span>{highlightSearchContentByTerms(item.value||'', terms)}</span>
}
</Descriptions.Item>
);
})
}
</Descriptions>
}
</div>
);
})
}
</Spin>
</div>
</div>
)
}
export default AssetAction;
\ No newline at end of file
......@@ -4,7 +4,6 @@ import { Space, Spin, Tooltip } from 'antd';
import { dispatch } from '../../../../model';
import record from '../../../../assets/record.png';
import DescriptionsItem from 'antd/lib/descriptions/Item';
const AssetDirectory = (props) => {
const { id } = props;
......
......@@ -191,7 +191,7 @@ const AssetEdit = (props) => {
{ (element.name==='资产项') ? <MetadataInfo /> : <Input disabled={element.manualMaintain==='否'} /> }
</Form.Item>
)
})}
})}
</>
);
}}
......
import React,{ useState, useEffect, useRef } from "react";
import { Card, Button, Pagination, Space, Modal, Input, Table, Divider, Tooltip } from "antd";
import { Button, Pagination, Space, Modal, Input, Table, Tooltip } from "antd";
import classNames from 'classnames';
import SmoothScroll from 'smooth-scroll';
......@@ -10,18 +10,18 @@ import AssetEdit from './AssetEdit';
import { dispatch, dispatchLatestHomepage } from '../../../../model';
import { showMessage, showNotifaction, getQueryParam, inputWidth, isSzseEnv } from '../../../../util';
import { AnchorId, AnchorTimestamp } from '../../../../util/constant';
import { AppContext } from '../../../../App';
import "./AssetTable.less";
const AssetTable = (props) => {
const { readOnly = false, className, nodeId, nodeType } = props;
const { readOnly = false, className, nodeId, nodeType, onSelect } = props;
const [ loading, setLoading ] = useState(false);
const [ columns, setColumns ] = useState([]);
const [ assets, setAssets ] = useState([]);
const [ total, setTotal ] = useState(0);
const [ selectedKeys, setSelectedKeys ] = useState([]);
const [ selectKey, setSelectKey ] = useState('');
const [ checkedKeys, setCheckedKeys ] = useState([]);
const [ importAssetVisible, setImportAssetVisible ] = useState(false);
const [ filterElementVisible, setFilterElementVisible ] = useState(false);
const [ assetEditVisible, setAssetEditVisible ] = useState(false);
......@@ -33,79 +33,6 @@ const AssetTable = (props) => {
const [ keyword, setKeyword ] = useState('');
const [ batchCatalogChange, setBatchCatalogChange ] = useState(false);
const actionColumn = {
title: '操作',
key: 'action',
width: readOnly?60:190,
fixed: 'right',
render: (_,record) => {
const metadata = record['metadata']||'';
return (
<div style={{ display: 'flex', alignItems: 'center' }}>
<AppContext.Consumer>
{
value => <Tooltip title={(typeof metadata==='string')?(readOnly?'暂无关联的元数据':'暂无关联的元数据,如需关联,请在资产项里进行设置'):''}>
<Button
type='link'
size='small'
onClick={() => {
value?.setGlobalState && value?.setGlobalState({
message: 'data-govern-show-metadata-message',
data: metadata
})
}}
style={{ padding: 0 }}
disabled={typeof metadata==='string'}
>
来源
</Button>
</Tooltip>
}
</AppContext.Consumer>
{
!readOnly && <React.Fragment>
<div>
<Divider type='vertical' />
</div>
<Button
type='link'
size='small'
onClick={() => { editAsset(record); }}
style={{ padding: 0 }}
>
编辑
</Button>
<div>
<Divider type='vertical' />
</div>
<Button
type='link'
size='small'
onClick={() => { deleteAsset(record); }}
style={{ padding: 0 }}
>
删除
</Button>
<div>
<Divider type='vertical' />
</div>
<Button
type='link'
size='small'
onClick={() => { mountAsset(record); }}
style={{ padding: 0 }}
>
{ (nodeType==='RecycleBin')?'挂载':'变更' }
</Button>
</React.Fragment>
}
</div>
)
}
};
const [ modal, contextHolder ] = Modal.useModal();
const anchorId = getQueryParam(AnchorId, props.location.search);
const timestamp = getQueryParam(AnchorTimestamp, props.location.search);
......@@ -122,13 +49,11 @@ const AssetTable = (props) => {
getDataAssetLocation();
} else {
setPagination({ ...pagination, pageNum: 1 });
}
setKeyword('');
setSelectedKeys([]);
setCheckedKeys([]);
}
//eslint-disable-next-line react-hooks/exhaustive-deps
......@@ -184,7 +109,7 @@ const AssetTable = (props) => {
}
const changeCurrent = (page,size) => {
setSelectedKeys([]);
setCheckedKeys([]);
setPagination({ pageNum: page, pageSize: size });
}
......@@ -262,7 +187,7 @@ const AssetTable = (props) => {
})
setAssets([]);
setColumns([..._columns, actionColumn]);
setColumns(_columns);
metadataIndexRef.current = _metadataIndex;
......@@ -319,6 +244,8 @@ const AssetTable = (props) => {
})
setAssets(_assets);
setSelectKey(_assets.length>0?_assets[0].id:'');
onSelect && onSelect(_assets.length>0?_assets[0].id:'')
setTotal(data.total||0);
setLoading(false);
},
......@@ -343,58 +270,11 @@ const AssetTable = (props) => {
refresh && getDataAssets();
}
const editAsset = (item) =>{
setCurrentAssetId(item.id);
setAssetEditAction('edit');
setAssetEditVisible(true);
}
const mountAsset = (item) => {
setBatchCatalogChange(false);
setCurrentAssetId(item.id);
setAssetMountVisible(true);
}
const onAssetMountCancel = (refresh = false) => {
setAssetMountVisible(false);
refresh && getDataAssets();
}
const deleteAsset = (item) =>{
modal.confirm({
title: '提示',
content: (nodeType!=='RecycleBin')?'该资产在所有目录上唯一存在,移除后,你可以前往“未挂载资产”重新挂载。': '您确定要永久删除该资产吗?',
onOk: () => {
let payload = {
data:[ item.id ]
}
if (nodeType !== 'RecycleBin') {
payload.params = {
dirId: nodeId
}
}
dispatch({
type: (nodeType!=='RecycleBin')?'assetmanage.unloadDataAssets':'assetmanage.deleteDataAssets',
payload,
callback: () => {
showMessage("success","删除成功");
getDataAssets();
const index = selectedKeys.findIndex((key) => key === item.id);
if (index !== -1) {
const newSelectedKeys = [...selectedKeys];
newSelectedKeys.splice(index, 1);
setSelectedKeys(newSelectedKeys);
}
},
error: () => {
}
})
}
})
}
const importAsset = () => {
setImportAssetVisible(true);
}
......@@ -404,10 +284,10 @@ const AssetTable = (props) => {
}
const exportAsset = () => {
if ((selectedKeys||[]).length === 0) {
if ((checkedKeys||[]).length === 0) {
showMessage('warn', '请先选择资产');
} else {
window.open(`/api/dataassetmanager/dataAssetApi/exportByDataAssetIds?dataAssetIds=${selectedKeys.join(',')}`);
window.open(`/api/dataassetmanager/dataAssetApi/exportByDataAssetIds?dataAssetIds=${checkedKeys.join(',')}`);
}
}
......@@ -417,13 +297,13 @@ const AssetTable = (props) => {
}
const deleteAssets = () => {
if ((selectedKeys||[]).length > 0) {
if ((checkedKeys||[]).length > 0) {
modal.confirm({
title: '提示',
content: (nodeType!=='RecycleBin')?'这些资产在所有目录上唯一存在,移除后,你可以前往“未挂载资产”重新挂载。': '您确定要永久删除这些资产吗?',
onOk: () => {
let payload = {
data: selectedKeys
data: checkedKeys
}
if (nodeType !== 'RecycleBin') {
......@@ -438,7 +318,7 @@ const AssetTable = (props) => {
callback: () => {
showMessage("success","删除成功");
getDataAssets();
setSelectedKeys([]);
setCheckedKeys([]);
},
error: () => {
}
......@@ -469,11 +349,11 @@ const AssetTable = (props) => {
}
const onSelectChange = keys => {
setSelectedKeys(keys);
setCheckedKeys(keys);
};
const rowSelection = {
selectedRowKeys: selectedKeys,
selectedRowKeys: checkedKeys,
onChange: onSelectChange,
};
......@@ -499,31 +379,29 @@ const AssetTable = (props) => {
{
(!readOnly&&(nodeType!=='RecycleBin')) && <Button onClick={importAsset}>导入</Button>
}
<Tooltip title={(selectedKeys||[]).length===0?'请先选择资产':''}>
<Button onClick={exportAsset} disabled={(selectedKeys||[]).length===0} >导出</Button>
<Tooltip title={(checkedKeys||[]).length===0?'请先选择资产':''}>
<Button onClick={exportAsset} disabled={(checkedKeys||[]).length===0} >导出</Button>
</Tooltip>
<Tooltip title={(selectedKeys||[]).length===0?'请先选择资产':''}>
<Button onClick={onBatchCatalogChangeBtnClick} disabled={(selectedKeys||[]).length===0} >变更目录</Button>
<Tooltip title={(checkedKeys||[]).length===0?'请先选择资产':''}>
<Button onClick={onBatchCatalogChangeBtnClick} disabled={(checkedKeys||[]).length===0} >变更目录</Button>
</Tooltip>
<Tooltip title={(selectedKeys||[]).length===0?'请先选择资产':''}>
<Button onClick={deleteAssets} disabled={(selectedKeys||[]).length===0} >删除</Button>
<Tooltip title={(checkedKeys||[]).length===0?'请先选择资产':''}>
<Button onClick={deleteAssets} disabled={(checkedKeys||[]).length===0} >删除</Button>
</Tooltip>
<Button onClick={onFilterElementClick}>要素设置</Button>
{
(nodeType==='RecycleBin') && <Tooltip title={(selectedKeys||[]).length===0?'请先选择资产':''}>
<Button onClick={onBatchCatalogChangeBtnClick} disabled={(selectedKeys||[]).length===0}>挂载</Button>
(nodeType==='RecycleBin') && <Tooltip title={(checkedKeys||[]).length===0?'请先选择资产':''}>
<Button onClick={onBatchCatalogChangeBtnClick} disabled={(checkedKeys||[]).length===0}>挂载</Button>
</Tooltip>
}
</Space>
<Space>
<Input
placeholder="请输入资产要素值"
allowClear
value={keyword}
onChange={onSearchInputChange}
style={{ width: inputWidth, marginLeft: 'auto' }}
/>
</Space>
<Input
placeholder="请输入资产要素值"
allowClear
value={keyword}
onChange={onSearchInputChange}
style={{ width: inputWidth }}
/>
</div>
<div
style={{
......@@ -535,10 +413,14 @@ const AssetTable = (props) => {
onRow={(record) => {
return {
id: `data-asset-${record?.id}`,
onClick: (e) => {
setSelectKey(record?.id);
onSelect && onSelect(record?.id);
}
}
}}
rowClassName={(record, index) => {
if (record?.id===anchorId) {
if (record?.id===anchorId || record?.id===selectKey) {
return 'highlight-row';
}
......@@ -582,7 +464,7 @@ const AssetTable = (props) => {
<AssetMount
visible={ assetMountVisible }
nodeType={nodeType}
ids={ batchCatalogChange?selectedKeys:[currentAssetId] }
ids={ batchCatalogChange?checkedKeys:[currentAssetId] }
onCancel={ onAssetMountCancel }
{...props}
/>
......
......@@ -2,10 +2,11 @@ import React, { useState } from 'react';
import classNames from 'classnames';
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons';
import AssetTable from './Component/AssetTable';
import AssetTree from './Component/AssetTree';
import ElementManage from './Component/ElementManage';
import AssetDirectory from './Component/AssetDirectory';
import AssetTree from './Component/AssetTree';
import AssetTable from './Component/AssetTable';
import AssetAction from './Component/AssetAction';
import './index.less';
......@@ -13,6 +14,7 @@ const AssetManage = (props) => {
const [ nodeId, setNodeId ] = useState('');
const [ nodeType, setNodeType ] = useState('');
const [ assetId, setAssetId ] = useState('');
const [ expandTree, setExpandTree ] = useState(true);
const onTreeSelect = (value, type) => {
......@@ -21,6 +23,10 @@ const AssetManage = (props) => {
setNodeType(type);
}
const onTableSelect = (value) => {
setAssetId(value);
}
const treeToggleClick = () => {
setExpandTree(!expandTree);
}
......@@ -39,10 +45,13 @@ const AssetManage = (props) => {
{ expandTree ? <CaretLeftOutlined /> : <CaretRightOutlined /> }
</div>
</div>
<div className='right'>
<div className='middle'>
<ElementManage />
<AssetDirectory id={nodeId} />
<AssetTable nodeId={nodeId} nodeType={nodeType} {...props} />
<AssetTable nodeId={nodeId} nodeType={nodeType} onSelect={onTableSelect} {...props} />
</div>
<div className='right'>
<AssetAction id={assetId} dirId={nodeId} action='detail' />
</div>
</div>
)
......
......@@ -32,8 +32,13 @@
}
}
.middle {
width: calc(100% - 250px - 400px);
}
.right {
width: calc(100% - 250px);
width: 400px;
border-left: 1px solid #EFEFEF;
}
}
......@@ -42,7 +47,7 @@
width: 0;
}
.right {
width: calc(100% - 20px);
.middle {
width: calc(100% - 20px - 400px);
}
}
\ No newline at end of file
export const requireElements = ['中文名称', '资产项', '使用方', '信息安全等级'];
export const unfoldedElements = ['编号', '中文名称', '英文名称', '描述', '表现形式', '数据类型', '来源系统', '资产项', '使用方', '标签', '共享级别', '信息安全等级', '来源单位', '状态', '所属部门', '维护方', '所属层次', '更新频度', '数据规模', '数据大小', '质量情况'];
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment