Commit 6eab010a by zhaochengxiang

移植迈瑞资产多模版

parent 2cd87653
...@@ -12,10 +12,14 @@ module.exports = { ...@@ -12,10 +12,14 @@ module.exports = {
'@ant-prefix': 'yy', '@ant-prefix': 'yy',
// '@border-color-split': 'hsv(0, 0, 85%)', // '@border-color-split': 'hsv(0, 0, 85%)',
'@border-radius-base': '4px', '@border-radius-base': '4px',
'@primary-color': '#196AD2', '@primary-color': '#ffbc00',
'@success-color': '#8FC31F', '@success-color': '#8FC31F',
'@warning-color': '#F7AB00', '@warning-color': '#F7AB00',
'@error-color': '#E94848', '@error-color': '#db0007',
'@menu-dark-bg': '#00477F',
'@menu-dark-submenu-bg': '#013D6C',
'@menu-dark-inline-submenu-bg': '#013D6C',
'@layout-header-background': '#00477F',
}, },
javascriptEnabled: true, javascriptEnabled: true,
}, },
......
...@@ -75,6 +75,6 @@ ...@@ -75,6 +75,6 @@
"last 1 safari version" "last 1 safari version"
] ]
}, },
"proxy": "http://139.198.127.28:17277", "proxy": "http://139.198.126.96:8089",
"homepage": "http://myhost/data-govern" "homepage": "http://myhost/data-govern"
} }
...@@ -4,7 +4,7 @@ import { ...@@ -4,7 +4,7 @@ import {
Route, Switch Route, Switch
} from 'react-router-dom'; } from 'react-router-dom';
import { $hostParams, ContextPath } from './util'; import { $hostParams, ContextPath, generateUUID } from './util';
import Signin from './view/Signin'; import Signin from './view/Signin';
import Home from './view/Home'; import Home from './view/Home';
import Manage from './view/Manage'; import Manage from './view/Manage';
...@@ -32,6 +32,8 @@ import { AssetMountReference } from './util/constant'; ...@@ -32,6 +32,8 @@ import { AssetMountReference } from './util/constant';
export const AppContext = React.createContext(); export const AppContext = React.createContext();
export const appId = generateUUID();
export class App extends React.Component { export class App extends React.Component {
constructor() { constructor() {
super(); super();
......
import { GetJSON } from "../util/axios" import { GetJSON, PostJSON, callFetchRaw, PostFile } from "../util/axios"
export function queryDatabase(payload) { export function queryDatabase(payload) {
return GetJSON("/metadatarepo/rest/tag/getDatabaseBySystemCode", payload); return GetJSON("/metadatarepo/rest/tag/getDatabaseBySystemCode", payload);
...@@ -15,3 +15,27 @@ export function queryAllDataTable(payload) { ...@@ -15,3 +15,27 @@ export function queryAllDataTable(payload) {
export function queryAllFields(payload) { export function queryAllFields(payload) {
return GetJSON("/metadatarepo/rest/metadata/getChild", payload); return GetJSON("/metadatarepo/rest/metadata/getChild", payload);
} }
export function getSystemAllGraph(payload) {
return GetJSON("/metadatarelation/getSystemAllGraph", payload);
}
export function getAttributes(payload) {
return PostJSON("/metadatarepo/rest/metadata/getByIdList", payload);
}
export function exportAttributes(payload) {
return callFetchRaw('post', '/metadatarepo/rest/download/exportAssetInfo', payload)
}
export function importAttributes(payload) {
return PostFile("/metadatarepo/rest/import/importAssetInf", payload);
}
export function listImportAssetLog(payload) {
return GetJSON('/metadatarepo/rest/import/listImportAssertLog', payload);
}
export function getImportAssetLogDetail(payload) {
return GetJSON('/metadatarepo/rest/import/getImportAssertLog', payload);
}
\ No newline at end of file
import axios from 'axios'; import axios from 'axios';
import LocalStorage from 'local-storage'; import LocalStorage from 'local-storage';
import { appId } from '../App';
import { IsArr, showMessage, isSzseEnv } from './index'; import { IsArr, showMessage, isSzseEnv } from './index';
...@@ -101,12 +102,16 @@ const callback = resp => { ...@@ -101,12 +102,16 @@ const callback = resp => {
return resp.data || resp; return resp.data || resp;
} }
export function getTemplateType() {
return LocalStorage.get(`templateType-${appId}`)
}
export function Get(url, params) { export function Get(url, params) {
const cancelToken = __source ? __source.token : null; const cancelToken = __source ? __source.token : null;
const env = LocalStorage.get('assetsEnv')??debugEnv; const env = LocalStorage.get('assetsEnv')??debugEnv;
return textplain.get(url, { return textplain.get(url, {
params: {...params, env}, cancelToken params: {...params, env, templateType: getTemplateType()}, cancelToken
}).then( }).then(
callback callback
) )
...@@ -117,7 +122,7 @@ export function GetJSON(url, params) { ...@@ -117,7 +122,7 @@ export function GetJSON(url, params) {
const env = LocalStorage.get('assetsEnv')??debugEnv; const env = LocalStorage.get('assetsEnv')??debugEnv;
return instance.get(url, { return instance.get(url, {
params: {...params, env}, cancelToken, params: {...params, env, templateType: getTemplateType()}, cancelToken,
validateStatus: false validateStatus: false
}).then( }).then(
callback callback
...@@ -129,7 +134,7 @@ export function Delete(url, params) { ...@@ -129,7 +134,7 @@ export function Delete(url, params) {
const env = LocalStorage.get('assetsEnv')??debugEnv; const env = LocalStorage.get('assetsEnv')??debugEnv;
return instance.delete(url, { return instance.delete(url, {
params: {...params, env}, cancelToken, params: {...params, env, templateType: getTemplateType()}, cancelToken,
}).then( }).then(
callback callback
) )
...@@ -141,11 +146,11 @@ export function PostJSON(url, payload) { ...@@ -141,11 +146,11 @@ export function PostJSON(url, payload) {
const env = LocalStorage.get('assetsEnv')??debugEnv; const env = LocalStorage.get('assetsEnv')??debugEnv;
return IsArr(data) ? instance.post(url, data, { return IsArr(data) ? instance.post(url, data, {
params: {...params, env}, cancelToken params: {...params, env, templateType: getTemplateType()}, cancelToken
}).then( }).then(
callback callback
) : instance.post(url, null, { ) : instance.post(url, null, {
params: {...params, env}, data, cancelToken params: {...params, env, templateType: getTemplateType()}, data, cancelToken
}).then( }).then(
callback callback
) )
...@@ -157,7 +162,7 @@ export function Post(url, payload) { ...@@ -157,7 +162,7 @@ export function Post(url, payload) {
const env = LocalStorage.get('assetsEnv')??debugEnv; const env = LocalStorage.get('assetsEnv')??debugEnv;
return textplain.post(url, null, { return textplain.post(url, null, {
params: {...params, env}, data, cancelToken params: {...params, env, templateType: getTemplateType()}, data, cancelToken
}).then( }).then(
callback callback
) )
...@@ -172,7 +177,7 @@ export function PostFile(url, payload, fileName='file') { ...@@ -172,7 +177,7 @@ export function PostFile(url, payload, fileName='file') {
formData.append(fileName, file); formData.append(fileName, file);
}); });
return fileplain.post(url, formData, { params: {...params, env} } ).then( return fileplain.post(url, formData, { params: {...params, env, templateType: getTemplateType()} } ).then(
callback callback
) )
} }
...@@ -191,6 +196,7 @@ export const callFetchRaw = (method, url, options) => { ...@@ -191,6 +196,7 @@ export const callFetchRaw = (method, url, options) => {
Object.keys(params||[]).forEach(key => { Object.keys(params||[]).forEach(key => {
bodyFormData.append(key, params[key]); bodyFormData.append(key, params[key]);
}); });
bodyFormData.append('templateType', getTemplateType());
return axios.request({ return axios.request({
method, method,
......
import { AxiosResponse } from "axios"
export default function (res: AxiosResponse<any>) {
const blob = res.data
const headers = res.headers
let tempName = headers["content-disposition"]
?.split(";")?.[1]
?.split("filename=")?.[1];
tempName = decodeURI(tempName);
// const blob = new Blob([content], { type: 'application/octet-stream' })
var url = (window.URL && window.URL.createObjectURL) ? window.URL.createObjectURL(blob) : window.webkitURL.createObjectURL(blob);
const link = document.createElement('a');
link.style.display = 'none';
link.href = url;
link.setAttribute('download', tempName); //or any other extension
document.body.appendChild(link);
link.click();
URL.revokeObjectURL(link.href) // 释放URL 对象
document.body.removeChild(link)
}
\ No newline at end of file
import { useEffect, useState, useContext } from 'react'; import { useEffect, useState } from 'react';
import { Radio } from 'antd'; import { Radio } from 'antd';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import Relation from './Relation'; import Relation from './Relation';
import Thermodynamic from './Thermodynamic'; import Thermodynamic from './Thermodynamic';
import { AssetBrowseReference, ResourceBrowseReference } from '../../../../util/constant'; import { AssetBrowseReference, ResourceBrowseReference } from '../../../../util/constant';
import { AppContext } from '../../../../App';
const relationTypes = [ const relationTypes = [
{ {
...@@ -15,6 +14,10 @@ const relationTypes = [ ...@@ -15,6 +14,10 @@ const relationTypes = [
{ {
title: '热力图', title: '热力图',
key: 'thermodynamic' key: 'thermodynamic'
},
{
title: '数据地图',
key: 'map',
} }
] ]
...@@ -22,8 +25,6 @@ const RelationContainer = (props) => { ...@@ -22,8 +25,6 @@ const RelationContainer = (props) => {
const { nodeParams, onChange, reference, resize } = props; const { nodeParams, onChange, reference, resize } = props;
const { env } = useContext(AppContext);
const [ type, setType ] = useState('relation'); const [ type, setType ] = useState('relation');
const [ dirs, setDirs ] = useState([]); const [ dirs, setDirs ] = useState([]);
const [ nodes, setNodes ] = useState([]); const [ nodes, setNodes ] = useState([]);
...@@ -33,7 +34,7 @@ const RelationContainer = (props) => { ...@@ -33,7 +34,7 @@ const RelationContainer = (props) => {
useEffect(() => { useEffect(() => {
getDirectoryData(); getDirectoryData();
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
}, [ env ]) }, [])
useEffect(() => { useEffect(() => {
if (type === 'relation') { if (type === 'relation') {
...@@ -45,7 +46,7 @@ const RelationContainer = (props) => { ...@@ -45,7 +46,7 @@ const RelationContainer = (props) => {
setRelationData(null); setRelationData(null);
} }
} else { } else {
if ((nodeParams?.centerId||'')!== '' && (dirs||[]).length>0) { if ((nodeParams?.centerId||'')!=='' && (dirs||[]).length>0) {
generateThermodynamicData(); generateThermodynamicData();
} else { } else {
setThermodynamicData(null); setThermodynamicData(null);
...@@ -184,8 +185,10 @@ const RelationContainer = (props) => { ...@@ -184,8 +185,10 @@ const RelationContainer = (props) => {
let nodeLevelId = `${node.levelId}-`; let nodeLevelId = `${node.levelId}-`;
let currentLevelId = `${currentNode.levelId}-`; let currentLevelId = `${currentNode.levelId}-`;
if (currentNode.levelId.split('-').length > 1) {
if ((node.levelId.split('-').length===currentNode.levelId.split('-').length+1) && node.levelId.slice(0, currentLevelId.length)===currentLevelId) { if ((node.levelId.split('-').length===currentNode.levelId.split('-').length+1) && node.levelId.slice(0, currentLevelId.length)===currentLevelId) {
node.show = true; node.show = !node.show;
}
} }
if (node.levelId.split('-').length >2) { if (node.levelId.split('-').length >2) {
...@@ -201,6 +204,7 @@ const RelationContainer = (props) => { ...@@ -201,6 +204,7 @@ const RelationContainer = (props) => {
} }
}) })
console.log('data', data)
setNodes(data); setNodes(data);
generateCenterNodeRelationData(data); generateCenterNodeRelationData(data);
...@@ -261,8 +265,12 @@ const RelationContainer = (props) => { ...@@ -261,8 +265,12 @@ const RelationContainer = (props) => {
} }
const onTypeChange = (e) => { const onTypeChange = (e) => {
if (e.target.value === 'map') {
window?.open('/center-home/menu/asset-map');
} else {
setType(e.target.value); setType(e.target.value);
} }
}
return ( return (
<div style={{ width: '100%', height: '100%', position: 'relative' }}> <div style={{ width: '100%', height: '100%', position: 'relative' }}>
......
import React from 'react'; import React from 'react';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { dispatch } from '../../../../model'
//https://echarts.apache.org/examples/zh/editor.html?c=treemap-show-parent&lang=js //https://echarts.apache.org/examples/zh/editor.html?c=treemap-show-parent&lang=js
class Thermodynamic extends React.Component { class Thermodynamic extends React.Component {
componentDidMount() { componentDidMount() {
const { data, onClick } = this.props; const { data, onClick } = this.props;
if (data) {
if (data && data.length>0 && (data[0].children||[]).length>0) {
this.graph = init(this)(this.elem, data, onClick); this.graph = init(this)(this.elem, data, onClick);
this.getScore();
} }
} }
...@@ -17,37 +16,20 @@ class Thermodynamic extends React.Component { ...@@ -17,37 +16,20 @@ class Thermodynamic extends React.Component {
const { data, onClick, resize } = this.props; const { data, onClick, resize } = this.props;
if (data !== prevProps.data) { if (data !== prevProps.data) {
this.graph?.dispose();
this.graph = init(this)(this.elem, data, onClick); this.graph = init(this)(this.elem, data, onClick);
this.getScore();
} else if (resize !== prevProps.resize) { } else if (resize !== prevProps.resize) {
this.graph?.resize(); this.graph?.resize();
} }
} }
getScore() {
const { data } = this.props;
dispatch({
type: 'assetmanage.getScore',
payload: {
dirId: (data?.length>0) ? data[0]?.nodeId: ''
},
callback: newScore => {
this.graph?.setOption({
title: {
subtext: `价值评分 ${newScore}`,
itemGap: 2,
}
})
}
})
}
elem = undefined; elem = undefined;
graph = undefined; graph = undefined;
render() { render() {
return ( return (
<div ref={ref => this.elem = ref} style={{ position: 'relative', width: '100%', height: '100%' }}></div> <div ref={ref => this.elem = ref} style={{ position: 'relative', width: '100%', height: '100%' }}>
</div>
); );
} }
} }
...@@ -61,7 +43,7 @@ const init = (ctx) => function (container, data, onClick) { ...@@ -61,7 +43,7 @@ const init = (ctx) => function (container, data, onClick) {
return [ return [
{ {
itemStyle: { itemStyle: {
borderColor: '#777', borderColor: ((data||[]).length>0)&&(data[0].dataAssetAndSubDirCount===0||(data[0].children||[]).reduce((preVal, item) => item?.dataAssetAndSubDirCount + preVal, 0)===0) ? '#97aeed' : '#777',
borderWidth: 0, borderWidth: 0,
gapWidth: 1 gapWidth: 1
}, },
...@@ -96,9 +78,9 @@ const init = (ctx) => function (container, data, onClick) { ...@@ -96,9 +78,9 @@ const init = (ctx) => function (container, data, onClick) {
title: { title: {
text: ((data||[]).length>0) ? `${data[0]?.text||''} (${data[0]?.dataAssetAndSubDirCount})` : '', text: ((data||[]).length>0) ? `${data[0]?.text||''} (${data[0]?.dataAssetAndSubDirCount})` : '',
left: 'center', left: 'center',
bottom: 0, bottom: 10,
textStyle: { textStyle: {
fontSize: 14 fontSize: 16
} }
}, },
tooltip: { tooltip: {
...@@ -117,20 +99,22 @@ const init = (ctx) => function (container, data, onClick) { ...@@ -117,20 +99,22 @@ const init = (ctx) => function (container, data, onClick) {
}, },
series: [ series: [
{ {
name: ((data||[]).length>0) ? `${data[0]?.text||''} (${data[0]?.dataAssetAndSubDirCount})` : '',
type: 'treemap', type: 'treemap',
height: '85%', height: '85%',
visibleMin: 0, visibleMin: 1,
childrenVisibleMin: 0, childrenVisibleMin: 1,
label: { label: {
show: true, show: true,
formatter: '{b}' formatter: '{b}'
}, },
upperLabel: { upperLabel: {
show: true, show: true,
height: 30 height: 30,
color: '#fff',
}, },
itemStyle: { itemStyle: {
borderColor: '#fff' borderColor: '#555'
}, },
breadcrumb: { breadcrumb: {
show: false, show: false,
...@@ -144,7 +128,6 @@ const init = (ctx) => function (container, data, onClick) { ...@@ -144,7 +128,6 @@ const init = (ctx) => function (container, data, onClick) {
myChart.setOption(option); myChart.setOption(option);
myChart.on('click', function (params) { myChart.on('click', function (params) {
console.log(params);
const { data } = params; const { data } = params;
if (onClick && data && data.nodeId) { if (onClick && data && data.nodeId) {
......
import React, { useState } from 'react'; import React, { useState } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons'; import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons';
import { ResizableBox } from 'react-resizable';
import AssetTree from '../AssetManage/Component/AssetTree'; import AssetTree from '../AssetManage/Component/AssetTree';
import AssetDirectory from '../AssetManage/Component/AssetDirectory'; import AssetDirectory from '../AssetManage/Component/AssetDirectory';
...@@ -16,16 +17,17 @@ const AssetBrowse = (props) => { ...@@ -16,16 +17,17 @@ const AssetBrowse = (props) => {
const { reference = AssetBrowseReference } = props; const { reference = AssetBrowseReference } = props;
const [ nodeParams, setNodeParams ] = useState({ centerId: '', expandId: '' }); const [ nodeParams, setNodeParams ] = useState({ centerId: null, expandId: '', nodeType: '' });
const [ expandTree, setExpandTree ] = useState(true); const [ expandTree, setExpandTree ] = useState(true);
const [ expandRelation, setExpandRelation ] = useState(true); const [ expandRelation, setExpandRelation ] = useState(true);
const [ assetCount, setAssetCount ] = useState(0); const [ assetCount, setAssetCount ] = useState(0);
const [ resizeRelation, setResizeRelation ] = useState(false); const [ resizeRelation, setResizeRelation ] = useState(false);
const [ assetFullScreen, setAssetFullScreen ] = useState(false);
const { centerId, expandId } = nodeParams; const { centerId, expandId } = nodeParams;
const onTreeSelect = (value, type) => { const onTreeSelect = (value, type) => {
setNodeParams({ centerId: value||'', expandId: '' }); setNodeParams({ centerId: value, expandId: '', nodeType: type });
} }
const treeToggleClick = () => { const treeToggleClick = () => {
...@@ -46,11 +48,8 @@ const AssetBrowse = (props) => { ...@@ -46,11 +48,8 @@ const AssetBrowse = (props) => {
setAssetCount(count); setAssetCount(count);
} }
let nodeId = ''; const onFullScreenChange = (value) => {
if ((expandId||'') !== '') { setAssetFullScreen(value);
nodeId = expandId;
} else {
nodeId = centerId;
} }
const classes = classNames('asset-browse', { const classes = classNames('asset-browse', {
...@@ -58,36 +57,46 @@ const AssetBrowse = (props) => { ...@@ -58,36 +57,46 @@ const AssetBrowse = (props) => {
'asset-browse-relation-collapse': !expandRelation, 'asset-browse-relation-collapse': !expandRelation,
}); });
const rightClasses = classNames('right', {
'right-fullscreen': assetFullScreen
});
return ( return (
<div className={classes}> <div className={classes}>
<div className='left'> <ResizableBox
className='left'
width={230}
height={Infinity}
axis='x'
minConstraints={[230, Infinity]} maxConstraints={[Infinity, Infinity]}
>
<AssetTree centerId={centerId} onSelect={onTreeSelect} reference={reference} {...props} /> <AssetTree centerId={centerId} onSelect={onTreeSelect} reference={reference} {...props} />
</div> </ResizableBox>
{ {
expandTree && <Separate width={15} /> expandTree && <Separate width={15} />
} }
<div className='right'> <div className={rightClasses}>
<AssetDirectory id={nodeId} assetCount={assetCount} reference={reference} /> {/* <AssetDirectory id={centerId} assetCount={assetCount} reference={reference} nodeType={nodeParams.nodeType} />
<Separate height={15} /> <Separate height={15} /> */}
<div className='flex' style={{ flex: 1, height: '100%', overflow: 'hidden' }}> <div className='flex' style={{ flex: 1, height: '100%', overflow: 'hidden' }}>
{ {
expandRelation && <React.Fragment> // expandRelation && <React.Fragment>
<div style={{ flex: 1, height: '100%', overflow: 'hidden' }}> // <div style={{ flex: 1, height: '100%', overflow: 'hidden' }}>
<RelationContainer reference={reference} nodeParams={nodeParams} onChange={onRelationChange} resize={resizeRelation} /> // <RelationContainer reference={reference} nodeParams={nodeParams} onChange={onRelationChange} resize={resizeRelation} />
</div> // </div>
<Separate width={15} /> // <Separate width={15} />
</React.Fragment> // </React.Fragment>
} }
<div style={{ flex: 1, overflow: 'hidden' }}> <div style={{ flex: 1, overflow: 'hidden' }}>
<AssetTable nodeId={nodeId} reference={reference} onCountChange={onAssetCountChange} {...props} /> <AssetTable nodeId={centerId} nodeType={nodeParams.nodeType} reference={reference} onCountChange={onAssetCountChange} onFullScreenChange={onFullScreenChange} {...props} />
</div>
</div> </div>
</div> </div>
<div className='tree-toggle' onClick={treeToggleClick}> <div className='tree-toggle' onClick={treeToggleClick}>
{ expandTree ? <CaretLeftOutlined /> : <CaretRightOutlined /> } { expandTree ? <CaretLeftOutlined /> : <CaretRightOutlined /> }
</div> </div>
<div className='relation-toggle' onClick={relationToggleClick}> {/* <div className='relation-toggle' onClick={relationToggleClick}>
{ expandRelation ? <CaretLeftOutlined /> : <CaretRightOutlined /> } { expandRelation ? <CaretLeftOutlined /> : <CaretRightOutlined /> }
</div> */}
</div> </div>
</div> </div>
) )
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
height: 100%; height: 100%;
.left { .left {
width: 230px; flex: 0 0 auto;
border-right: 1px solid #EFEFEF; border-right: 1px solid #EFEFEF;
overflow: hidden; overflow: hidden;
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
right: 0; right: 0;
background: #f2f5fc; background: #f2f5fc;
position: absolute; position: absolute;
left: 245px; left: 0px;
top: calc(50% - 40px); top: calc(50% - 40px);
width: 12px; width: 12px;
height: 80px; height: 80px;
...@@ -29,18 +29,24 @@ ...@@ -29,18 +29,24 @@
} }
.right { .right {
position: relative;
display: flex; display: flex;
width: calc(100% - 245px); flex: 1;
overflow: hidden;
flex-direction: column; flex-direction: column;
} }
.right-fullscreen {
position: static;
}
.relation-toggle { .relation-toggle {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background: #f2f5fc; background: #f2f5fc;
position: absolute; position: absolute;
left: calc(50% + 130px); left: calc(50% + 7.5px);
top: calc(50% - 40px); top: calc(50% - 40px);
width: 12px; width: 12px;
height: 80px; height: 80px;
...@@ -52,24 +58,20 @@ ...@@ -52,24 +58,20 @@
&.asset-browse-relation-collapse { &.asset-browse-relation-collapse {
.relation-toggle { .relation-toggle {
left: 245px; left: 0px;
} }
} }
} }
.asset-browse-tree-collapse { .asset-browse-tree-collapse {
.left { .left {
width: 0; width: 0 !important;
} }
.tree-toggle { .tree-toggle {
left: 0; left: 0;
} }
.right {
width: 100%;
}
.relation-toggle { .relation-toggle {
left: calc(50% + 7.5px); left: calc(50% + 7.5px);
} }
......
...@@ -45,6 +45,16 @@ const AddAssetModel = (props) => { ...@@ -45,6 +45,16 @@ const AddAssetModel = (props) => {
setConfirmLoading(true); setConfirmLoading(true);
dispatch({ dispatch({
type: 'assetmanage.checkCodeIsExist',
payload: {
data: { elements: newElements }
},
callback: isExist => {
if (isExist === 'true') {
setConfirmLoading(false);
showMessage('warn', '已存在相同的资产目录编号,请重新输入');
} else {
dispatch({
type: 'assetmanage.addOrUpdateDataAsset', type: 'assetmanage.addOrUpdateDataAsset',
payload: { payload: {
params, params,
...@@ -59,6 +69,12 @@ const AddAssetModel = (props) => { ...@@ -59,6 +69,12 @@ const AddAssetModel = (props) => {
setConfirmLoading(false); setConfirmLoading(false);
} }
}) })
}
},
error: () => {
setConfirmLoading(false);
}
})
} catch (errInfo) { } catch (errInfo) {
console.log('Validate Failed:', errInfo); console.log('Validate Failed:', errInfo);
...@@ -70,7 +86,7 @@ const AddAssetModel = (props) => { ...@@ -70,7 +86,7 @@ const AddAssetModel = (props) => {
<Modal <Modal
forceRender forceRender
className='asset-add' className='asset-add'
title='新增资产信息' title='新增资产目录信息'
visible={ visible } visible={ visible }
width={ 600 } width={ 600 }
onCancel={() => { onCancel && onCancel(); } } onCancel={() => { onCancel && onCancel(); } }
......
.asset-action {
.yy-table-tbody > tr > td {
padding: 8px 8px !important;
}
}
\ No newline at end of file
import { useState } from "react";
import { Modal, Radio, Popover } from "antd";
import { QuestionCircleOutlined } from '@ant-design/icons';
const AssetDeleteModal = (props) => {
const { visible, onCancel, onDelete, onDeleteAll } = props;
const [ value, setValue ] = useState(1);
const onChange = (e) => {
setValue(e.target.value);
};
return (
<Modal
title="删除资产目录"
visible={visible}
width={530}
onCancel={
() => {
onCancel && onCancel();
}
}
onOk={
() => {
if (value === 1) {
onDelete && onDelete();
} else {
onDeleteAll && onDeleteAll();
}
}
}
>
<Radio.Group onChange={onChange} value={value}>
<Radio value={1}>
<span>删除本目录下的资产目录</span>
&nbsp;
<Popover content={
<span>
当要删除的资产目录,只存在一个目录时,删除该资产目录并且设置为未分类资产目录;<br/>
存在多个目录时,只删除该目录下的这项资产目录,不会设置为未分类资产目录
</span>
}
>
<QuestionCircleOutlined className='pointer' />
</Popover>
</Radio>
<Radio value={2}>
<span>删除该资产目录(所有目录下的资产目录均删除)</span>
&nbsp;
<Popover content='该资产目录所在的目录内,均删除该项资产目录,并设置为未分类资产目录' >
<QuestionCircleOutlined className='pointer' />
</Popover>
</Radio>
</Radio.Group>
</Modal>
);
}
export default AssetDeleteModal;
\ No newline at end of file
...@@ -4,33 +4,70 @@ import { Spin, Descriptions, Divider } from "antd"; ...@@ -4,33 +4,70 @@ import { Spin, Descriptions, Divider } from "antd";
import MetadataInfo from './MetadataInfo'; import MetadataInfo from './MetadataInfo';
import { highlightSearchContentByTerms } from '../../../../util'; import { highlightSearchContentByTerms } from '../../../../util';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import StandardName from './StandardName'; import IndexCode from './IndexCode';
// import SelectUser from '../../Model/Component/SelectUsers';
const AssetDetail = (props)=>{ const AssetDetail = (props)=>{
const { id, dirId, terms } = props; const { id, dirId, terms, reference = '' } = props;
const [ asset, setAsset ] = useState(''); const [ asset, setAsset ] = useState('');
const [ types, setTypes ] = useState([]); const [ types, setTypes ] = useState([]);
const [ loading, setLoading ] = useState(false); const [ loading, setLoading ] = useState(false);
const [ users, setUsers ] = useState([]);
useEffect(() => { useEffect(() => {
if ((id||'') !== '') { if ((id||'') !== '') {
getAssetThenGetAssetName(); // getUserElements();
getUsers();
getAsset([]);
} }
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
}, [ id ]) }, [ id ])
const getAssetThenGetAssetName = () => { const getUserElements = () => {
setLoading(true);
dispatch({
type: 'assetmanage.listUserElements',
callback: data => {
getAsset(data||[]);
},
error: () => {
setLoading(false);
}
})
}
const getUsers = () => {
dispatch({
type: 'pds.getOwners',
callback: (data) => {
setUsers(data);
}
})
}
const getAsset = (userElements) => {
setLoading(true); setLoading(true);
dispatch({ dispatch({
type: 'assetmanage.getDataAssetDetail', type: 'assetmanage.getDataAssetDetail',
payload: { payload: {
dataAssetId: id, dataAssetId: id,
dirId: dirId||'' dirId: dirId||'',
checkPermission: true
}, },
callback: data => { callback: data => {
setLoading(false); setLoading(false);
// const userElementIds = [];
// (userElements||[]).forEach(element => {
// userElementIds.push(element?.id);
// })
// const filterElements = (data?.elements||[]).filter(element => userElementIds.indexOf(element?.id) !== -1);
// data = { ...data, elements: filterElements }
setAsset(data); setAsset(data);
const _types = []; const _types = [];
...@@ -48,6 +85,26 @@ const AssetDetail = (props)=>{ ...@@ -48,6 +85,26 @@ const AssetDetail = (props)=>{
}) })
} }
const elementItemComponent = (item) => {
if (item.name === '资产项') {
return <MetadataInfo config={false} value={item.value||''} terms={terms} />;
}
if (item.name === '指标标准编码') {
return <IndexCode value={item.value||''} terms={terms} />;
}
// if (item.name==='数据关键用户' || item.name==='业务部门负责人' || item.name?.toLowerCase()==='it责任人' || item.name==='创建人' || item.name==='更新人') {
// return <SelectUser
// type='detail'
// users={users}
// value={item.value||''}
// />
// }
return <span className='text-color'>{highlightSearchContentByTerms(item.value||'', terms)}</span>;
}
return( return(
<Spin spinning={loading}> <Spin spinning={loading}>
{ {
...@@ -67,7 +124,7 @@ const AssetDetail = (props)=>{ ...@@ -67,7 +124,7 @@ const AssetDetail = (props)=>{
return ( return (
<div key={index}> <div key={index}>
<div className='flex' style={{ alignItems: 'center', padding: '15px 0' }}> <div className='flex' style={{ alignItems: 'center', padding: (reference==='full-search'&&index===0)?'0 0 15px':'15px 0' }}>
<div style={{ width: 3, height: 14, backgroundColor: '#0069AC', marginRight: 5 }} /> <div style={{ width: 3, height: 14, backgroundColor: '#0069AC', marginRight: 5 }} />
<span style={{ fontWeight: 'bold', color: '#464646' }}>{type||''}</span> <span style={{ fontWeight: 'bold', color: '#464646' }}>{type||''}</span>
</div> </div>
...@@ -77,15 +134,7 @@ const AssetDetail = (props)=>{ ...@@ -77,15 +134,7 @@ const AssetDetail = (props)=>{
(_currentValues||[]).map((item, index) => { (_currentValues||[]).map((item, index) => {
return ( return (
<Descriptions.Item label={item.name||''} key={index}> <Descriptions.Item label={item.name||''} key={index}>
{ { elementItemComponent(item) }
item.name==='资产项' && <MetadataInfo config={false} value={item.value||''} terms={terms} />
}
{
item.name==='关联标准' && <StandardName value={item.value||''} terms={terms} />
}
{
item.name!=='资产项' && item.name!=='关联标准' && <span className='text-color'>{highlightSearchContentByTerms(item.value||'', terms)}</span>
}
</Descriptions.Item> </Descriptions.Item>
); );
}) })
......
...@@ -4,24 +4,26 @@ import { Drawer, Form } from 'antd'; ...@@ -4,24 +4,26 @@ import { Drawer, Form } from 'antd';
import AssetAction from './AssetAction'; import AssetAction from './AssetAction';
const AssetDetailDrawer = (props) => { const AssetDetailDrawer = (props) => {
const { onCancel, visible, id, dirId } = props; const { onCancel, visible, id, dirId, reference } = props;
const [ form ] = Form.useForm(); const [ form ] = Form.useForm();
return ( return (
<Drawer <Drawer
forceRender
visible={ visible } visible={ visible }
title='资产详情' title='资产目录详情'
width={600} width='80%'
placement="right" placement="right"
closable={ true } closable={ true }
destroyOnClose
onClose={() => { onClose={() => {
onCancel && onCancel(); onCancel && onCancel();
}} }}
> >
{ {
visible && <AssetAction form={form} id={id} dirId={dirId} action='detail' readOnly /> visible && <AssetAction reference={reference} form={form} id={id} dirId={dirId} action='detail' onChange={() => {
onCancel?.(true);
}} />
} }
</Drawer> </Drawer>
) )
......
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import LocalStorage from 'local-storage';
import { Spin } from "antd";
import AssetDetail from './AssetDetail'; import AssetAction from "./AssetAction";
import { getQueryParam } from '../../../../util'; import { getQueryParam } from '../../../../util';
import { dispatch } from '../../../../model';
import './AssetDetailPage.less'; import './AssetDetailPage.less';
import { getDataAssetDetail } from "../../../../service/dataassetmanager";
import { appId } from "../../../../App";
const AssetDetailPage = (props)=>{ const AssetDetailPage = (props)=>{
const [ data, setData ] = useState({ id: '', dirId: '' }); const [ data, setData ] = useState({ id: '', dirId: '' });
const [loading, setLoading] = useState(false)
const [templateType, setTemplateType] = useState()
const { id, dirId } = data; const { id, dirId } = data;
useEffect(() => { useEffect(() => {
...@@ -16,20 +22,48 @@ const AssetDetailPage = (props)=>{ ...@@ -16,20 +22,48 @@ const AssetDetailPage = (props)=>{
const _id = getQueryParam('id', props.location.search); const _id = getQueryParam('id', props.location.search);
const _dirId = getQueryParam('dirId', props.location.search); const _dirId = getQueryParam('dirId', props.location.search);
setData({ id: _id, dirId: _dirId }); setData({ id: _id, dirId: _dirId });
getDataAssetDetail()
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
}, []) }, [])
const getDataAssetDetail = () => {
const _id = getQueryParam('id', props.location.search);
const _dirId = getQueryParam('dirId', props.location.search);
dispatch({
type: 'assetmanage.getDataAssetDetail',
payload: {
dataAssetId: _id,
dirId: _dirId||'',
checkPermission: true
},
callback: data => {
setLoading(false);
LocalStorage.set(`templateType-${appId}`, data?.templateType)
setTemplateType(data?.templateType)
},
error: () => {
setLoading(false);
}
})
}
return( return(
<div className='asset-detail position-relative'> <div className='asset-detail position-relative'>
<div className='detail-header'> <div className='detail-header'>
<span style={{ fontSize: 16, fontWeight: 'bold', color: '#fff' }}>资产详情</span> <span style={{ fontSize: 16, fontWeight: 'bold', color: '#000' }}>资产目录详情</span>
</div> </div>
<Spin spinning={loading}>
<div className='detail-container'> <div className='detail-container'>
<div className='detail-container-card'> <div className='detail-container-card'>
<AssetDetail id={id} dirId={dirId} /> {
templateType && <AssetAction id={id} dirId={dirId} action='detail' />
}
</div> </div>
</div> </div>
</Spin>
</div> </div>
) )
} }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
width: 100%; width: 100%;
height: 44px; height: 44px;
padding: 0 15px; padding: 0 15px;
background-color: #464d6e; background-color: white;
align-items: center; align-items: center;
position: fixed; position: fixed;
justify-content: space-between; justify-content: space-between;
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Spin, Tooltip, Typography, Dropdown, Menu } from 'antd'; import { Spin, Tooltip, Typography, Dropdown, Menu } from 'antd';
import LocalStorage from 'local-storage';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { AssetManageReference, ResourceBrowseReference } from '../../../../util/constant'; import { AssetBrowseReference, AssetManageReference, ResourceBrowseReference } from '../../../../util/constant';
import ImportElement from './ImportElement'; import ImportElement from './ImportElement';
import ExportElement from './ExportElement';
import AttributeRelationModal from "./AttributeRelationModal"; import AttributeRelationModal from "./AttributeRelationModal";
import FilterElementModal from './FilterElementModal'; import FilterElementModal from './FilterElementModal';
import { showNotifaction } from '../../../../util'; import { showNotifaction } from '../../../../util';
...@@ -14,15 +12,15 @@ import Separate from './Separate'; ...@@ -14,15 +12,15 @@ import Separate from './Separate';
import record from '../Assets/record.png'; import record from '../Assets/record.png';
import './AssetDirectory.less'; import './AssetDirectory.less';
import { getTemplateType } from '../../../../util/axios';
const { Paragraph, Text } = Typography; const { Paragraph, Text } = Typography;
const AssetDirectory = (props) => { const AssetDirectory = (props) => {
const { id, directoryChanged, assetCount, reference = AssetManageReference, onElementsChange } = props; const { id, directoryChanged, assetCount, reference = AssetManageReference, onElementsChange, nodeType } = props;
const [ dir, setDir ] = useState(null); const [ dir, setDir ] = useState(null);
const [ loading, setLoading ] = useState(false); const [ loading, setLoading ] = useState(false);
const [ importElementVisible, setImportElementVisible ] = useState(false); const [ importElementVisible, setImportElementVisible ] = useState(false);
const [ exportElementVisible, setExportElementVisible ] = useState(false);
const [ attributeRelationModalVisible, setAttributeRelationModalVisible ] = useState(false); const [ attributeRelationModalVisible, setAttributeRelationModalVisible ] = useState(false);
const [ filterElementVisible, setFilterElementVisible ] = useState(false); const [ filterElementVisible, setFilterElementVisible ] = useState(false);
const [ resourceState, setResourceState ] = useState(null); const [ resourceState, setResourceState ] = useState(null);
...@@ -47,14 +45,21 @@ const AssetDirectory = (props) => { ...@@ -47,14 +45,21 @@ const AssetDirectory = (props) => {
useEffect(() => { useEffect(() => {
if ((id||'')!=='') { if ((id||'')!=='') {
getDirectory(); getDirectory();
} else {
setDir()
} }
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
}, [ id, directoryChanged ]) }, [ id, directoryChanged ])
const getDirectory = () => { const getDirectory = () => {
let url = 'assetmanage.getDirectoryById';
if ((reference===AssetBrowseReference|| reference===ResourceBrowseReference) && nodeType==='custom') {
url = 'assetmanage.getPersonalCustomDirectoryById';
}
setLoading(true); setLoading(true);
dispatch({ dispatch({
type: 'assetmanage.getDirectoryById', type: url,
payload: { payload: {
dirId: id dirId: id
}, },
...@@ -93,7 +98,7 @@ const AssetDirectory = (props) => { ...@@ -93,7 +98,7 @@ const AssetDirectory = (props) => {
} }
const onExportElementBtnClick = () => { const onExportElementBtnClick = () => {
setExportElementVisible(true); window.open(`/api/dataassetmanager/elementApi/export?templateType=${getTemplateType()}`);
} }
const onFilterElementClick = () => { const onFilterElementClick = () => {
...@@ -116,10 +121,6 @@ const AssetDirectory = (props) => { ...@@ -116,10 +121,6 @@ const AssetDirectory = (props) => {
} }
} }
const onExportElementCancel = () => {
setExportElementVisible(false);
}
const onFilterElementModalCancel = () => { const onFilterElementModalCancel = () => {
setFilterElementVisible(false); setFilterElementVisible(false);
} }
...@@ -132,22 +133,22 @@ const AssetDirectory = (props) => { ...@@ -132,22 +133,22 @@ const AssetDirectory = (props) => {
<Menu> <Menu>
<Menu.Item> <Menu.Item>
<div className='text-center' onClick={onImportElementBtnClick}> <div className='text-center' onClick={onImportElementBtnClick}>
导入资产属性 导入资产目录属性
</div> </div>
</Menu.Item> </Menu.Item>
<Menu.Item> <Menu.Item>
<div className='text-center' onClick={onExportElementBtnClick}> <div className='text-center' onClick={onExportElementBtnClick}>
导出资产属性 导出资产目录属性
</div> </div>
</Menu.Item> </Menu.Item>
<Menu.Item> <Menu.Item>
<div className='text-center' onClick={onFilterElementClick}> <div className='text-center' onClick={onFilterElementClick}>
资产属性管理 资产目录浏览管理
</div> </div>
</Menu.Item> </Menu.Item>
<Menu.Item> <Menu.Item>
<div className='text-center' onClick={onAttributeRelationBtnClick}> <div className='text-center' onClick={onAttributeRelationBtnClick}>
资产属性关联 资产目录属性关联
</div> </div>
</Menu.Item> </Menu.Item>
</Menu> </Menu>
...@@ -185,7 +186,7 @@ const AssetDirectory = (props) => { ...@@ -185,7 +186,7 @@ const AssetDirectory = (props) => {
</Tooltip> </Tooltip>
</Paragraph> </Paragraph>
</div> </div>
<div className={(reference===AssetManageReference || reference===ResourceBrowseReference)?'mb-common':''}> <div className={(reference===AssetManageReference)?'mb-common':''}>
<Paragraph> <Paragraph>
<Tooltip title={dir?.desc||''}> <Tooltip title={dir?.desc||''}>
<Text className='title-color' ellipsis={true}> <Text className='title-color' ellipsis={true}>
...@@ -196,9 +197,7 @@ const AssetDirectory = (props) => { ...@@ -196,9 +197,7 @@ const AssetDirectory = (props) => {
</Paragraph> </Paragraph>
</div> </div>
{ {
(reference===AssetManageReference || reference===ResourceBrowseReference) && <div className='flex'> (reference===AssetManageReference) && <div className='flex'>
{
(reference === AssetManageReference) && <React.Fragment>
<Paragraph style={{ flex: 1, overflow: 'hidden' }}> <Paragraph style={{ flex: 1, overflow: 'hidden' }}>
<Tooltip title={dir?.remarks||''}> <Tooltip title={dir?.remarks||''}>
<Text className='title-color' ellipsis={true}> <Text className='title-color' ellipsis={true}>
...@@ -208,10 +207,8 @@ const AssetDirectory = (props) => { ...@@ -208,10 +207,8 @@ const AssetDirectory = (props) => {
</Tooltip> </Tooltip>
</Paragraph> </Paragraph>
<Separate width={10} background='#fff' /> <Separate width={10} background='#fff' />
</React.Fragment> {/* {
} resourceState && <React.Fragment>
{
(reference===ResourceBrowseReference || resourceState) && <React.Fragment>
<Paragraph style={{ flex: 1, overflow: 'hidden' }}> <Paragraph style={{ flex: 1, overflow: 'hidden' }}>
<Tooltip title={resourceState?.relatedAsset}> <Tooltip title={resourceState?.relatedAsset}>
<Text className='title-color' ellipsis={true}> <Text className='title-color' ellipsis={true}>
...@@ -239,7 +236,7 @@ const AssetDirectory = (props) => { ...@@ -239,7 +236,7 @@ const AssetDirectory = (props) => {
</Tooltip> </Tooltip>
</Paragraph> </Paragraph>
</React.Fragment> </React.Fragment>
} } */}
</div> </div>
} }
</div> </div>
...@@ -266,7 +263,7 @@ const AssetDirectory = (props) => { ...@@ -266,7 +263,7 @@ const AssetDirectory = (props) => {
</div> </div>
</div> </div>
{ {/* {
(reference===AssetManageReference) && <Dropdown overlay={elementManageMenu} placement="bottomCenter"> (reference===AssetManageReference) && <Dropdown overlay={elementManageMenu} placement="bottomCenter">
<div <div
className='flex more-container' className='flex more-container'
...@@ -281,7 +278,7 @@ const AssetDirectory = (props) => { ...@@ -281,7 +278,7 @@ const AssetDirectory = (props) => {
<span style={{ fontSize: 10 }}>更多</span> <span style={{ fontSize: 10 }}>更多</span>
</div> </div>
</Dropdown> </Dropdown>
} } */}
</div> </div>
...@@ -290,11 +287,6 @@ const AssetDirectory = (props) => { ...@@ -290,11 +287,6 @@ const AssetDirectory = (props) => {
onCancel={onImportElementCancel} onCancel={onImportElementCancel}
/> />
<ExportElement
visible={exportElementVisible}
onCancel={onExportElementCancel}
/>
<FilterElementModal <FilterElementModal
visible={ filterElementVisible } visible={ filterElementVisible }
onCancel={ onFilterElementModalCancel} onCancel={ onFilterElementModalCancel}
......
...@@ -2,20 +2,20 @@ ...@@ -2,20 +2,20 @@
.asset-directory { .asset-directory {
// .more-container { .more-container {
// cursor: pointer; cursor: pointer;
// color: @icon-normal-color; color: @icon-normal-color;
// .icon { .icon {
// fill: @icon-normal-color !important; fill: @icon-normal-color !important;
// } }
// &:hover { &:hover {
// color: @icon-hover-color; color: @icon-hover-color;
// .icon { .icon {
// fill: @icon-hover-color !important; fill: @icon-hover-color !important;
// } }
// } }
// } }
} }
\ No newline at end of file
@import '../../../../variables.less';
.asset-manage-tree {
.yy-card-head-title {
padding: 0;
}
.yy-tree{
height: calc(100vh - @header-height - @breadcrumb-height - 25px - 57px - 62px) !important;
overflow: auto !important;
}
// .root {
// display: flex;
// position: relative;
// width: 100%;
// background-color: #e7f2ff;
// margin-bottom: 3px;
// padding: 5px;
// align-items: center;
// .yy-tree-switcher {
// display: block;
// position: absolute;
// opacity: 0 !important;
// left: 0;
// top: 0;
// width: 100%;
// height: 100%;
// }
// .yy-tree-node-content-wrapper {
// margin-left: 20px;
// }
// }
// .yy-tree-indent .yy-tree-indent-unit:first-child {
// opacity: 0 !important;
// }
.site-tree-search-value {
color: #f50;
}
}
.asset-manage-tree-read-only {
.yy-tree {
height: calc(100vh - @header-height - @breadcrumb-height - 25px - 62px) !important;;
overflow: auto !important;
}
}
.asset-manage-tree-asset-mount-reference {
.yy-tree {
height: 400px !important;
overflow: auto !important;
}
}
\ No newline at end of file
...@@ -3,6 +3,7 @@ import { Modal, Form, Input, Space, Button, Select } from 'antd'; ...@@ -3,6 +3,7 @@ import { Modal, Form, Input, Space, Button, Select } from 'antd';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { AppContext } from '../../../../App'; import { AppContext } from '../../../../App';
import MetadataInfo from './MetadataInfo'; import MetadataInfo from './MetadataInfo';
import { showMessage } from '../../../../util';
const { Option } = Select; const { Option } = Select;
...@@ -48,7 +49,7 @@ const DirsSelect = ({ value = [], data = [], onChange, ...restProps }) => { ...@@ -48,7 +49,7 @@ const DirsSelect = ({ value = [], data = [], onChange, ...restProps }) => {
const AssetTagModal = (props) => { const AssetTagModal = (props) => {
const { onCancel, visible, id, keyword, creator } = props; const { onCancel, visible, id, tag, creator } = props;
const [ form ] = Form.useForm(); const [ form ] = Form.useForm();
const [ confirmLoading, setConfirmLoading ] = useState(false); const [ confirmLoading, setConfirmLoading ] = useState(false);
const [ elements, setElements ] = useState([]); const [ elements, setElements ] = useState([]);
...@@ -69,12 +70,12 @@ const AssetTagModal = (props) => { ...@@ -69,12 +70,12 @@ const AssetTagModal = (props) => {
useEffect(() => { useEffect(() => {
if (visible && (keyword||'')!=='') { if (visible && (tag?.name||'')!=='') {
getDirectoryByName(keyword); getDirectoryByName(tag?.name);
} }
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
}, [ visible, keyword ]) }, [ visible ])
const getAsset = () => { const getAsset = () => {
dispatch({ dispatch({
...@@ -140,7 +141,7 @@ const AssetTagModal = (props) => { ...@@ -140,7 +141,7 @@ const AssetTagModal = (props) => {
}); });
const params = { const params = {
dirId: row.tags.join(','), dirId: (row.dirs||[]).join(','),
} }
if ((metadataId||'')!=='') { if ((metadataId||'')!=='') {
...@@ -150,38 +151,38 @@ const AssetTagModal = (props) => { ...@@ -150,38 +151,38 @@ const AssetTagModal = (props) => {
setConfirmLoading(true); setConfirmLoading(true);
dispatch({ dispatch({
type: 'assetmanage.addOrUpdateDataAsset', type: 'assetmanage.checkCodeIsExist',
payload: { payload: {
params,
data: { ...asset, elements: newElements } data: { ...asset, elements: newElements }
}, },
callback: () => { callback: isExist => {
const nameList = []; if (isExist === 'true') {
(dirs||[]).forEach(dir=>{ setConfirmLoading(false);
if (row.tags.indexOf(dir.id) !== -1) { showMessage('warn', '已存在相同的资产目录编号,请重新输入');
nameList.push(dir.path); } else {
}
})
dispatch({ dispatch({
type: 'tag.getTagIdListByNameList', type: 'assetmanage.addOrUpdateDataAsset',
payload: { payload: {
params: { params,
nameList: nameList.join(',') data: { ...asset, elements: newElements }
}
}, },
callback: data => { callback: data => {
const ids = [id];
if (data && ((data?.id||'')!=='') && (data?.id!==id)) {
ids.push(data?.id);
}
dispatch({ dispatch({
type: 'tag.batchAddTagResourceByTagList', type: 'tag.batchAddTagResourceByTagList',
payload: { payload: {
params: { params: {
tagIds: (data||[]).join(','), tagIds: tag?.tagId,
resourceIds: id, resourceIds: ids.join(','),
type: 'dataAsset', type: 'dataAsset',
creator creator
} }
}, },
callback: () => { callback: () => {
setConfirmLoading(false);
reset(); reset();
onCancel && onCancel(true); onCancel && onCancel(true);
}, },
...@@ -194,6 +195,7 @@ const AssetTagModal = (props) => { ...@@ -194,6 +195,7 @@ const AssetTagModal = (props) => {
setConfirmLoading(false); setConfirmLoading(false);
} }
}) })
}
}, },
error: () => { error: () => {
setConfirmLoading(false); setConfirmLoading(false);
...@@ -226,7 +228,7 @@ const AssetTagModal = (props) => { ...@@ -226,7 +228,7 @@ const AssetTagModal = (props) => {
<Modal <Modal
forceRender forceRender
className='asset-add' className='asset-add'
title='资产打标签' title='资产目录打标签'
visible={ visible } visible={ visible }
width={ 600 } width={ 600 }
onCancel={() => { onCancel={() => {
...@@ -259,8 +261,14 @@ const AssetTagModal = (props) => { ...@@ -259,8 +261,14 @@ const AssetTagModal = (props) => {
return ( return (
<> <>
<Form.Item <Form.Item
label='资产标签' label='资产目录标签'
name='tags' name='tag'
>
<span>{tag?.name||''}</span>
</Form.Item>
<Form.Item
label='挂载目录'
name='dirs'
required={true} required={true}
> >
<DirsSelect data={dirs||[]} /> <DirsSelect data={dirs||[]} />
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
} }
.yy-tree{ .yy-tree{
height: calc(100vh - @header-height - @breadcrumb-height - 25px - 40px - 62px) !important; height: calc(100vh - @header-height - @breadcrumb-height - 25px - 57px - 62px) !important;
overflow: auto !important; overflow: auto !important;
} }
...@@ -15,17 +15,3 @@ ...@@ -15,17 +15,3 @@
color: #f50; color: #f50;
} }
} }
\ No newline at end of file
.asset-tree-read-only {
.yy-tree {
height: calc(100vh - @header-height - @breadcrumb-height - 25px - 62px) !important;;
overflow: auto !important;
}
}
.asset-tree-asset-mount-reference {
.yy-tree {
height: 400px !important;
overflow: auto !important;
}
}
\ No newline at end of file
...@@ -389,7 +389,7 @@ const AttributeRelationModal = (props) => { ...@@ -389,7 +389,7 @@ const AttributeRelationModal = (props) => {
return ( return (
<Modal <Modal
forceRender forceRender
title={'资产属性关联'} title={'资产目录属性关联'}
visible={visible} visible={visible}
width={1000} width={1000}
onCancel={() => { onCancel={() => {
......
import React, { useEffect, useState, useMemo } from 'react';
import { Modal, Checkbox, Row, Input, Col, Space, Button } from 'antd';
import { dispatch } from '../../../../model';
import { showMessage } from '../../../../util';
import { AssetActionSubject } from './AssetAction';
const FC = (props) => {
const { visible, onCancel } = props;
const [keyword, setKeyword] = useState('');
const [elements, setElements] = useState([]);
const [checkedValues, setCheckedValues] = useState([]);
const [confirmLoading, setConfirmLoading] = useState(false);
useEffect(() => {
if (visible) {
getComputableElements();
}
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [visible])
const filterElements = useMemo(() => {
return elements?.filter(item => (item.name||'').indexOf(keyword)!==-1);
}, [keyword, elements])
const getComputableElements = () => {
dispatch({
type: 'assetmanage.listComputableElements',
callback: data => {
setElements(data);
}
})
}
const onSearchChange = (e) => {
setKeyword(e.target.value);
}
const onCheckboxChange = (newValues) => {
setCheckedValues(newValues);
}
const reset = () => {
setConfirmLoading(false);
setKeyword('');
setCheckedValues([]);
setElements([]);
}
const onOk = () => {
if ((checkedValues||[]).length === 0) {
showMessage('info', '请先选择要素');
return;
}
setConfirmLoading(true);
dispatch({
type: 'assetmanage.computeBySelectElements',
payload: {
data: checkedValues
},
callback: data => {
setConfirmLoading(false);
reset();
AssetActionSubject.next({type: 'update'})
onCancel?.();
},
error: () => {
setConfirmLoading(false);
}
})
}
return (
<Modal
forceRender
title='资产价值评分'
visible={visible}
width={800}
confirmLoading={confirmLoading}
onCancel={() => {
reset();
onCancel?.();
}}
footer={
<Space>
<Button onClick={() => onCancel?.() }>取消</Button>
<Button type="primary" onClick={ onOk } loading={ confirmLoading }>计算</Button>
</Space>
}
>
<div>
<div className='mb-3'>资产要素</div>
<Input
value={keyword}
allowClear
placeholder='请输入资产要素'
style={{ marginBottom:10 }}
onChange={(e) => { onSearchChange(e) }}
/>
<div style={{ maxHeight: 500, overflow: 'auto' }}>
<Checkbox.Group value={checkedValues} onChange={onCheckboxChange} style={{ width: '100%' }}>
<Row>
{
elements?.map((item, index) => {
const exsit = filterElements?.some(filterItem => filterItem.id === item.id);
return (
<Col key={index} span={6} style={{ display: exsit?'':'none' }}>
<Checkbox value={item.id||''}>{item.name||''}</Checkbox>
</Col>
);
})
}
</Row>
</Checkbox.Group>
</div>
</div>
</Modal>
);
}
export default FC;
\ No newline at end of file
import React, { useEffect, useState, useCallback } from 'react'; import React, { useEffect, useState, useCallback } from 'react';
import { Modal, Checkbox, Row, Col, Form, Input, Empty } from 'antd'; import { Modal, Checkbox, Row, Col, Form, Input, Empty, Select } from 'antd';
import { DndProvider } from 'react-dnd'; import { DndProvider } from 'react-dnd';
import { HTML5Backend } from 'react-dnd-html5-backend'; import { HTML5Backend } from 'react-dnd-html5-backend';
import update from 'immutability-helper'; import update from 'immutability-helper';
...@@ -7,11 +7,18 @@ import update from 'immutability-helper'; ...@@ -7,11 +7,18 @@ import update from 'immutability-helper';
import DragTag from './DragTag'; import DragTag from './DragTag';
import PreviewTree from './PreviewTree'; import PreviewTree from './PreviewTree';
import { dispatch, dispatchLatest } from '../../../../model'; import { dispatch, dispatchLatest } from '../../../../model';
import { AssetManageReference, AssetBrowseReference, ResourceBrowseReference } from '../../../../util/constant';
import { showMessage } from '../../../../util'; import { showMessage } from '../../../../util';
const resourceTypes = [
{ key: 'innerSource', name: '内部资源' },
{ key: 'outerSource', name: '外部资源' },
{ key: 'dataAsset', name: '资产' },
]
const CustomDirectoryModal = (props) => { const CustomDirectoryModal = (props) => {
const { visible, onCancel, action, dirId } = props; const { visible, onCancel, action, dirId, reference = AssetManageReference } = props;
const [ keyword, setKeyword ] = useState(''); const [ keyword, setKeyword ] = useState('');
const [ data, setData ] = useState([]); const [ data, setData ] = useState([]);
...@@ -67,11 +74,33 @@ const CustomDirectoryModal = (props) => { ...@@ -67,11 +74,33 @@ const CustomDirectoryModal = (props) => {
} }
const getPreviewTreeData = () => { const getPreviewTreeData = () => {
dispatchLatest({ if ((checkedValues||[]).length === 0) {
type: 'assetmanage.previewTreeByCustomElements', return;
payload: { }
let url = 'assetmanage.previewTreeByCustomElements';
let payload = {
data: checkedValues data: checkedValues
}, }
if (reference===AssetManageReference) {
payload.params = {
resourceTypes: (form.getFieldValue('resourceTypes')||[]).join(',')
};
}
if (reference===AssetBrowseReference || reference===ResourceBrowseReference) {
url = 'assetmanage.previewTreeByCustomElementsAndResourceType';
payload.params = {
resourceType: (reference===ResourceBrowseReference)?'resource':'dataAsset',
}
}
dispatchLatest({
type: url,
payload,
callback: data => { callback: data => {
setPreviewTreeData((data||[]).length>0?data[0]:{}); setPreviewTreeData((data||[]).length>0?data[0]:{});
} }
...@@ -98,6 +127,12 @@ const CustomDirectoryModal = (props) => { ...@@ -98,6 +127,12 @@ const CustomDirectoryModal = (props) => {
setCheckedData(_checkedData); setCheckedData(_checkedData);
} }
const onValuesChange = (changedValues, allValues) => {
if (changedValues.hasOwnProperty('resourceTypes')) {
getPreviewTreeData();
}
}
const reset = () => { const reset = () => {
setConfirmLoading(false); setConfirmLoading(false);
setKeyword(''); setKeyword('');
...@@ -127,8 +162,23 @@ const CustomDirectoryModal = (props) => { ...@@ -127,8 +162,23 @@ const CustomDirectoryModal = (props) => {
payload.params = {...payload.params, dirId}; payload.params = {...payload.params, dirId};
} }
let url = 'assetmanage.saveTreeByCustomElements';
if (reference===AssetManageReference) {
payload.params = {
...payload.params,
resourceTypes: (row.resourceTypes||[]).join(',')
}
}
if (reference===AssetBrowseReference || reference===ResourceBrowseReference) {
url = 'assetmanage.saveTreeByCustomElementsAndResourceType';
payload.params = { ...payload.params, resourceType: (reference===ResourceBrowseReference)?'resource':'dataAsset' };
}
dispatch({ dispatch({
type: 'assetmanage.saveTreeByCustomElements', type: url,
payload, payload,
callback: data => { callback: data => {
setConfirmLoading(false); setConfirmLoading(false);
...@@ -194,6 +244,7 @@ const CustomDirectoryModal = (props) => { ...@@ -194,6 +244,7 @@ const CustomDirectoryModal = (props) => {
title={action==='add'?'新增自定义':'修改自定义'} title={action==='add'?'新增自定义':'修改自定义'}
visible={visible} visible={visible}
width={800} width={800}
centered
confirmLoading={confirmLoading} confirmLoading={confirmLoading}
onCancel={() => { onCancel={() => {
reset(); reset();
...@@ -203,10 +254,10 @@ const CustomDirectoryModal = (props) => { ...@@ -203,10 +254,10 @@ const CustomDirectoryModal = (props) => {
> >
<Row gutter={30}> <Row gutter={30}>
<Col span={8} style={{ borderRight: '1px solid #EFEFEF' }}> <Col span={8} style={{ borderRight: '1px solid #EFEFEF' }}>
<div className='mb-3'>资产要素</div> <div className='mb-3'>资产目录要素</div>
<Input <Input
value={keyword} value={keyword}
placeholder='请输入资产要素' placeholder='请输入资产目录要素'
style={{ marginBottom:10 }} style={{ marginBottom:10 }}
onChange={(e) => { onSearchChange(e) }} onChange={(e) => { onSearchChange(e) }}
/> />
...@@ -244,7 +295,7 @@ const CustomDirectoryModal = (props) => { ...@@ -244,7 +295,7 @@ const CustomDirectoryModal = (props) => {
</div> </div>
</> </>
} }
<Form className='mt-5' {...formItemLayout} form={form}> <Form className='mt-5' {...formItemLayout} form={form} onValuesChange={onValuesChange}>
<Form.Item <Form.Item
label='命名' label='命名'
name='name' name='name'
...@@ -252,6 +303,20 @@ const CustomDirectoryModal = (props) => { ...@@ -252,6 +303,20 @@ const CustomDirectoryModal = (props) => {
> >
<Input /> <Input />
</Form.Item> </Form.Item>
{
reference===AssetManageReference && <Form.Item
label='数据范围'
name='resourceTypes'
>
<Select mode="multiple" allowClear>
{
resourceTypes.map((item,index) => {
return <Select.Option key={item.key}>{item.name}</Select.Option>
})
}
</Select>
</Form.Item>
}
<Form.Item <Form.Item
label='描述或原因' label='描述或原因'
name='desc' name='desc'
......
import React, { useEffect, useState } from 'react';
import { Button, Upload, Modal, Select, Space, Spin } from 'antd';
import { DownloadOutlined, UploadOutlined } from '@ant-design/icons';
import LocalStorage from 'local-storage';
import { dispatchLatest, dispatch } from '../../../../model';
import { showMessage } from '../../../../util';
const FC = (props) => {
const { onCancel, visible } = props;
const [ resourceTypes, setResourceTypes ] = useState(undefined);
const [ currentResourceType, setCurrentResourceType ] = useState(undefined);
const [ loading, setLoading ] = useState(false);
useEffect(() => {
if (visible) {
getResourceTypes();
}
}, [visible])
const getResourceTypes = () => {
setLoading(true);
dispatch({
type: 'assetmanage.getResourceTypes',
callback: data => {
setLoading(false);
setResourceTypes(data);
if ((data||[]).length > 0) {
setCurrentResourceType(data[0].code);
}
},
error: () => {
setLoading(false);
}
})
}
const handleOk = () => {
if (!currentResourceType) {
showMessage('info', '请先选择资产类型');
return;
}
const env = LocalStorage.get('assetsEnv');
window.open(`/api/dataassetmanager/elementApi/export?env=${env}&resourceType=${currentResourceType}`);
reset();
onCancel();
}
const reset = () => {
setLoading(false);
}
return (
<Modal
forceRender
visible={visible}
title='资产属性导出'
width={520}
onCancel={() => {
reset();
onCancel && onCancel();
}}
onOk={handleOk}
>
<Spin spinning={loading} >
<div className='mb-3 flex'>
<Select
value={currentResourceType}
placeholder='请选择资产类型'
onChange={(val) => {
setCurrentResourceType(val);
}}
style={{ width: 200 }}
>
{
resourceTypes?.map((item,index) => {
return <Select.Option key={item.code}>{item.name}</Select.Option>
})
}
</Select>
</div>
</Spin>
</Modal>
)
}
export default FC;
\ No newline at end of file
...@@ -3,6 +3,7 @@ import { Row, Col, Checkbox, Typography, Button, Switch, Modal } from 'antd'; ...@@ -3,6 +3,7 @@ import { Row, Col, Checkbox, Typography, Button, Switch, Modal } from 'antd';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import './FilterElementModal.less'; import './FilterElementModal.less';
import { AssetManageReference } from '../../../../util/constant';
//type //type
//global 全局设置 //global 全局设置
...@@ -11,7 +12,7 @@ import './FilterElementModal.less'; ...@@ -11,7 +12,7 @@ import './FilterElementModal.less';
const FilterElementModal = (props) => { const FilterElementModal = (props) => {
const { visible, onCancel, type = 'global' } = props; const { visible, onCancel, type = 'global', reference = AssetManageReference } = props;
const [ elements, setElements ] = useState([]); const [ elements, setElements ] = useState([]);
const [ typesOfElements, setTypesOfElements ] = useState([]); const [ typesOfElements, setTypesOfElements ] = useState([]);
const [ selectedKeys, setSelectedKeys ] = useState([]); const [ selectedKeys, setSelectedKeys ] = useState([]);
...@@ -28,14 +29,19 @@ const FilterElementModal = (props) => { ...@@ -28,14 +29,19 @@ const FilterElementModal = (props) => {
const getAllFilterElementIdsThenGetAllElements = () => { const getAllFilterElementIdsThenGetAllElements = () => {
let url = ''; let url = '';
let payload = null;
if (type === 'global') { if (type === 'global') {
url = 'assetmanage.listFilterElementIdsConfig'; url = 'assetmanage.listFilterElementIdsConfig';
} else { } else {
url = 'assetmanage.listFilterElementIds'; url = 'assetmanage.listFilterElementIds';
payload = {
isAdmin: (reference===AssetManageReference)
}
} }
dispatch({ dispatch({
type: url, type: url,
payload,
callback: data => { callback: data => {
setSelectedKeys(data||[]); setSelectedKeys(data||[]);
getAllElements(); getAllElements();
...@@ -123,7 +129,10 @@ const FilterElementModal = (props) => { ...@@ -123,7 +129,10 @@ const FilterElementModal = (props) => {
dispatch({ dispatch({
type: url, type: url,
payload: { payload: {
data: selectedKeys data: selectedKeys,
params: {
isAdmin: (reference===AssetManageReference)
}
}, },
callback: () => { callback: () => {
reset(); reset();
...@@ -148,7 +157,7 @@ const FilterElementModal = (props) => { ...@@ -148,7 +157,7 @@ const FilterElementModal = (props) => {
<Modal <Modal
forceRender forceRender
visible={visible} visible={visible}
title={type==='global'?'资产属性管理':'可见列设置'} title={type==='global'?'资产目录浏览管理':'可见列设置'}
width={520} width={520}
onCancel={cancel} onCancel={cancel}
footer={[ footer={[
......
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect, useContext } from 'react';
import { Button, Upload, Drawer, Table, Pagination, Divider, Form, Select } from 'antd'; import { Button, Upload, Drawer, Table, Pagination, Divider, Form, Typography } from 'antd';
import { UploadOutlined, DownloadOutlined } from '@ant-design/icons'; import { UploadOutlined, DownloadOutlined } from '@ant-design/icons';
import LocalStorage from 'local-storage';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { showMessage, formatDate } from '../../../../util'; import { showMessage, formatDate } from '../../../../util';
import { AppContext } from '../../../../App';
import { getTemplateType } from '../../../../util/axios';
const ImportAssetDrawer = (props) => { const ImportAssetDrawer = (props) => {
const { onCancel, onSuccess, visible, nodeId } = props; const { onCancel, onSuccess, visible, nodeId } = props;
...@@ -16,8 +17,9 @@ const ImportAssetDrawer = (props) => { ...@@ -16,8 +17,9 @@ const ImportAssetDrawer = (props) => {
const [ pagination, setPagination ] = useState( { pageNum: 1, pageSize: 20 } ); const [ pagination, setPagination ] = useState( { pageNum: 1, pageSize: 20 } );
const { pageNum, pageSize } = pagination; const { pageNum, pageSize } = pagination;
const [ total, setTotal ] = useState(0); const [ total, setTotal ] = useState(0);
const [ resourceTypes, setResourceTypes ] = useState(undefined); const [ users, setUsers ] = useState([]);
const [ currentResourceType, setCurrentResourceType ] = useState(undefined);
const app = useContext(AppContext);
const columns = [ const columns = [
{ {
...@@ -60,6 +62,14 @@ const ImportAssetDrawer = (props) => { ...@@ -60,6 +62,14 @@ const ImportAssetDrawer = (props) => {
dataIndex: 'operator', dataIndex: 'operator',
width: 100, width: 100,
ellipsis: true, ellipsis: true,
render: (text, record) => {
const user = users?.filter((user)=>user.pernr===text);
if (user && user.length > 0) {
return user[0].nachn?`${user[0].nachn}(${user[0].pernr})`:user[0].pernr;
}
return text;
}
}, },
{ {
title: '导入状态', title: '导入状态',
...@@ -72,41 +82,15 @@ const ImportAssetDrawer = (props) => { ...@@ -72,41 +82,15 @@ const ImportAssetDrawer = (props) => {
if (visible) { if (visible) {
setPagination({ pageNum: 1, pageSize: 20 }); setPagination({ pageNum: 1, pageSize: 20 });
getUsers();
getLogs(); getLogs();
getResourceTypes();
} }
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
}, [visible]) }, [visible])
const getResourceTypes = () => {
dispatch({
type: 'assetmanage.getResourceTypes',
callback: data => {
setResourceTypes(data);
if ((data||[]).length > 0) {
setCurrentResourceType(data[0].code);
}
}
})
}
const downloadTemplate = () => { const downloadTemplate = () => {
if (!currentResourceType) { window.open(`/api/dataassetmanager/dataAssetApi/getImportTemplate?templateType=${getTemplateType()}`);
showMessage('warn', '请先选择资产类型');
return;
}
const env = LocalStorage.get('assetsEnv');
dispatch({
type: 'assetmanage.getDirectoryById',
payload: {
dirId: nodeId
},
callback: data => {
window.open(`/api/dataassetmanager/dataAssetApi/getImportTemplate?env=${env}&resourceType=${currentResourceType}`);
}
})
} }
const getLogs = (p = 1, s = 20) => { const getLogs = (p = 1, s = 20) => {
...@@ -128,6 +112,15 @@ const ImportAssetDrawer = (props) => { ...@@ -128,6 +112,15 @@ const ImportAssetDrawer = (props) => {
}) })
} }
const getUsers = () => {
dispatch({
type: 'pds.getOwners',
callback: (data) => {
setUsers(data);
}
})
}
const uploadProps = { const uploadProps = {
onRemove: file => { onRemove: file => {
...@@ -154,24 +147,21 @@ const ImportAssetDrawer = (props) => { ...@@ -154,24 +147,21 @@ const ImportAssetDrawer = (props) => {
}; };
const handleOk = () => { const handleOk = () => {
if (!currentResourceType) {
showMessage('warn', '请先选择资产类型');
return;
}
if ((fileList||[]).length === 0) { if ((fileList||[]).length === 0) {
showMessage('info', '请先选择模上传'); showMessage('info', '请先选择模上传');
return; return;
} }
setConfirmLoading(true); setConfirmLoading(true);
dispatch({ dispatch({
type: 'assetmanage.assetImport', type: 'assetmanage.assetImport',
payload: { fileList: fileList, params: { dirId: nodeId, resourceType: currentResourceType } }, payload: { fileList: fileList, params: { env: `${app?.env?.domainId}` } },
callback: data => { callback: data => {
setConfirmLoading(false); setConfirmLoading(false);
setFileList([]); setFileList([]);
getLogs(pageNum, pageSize); getLogs(pageNum, pageSize);
showMessage('success', '导入动作完成,详情查看日志');
onSuccess && onSuccess(data||''); onSuccess && onSuccess(data||'');
}, },
error: () => { error: () => {
...@@ -189,7 +179,7 @@ const ImportAssetDrawer = (props) => { ...@@ -189,7 +179,7 @@ const ImportAssetDrawer = (props) => {
<Drawer <Drawer
forceRender forceRender
visible={ visible } visible={ visible }
title='资产导入' title='资产目录导入'
width={900} width={900}
placement="right" placement="right"
closable={ true } closable={ true }
...@@ -198,11 +188,11 @@ const ImportAssetDrawer = (props) => { ...@@ -198,11 +188,11 @@ const ImportAssetDrawer = (props) => {
onCancel && onCancel(); onCancel && onCancel();
}} }}
> >
<div className='mt-3 flex' style={{ justifyContent: 'space-between' }}> <div className='mt-3'>
<Form layout='inline'> <Form layout='inline'>
<Form.Item label='Word上传:'> <Form.Item label='Excel导入:'>
<Button className='mr-2' icon={<DownloadOutlined />} onClick={ downloadTemplate }> <Button className='mr-2' icon={<DownloadOutlined />} onClick={ downloadTemplate }>
下载 下载
</Button> </Button>
<Upload style={{ display: 'inline' }} {...uploadProps }> <Upload style={{ display: 'inline' }} {...uploadProps }>
<Button icon={ <Button icon={
...@@ -214,21 +204,8 @@ const ImportAssetDrawer = (props) => { ...@@ -214,21 +204,8 @@ const ImportAssetDrawer = (props) => {
<Form.Item> <Form.Item>
<Button type='primary' onClick={handleOk} loading={confirmLoading}>确定导入</Button> <Button type='primary' onClick={handleOk} loading={confirmLoading}>确定导入</Button>
</Form.Item> </Form.Item>
<Button onClick={() => getLogs()} style={{ marginLeft: 'auto' }}>刷新日志</Button>
</Form> </Form>
<Select
value={currentResourceType}
placeholder='请选择资产类型'
onChange={(val) => {
setCurrentResourceType(val);
}}
style={{ width: 200 }}
>
{
resourceTypes?.map((item,index) => {
return <Select.Option key={item.code}>{item.name}</Select.Option>
})
}
</Select>
</div> </div>
<Divider orientation="left">导入日志</Divider> <Divider orientation="left">导入日志</Divider>
<Table <Table
...@@ -239,7 +216,11 @@ const ImportAssetDrawer = (props) => { ...@@ -239,7 +216,11 @@ const ImportAssetDrawer = (props) => {
pagination={false} pagination={false}
loading={loading} loading={loading}
expandable={{ expandable={{
expandedRowRender: record => <p style={{ margin: 0 }}>{record.message||''}</p> expandedRowRender: record => <React.Fragment>
{record.message?.split('<br/>').map((info, index) => {
return <Typography.Paragraph key={index}>{info}</Typography.Paragraph>
})}
</React.Fragment>
}} }}
sticky sticky
/> />
......
...@@ -4,6 +4,7 @@ import { UploadOutlined } from '@ant-design/icons'; ...@@ -4,6 +4,7 @@ import { UploadOutlined } from '@ant-design/icons';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { showNotifaction } from '../../../../util'; import { showNotifaction } from '../../../../util';
import { getTemplateType } from '../../../../util/axios';
const ImportDirectory = (props) => { const ImportDirectory = (props) => {
const { visible, onCancel, dirId } = props; const { visible, onCancel, dirId } = props;
...@@ -41,7 +42,7 @@ const ImportDirectory = (props) => { ...@@ -41,7 +42,7 @@ const ImportDirectory = (props) => {
} }
const download = () => { const download = () => {
window.open("/data-govern/docs/AssetThemeModel.xlsx"); window.open(`/api/dataassetmanager/directoryApi/getImportTemplate?templateType=${getTemplateType()}`);
} }
const upload = async (ignoreRepeatPath = false) => { const upload = async (ignoreRepeatPath = false) => {
...@@ -51,23 +52,12 @@ const ImportDirectory = (props) => { ...@@ -51,23 +52,12 @@ const ImportDirectory = (props) => {
setUploading(true); setUploading(true);
let payload; const payload = {
if (row.type === 'root') {
payload = {
params: { params: {
ignoreRepeatPath ignoreRepeatPath
}, },
fileList: fileList, fileList: fileList,
}; };
} else {
payload = {
params: {
ignoreRepeatPath,
parentPath: dir.path
},
fileList: fileList
};
}
dispatch({ dispatch({
type: 'assetmanage.directoryImport', type: 'assetmanage.directoryImport',
...@@ -143,7 +133,7 @@ const ImportDirectory = (props) => { ...@@ -143,7 +133,7 @@ const ImportDirectory = (props) => {
onCancel={() => { onCancel && onCancel() }} onCancel={() => { onCancel && onCancel() }}
footer={ footer={
<Space> <Space>
<Button type="primary" onClick={ download } >下载</Button> <Button type="primary" onClick={ download } >下载</Button>
<Button type="primary" onClick={() => { upload(false); } } loading={uploading}>上传</Button> <Button type="primary" onClick={() => { upload(false); } } loading={uploading}>上传</Button>
<Button onClick={() => { onCancel && onCancel() }}>返回</Button> <Button onClick={() => { onCancel && onCancel() }}>返回</Button>
</Space> </Space>
...@@ -152,13 +142,10 @@ const ImportDirectory = (props) => { ...@@ -152,13 +142,10 @@ const ImportDirectory = (props) => {
<Form {...formItemLayout} form={form}> <Form {...formItemLayout} form={form}>
<Form.Item <Form.Item
label="挂载位置" label="挂载位置"
name="type" // name="type"
rules={[{ required: true, message: '必填项'}]} rules={[{ required: true, message: '必填项'}]}
> >
<Radio.Group > <span>根节点导入</span>
<Radio value='root' >根节点导入</Radio>
<Radio value='self' disabled={ dirId===null }>选中节点导入</Radio>
</Radio.Group>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="文件" label="文件"
......
import React, { useEffect, useState } from 'react'; import React, { useState } from 'react';
import { Button, Upload, Modal, Select, Space, Spin } from 'antd'; import { Button, Upload, Modal } from 'antd';
import { DownloadOutlined, UploadOutlined } from '@ant-design/icons'; import { DownloadOutlined, UploadOutlined } from '@ant-design/icons';
import { dispatchLatest, dispatch } from '../../../../model'; import { dispatchLatest } from '../../../../model';
import { showMessage } from '../../../../util'; import { showMessage } from '../../../../util';
import { getTemplateType } from '../../../../util/axios';
const ImportElement = (props) => { const ImportElement = (props) => {
const { onCancel, visible } = props; const { onCancel, visible } = props;
const [ fileList, setFileList ] = useState([]); const [ fileList, setFileList ] = useState([]);
const [ confirmLoading, setConfirmLoading ] = useState(false); const [ confirmLoading, setConfirmLoading ] = useState(false);
const [ resourceTypes, setResourceTypes ] = useState(undefined);
const [ currentResourceType, setCurrentResourceType ] = useState(undefined);
const [ loading, setLoading ] = useState(false);
useEffect(() => {
if (visible) {
getResourceTypes();
}
}, [visible])
const getResourceTypes = () => {
setLoading(true);
dispatch({
type: 'assetmanage.getResourceTypes',
callback: data => {
setLoading(false);
setResourceTypes(data);
if ((data||[]).length > 0) {
setCurrentResourceType(data[0].code);
}
},
error: () => {
setLoading(false);
}
})
}
const downloadTemplate = () => { const downloadTemplate = () => {
window.open("/data-govern/docs/ElementModel.xlsx"); window.open(`/api/dataassetmanager/elementApi/getImportTemplate?templateType=${getTemplateType()}`);
} }
const uploadProps = { const uploadProps = {
...@@ -61,19 +36,14 @@ const ImportElement = (props) => { ...@@ -61,19 +36,14 @@ const ImportElement = (props) => {
const handleOk = () => { const handleOk = () => {
if ((fileList||[]).length === 0) { if ((fileList||[]).length === 0) {
showMessage('info', '请先选择模上传'); showMessage('info', '请先选择模上传');
return; return;
} }
setConfirmLoading(true); setConfirmLoading(true);
dispatchLatest({ dispatchLatest({
type: 'assetmanage.importElement', type: 'assetmanage.importElement',
payload: { payload: { fileList },
params: {
resourceType: currentResourceType
},
fileList
},
callback: data => { callback: data => {
setConfirmLoading(false); setConfirmLoading(false);
reset(); reset();
...@@ -87,15 +57,13 @@ const ImportElement = (props) => { ...@@ -87,15 +57,13 @@ const ImportElement = (props) => {
const reset = () => { const reset = () => {
setFileList([]); setFileList([]);
setLoading(false);
setConfirmLoading(false);
} }
return ( return (
<Modal <Modal
forceRender forceRender
visible={visible} visible={visible}
title='资产属性导入' title='资产目录属性导入'
width={520} width={520}
confirmLoading={confirmLoading} confirmLoading={confirmLoading}
onCancel={() => { onCancel={() => {
...@@ -104,34 +72,18 @@ const ImportElement = (props) => { ...@@ -104,34 +72,18 @@ const ImportElement = (props) => {
}} }}
onOk={handleOk} onOk={handleOk}
> >
<Spin spinning={loading} > <div>
<div className='mb-3 flex'> <Button icon={<DownloadOutlined />} onClick={ downloadTemplate }>
<Select 模板下载
value={currentResourceType} </Button>
placeholder='请选择资产类型'
onChange={(val) => {
setCurrentResourceType(val);
}}
style={{ width: 200 }}
>
{
resourceTypes?.map((item,index) => {
return <Select.Option key={item.code}>{item.name}</Select.Option>
})
}
</Select>
</div> </div>
<Space> <div className='mt-3'>
<Upload {...uploadProps}> <Upload {...uploadProps}>
<Button icon={<UploadOutlined />}> <Button icon={<UploadOutlined />}>
选择文件上传 选择文件上传
</Button> </Button>
</Upload> </Upload>
<Button icon={<DownloadOutlined />} onClick={ downloadTemplate }> </div>
模版下载
</Button>
</Space>
</Spin>
</Modal> </Modal>
) )
} }
......
...@@ -9,7 +9,7 @@ const FC = ({ value = '', terms = [] }) => { ...@@ -9,7 +9,7 @@ const FC = ({ value = '', terms = [] }) => {
{ {
appValue => <a onClick={() => { appValue => <a onClick={() => {
appValue?.setGlobalState && appValue?.setGlobalState({ appValue?.setGlobalState && appValue?.setGlobalState({
message: 'data-govern-show-standard-detail-message', message: 'data-govern-show-index-detail-message',
data: { name: value } data: { name: value }
}) })
}}> }}>
......
...@@ -2,9 +2,10 @@ import React from 'react'; ...@@ -2,9 +2,10 @@ import React from 'react';
import { Button } from 'antd'; import { Button } from 'antd';
import { SettingFilled } from '@ant-design/icons'; import { SettingFilled } from '@ant-design/icons';
import { highlightSearchContentByTerms } from '../../../../util';
import { AppContext } from '../../../../App'; import { AppContext } from '../../../../App';
const MetadataInfo = ({ value = '', config = true }) => { const MetadataInfo = ({ value = '', config = true, terms = [] }) => {
let metadata = {}; let metadata = {};
try { try {
...@@ -18,13 +19,13 @@ const MetadataInfo = ({ value = '', config = true }) => { ...@@ -18,13 +19,13 @@ const MetadataInfo = ({ value = '', config = true }) => {
{ {
value => <div className='flex'> value => <div className='flex'>
{ {
(typeof metadata==='string') ? <span style={{ marginRight: 5 }}>{metadata||''}</span> : <div className='flex' style={{ flexDirection: 'column' }}> (typeof metadata==='string') ? <span style={{ marginRight: 5 }}>{highlightSearchContentByTerms(metadata||'', terms)}</span> : <div className='flex' style={{ flexDirection: 'column' }}>
<a onClick={() => { <a onClick={() => {
value?.setGlobalState && value?.setGlobalState({ value?.setGlobalState && value?.setGlobalState({
message: 'data-govern-show-metadata-message', message: 'data-govern-show-metadata-message',
data: metadata data: metadata
}) })
}} style={{ marginRight: 5, marginTop: config?5:0 }}>{metadata?.tableName||''} }} style={{ marginRight: 5, marginTop: config?5:0 }}>{highlightSearchContentByTerms(metadata?.tableName||'',terms)}
</a> </a>
{ {
(metadata?.columnItems||[]).map((item, index) => { (metadata?.columnItems||[]).map((item, index) => {
...@@ -36,7 +37,7 @@ const MetadataInfo = ({ value = '', config = true }) => { ...@@ -36,7 +37,7 @@ const MetadataInfo = ({ value = '', config = true }) => {
_content += item.metadataColumnName||''; _content += item.metadataColumnName||'';
return <span key={index}>{_content}</span> return <span key={index}>{highlightSearchContentByTerms(_content,terms)}</span>
}) })
} }
</div> </div>
......
import React, { useEffect, useState } from "react";
import { Modal, Button, Space, Tree, Row, Col, Table, Pagination, Select, Input, Divider, Spin } from "antd";
import { getAttributesByMetadataModel } from "../../../../service/dataassetmanager";
import { dispatch } from '../../../../model';
import { showMessage } from "../../../../util";
import useDebounce from "../../../../layout/useDebounce";
const options = [
{ name: '基础数据名称', key: 'name' },
{ name: '基础数据编码', key: 'code' },
]
const FC = (props) => {
const { visible, onCancel, id } = props;
const [treeData, setTreeData] = useState(undefined);
const [tableData, setTableData] = useState(undefined);
const [total, setTotal] = useState(0);
const [ pagination, setPagination ] = useState( { pageNum: 1, pageSize: 20 } );
const [loadingTree, setLoadingTree] = useState(false);
const [loadingTable,setLoadingTable] = useState(false);
const [currentTreeParams, setCurrentTreeParams] = useState({
treeId: undefined,
dataType: undefined,
});
const [queryProperty, setQueryProperty] = useState(options[0].key);
const [keyword, setKeyword] = useState(undefined);
const debouncedKeyword = useDebounce(keyword, 300);
const { pageNum, pageSize } = pagination;
const columns = [
{
title: '序号',
dataIndex: 'key',
render: (text, record, index) => {
return (index+1).toString();
},
width: 60,
ellipsis: true,
},
{
title: '基础数据编码',
dataIndex: 'code',
ellipsis: true,
render: (text, record) => {
return <a onClick={() => {
onOk(record._id);
}}>
{text}
</a>
}
},
{
title: '基础数据名称',
dataIndex: 'name',
ellipsis: true,
render: (text, record) => {
return <a onClick={() => {
onOk(record._id);
}}>
{text}
</a>
}
},
];
useEffect(() => {
if (visible) {
getTreeData();
}
}, [visible])
useEffect(() => {
if (visible && currentTreeParams.treeId) {
getTableData();
}
}, [visible, pagination, currentTreeParams, queryProperty, debouncedKeyword])
const getTreeData = () => {
setLoadingTree(true);
dispatch({
type: 'assetmanage.getStandardTree',
payload: {
namePath: 0,
needOrg: true,
parentClass: 'Catalog'
},
callback: data => {
setLoadingTree(false);
const filterData = data?.filter(item => item.name !== '草稿');
if (filterData && filterData.length > 0) {
if (filterData[0].cnName === '指标标准') {
setCurrentTreeParams({ treeId: filterData[0]._id, dataType: 'IndicatorStandard' });
} else if (filterData[0].cnName === '维度标准') {
setCurrentTreeParams({ treeId: filterData[0]._id, dataType: 'DimensionStandard' });
} else {
setCurrentTreeParams({ treeId: filterData[0]._id, dataType: filterData[0].type });
}
}
setTreeData(filterData);
},
error: () => {
setLoadingTree(false);
}
});
}
const getTableData = () => {
setLoadingTable(true);
dispatch({
type: 'assetmanage.getStandardList',
payload: {
params: {
page: pageNum,
size: pageSize,
parentId: currentTreeParams.treeId,
keyword: debouncedKeyword,
queryProperty: queryProperty,
},
data: [`Catalog,StandardCatalog,${currentTreeParams.dataType}`]
},
callback: data => {
setLoadingTable(false);
data.content?.forEach(item => {
item.children = null;
});
setTableData(data.content);
setTotal(data.totalElements);
},
error: () => {
setLoadingTable(false);
}
});
}
const onOk = (standardId) => {
dispatch({
type: 'assetmanage.getMetadataStandardList',
payload: {
data: {
metadataId: id
},
params: {
page: 1,
size: 999999
}
},
callback: data => {
if ((data.content||[]).length === 0) {
dispatch({
type: 'assetmanage.standardBatchMetadata',
payload: {
params: {
metadataIds: id,
standardId
},
},
callback: () => {
showMessage('success', '关联成功');
onCancel?.(true);
}
});
} else {
dispatch({
type: 'assetmanage.deleteStandardBatchMetadata',
payload: {
params: {
ids: data.content?.map(item => item.id).toString()
}
},
callback: () => {
dispatch({
type: 'assetmanage.standardBatchMetadata',
payload: {
params: {
metadataIds: id,
standardId
},
},
callback: () => {
showMessage('success', '关联成功');
onCancel?.(true);
}
});
}
});
}
},
});
}
const onTreeSelect = (keys, {node}) => {
if (keys.length > 0) {
let paths = node.namePath.split(',');
if(paths[1]==='指标标准'){
setCurrentTreeParams({ treeId: keys[0], dataType: 'IndicatorStandard' });
}else if(paths[1]==='维度标准'){
setCurrentTreeParams({ treeId: keys[0], dataType: 'DimensionStandard' });
}else{
setCurrentTreeParams({ treeId: keys[0], dataType: node.type });
}
}
}
const onSelectChange = (value) => {
setQueryProperty(value);
}
const onSearchChange = (e) => {
setKeyword(e.target.value);
}
const changeCurrent = (page,size) => {
setPagination({ pageNum: page, pageSize: size });
}
const reset = () => {
setLoadingTree(false);
setLoadingTable(false);
setCurrentTreeParams({
treeId: undefined,
dataType: undefined,
});
setQueryProperty(options[0].key);
setKeyword(undefined);
setPagination({ pageNum: 1, pageSize: 20 });
}
const loop = (data) =>
data?.map(item => {
if (item.children && item.children.length>0) {
return {...item, title: item.name, key: item._id, children: loop(item.children)};
}
return {...item, title: item.name, key: item._id, children: null};
});
return (
<Modal
title='选择标准'
visible={ visible }
centered
width='90%'
onCancel={() => {
reset();
onCancel?.();
}}
footer={
<Space>
<Button onClick={() => {
reset();
onCancel?.();
}}>取消</Button>
</Space>
}
bodyStyle={{ padding: '24px', height: '70vh', overflow: 'auto' }}
>
<Row>
<Col span={5}>
<Spin spinning={loadingTree}>
<Tree
showLine={true}
showIcon={false}
treeData={loop(treeData)}
onSelect={onTreeSelect}
selectedKeys={currentTreeParams.treeId ? [currentTreeParams.treeId]: undefined}
/>
</Spin>
</Col>
<Col span={1}>
<div style={{ width: 1, height: 'calc(70vh - 48px)', backgroundColor: '#f0f0f0' }} ></div>
</Col>
<Col span={18}>
<div>
<Space>
<Select
value={queryProperty}
onChange={onSelectChange}
style={{ width: 160 }}
>
{
options.map((option, index) => {
return (
<Select.Option key={index} value={option.key} >{option.name}</Select.Option>
)
})
}
</Select>
<Input value={keyword} onChange={onSearchChange} placeholder='请输入关键字' />
</Space>
</div>
<Divider style={{ margin: '10px 0' }} />
<Table
loading={loadingTable}
columns={columns}
dataSource={tableData||[]}
rowKey='_id'
pagination={false}
/>
<Pagination
className="m-3"
size='small'
position={['bottomLeft']}
onChange={changeCurrent}
onShowSizeChange={changeCurrent}
current={pageNum}
pageSize={pageSize}
defaultCurrent={1}
total={total}
showTotal={total => `共 ${total} 条`}
/>
</Col>
</Row>
</Modal>
)
}
export default FC;
\ No newline at end of file
import React, { useState, useContext } from 'react';
import { Modal, Form, Input } from 'antd';
import { dispatchLatest } from '../../../../model';
import { showNotifaction } from '../../../../util';
import { AppContext } from '../../../../App';
const StartFlowModal = (props) => {
const { visible, onCancel, ids } = props;
const [ form ] = Form.useForm();
const [ confirmLoading, setConfirmLoading ] = useState(false);
const app = useContext(AppContext);
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 4 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 },
},
};
const handleOk = async () => {
try {
const values = await form.validateFields();
setConfirmLoading(true);
dispatchLatest({
type: 'assetmanage.startFlow',
payload: {
params: {
env: app?.env?.domainId,
dataAssetIds: ids.join(','),
applyReason: values?.desc
}
},
callback: data => {
reset();
if (data) {
showNotifaction('申请提示', (data === 'ok')?'资产目录申请成功,请在我的流程》我的申请中查看详情':data, 5);
}
onCancel && onCancel(true);
},
error: () => {
setConfirmLoading(false);
}
})
} catch (errInfo) {
}
}
const reset = () => {
setConfirmLoading(false);
form.resetFields();
}
return (
<Modal
forceRender
visible={visible}
title='资产目录申请'
width={520}
confirmLoading={confirmLoading}
onCancel={() => {
reset();
onCancel && onCancel();
}}
onOk={handleOk}
>
<Form
{...formItemLayout}
form={form}
>
<Form.Item
label="申请原因"
name="desc"
rules={[{ required: true, message: '请在申请原因栏中描述用途说明以及必要性(资产目录和服务权限申请需要说明请求字段)' }]}
>
<Input.TextArea rows={6} />
</Form.Item>
</Form>
</Modal>
);
}
export default StartFlowModal;
\ No newline at end of file
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState, useMemo } from 'react';
import { Modal, Form, Input, Space, Button, Radio, Select } from 'antd'; import { Modal, Form, Input, Space, Button, Radio, Select } from 'antd';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { showMessage } from '../../../../util'; import { showMessage } from '../../../../util';
// const resourceTypes = [ // const resourceTypes = [
// { key: 'innerSource', name: '内部资源' }, // // { key: 'innerSource', name: '内部资源' },
// { key: 'outerSource', name: '外部资源' }, // // { key: 'outerSource', name: '外部资源' },
// { key: 'dataAsset', name: '资产' }, // { key: 'dataAsset', name: '资产' },
// { key: 'custom', name: '自定义' },
// ] // ]
const CodeInput = ({ value = '', onChange, restrict = false, action }) => {
const onCodeChange = (e) => {
if (!restrict || (
restrict&&(e.target.value===''||/^[A-Z]+$/.test(e.target.value))
)) {
onChange?.(e.target.value);
}
}
return <Input
placeholder="请输入编号(只允许输入大写英文字母,并且最多3个)"
disabled={action!=='add'}
maxLength={restrict?3:null}
value={value}
onChange={onCodeChange}
/>
}
const UpdateDirectoryModal = (props) => { const UpdateDirectoryModal = (props) => {
const { visible, onCancel, dirId, action } = props; const { visible, onCancel, dirId, action } = props;
...@@ -18,7 +38,6 @@ const UpdateDirectoryModal = (props) => { ...@@ -18,7 +38,6 @@ const UpdateDirectoryModal = (props) => {
const [ dir, setDir ] = useState(null); const [ dir, setDir ] = useState(null);
const [ confirmLoading, setConfirmLoading ] = useState(false); const [ confirmLoading, setConfirmLoading ] = useState(false);
const [ isThemeAdd, setIsThemeAdd ] = useState(false); const [ isThemeAdd, setIsThemeAdd ] = useState(false);
const [ resourceTypes, setResourceTypes ] = useState(undefined);
useEffect(() => { useEffect(() => {
...@@ -26,7 +45,10 @@ const UpdateDirectoryModal = (props) => { ...@@ -26,7 +45,10 @@ const UpdateDirectoryModal = (props) => {
setDir(null); setDir(null);
form.resetFields(); form.resetFields();
getResourceTypes(); if (action === 'add') {
form.setFieldsValue({ resourceType: 'dataAsset' });
}
if ((dirId||'')!=='') { if ((dirId||'')!=='') {
getDirectory(); getDirectory();
} }
...@@ -35,15 +57,18 @@ const UpdateDirectoryModal = (props) => { ...@@ -35,15 +57,18 @@ const UpdateDirectoryModal = (props) => {
//eslint-disable-next-line react-hooks/exhaustive-deps //eslint-disable-next-line react-hooks/exhaustive-deps
}, [ visible ]) }, [ visible ])
const getResourceTypes = () => { const codeRestrict = useMemo(() => {
dispatch({ if (action === 'add') {
type: 'assetmanage.getResourceTypes', if (isThemeAdd) return true;
callback: data => {
setResourceTypes(data); return (dir && dir.level === 1) ? true : false;
} } else {
}) return (dir && dir.level <= 2) ? true : false;
} }
return false;
}, [action, dir, isThemeAdd])
const getDirectory = () => { const getDirectory = () => {
setDir(null); setDir(null);
dispatch({ dispatch({
...@@ -55,7 +80,7 @@ const UpdateDirectoryModal = (props) => { ...@@ -55,7 +80,7 @@ const UpdateDirectoryModal = (props) => {
setDir(data); setDir(data);
if (action !== 'add') { if (action !== 'add') {
form.setFieldsValue({ code: data?.code, name: data?.name||'', desc: data?.desc||'', remarks: data?.remarks||'', resourceType: data?.resourceType }); form.setFieldsValue({ code: data?.code, name: data?.name||'', desc: data?.desc||'', remarks: data?.remarks||'' });
} }
} }
}) })
...@@ -73,7 +98,7 @@ const UpdateDirectoryModal = (props) => { ...@@ -73,7 +98,7 @@ const UpdateDirectoryModal = (props) => {
name: row.name, name: row.name,
desc: row.desc, desc: row.desc,
remarks: row.remarks, remarks: row.remarks,
resourceType: row.resourceType resourceType: 'dataAsset',
} }
}; };
...@@ -81,7 +106,7 @@ const UpdateDirectoryModal = (props) => { ...@@ -81,7 +106,7 @@ const UpdateDirectoryModal = (props) => {
if (row.type === 'directory') { if (row.type === 'directory') {
if (dir === null) { if (dir === null) {
showMessage('warn', '资产目录节点信息正在加载中...'); showMessage('warn', '资产目录的目录节点信息正在加载中...');
return; return;
} }
...@@ -89,16 +114,19 @@ const UpdateDirectoryModal = (props) => { ...@@ -89,16 +114,19 @@ const UpdateDirectoryModal = (props) => {
parentPath: dir.path||'' parentPath: dir.path||''
}}; }};
} else { } else {
payload.data.resourceType = row.resourceType; payload.data.resourceType = 'dataAsset';
} }
} else { } else {
if (dir === null) { if (dir === null) {
showMessage('warn', '资产目录节点信息正在加载中...'); showMessage('warn', '资产目录的目录节点信息正在加载中...');
return; return;
} }
payload.data = { ...payload.data, ...{ order: dir.order, id: dirId } }; payload.data = { ...payload.data, ...{ order: dir.order, id: dirId } };
if (dir.level === 3) {
payload.data = { ...payload.data, code: dir.code };
}
const parentPath = dir.path.substring(0, dir.path.lastIndexOf("/"));; const parentPath = dir.path.substring(0, dir.path.lastIndexOf("/"));;
payload = { ...payload, params: { payload = { ...payload, params: {
...@@ -111,6 +139,7 @@ const UpdateDirectoryModal = (props) => { ...@@ -111,6 +139,7 @@ const UpdateDirectoryModal = (props) => {
payload: payload, payload: payload,
callback: data => { callback: data => {
setConfirmLoading(false); setConfirmLoading(false);
reset();
onCancel && onCancel(true, data?.id||''); onCancel && onCancel(true, data?.id||'');
}, },
error: () => { error: () => {
...@@ -123,16 +152,23 @@ const UpdateDirectoryModal = (props) => { ...@@ -123,16 +152,23 @@ const UpdateDirectoryModal = (props) => {
} }
} }
const reset = () => {
setIsThemeAdd(false);
setDir(undefined);
form.resetFields();
}
const onReset = () => { const onReset = () => {
if(action === 'add') { if(action === 'add') {
setIsThemeAdd(false); setIsThemeAdd(false);
form.resetFields(); form.resetFields();
} else { } else {
if (dir === null) { if (dir === null) {
showMessage('warn', '资产目录节点信息正在加载中...'); showMessage('warn', '资产目录的目录节点信息正在加载中...');
return; return;
} }
form.resetFields();
form.setFieldsValue({ code: dir?.code, name: dir?.name||'', desc: dir?.desc||'', remarks: dir?.remarks||'' });
} }
} }
...@@ -140,6 +176,9 @@ const UpdateDirectoryModal = (props) => { ...@@ -140,6 +176,9 @@ const UpdateDirectoryModal = (props) => {
if (action==='add') { if (action==='add') {
if (changedValues.type === 'theme') { if (changedValues.type === 'theme') {
setIsThemeAdd(true); setIsThemeAdd(true);
// if (allValues.code?.length > 3 || !(/^[A-Z]+$/.test(allValues.code))) {
// form.setFieldsValue({ code: '' });
// }
} else if (changedValues.type === 'directory') { } else if (changedValues.type === 'directory') {
setIsThemeAdd(false); setIsThemeAdd(false);
} }
...@@ -160,15 +199,21 @@ const UpdateDirectoryModal = (props) => { ...@@ -160,15 +199,21 @@ const UpdateDirectoryModal = (props) => {
return ( return (
<Modal <Modal
forceRender forceRender
title={'资产目录信息'} title={'资产目录的目录信息'}
visible={visible} visible={visible}
width={600} width={600}
onCancel={() => { onCancel && onCancel() }} onCancel={() => {
reset();
onCancel && onCancel();
}}
footer={ footer={
<Space> <Space>
<Button type="primary" onClick={onOk} loading={confirmLoading}>提交</Button> <Button type="primary" onClick={onOk} loading={confirmLoading}>提交</Button>
<Button onClick={onReset} >重置</Button> <Button onClick={onReset} >重置</Button>
<Button onClick={() => onCancel && onCancel() }>返回</Button> <Button onClick={() => {
reset();
onCancel && onCancel();
}}>返回</Button>
</Space> </Space>
} }
> >
...@@ -180,34 +225,20 @@ const UpdateDirectoryModal = (props) => { ...@@ -180,34 +225,20 @@ const UpdateDirectoryModal = (props) => {
rules={[{ required: true, message: '必填项' }]} rules={[{ required: true, message: '必填项' }]}
> >
<Radio.Group> <Radio.Group>
<Radio value='theme'>主题</Radio> <Radio value='theme'>栏目</Radio>
<Radio value='directory' disabled={ dirId===null }>目录</Radio> <Radio value='directory' disabled={ !dirId }>目录</Radio>
</Radio.Group> </Radio.Group>
</Form.Item> </Form.Item>
} }
{ {
((action==='add'&&isThemeAdd) || action!=='add') && <Form.Item codeRestrict && <Form.Item
label="资产类型"
name="resourceType"
placeholder='请选择资产类型'
rules={[{ required: true, message: '必填项' }]}
>
<Select>
{
resourceTypes?.map((item,index) => {
return <Select.Option key={item.code}>{item.name}</Select.Option>
})
}
</Select>
</Form.Item>
}
<Form.Item
label="编号" label="编号"
name="code" name="code"
rules={[{ required: true, message: '必填项' }]} rules={[{ required: true, message: '必填项' }]}
> >
<Input placeholder="请输入编号" /> <CodeInput restrict={codeRestrict} action={action} />
</Form.Item> </Form.Item>
}
<Form.Item <Form.Item
label="名称" label="名称"
name="name" name="name"
......
import React, { useState, useEffect } from 'react';
import { Drawer, Pagination, List } from 'antd';
import { dispatch } from '../../../../model';
const WorkbookDrawer = (props) => {
const { onCancel, visible, type = 'tableau' } = props;
const [ loading, setLoading ] = useState(false);
const [ workbooks, setWorkbooks ] = useState([]);
const [ pagination, setPagination ] = useState( { pageNum: 1, pageSize: 20 } );
const { pageNum, pageSize } = pagination;
const [ total, setTotal ] = useState(0);
useEffect(() => {
if (visible) {
setPagination({ pageNum: 1, pageSize: 20 });
getWorkbooks();
}
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [visible])
const getWorkbooks = (p = 1, s = 20) => {
setLoading(true);
const url = (type==='tableau') ? 'assetmanage.listWorkbooks' : 'assetmanage.listSmartBIWorkbooks';
dispatch({
type: url,
payload: {
pageNum: p,
pageSize: s
},
callback: data => {
setLoading(false);
setTotal(data.total);
setWorkbooks(data.data||[]);
},
error: () => {
setLoading(false);
}
})
}
// const onDeleteClick = (id) => {
// dispatch({
// type: 'assetmanage.deleteWorkbooks',
// payload: {
// data: [id]
// },
// callback: () => {
// getWorkbooks();
// }
// })
// }
const onDevelopClick = (id) => {
const url = (type==='tableau') ? 'assetmanage.getWorkbookUrl' : 'assetmanage.getSmartBIWorkbookUrl';
dispatch({
type: url,
payload: {
workbookId: id,
},
callback: data => {
window.open(data||'');
}
})
}
return (
<Drawer
forceRender
visible={ visible }
title={`${type}工作簿`}
width={900}
placement="right"
closable={ true }
onClose={() => {
onCancel && onCancel();
}}
>
<List
itemLayout="horizontal"
size="small"
loading={loading}
dataSource={workbooks}
renderItem={item => (
<List.Item
key={item.id}
actions={[<a key="develop" onClick={() => { onDevelopClick(item.id); }}>报表开发</a>]}
>
<List.Item.Meta
title={item.name}
/>
</List.Item>
)}
/>
<Pagination
className="text-center mt-3"
showSizeChanger
showQuickJumper
onChange={(_pageNum, _pageSize) => {
setPagination({ pageNum: _pageNum||1, pageSize: _pageSize || 20 });
getWorkbooks(_pageNum||1, _pageSize||20);
}}
onShowSizeChange={(_pageNum, _pageSize) => {
setPagination({ pageNum: _pageNum || 1, pageSize: _pageSize || 20 });
getWorkbooks(_pageNum||1, _pageSize||20);
}}
current={pageNum}
pageSize={pageSize}
defaultCurrent={1}
total={total}
pageSizeOptions={[10,20]}
showTotal={total => `共 ${total} 条`}
/>
</Drawer>
)
}
export default WorkbookDrawer;
\ No newline at end of file
import React, { useEffect, useState } from 'react';
import { Modal, Form, Button, Space, Input, Checkbox, Row, Col, Typography } from 'antd';
import { dispatch } from '../../../../model';
import { showMessage } from '../../../../util';
const WorksheetModal = (props) => {
const { onCancel, visible, id, type = 'tableau', metadata = {} } = props;
const [ confirmLoading, setConfirmLoading ] = useState(false);
const [ form ] = Form.useForm();
useEffect(() => {
if (visible) {
form?.setFieldsValue({ tableName: metadata?.tableName, columnNames: metadata?.columnItems?.map(item => item.metadataColumnName) });
}
}, [visible, type])
const onOk = async() => {
try {
const row = await form?.validateFields();
setConfirmLoading(true);
const url = (type === 'tableau') ? 'assetmanage.saveWorkbook': 'assetmanage.saveSmartBIWorkbook';
let metadataTableId = '';
metadata?.columnItems?.forEach(item => {
if (!metadataTableId) {
metadataTableId = item.metadataTableId;
}
})
dispatch({
type: url,
payload: {
data: {
dataAssetId:id,
metadataTableId,
...row,
}
},
callback: data => {
window.open(data);
reset();
setConfirmLoading(false);
showMessage("success","新增成功");
onCancel && onCancel(true);
},
error: () => {
setConfirmLoading(false);
}
})
} catch (errInfo) {
console.log('Validate Failed:', errInfo);
setConfirmLoading(false);
}
}
const reset = () => {
setConfirmLoading(false);
form?.resetFields();
}
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 3 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 21 },
},
};
return (
<Modal
forceRender
title='工作簿信息'
visible={ visible }
width={ 600 }
onCancel={() => {
reset();
onCancel && onCancel();
}}
footer={
<Space>
<Button onClick={() => {
reset();
onCancel && onCancel();
}}>取消</Button>
<Button type="primary" onClick={ onOk } loading={ confirmLoading }>确定</Button>
</Space>
}
>
<Form form={form} style={{ maxHeight: 600, overflow: 'auto' }} {...formItemLayout}>
<Form.Item
label="名称"
name="name"
rules={[{ required: true, message: '请填写工作簿名称!' }]}
>
<Input />
</Form.Item>
<Form.Item
label="字段"
name="columnNames"
>
<Checkbox.Group>
<Row>
{
metadata?.columnItems?.map((item, index) => <Col key={index} span={8}>
<Checkbox
value={item.metadataColumnName}
style={{
lineHeight: '32px',
}}
>
<Typography.Text style={{ width: 120 }} ellipsis>{item.metadataColumnName}</Typography.Text>
</Checkbox>
</Col>)
}
</Row>
</Checkbox.Group>
</Form.Item>
<Form.Item
label="元数据"
name="tableName"
hidden={true}
>
<Input />
</Form.Item>
</Form>
</Modal>
);
}
export default WorksheetModal;
\ No newline at end of file
...@@ -2,8 +2,9 @@ import React, { useState } from 'react'; ...@@ -2,8 +2,9 @@ import React, { useState } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { Form } from 'antd'; import { Form } from 'antd';
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons'; import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons';
import { ResizableBox } from 'react-resizable';
import AssetTree from './Component/AssetTree'; import AssetTree from './Component/AssetManageTree';
import AssetDirectory from './Component/AssetDirectory'; import AssetDirectory from './Component/AssetDirectory';
import AssetTable from './Component/AssetTable'; import AssetTable from './Component/AssetTable';
import AssetAction from './Component/AssetAction'; import AssetAction from './Component/AssetAction';
...@@ -15,10 +16,12 @@ import './index.less'; ...@@ -15,10 +16,12 @@ import './index.less';
const AssetManage = (props) => { const AssetManage = (props) => {
const [ nodeId, setNodeId ] = useState(''); const [ nodeId, setNodeId ] = useState(null);
const [ nodeType, setNodeType ] = useState(''); const [ nodeType, setNodeType ] = useState('');
const [ nodeLevel, setNodeLevel ] = useState(null);
const [ assetParams, setAssetParams ] = useState({ assetId: '', assetDirId: '' }) const [ assetParams, setAssetParams ] = useState({ assetId: '', assetDirId: '' })
const [ expandTree, setExpandTree ] = useState(true); const [ expandTree, setExpandTree ] = useState(true);
const [ assetFullScreen, setAssetFullScreen ] = useState(false);
const [ assetCount, setAssetCount ] = useState(0); const [ assetCount, setAssetCount ] = useState(0);
const [ directoryChanged, setDirectoryChanged ] = useState(false); const [ directoryChanged, setDirectoryChanged ] = useState(false);
...@@ -28,9 +31,11 @@ const AssetManage = (props) => { ...@@ -28,9 +31,11 @@ const AssetManage = (props) => {
const { assetId, assetDirId } = assetParams; const { assetId, assetDirId } = assetParams;
const onTreeSelect = (value, type) => { const onTreeSelect = (value, type, level) => {
setNodeId(value||''); setNodeId(value);
setNodeType(type); setNodeType(type);
setNodeLevel(level);
} }
const onTableSelect = (id, did) => { const onTableSelect = (id, did) => {
...@@ -57,31 +62,45 @@ const AssetManage = (props) => { ...@@ -57,31 +62,45 @@ const AssetManage = (props) => {
setAssetCount(count); setAssetCount(count);
} }
const onFullScreenChange = (value) => {
setAssetFullScreen(value);
}
const classes = classNames('asset-manage', { const classes = classNames('asset-manage', {
'asset-manage-collapse': !expandTree 'asset-manage-collapse': !expandTree
}); });
const middleClasses = classNames('middle', {
'middle-fullscreen': assetFullScreen
});
return ( return (
<div className={classes}> <div className={classes}>
<div className='left'> <ResizableBox
className='left'
width={230}
height={Infinity}
axis='x'
minConstraints={[230, Infinity]} maxConstraints={[Infinity, Infinity]}
>
<AssetTree onSelect={onTreeSelect} onDirectoryChange={onDirectoryChange} {...props} /> <AssetTree onSelect={onTreeSelect} onDirectoryChange={onDirectoryChange} {...props} />
</div> </ResizableBox>
{ {
expandTree && <Separate width={15} /> expandTree && <Separate width={15} />
} }
<div className='middle'> <div className={middleClasses}>
<AssetDirectory id={nodeId} assetCount={assetCount} directoryChanged={directoryChanged} onElementsChange={onElementsChange} /> {/* <AssetDirectory id={nodeId} assetCount={assetCount} directoryChanged={directoryChanged} onElementsChange={onElementsChange} />
<Separate height={15} /> <Separate height={15} /> */}
<AssetTable nodeId={nodeId} nodeType={nodeType} reference={AssetManageReference} elementsChanged={elementsChanged} assetActionChanged={assetActionChanged} onSelect={onTableSelect} onCountChange={onAssetCountChange} {...props} /> <AssetTable nodeId={nodeId} nodeType={nodeType} nodeLevel={nodeLevel} reference={AssetManageReference} elementsChanged={elementsChanged} assetActionChanged={assetActionChanged} onSelect={onTableSelect} onCountChange={onAssetCountChange} onFullScreenChange={onFullScreenChange} {...props} />
</div>
<Separate width='15px' />
<div className='right'>
<AssetAction form={form} id={assetId} dirId={assetDirId} action='detail' onChange={onAssetActionChange} />
</div>
<div className='tree-toggle' onClick={treeToggleClick}> <div className='tree-toggle' onClick={treeToggleClick}>
{ expandTree ? <CaretLeftOutlined /> : <CaretRightOutlined /> } { expandTree ? <CaretLeftOutlined /> : <CaretRightOutlined /> }
</div> </div>
</div> </div>
{/* <Separate width='15px' />
<div className='right'>
<AssetAction form={form} id={assetId} dirId={assetDirId} action='detail' onChange={onAssetActionChange} />
</div> */}
</div>
) )
} }
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
height: 100%; height: 100%;
.left { .left {
width: 230px; flex: 0 0 auto;
border-right: 1px solid #EFEFEF; border-right: 1px solid #EFEFEF;
overflow: hidden; overflow: hidden;
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
left: 245px; left: 0px;
right: 0; right: 0;
background: #f2f5fc; background: #f2f5fc;
position: absolute; position: absolute;
...@@ -28,7 +28,13 @@ ...@@ -28,7 +28,13 @@
} }
.middle { .middle {
width: calc(100% - 230px - 400px - 30px); position: relative;
flex: 1;
overflow: hidden;
}
.middle-fullscreen {
position: static;
} }
.right { .right {
...@@ -39,14 +45,10 @@ ...@@ -39,14 +45,10 @@
.asset-manage-collapse { .asset-manage-collapse {
.left { .left {
width: 0; width: 0 !important;
} }
.tree-toggle { .tree-toggle {
left: 0; left: 0;
} }
.middle {
width: calc(100% - 400px - 30px);
}
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ import React, { useState } from "react"; ...@@ -2,7 +2,7 @@ import React, { useState } from "react";
import { Modal } from "antd"; import { Modal } from "antd";
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import AssetTree from '../../AssetManage/Component/AssetTree'; import AssetTree from '../../AssetManage/Component/AssetManageTree';
import { showMessage } from '../../../../util'; import { showMessage } from '../../../../util';
import { AssetManageReference, AssetRecycleReference, AssetMountReference } from "../../../../util/constant"; import { AssetManageReference, AssetRecycleReference, AssetMountReference } from "../../../../util/constant";
...@@ -19,7 +19,7 @@ const AssetMount = (props) => { ...@@ -19,7 +19,7 @@ const AssetMount = (props) => {
const onOk = () => { const onOk = () => {
if ((dirIds||[]).length === 0) { if ((dirIds||[]).length === 0) {
showMessage('warn', '请先选择资产目录'); showMessage('warn', '请先选择资产目录的目录');
return; return;
} }
...@@ -50,6 +50,7 @@ const AssetMount = (props) => { ...@@ -50,6 +50,7 @@ const AssetMount = (props) => {
return( return(
<Modal <Modal
forceRender
title={(reference===AssetRecycleReference)?'挂载目录详情':'变更目录详情'} title={(reference===AssetRecycleReference)?'挂载目录详情':'变更目录详情'}
visible={ visible } visible={ visible }
width={ 400 } width={ 400 }
...@@ -60,12 +61,14 @@ const AssetMount = (props) => { ...@@ -60,12 +61,14 @@ const AssetMount = (props) => {
}} }}
onOk={ onOk } onOk={ onOk }
> >
<AssetTree {
visible && <AssetTree
checkable={true} checkable={true}
onCheck={onCheck} onCheck={onCheck}
tableId={(reference===AssetManageReference&&(ids||[].length>0))?ids[0]:''} tableId={(reference===AssetManageReference&&(ids||[].length>0))?ids[0]:''}
reference={AssetMountReference} reference={AssetMountReference}
/> />
}
</Modal> </Modal>
) )
} }
......
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