Commit 9618f576 by zhaochengxiang

合并资产一期优化代码

parents 4bc2512e e4002b20
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
"crypto-js": "^4.0.0", "crypto-js": "^4.0.0",
"echarts": "^5.3.1", "echarts": "^5.3.1",
"eslint-config-react-app": "^7.0.1", "eslint-config-react-app": "^7.0.1",
"immer": "9.0.15",
"immutability-helper": "^3.1.1", "immutability-helper": "^3.1.1",
"insert-css": "^2.0.0", "insert-css": "^2.0.0",
"less": "^4.1.1", "less": "^4.1.1",
......
...@@ -8,7 +8,7 @@ import { $hostParams, ContextPath } from './util'; ...@@ -8,7 +8,7 @@ import { $hostParams, ContextPath } from './util';
import loadable from "./util/loadable"; import loadable from "./util/loadable";
import { AssetMountReference } from './util/constant'; import { AssetMountReference } from './util/constant';
import { Basic as AssetResourceTree } from './view/Manage/AssetResourceManage/change-catalog';
export const AppContext = React.createContext(); export const AppContext = React.createContext();
const Signin = loadable(()=> import('./view/Signin')); const Signin = loadable(()=> import('./view/Signin'));
...@@ -16,20 +16,23 @@ const Home = loadable(()=> import('./view/Home')); ...@@ -16,20 +16,23 @@ const Home = loadable(()=> import('./view/Home'));
const Manage = loadable(()=> import('./view/Manage')); const Manage = loadable(()=> import('./view/Manage'));
const Model = loadable(()=> import('./view/Manage/Model')); const Model = loadable(()=> import('./view/Manage/Model'));
const ModelConfig = loadable(()=> import('./view/Manage/ModelConfig')); const ModelConfig = loadable(()=> import('./view/Manage/ModelConfig'));
const AssetResourceManage = loadable(()=> import('./view/Manage/AssetResourceManage'));
const AssetManage = loadable(()=> import('./view/Manage/AssetManage')); const AssetManage = loadable(()=> import('./view/Manage/AssetManage'));
const AssetResourceBrowse = loadable(()=> import('./view/Manage/AssetResourceBrowse')); const AssetResourceBrowse = loadable(()=> import('./view/Manage/AssetResourceBrowse'));
const AssetBrowse = loadable(()=> import('./view/Manage/AssetBrowse')); const AssetBrowse = loadable(()=> import('./view/Manage/AssetBrowse'));
const TaskManage = loadable(()=> import('./view/Manage/AssetTask'));
const AssetRecycle = loadable(()=> import('./view/Manage/AssetRecycle')); const AssetRecycle = loadable(()=> import('./view/Manage/AssetRecycle'));
const AssetOperation = loadable(()=> import('./view/Manage/AssetOperation'));
const DatasourceManage = loadable(()=> import('./view/Manage/DatasourceManage')); const DatasourceManage = loadable(()=> import('./view/Manage/DatasourceManage'));
const AssetDetailPage = loadable(()=> import('./view/Manage/AssetManage/Component/AssetDetailPage')); const AssetDetailPage = loadable(()=> import('./view/Manage/AssetManage/Component/AssetDetailPage'));
const AssetDetail = loadable(()=> import('./view/Manage/AssetManage/Component/AssetDetail')); const AssetDetail = loadable(()=> import('./view/Manage/AssetManage/Component/AssetDetail'));
const ImportAction = loadable(()=> import('./view/Manage/Model/Component/ImportAction')); const ImportAction = loadable(()=> import('./view/Manage/Model/Component/ImportAction'));
const EditModel = loadable(()=> import('./view/Manage/Model/Component/EditModel')); const EditModel = loadable(()=> import('./view/Manage/Model/Component/EditModel'));
const EditTemplate = loadable(()=> import('./view/Manage/ModelConfig/Component/EditTemplate')); const EditTemplate = loadable(()=> import('./view/Manage/ModelConfig/Component/EditTemplate'));
const AssetTree = loadable(()=> import('./view/Manage/AssetManage/Component/AssetManageTree'));
const DataMasterDefine = loadable(()=> import('./view/Manage/DataMaster/Define')); const DataMasterDefine = loadable(()=> import('./view/Manage/DataMaster/Define'));
const DataMasterManage = loadable(()=> import('./view/Manage/DataMaster/Manage')); const DataMasterManage = loadable(()=> import('./view/Manage/DataMaster/Manage'));
const MetadataHarvester = loadable(() => import('./view/Manage/MetadataHarvester')); const MetadataHarvester = loadable(() => import('./view/Manage/MetadataHarvester'));
const EditAssets = loadable(()=> import('./view/Manage/AssetResourceManage/edit-assets'));
export class App extends React.Component { export class App extends React.Component {
constructor() { constructor() {
...@@ -100,10 +103,9 @@ export class App extends React.Component { ...@@ -100,10 +103,9 @@ export class App extends React.Component {
); );
} }
if (message === 'showAssetTree') { if (message === 'showAssetResourceTree') {
return ( return (
<AssetTree <AssetResourceTree
reference={AssetMountReference}
checkable={true} checkable={true}
onCheck={(values) => { onCheck={(values) => {
hostParams.callback&&hostParams.callback(values); hostParams.callback&&hostParams.callback(values);
...@@ -140,8 +142,8 @@ export class App extends React.Component { ...@@ -140,8 +142,8 @@ export class App extends React.Component {
<Route path={`${ContextPath}/manage`} component={Manage} /> <Route path={`${ContextPath}/manage`} component={Manage} />
<Route path={`${ContextPath}/data-model-action`} component={EditModel} exact /> <Route path={`${ContextPath}/data-model-action`} component={EditModel} exact />
<Route path={`${ContextPath}/model-template-action`} component={EditTemplate} exact /> <Route path={`${ContextPath}/model-template-action`} component={EditTemplate} exact />
<Route path={`${ContextPath}/asset-detail`} component={AssetDetailPage} exact /> <Route path={`${ContextPath}/asset-detail`} component={AssetDetailPage} exact />
<Route path={`${ContextPath}/edit-assets`} component={EditAssets} exact />
<Route path={'/center-home/view/datasource-manage'} component={DatasourceManage} exact /> <Route path={'/center-home/view/datasource-manage'} component={DatasourceManage} exact />
<Route path={'/center-home/view/data-model'} component={Model} exact /> <Route path={'/center-home/view/data-model'} component={Model} exact />
...@@ -154,10 +156,13 @@ export class App extends React.Component { ...@@ -154,10 +156,13 @@ export class App extends React.Component {
<Route path={'/center-home/menu/datasource-manage'} component={DatasourceManage} exact /> <Route path={'/center-home/menu/datasource-manage'} component={DatasourceManage} exact />
<Route path={'/center-home/menu/data-model'} component={Model} exact /> <Route path={'/center-home/menu/data-model'} component={Model} exact />
<Route path={'/center-home/menu/model-config'} component={ModelConfig} exact /> <Route path={'/center-home/menu/model-config'} component={ModelConfig} exact />
<Route path={'/center-home/menu/asset-resource-manage'} component={AssetResourceManage} exact />
<Route path={'/center-home/menu/asset-manage'} component={AssetManage} exact /> <Route path={'/center-home/menu/asset-manage'} component={AssetManage} exact />
<Route path={'/center-home/menu/asset-resource-browse'} component={AssetResourceBrowse} exact /> <Route path={'/center-home/menu/asset-resource-browse'} component={AssetResourceBrowse} exact />
<Route path={'/center-home/menu/asset-browse'} component={AssetBrowse} exact /> <Route path={'/center-home/menu/asset-browse'} component={AssetBrowse} exact />
<Route path={'/center-home/menu/asset-recycle'} component={AssetRecycle} exact /> <Route path={'/center-home/menu/task-manage'} component={TaskManage} exact />
<Route path={'/center-home/menu/asset-recycle'} component={AssetRecycle} exact />
<Route path={'/center-home/menu/asset-operation'} component={AssetOperation} exact />
<Route path={'/center-home/menu/msd-define'} component={DataMasterDefine} exact /> <Route path={'/center-home/menu/msd-define'} component={DataMasterDefine} exact />
<Route path={'/center-home/menu/msd-manage'} component={DataMasterManage} exact /> <Route path={'/center-home/menu/msd-manage'} component={DataMasterManage} exact />
<Route path={'/center-home/menu/metadata-harvester'} component={MetadataHarvester} exact /> <Route path={'/center-home/menu/metadata-harvester'} component={MetadataHarvester} exact />
......
...@@ -386,4 +386,8 @@ svg { ...@@ -386,4 +386,8 @@ svg {
.yy-tree .yy-tree-treenode { .yy-tree .yy-tree-treenode {
white-space: nowrap; white-space: nowrap;
}
tbody > tr > td.table-tag-cell {
padding: 12px 8px !important;
} }
\ No newline at end of file
import * as service from '../service/dataassetmanager'; import * as service from '../service/dataassetmanager';
import * as metadataService from '../service/metadata';
import { call } from 'redux-saga/effects'; import { call } from 'redux-saga/effects';
export function* importElement(payload) { export function* importElement(payload) {
...@@ -17,16 +18,16 @@ export function* listUserElements(payload) { ...@@ -17,16 +18,16 @@ export function* listUserElements(payload) {
return yield call(service.listUserElements, payload); return yield call(service.listUserElements, payload);
} }
export function* listCustomElements() { export function* listCustomElements(payload) {
return yield call(service.listCustomElements); return yield call(service.listCustomElements, payload);
} }
export function* listFilterElementIds() { export function* listFilterElementIds(payload) {
return yield call(service.listFilterElementIds); return yield call(service.listFilterElementIds, payload);
} }
export function* listFilterElements() { export function* listFilterElements(payload) {
return yield call(service.listFilterElements); return yield call(service.listFilterElements, payload);
} }
export function* listFilterElementsGroupByType(payload) { export function* listFilterElementsGroupByType(payload) {
...@@ -37,8 +38,8 @@ export function* setupFilterElementIds(payload) { ...@@ -37,8 +38,8 @@ export function* setupFilterElementIds(payload) {
return yield call(service.setupFilterElementIds, payload); return yield call(service.setupFilterElementIds, payload);
} }
export function* listFilterElementIdsConfig() { export function* listFilterElementIdsConfig(payload) {
return yield call(service.listFilterElementIdsConfig); return yield call(service.listFilterElementIdsConfig, payload);
} }
export function* setupFilterElementIdsConfig(payload) { export function* setupFilterElementIdsConfig(payload) {
...@@ -65,10 +66,22 @@ export function* getDataAssetDetail(payload) { ...@@ -65,10 +66,22 @@ export function* getDataAssetDetail(payload) {
return yield call(service.getDataAssetDetail, payload); return yield call(service.getDataAssetDetail, payload);
} }
export function* getResourceRelateDataAssetDetail(payload) {
return yield call(service.getResourceRelateDataAssetDetail, payload);
}
export function* listDataAssetsByPage(payload) { export function* listDataAssetsByPage(payload) {
return yield call(service.listDataAssetsByPage, payload); return yield call(service.listDataAssetsByPage, payload);
} }
export function* getAssetPublishStatus() {
return yield call(service.getAssetPublishStatus)
}
export function* listDataResourcesByPage(payload) {
return yield call(service.listDataResourcesByPage, payload);
}
export function* listDataAssetsByPersonalCustomType(payload) { export function* listDataAssetsByPersonalCustomType(payload) {
return yield call(service.listDataAssetsByPersonalCustomType, payload); return yield call(service.listDataAssetsByPersonalCustomType, payload);
} }
...@@ -91,6 +104,12 @@ export function* existDataAsset(payload) { ...@@ -91,6 +104,12 @@ export function* existDataAsset(payload) {
export function* queryAllDirectoryAsTree() { export function* queryAllDirectoryAsTree() {
return yield call(service.queryAllDirectoryAsTree); return yield call(service.queryAllDirectoryAsTree);
} }
export function* queryResourceManageTree() {
return yield call(service.queryResourceManageTree);
}
export function* queryDataAssetManageTree() {
return yield call(service.queryDataAssetManageTree);
}
export function* queryResourceDirectoryAsTree() { export function* queryResourceDirectoryAsTree() {
return yield call(service.queryResourceDirectoryAsTree); return yield call(service.queryResourceDirectoryAsTree);
} }
...@@ -157,6 +176,10 @@ export function* loadDataAssets(payload) { ...@@ -157,6 +176,10 @@ export function* loadDataAssets(payload) {
return yield call(service.loadDataAssets, payload); return yield call(service.loadDataAssets, payload);
} }
export function* dataAssetAddResources(payload) {
return yield call(service.dataAssetAddResources, payload);
}
export function* unloadDataAssets(payload) { export function* unloadDataAssets(payload) {
return yield call(service.unloadDataAssets, payload); return yield call(service.unloadDataAssets, payload);
} }
...@@ -189,8 +212,8 @@ export function* getAttributesByMetadataModel(payload) { ...@@ -189,8 +212,8 @@ export function* getAttributesByMetadataModel(payload) {
return yield call(service.getAttributesByMetadataModel, payload); return yield call(service.getAttributesByMetadataModel, payload);
} }
export function* loadElementWithoutCustom() { export function* loadElementWithoutCustom(payload) {
return yield call(service.loadElementWithoutCustom); return yield call(service.loadElementWithoutCustom, payload);
} }
export function* saveEleAndAttrRel(payload) { export function* saveEleAndAttrRel(payload) {
...@@ -213,10 +236,18 @@ export function* getAssetPaths(payload) { ...@@ -213,10 +236,18 @@ export function* getAssetPaths(payload) {
return yield call(service.getAssetPaths, payload); return yield call(service.getAssetPaths, payload);
} }
export function* getMetadataItems(payload) {
return yield call(service.getMetadataItems, payload);
}
export function* getResourceRelations(payload) { export function* getResourceRelations(payload) {
return yield call(service.getResourceRelations, payload); return yield call(service.getResourceRelations, payload);
} }
export function* getResourceRelateDataAssetsWhenChecking(payload) {
return yield call(service.getResourceRelateDataAssetsWhenChecking, payload);
}
export function* updateResourceState(payload) { export function* updateResourceState(payload) {
return yield call(service.updateResourceState, payload); return yield call(service.updateResourceState, payload);
} }
...@@ -231,4 +262,152 @@ export function* getPrivilegeByRangeAndDirId(payload) { ...@@ -231,4 +262,152 @@ export function* getPrivilegeByRangeAndDirId(payload) {
export function* getPreviewRangeByDirId(payload) { export function* getPreviewRangeByDirId(payload) {
return yield call(service.getPreviewRangeByDirId, payload); return yield call(service.getPreviewRangeByDirId, payload);
}
export function* resourceAddOrUpdateDirectory(payload) {
return yield call(service.resourceAddOrUpdateDirectory, payload)
}
export function* getSystems() {
return yield call(metadataService.getSystems)
}
export function* getDatasources(payload) {
return yield call(metadataService.getDatasources, payload)
}
export function* getDatabases(payload) {
return yield call(metadataService.getDatabases, payload)
}
export function* getSchemas(payload) {
return yield call(metadataService.getSchemas, payload)
}
export function* resourceTestSyncStrategy(payload) {
return yield call(service.resourceTestSyncStrategy, payload)
}
export function* getDirectoryWithSyncStrategy(payload) {
return yield call(service.getDirectoryWithSyncStrategy, payload)
}
export function* resourceSyncSchema(payload) {
return yield call(service.resourceSyncSchema, payload)
}
export function* getResourceSortingStatus() {
return yield call(service.getResourceSortingStatus)
}
export function* getResourceRelatedMetadataStatus() {
return yield call(service.getResourceRelatedMetadataStatus)
}
export function* getElementValues(payload) {
return yield call(service.getElementValues, payload)
}
export function* getResourceBatchEditInfo(payload) {
return yield call(service.getResourceBatchEditInfo, payload)
}
export function* resourceBatchEdit(payload) {
return yield call(service.resourceBatchEdit, payload)
}
export function* getResourceDraft(payload) {
return yield call(service.getResourceDraft, payload)
}
export function* syncResourceDraft(payload) {
return yield call(service.syncResourceDraft, payload)
}
export function* deleteResources(payload) {
return yield call(service.deleteResources, payload)
}
export function* checkResources(payload) {
return yield call(service.checkResources, payload)
}
export function* addOrUpdateResource(payload) {
return yield call(service.addOrUpdateResource, payload)
}
export function* resourceAddAsAsset(payload) {
return yield call(service.resourceAddAsAsset, payload)
}
export function* resourceFillElementValueBeforeAddAsAsset(payload) {
return yield call(service.resourceFillElementValueBeforeAddAsAsset, payload)
}
export function* resourceCombineDataAsset(payload) {
return yield call(service.resourceCombineDataAsset, payload)
}
export function* changeElementValue(payload) {
return yield call(service.changeElementValue, payload)
}
export function* getDistinctValuesByElementId(payload) {
return yield call(service.getDistinctValuesByElementId, payload)
}
export function* getTasks(payload) {
return yield call(service.getTasks, payload)
}
export function* distributeTask(payload) {
return yield call(service.distributeTask, payload)
}
export function* reDistributeTask(payload) {
return yield call(service.reDistributeTask, payload)
}
export function* autoDistributeTask(payload) {
return yield call(service.autoDistributeTask, payload)
}
export function* listAutoDistributeUserDepartments(payload) {
return yield call(service.listAutoDistributeUserDepartments, payload)
}
export function* getNoticeTypes(payload) {
return yield call(service.getNoticeTypes, payload)
}
export function* listDistributeAbleUsersByName(payload) {
return yield call(service.listDistributeAbleUsersByName, payload)
}
export function* getMetadataColumns(payload) {
return yield call(metadataService.getMetadataColumns, payload)
}
export function* operationOverview() {
return yield call(service.operationOverview)
}
export function* getOperationSupportDataAssetStatisticsObject() {
return yield call(service.getOperationSupportDataAssetStatisticsObject)
}
export function* getOperationSupportResourceStatisticsObject() {
return yield call(service.getOperationSupportResourceStatisticsObject)
}
export function* operationCountByStatisticsObject(payload) {
return yield call(service.operationCountByStatisticsObject, payload)
}
export function* getOperationPopularDataAssetRanking() {
return yield call(service.getOperationPopularDataAssetRanking)
}
export function* getOperationLatestDataAssetRanking() {
return yield call(service.getOperationLatestDataAssetRanking)
} }
\ No newline at end of file
...@@ -24,6 +24,10 @@ export const routes = [ ...@@ -24,6 +24,10 @@ export const routes = [
text: '模型配置', text: '模型配置',
}, },
{ {
name: 'asset-resource-manage',
text: '资源管理',
},
{
name: 'asset-manage', name: 'asset-manage',
text: '资产管理', text: '资产管理',
}, },
...@@ -36,10 +40,18 @@ export const routes = [ ...@@ -36,10 +40,18 @@ export const routes = [
text: '资产浏览' text: '资产浏览'
}, },
{ {
name: 'task-manage',
text: '任务管理',
},
{
name: 'asset-recycle', name: 'asset-recycle',
text: '未挂载资产', text: '未挂载资产',
}, },
{ {
name: 'asset-operation',
text: '资产运营',
},
{
name: 'msd-define', name: 'msd-define',
text: '主数据定义' text: '主数据定义'
}, },
......
...@@ -16,16 +16,16 @@ export function listUserElements(payload) { ...@@ -16,16 +16,16 @@ export function listUserElements(payload) {
return PostJSON("/dataassetmanager/elementApi/listSelectedRangeElements", payload); return PostJSON("/dataassetmanager/elementApi/listSelectedRangeElements", payload);
} }
export function listCustomElements() { export function listCustomElements(payload) {
return GetJSON("/dataassetmanager/elementApi/listCustomElements"); return GetJSON("/dataassetmanager/elementApi/listCustomElements", payload);
} }
export function listFilterElementIds() { export function listFilterElementIds(payload) {
return GetJSON("/dataassetmanager/elementApi/listFilterElementIds"); return GetJSON("/dataassetmanager/elementApi/listFilterElementIds", payload);
} }
export function listFilterElements() { export function listFilterElements(payload) {
return GetJSON("/dataassetmanager/elementApi/listFilterElements"); return GetJSON("/dataassetmanager/elementApi/listFilterElements", payload);
} }
export function listFilterElementsGroupByType(payload) { export function listFilterElementsGroupByType(payload) {
...@@ -36,8 +36,8 @@ export function setupFilterElementIds(payload) { ...@@ -36,8 +36,8 @@ export function setupFilterElementIds(payload) {
return PostJSON("/dataassetmanager/elementApi/setupFilterElementIds", payload); return PostJSON("/dataassetmanager/elementApi/setupFilterElementIds", payload);
} }
export function listFilterElementIdsConfig() { export function listFilterElementIdsConfig(payload) {
return PostJSON("/dataassetmanager/configApi/listFilterElementIds"); return PostJSON("/dataassetmanager/configApi/listFilterElementIds", payload);
} }
export function setupFilterElementIdsConfig(payload) { export function setupFilterElementIdsConfig(payload) {
...@@ -45,7 +45,7 @@ export function setupFilterElementIdsConfig(payload) { ...@@ -45,7 +45,7 @@ export function setupFilterElementIdsConfig(payload) {
} }
export function addOrUpdateDataAsset(payload) { export function addOrUpdateDataAsset(payload) {
return PostJSON("/dataassetmanager/dataAssetApi/addOrUpdateDataAsset", payload); return PostJSON("/dataassetmanager/dataAssetApi/addDataAsset", payload);
} }
export function checkCodeIsExist(payload) { export function checkCodeIsExist(payload) {
...@@ -64,8 +64,20 @@ export function getDataAssetDetail(payload) { ...@@ -64,8 +64,20 @@ export function getDataAssetDetail(payload) {
return GetJSON("/dataassetmanager/dataAssetApi/getDataAssetDetail", payload); return GetJSON("/dataassetmanager/dataAssetApi/getDataAssetDetail", payload);
} }
export function getResourceRelateDataAssetDetail(payload) {
return GetJSON("/dataassetmanager/resourceApi/getResourceRelateDataAssetDetail", payload)
}
export function listDataAssetsByPage(payload) { export function listDataAssetsByPage(payload) {
return GetJSON("/dataassetmanager/dataAssetApi/listDataAssetsByPage", payload); return PostJSON("/dataassetmanager/dataAssetApi/listDataAssetsByPage", payload);
}
export function getAssetPublishStatus() {
return GetJSON("/dataassetmanager/dataAssetApi/listPublishStatus");
}
export function listDataResourcesByPage(payload) {
return PostJSON("/dataassetmanager/resourceApi/listResourcesByPage", payload);
} }
export function listDataAssetsByPersonalCustomType(payload) { export function listDataAssetsByPersonalCustomType(payload) {
...@@ -80,6 +92,10 @@ export function loadDataAssets(payload) { ...@@ -80,6 +92,10 @@ export function loadDataAssets(payload) {
return PostJSON("/dataassetmanager/dataAssetApi/loadDataAssets", payload); return PostJSON("/dataassetmanager/dataAssetApi/loadDataAssets", payload);
} }
export function dataAssetAddResources(payload) {
return PostJSON("/dataassetmanager/dataAssetApi/addResources", payload);
}
export function unloadDataAssets(payload) { export function unloadDataAssets(payload) {
return PostJSON("/dataassetmanager/dataAssetApi/unloadDataAssetsByDataAssetIdAndDirId", payload); return PostJSON("/dataassetmanager/dataAssetApi/unloadDataAssetsByDataAssetIdAndDirId", payload);
} }
...@@ -108,6 +124,10 @@ export function getAssetPaths(payload) { ...@@ -108,6 +124,10 @@ export function getAssetPaths(payload) {
return GetJSON("/dataassetmanager/dataAssetApi/getMultiPath", payload); return GetJSON("/dataassetmanager/dataAssetApi/getMultiPath", payload);
} }
export function getMetadataItems(payload) {
return PostJSON("/dataassetmanager/dataAssetApi/getMetadataItems", payload);
}
export function addOrUpdateDirectory(payload) { export function addOrUpdateDirectory(payload) {
return PostJSON("/dataassetmanager/directoryApi/addOrUpdateDirectory", payload); return PostJSON("/dataassetmanager/directoryApi/addOrUpdateDirectory", payload);
} }
...@@ -128,8 +148,16 @@ export function queryAllDirectoryAsTree() { ...@@ -128,8 +148,16 @@ export function queryAllDirectoryAsTree() {
return GetJSON("/dataassetmanager/directoryApi/queryAllDirectoryAsTree"); return GetJSON("/dataassetmanager/directoryApi/queryAllDirectoryAsTree");
} }
export function queryResourceManageTree() {
return GetJSON("/dataassetmanager/resourceApi/queryResourceManageTree")
}
export function queryDataAssetManageTree() {
return GetJSON("/dataassetmanager/dataAssetApi/queryDataAssetManageTree");
}
export function queryResourceDirectoryAsTree() { export function queryResourceDirectoryAsTree() {
return PostJSON("/dataassetmanager/directoryApi/querySourceTypeAsTree"); return GetJSON("/dataassetmanager/directoryApi/querySourceTypeAsTree");
} }
export function queryAssetDirectoryAsTree() { export function queryAssetDirectoryAsTree() {
...@@ -200,8 +228,8 @@ export function getAttributesByMetadataModel(payload) { ...@@ -200,8 +228,8 @@ export function getAttributesByMetadataModel(payload) {
return GetJSON("/dataassetmanager/eleAndAttrApi/getModelAttributes", payload); return GetJSON("/dataassetmanager/eleAndAttrApi/getModelAttributes", payload);
} }
export function loadElementWithoutCustom() { export function loadElementWithoutCustom(payload) {
return GetJSON("/dataassetmanager/eleAndAttrApi/loadElementWithoutCustom"); return GetJSON("/dataassetmanager/eleAndAttrApi/loadElementWithoutCustom", payload);
} }
export function saveEleAndAttrRel(payload) { export function saveEleAndAttrRel(payload) {
...@@ -224,6 +252,10 @@ export function getResourceRelations(payload) { ...@@ -224,6 +252,10 @@ export function getResourceRelations(payload) {
return GetJSON("/dataassetmanager/resourceApi/getResourceRelations", payload); return GetJSON("/dataassetmanager/resourceApi/getResourceRelations", payload);
} }
export function getResourceRelateDataAssetsWhenChecking(payload) {
return GetJSON("/dataassetmanager/resourceApi/getResourceRelateDataAssetsWhenChecking", payload);
}
export function updateResourceState(payload) { export function updateResourceState(payload) {
return PostJSON("/dataassetmanager/resourceApi/updateResourceState", payload); return PostJSON("/dataassetmanager/resourceApi/updateResourceState", payload);
} }
...@@ -238,4 +270,132 @@ export function getPrivilegeByRangeAndDirId(payload) { ...@@ -238,4 +270,132 @@ export function getPrivilegeByRangeAndDirId(payload) {
export function getPreviewRangeByDirId(payload) { export function getPreviewRangeByDirId(payload) {
return Get("/dataassetmanager/dataAssetApi/getPreviewRangeByDirId", payload); return Get("/dataassetmanager/dataAssetApi/getPreviewRangeByDirId", payload);
}
export function resourceAddOrUpdateDirectory(payload) {
return PostJSON("/dataassetmanager/resourceApi/addOrUpdateDirectory", payload);
}
export function resourceTestSyncStrategy(payload) {
return Post("/dataassetmanager/resourceApi/testSyncStrategy", payload)
}
export function getDirectoryWithSyncStrategy(payload) {
return GetJSON("/dataassetmanager/resourceApi/getDirectoryWithSyncStrategy", payload)
}
export function resourceSyncSchema(payload) {
return Post("/dataassetmanager/resourceApi/syncSchema", payload);
}
export function getResourceSortingStatus() {
return GetJSON("/dataassetmanager/resourceApi/listSortingStatus");
}
export function getResourceRelatedMetadataStatus() {
return GetJSON("/dataassetmanager/resourceApi/listRelatedMetadataStatus");
}
export function getElementValues(payload) {
return GetJSON("/dataassetmanager/parameterApi/conf/getPropertiesByDataAssetType", payload);
}
export function getResourceBatchEditInfo(payload) {
return GetJSON("/dataassetmanager/resourceApi/getBatchEditInfo", payload)
}
export function resourceBatchEdit(payload) {
return PostJSON("/dataassetmanager/resourceApi/batchEdit", payload)
}
export function getResourceDraft(payload) {
return GetJSON("/dataassetmanager/resourceApi/getDraft", payload)
}
export function syncResourceDraft(payload) {
return PostJSON("/dataassetmanager/resourceApi/syncDraft", payload)
}
export function deleteResources(payload) {
return PostJSON("/dataassetmanager/resourceApi/deleteResources", payload)
}
export function checkResources(payload) {
return PostJSON("/dataassetmanager/resourceApi/check", payload)
}
export function addOrUpdateResource(payload) {
return PostJSON("/dataassetmanager/resourceApi/addResource", payload);
}
export function resourceAddAsAsset(payload) {
return PostJSON("/dataassetmanager/resourceApi/addAsAsset", payload);
}
export function resourceFillElementValueBeforeAddAsAsset(payload) {
return GetJSON("/dataassetmanager/resourceApi/fillElementValueBeforeAddAsAsset", payload);
}
export function resourceCombineDataAsset(payload) {
return PostJSON("/dataassetmanager/resourceApi/combineExistDataAsset", payload);
}
export function changeElementValue(payload) {
return PostJSON("/dataassetmanager/resourceApi/batchChangeElementValue", payload);
}
export function getDistinctValuesByElementId(payload) {
return GetJSON("/dataassetmanager/resourceApi/getDistinctValuesByElementId", payload);
}
export function getTasks(payload) {
return GetJSON("/dataassetmanager/resource/taskApi/listTasksByPage", payload)
}
export function distributeTask(payload) {
return PostJSON("/dataassetmanager/resource/taskApi/distributeTask", payload)
}
export function reDistributeTask(payload) {
return PostJSON("/dataassetmanager/resource/taskApi/reDistributeTask", payload)
}
export function autoDistributeTask(payload) {
return PostJSON("/dataassetmanager/resource/taskApi/autoDistributeTask", payload)
}
export function listAutoDistributeUserDepartments(payload) {
return PostJSON("/dataassetmanager/resource/taskApi/listAutoDistributeUserDepartments", payload)
}
export function getNoticeTypes() {
return GetJSON("/dataassetmanager/resource/taskApi/listNoticeTypes")
}
export function listDistributeAbleUsersByName(payload) {
return GetJSON("/dataassetmanager/userApi/listDistributeAbleUsersByName", payload)
}
export function operationOverview() {
return GetJSON("/dataassetmanager/operationApi/statisticalOverview")
}
export function getOperationSupportDataAssetStatisticsObject() {
return GetJSON("/dataassetmanager/operationApi/listSupportDataAssetStatisticsObject")
}
export function getOperationSupportResourceStatisticsObject() {
return GetJSON("/dataassetmanager/operationApi/listSupportResourceStatisticsObject")
}
export function operationCountByStatisticsObject(payload) {
return PostJSON("/dataassetmanager/operationApi/countByStatisticsObject", payload)
}
export function getOperationPopularDataAssetRanking() {
return GetJSON("/dataassetmanager/operationApi/getPopularDataAssetRanking")
}
export function getOperationLatestDataAssetRanking() {
return GetJSON("/dataassetmanager/operationApi/getLatestDataAssetRanking")
} }
\ No newline at end of file
import { GetJSON } from "../util/axios" import { GetJSON, PostJSON } 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);
...@@ -18,4 +18,24 @@ export function queryAllFields(payload) { ...@@ -18,4 +18,24 @@ export function queryAllFields(payload) {
export function getSystemAllGraph(payload) { export function getSystemAllGraph(payload) {
return GetJSON("/metadatarelation/getSystemAllGraph", payload); return GetJSON("/metadatarelation/getSystemAllGraph", payload);
}
export function getSystems() {
return PostJSON('/metadatarepo/rest/system/listAllSystem')
}
export function getDatasources(payload) {
return GetJSON('/metadatarepo/rest/user/getUserSystem', payload)
}
export function getDatabases(payload) {
return PostJSON('/metadatarepo/rest/metadata/getChildBySysAndPath', payload)
}
export function getSchemas(payload) {
return GetJSON('/metadatarepo/rest/query/getChildBySys', payload)
}
export function getMetadataColumns(payload) {
return PostJSON('/metadatarepo/rest/metadata/getChild', payload)
} }
\ No newline at end of file
// @import (reference) "@/less" 只导入变量
@ant-prefix: foobar;
.ssetable {
.react-resizable{
position: relative;
background-clip: padding-box;
user-select: none;
}
.react-resizable-handle {
position: absolute;
width: 10px;
height: 100%;
bottom: 0;
right: -5px;
cursor: col-resize;
// background: red;
z-index: 999;
}
.@{ant-prefix}-table-thead > tr > th {
padding: 8px 8px !important;
white-space: nowrap;
text-overflow: ellipsis;
}
// .@{ant-prefix}-table-tbody > tr > td {
// padding: 12px 8px !important;
// }
.@{ant-prefix}-table-tbody > .@{ant-prefix}-table-measure-row > td {
padding: 0px !important;
}
.@{ant-prefix}-table-tbody > tr .@{ant-prefix}-table-row-selected > td {
background: #fff !important;
}
tr.@{ant-prefix}-table-expanded-row > td {
padding: 0 !important;
background: #fff !important;
}
tr.@{ant-prefix}-table-expanded-row {
.@{ant-prefix}-table {
margin: 0 !important;
}
}
.@{ant-prefix}-table-thead > tr > th {
background-color: #F2F5FC !important;
}
}
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { PaginationProps, Table, TableColumnType, TableProps } from 'antd'
import type { SortOrder, ColumnGroupType, ColumnType } from 'antd/lib/table/interface'
import { Resizable } from 'react-resizable'
import ResizeObserver from 'rc-resize-observer'
import produce from 'immer'
import { nanoid } from 'nanoid'
import { getScrollbarWidth } from '..'
import { defaultPageSizeOptions } from '../hooks/page'
import ToolTip from './Tooltip'
import { Menu, useContextMenu } from 'react-contexify'
import { generateUUID } from ".."
import PermissionRcItem from './PermissionRcItem'
import 'react-contexify/dist/ReactContexify.css'
import './Table.less'
interface Props<RowType> {
width: number
maxHeight?: string | number
pageSize: number
pageNum: number
total: number
pageSizeOptions: string[] | number[]
onPaginate: PaginationProps["onChange"]
rowSelection?: TableProps<RowType>
bodyCell: any
extraColWidth?: number
menuData: string[]
menuPermissions: string[]
onMenuItemClick: Function
onRowClick: Function
shouldRowContextMenu: Function
}
const scrollbarWidth = getScrollbarWidth()
function FC<RowType extends object = any>({ width, maxHeight, pageSize, pageNum, total, pageSizeOptions, onPaginate, columns, bodyCell, extraColWidth = 0, menuData, menuPermissions, onMenuItemClick, onRowClick, shouldRowContextMenu, ...rest }: TableProps<RowType> & Props<RowType>) {
type Columns = typeof columns
const MENU_ID = generateUUID()
const [tableWidth, setTableWidth] = useState(0)
const { show } = useContextMenu({
id: MENU_ID,
})
const paddingCol = useRef<TableColumnType<any>>({
key: 'padding',
width: 0,
render: () => undefined
})
const handleResize = (index: number) => (e: any, { size }: any) => {
setCols((prevCols) => {
const nextColumns = [...(prevCols ?? [])];
nextColumns[index] = {
...nextColumns[index],
width: size.width,
};
return nextColumns;
});
};
const [cols, setCols] = useState<Columns>()
useEffect(() => {
if (!!columns && tableWidth > 0) {
const contentWidth = getWidth(width ?? tableWidth,extraColWidth)
setDefaultWidth(columns, contentWidth)
paddingCol.current.width = 0
const cols = columns
.map((col, index) => {
const render = getRender(col);
const colWidth = col.width ?? 100;
return {
...col, /* colRef: createRef(), */ width: colWidth, render, ellipsis: true,
onHeaderCell: (column: any) => ({
width: column.width,
// colRef: column.colRef,
onResize: handleResize(index),
}),
};
})
setCols(cols)
}
}, [columns, tableWidth, width, extraColWidth])
// add padding column
const cols1 = useMemo(() => !!cols ? [...cols, paddingCol.current] : undefined, [cols, pageSize, pageNum])
const scroll = useMemo(() => (maxHeight === undefined || total === 0 /* fix 暂无数据显示滚动条? */ ? { x: '100%' } : { y: maxHeight, x: '100%' /* 'max-content' 所有列显示全宽*/ }), [maxHeight, total])
const ref = useRef<HTMLDivElement>(null)
const [rightClickNode, setRightClickNode] = React.useState(undefined)
const handleContextMenu = (event, node) => {
show(event, {
position: {
x: event.clientX + 30,
y: event.clientY - 10
}
})
}
return (
<ResizeObserver
onResize={(size) => {
setTableWidth(size?.width)
}}
>
<Table
ref={ref}
className="ssetable"
size='middle'
rowKey="id" // could be overrided in rest.
showSorterTooltip={false}
columns={cols1}
pagination={{
pageSizeOptions: pageSizeOptions ?? defaultPageSizeOptions, showSizeChanger: true,
position: ['bottomCenter'], pageSize, current: pageNum, total, onChange: onPaginate,
showTotal: total => `共 ${total} 条`,
}}
components={{
body: {
cell: bodyCell ?? null
},
header: {
cell: ResizableTitle,
},
}}
onRow={(record, index) => {
return {
id: record?.id,
onClick: event => {
onRowClick?.(event, record)
},
onContextMenu: event => {
setRightClickNode(record)
if (shouldRowContextMenu?.(record)) {
handleContextMenu(event, record)
}
},
}
}}
scroll={scroll}
{...rest}
/>
<Menu id={MENU_ID}>
{
menuData?.map(item => <PermissionRcItem
key={item}
id={item}
disabled={rightClickNode?.[`${item}`]?.disabled}
tip={rightClickNode?.[`${item}`]?.tip}
permissions={rightClickNode?.permissions||menuPermissions}
permissionKey={item}
onClick={() => onMenuItemClick?.(item, rightClickNode)}>
{item}
</PermissionRcItem>)
}
</Menu>
</ResizeObserver>
)
}
// 可变列宽
const ResizableTitle = (props: any) => {
const { onResize, width, ...restProps } = props;
if (!width) {
return <th {...restProps} />;
}
return (
<Resizable
width={width}
height={0}
handle={
<span
className="react-resizable-handle"
onClick={e => {
e.stopPropagation();
}}
/>
}
onResize={onResize}
draggableOpts={{ enableUserSelectHack: false }}
>
<th {...restProps} />
</Resizable>
);
};
function setDefaultWidth(columns: any[], width: number) {
let rowWidth = 0, count = 0
for (const col of columns) {
if (typeof col.width === 'number') {
rowWidth += col.width
} else {
count++
}
}
if (count > 0) {
const defaultW = (rowWidth > width ? 0 : width - rowWidth) / count
for (const col of columns) {
if (typeof col.width !== 'number') {
col.width = (defaultW < 100) ? 100 : defaultW
}
}
}
}
function getWidth(tableWidth: number, extraColWidth: number): number {
return tableWidth - scrollbarWidth - extraColWidth // scrollbar width, checkbox column
}
function getRender<T>(col: ColumnGroupType<T> | ColumnType<T>) {
return (value: any, record: T, index: number) => {
// 用户自定render
if (col.render) {
const rs = col.render(value, record, index)
if (typeof rs === 'string') {
return (<ToolTip msg={rs} defaultStyle />)
}
return rs
} else {
return (<ToolTip msg={value} defaultStyle />)
}
}
}
export default FC
export function getStringSorter<T>(k: keyof T) {
return (a: T, b: T, sortOrder?: SortOrder) => {
const aVal = a[k], bVal = b[k]
if (typeof aVal === 'string' && typeof bVal === 'string')
return aVal.localeCompare(bVal);
return 0
}
}
export function getNumberSorter<T>(k: keyof T) {
return (a: T, b: T, sortOrder?: SortOrder) => {
const aVal = a[k], bVal = b[k]
if (typeof aVal === 'number' && typeof bVal === 'number')
return aVal - bVal;
return 0
}
}
export function generateId<T = any>(data: T[], id = 'id') {
return produce(data, (draft) => {
draft?.forEach((row: any) => {
row[id] = nanoid()
})
})
}
export function generateIdFromArrayRow<T extends unknown[]>(data?: T[], id = 'id'): unknown[] | undefined {
return data?.map((row, i) => {
const obj: { [key: string]: unknown } = { [id]: nanoid() }
row.forEach((cell, j) => {
obj[j] = cell
})
return obj
})
}
export function filterRows<RowType = unknown>(rows: RowType[] | undefined, filter: (row: RowType) => boolean) {
if (rows) {
const matched = rows.filter(filter)
return matched
}
return rows
}
\ No newline at end of file
import React, { CSSProperties, HTMLAttributes, useEffect, useRef, useState } from "react";
import { Tooltip as Tooltip_, TooltipProps } from "antd";
import type { TooltipPlacement } from "antd/es/tooltip";
const DefaultStyle: CSSProperties = {
overflow: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
// backgroundColor: "red"
}
export default function ({ msg, defaultStyle, style, placement, children, ...rest }: { msg: string | JSX.Element, defaultStyle?: boolean, placement?: TooltipPlacement } & HTMLAttributes<any>) {
const wrapper = useRef<HTMLDivElement>(null);
const text = useRef<HTMLSpanElement>(null);
const [toolTip, setToolTip] = useState(false);
useEffect(() => {
const wrapperRect = wrapper.current!.getBoundingClientRect(),
textRect = text.current!.getBoundingClientRect();
if (wrapperRect.width < textRect.width) {
setToolTip(true);
}
}, [msg]);
const _text = (
<div
ref={wrapper}
style={defaultStyle ? { ...DefaultStyle, ...style } : style}
{...rest}
>
<span ref={text}>{children ?? msg}</span>
{/* {msg} */}
</div>
);
if (toolTip) {
return <Tooltip_ title={msg} placement={placement} /* color="#fff" overlayInnerStyle={{ color: '#000' }} */ >{_text}</Tooltip_>;
} else {
return _text;
}
}
export const Tooltip = ({ children, color, ...props }: TooltipProps) => {
return <Tooltip_ /* color="#fff" overlayInnerStyle={{ color: '#000' }} */ {...props} >{children}</Tooltip_>
}
\ No newline at end of file
import React from "react"
import { Tree } from "antd"
import { Menu, Item, useContextMenu } from 'react-contexify'
import { generateUUID } from ".."
import 'react-contexify/dist/ReactContexify.css';
const FC = ({ shouldRowContextMenu, menuData, onMenuItemClick, ...restProps }) => {
const MENU_ID = generateUUID()
const { show } = useContextMenu({
id: MENU_ID,
})
const [rightClickNode, setRightClickNode] = React.useState(undefined)
const handleContextMenu = (event, node) => {
show(event, {
position: {
x: event.clientX + 30,
y: event.clientY - 10
}
})
}
return (
<div>
<Tree
onRightClick={({event, node}) => {
setRightClickNode(node)
if (shouldRowContextMenu?.(node)) {
handleContextMenu(event, node)
}
}}
{...restProps}
/>
<Menu id={MENU_ID}>
{
menuData?.map(item => <Item key={item.id} id={item.id} onClick={() => onMenuItemClick?.(item.id, rightClickNode)}>{item.title}</Item>)
}
</Menu>
</div>
)
}
export default FC
\ No newline at end of file
...@@ -23,6 +23,7 @@ export const DataModelerRoleUser = 'user'; ...@@ -23,6 +23,7 @@ export const DataModelerRoleUser = 'user';
export const DataModelerRoleReader = 'reader'; export const DataModelerRoleReader = 'reader';
//资产 //资产
export const ResourceManageReference = 'resource-manage';
export const AssetManageReference = 'asset-manage'; export const AssetManageReference = 'asset-manage';
export const AssetBrowseReference = 'asset-browse'; export const AssetBrowseReference = 'asset-browse';
export const ResourceBrowseReference = 'resource-browse'; export const ResourceBrowseReference = 'resource-browse';
......
import { useState } from "react"
export interface Page {
pageSize: number
pageNum: number
}
export const defaultPageSize = 20
export const defaultPageSizeOptions = [10, 20, 50, 100]
export type PageSizeOptions = typeof defaultPageSizeOptions[number]
export const defaultPage = {
pageSize: defaultPageSize,
pageNum: 1
}
export function usePage(pageSize?: number): [Page, React.Dispatch<React.SetStateAction<Page>>, (pageNum: number) => void] {
const [page, setPage] = useState<Page>(() => ({
pageSize: pageSize ?? defaultPageSize, pageNum: 1,
}))
const gotoPage = (pageNum: number) => {
setPage(prev => ({ ...prev, pageNum }))
}
return [page, setPage, gotoPage]
}
export type PageType = ReturnType<typeof usePage>[0]
export function paginate<T>(list: T[] | undefined, page: Page) {
if (list) {
const { pageSize, pageNum } = page
const start = (pageNum - 1) * pageSize
const end = start + pageSize
return list.slice(start, end)
}
return list
}
\ No newline at end of file
...@@ -8,7 +8,7 @@ import LocalStorage from 'local-storage'; ...@@ -8,7 +8,7 @@ import LocalStorage from 'local-storage';
import { dispatchLatest, action } from '../model'; import { dispatchLatest, action } from '../model';
import { set_sess_state } from "../model/reducer"; import { set_sess_state } from "../model/reducer";
import { DataModelerRoleAdmin, DataModelerRoleUser, DataModelerRoleReader, AssetManageReference, AssetBrowseReference, ResourceBrowseReference, AssetRecycleReference } from './constant'; import { DataModelerRoleAdmin, DataModelerRoleUser, DataModelerRoleReader, AssetManageReference, AssetBrowseReference, ResourceBrowseReference, AssetRecycleReference, ResourceManageReference } from './constant';
//内网深交所环境 isSzseEnv true //内网深交所环境 isSzseEnv true
//元曜公网环境 isSzseEnv false //元曜公网环境 isSzseEnv false
...@@ -410,8 +410,14 @@ export function getDataModelerRole(user) { ...@@ -410,8 +410,14 @@ export function getDataModelerRole(user) {
return DataModelerRoleAdmin; return DataModelerRoleAdmin;
} }
export function getAssetType(reference) {
return (reference===AssetManageReference || reference===AssetBrowseReference) ? 'dataAsset' : 'resource'
}
export function getAssetRange(menuName) { export function getAssetRange(menuName) {
if (menuName === AssetManageReference) { if (menuName === ResourceManageReference ) {
return 'dataAsset_resourceManage';
} else if (menuName === AssetManageReference) {
return 'dataAsset_dataAssetManage'; return 'dataAsset_dataAssetManage';
} else if (menuName === AssetBrowseReference) { } else if (menuName === AssetBrowseReference) {
return 'dataAsset_dataAssetBrowse'; return 'dataAsset_dataAssetBrowse';
...@@ -467,4 +473,35 @@ export function checkMenuAdmit(menuinfo) { ...@@ -467,4 +473,35 @@ export function checkMenuAdmit(menuinfo) {
} }
return false; return false;
}
export function getScrollbarWidth() {
// Creating invisible container
const outer = document.createElement('div');
outer.style.visibility = 'hidden';
outer.style.overflow = 'scroll'; // forcing scrollbar to appear
outer.style.msOverflowStyle = 'scrollbar'; // needed for WinJS apps
document.body.appendChild(outer);
// Creating inner element and placing it in the container
const inner = document.createElement('div');
outer.appendChild(inner);
// Calculating difference between container's full width and the child width
const scrollbarWidth = (outer.offsetWidth - inner.offsetWidth);
// Removing temporary elements from the DOM
outer.parentNode?.removeChild(outer);
return scrollbarWidth;
}
export function getValidString(strs) {
for (const str of strs) {
if (typeof str === 'string' && str.length > 0) {
return str
}
}
} }
\ No newline at end of file
...@@ -6,7 +6,7 @@ import { ResizableBox } from 'react-resizable'; ...@@ -6,7 +6,7 @@ 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';
import RelationContainer from './Component/RelationContainer'; import RelationContainer from './Component/RelationContainer';
import AssetTable from "../AssetManage/Component/AssetTable"; import AssetTable from "./table";
import Separate from '../AssetManage/Component/Separate'; import Separate from '../AssetManage/Component/Separate';
import { AssetBrowseReference } from '../../../util/constant'; import { AssetBrowseReference } from '../../../util/constant';
...@@ -14,9 +14,6 @@ import { AssetBrowseReference } from '../../../util/constant'; ...@@ -14,9 +14,6 @@ import { AssetBrowseReference } from '../../../util/constant';
import './index.less'; import './index.less';
const AssetBrowse = (props) => { const AssetBrowse = (props) => {
const { reference = AssetBrowseReference } = props;
const [ nodeParams, setNodeParams ] = useState({ centerId: '', expandId: '', nodeType: '' }); const [ nodeParams, setNodeParams ] = useState({ centerId: '', expandId: '', nodeType: '' });
const [ expandTree, setExpandTree ] = useState(true); const [ expandTree, setExpandTree ] = useState(true);
const [ expandRelation, setExpandRelation ] = useState(true); const [ expandRelation, setExpandRelation ] = useState(true);
...@@ -77,25 +74,25 @@ const AssetBrowse = (props) => { ...@@ -77,25 +74,25 @@ const AssetBrowse = (props) => {
axis='x' axis='x'
minConstraints={[230, Infinity]} maxConstraints={[Infinity, Infinity]} minConstraints={[230, Infinity]} maxConstraints={[Infinity, Infinity]}
> >
<AssetTree centerId={centerId} onSelect={onTreeSelect} reference={reference} {...props} /> <AssetTree centerId={centerId} onSelect={onTreeSelect} reference={AssetBrowseReference} {...props} />
</ResizableBox> </ResizableBox>
{ {
expandTree && <Separate width={15} /> expandTree && <Separate width={15} />
} }
<div className={rightClasses}> <div className={rightClasses}>
<AssetDirectory id={nodeId} assetCount={assetCount} reference={reference} nodeType={nodeParams.nodeType} /> <AssetDirectory id={nodeId} assetCount={assetCount} reference={AssetBrowseReference} 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={AssetBrowseReference} 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} nodeType={nodeParams.nodeType} reference={reference} onCountChange={onAssetCountChange} onFullScreenChange={onFullScreenChange} {...props} /> <AssetTable node={{ nodeId, type: nodeParams.nodeType }} onFullScreenChange={onFullScreenChange} {...props} />
</div> </div>
</div> </div>
<div className='tree-toggle' onClick={treeToggleClick}> <div className='tree-toggle' onClick={treeToggleClick}>
......
...@@ -5,10 +5,11 @@ import { dispatch } from '../../../../model'; ...@@ -5,10 +5,11 @@ import { dispatch } from '../../../../model';
import AssetAction from './AssetAction'; import AssetAction from './AssetAction';
import './AddAssetModel.less'; import './AddAssetModel.less';
import { AssetManageReference, ResourceManageReference } from '../../../../util/constant';
const AddAssetModel = (props) => { const AddAssetModel = (props) => {
const { onCancel, visible, nodeId } = props; const { onCancel, visible, nodeId, reference = AssetManageReference } = props;
const [ confirmLoading, setConfirmLoading ] = useState(false); const [ confirmLoading, setConfirmLoading ] = useState(false);
const [ metadataId, setMetadataId ] = useState(''); const [ metadataId, setMetadataId ] = useState('');
const [ elements, setElements ] = useState([]); const [ elements, setElements ] = useState([]);
...@@ -34,12 +35,8 @@ const AddAssetModel = (props) => { ...@@ -34,12 +35,8 @@ const AddAssetModel = (props) => {
} }
}); });
const params = { let params = {
dirId: nodeId, dirIds: nodeId,
}
if ((metadataId||'')!=='') {
params.metadataId = metadataId;
} }
setConfirmLoading(true); setConfirmLoading(true);
...@@ -55,7 +52,7 @@ const AddAssetModel = (props) => { ...@@ -55,7 +52,7 @@ const AddAssetModel = (props) => {
showMessage('warn', '已存在相同的资产编号,请重新输入'); showMessage('warn', '已存在相同的资产编号,请重新输入');
} else { } else {
dispatch({ dispatch({
type: 'assetmanage.addOrUpdateDataAsset', type: (reference===ResourceManageReference)?'assetmanage.addOrUpdateResource':'assetmanage.addOrUpdateDataAsset',
payload: { payload: {
params, params,
data: { elements: newElements } data: { elements: newElements }
...@@ -103,6 +100,7 @@ const AddAssetModel = (props) => { ...@@ -103,6 +100,7 @@ const AddAssetModel = (props) => {
form={form} form={form}
dirId={nodeId} dirId={nodeId}
action='add' action='add'
reference={reference}
onMetadataChange={onMetadataChange} onMetadataChange={onMetadataChange}
onElementsChange={onElementsChange} onElementsChange={onElementsChange}
/> />
......
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Form, Spin, Input, Descriptions, Space, Button, Tooltip } from 'antd'; import { Form, Spin, Input, Descriptions, Space, Button, Tooltip, Select } from 'antd';
import { DownOutlined, UpOutlined } from '@ant-design/icons'; import { DownOutlined, UpOutlined } from '@ant-design/icons';
import MetadataInfo from './MetadataInfo';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { highlightSearchContentByTerms, showMessage, getAssetRange, checkMenuAdmit } from '../../../../util'; import { highlightSearchContentByTerms, showMessage, getAssetRange, checkMenuAdmit, getAssetType } from '../../../../util';
import { AppContext } from '../../../../App'; import { AppContext } from '../../../../App';
import Separate from './Separate'; import Separate from './Separate';
import { AnchorId, AnchorDirId, AssetManageReference } from '../../../../util/constant'; import { AnchorId, AnchorDirId, AssetManageReference, ResourceManageReference } from '../../../../util/constant';
import PermissionButton from '../../../../util/Component/PermissionButton'; import PermissionButton from '../../../../util/Component/PermissionButton';
import DataQuality, { DataQualityFeignTagList } from '../../../QianKun/data-quality' import DataQuality, { DataQualityFeignTagList } from '../../../QianKun/data-quality'
import AssetItem from '../asset-item';
import ResourceItem from '../../AssetResourceManage/resource-item';
import { CancelSvg, EditSvg, SaveSvg, FullScreenSvg, CancelFullScreenSvg } from './AssetSvg'; import { CancelSvg, EditSvg, SaveSvg, FullScreenSvg, CancelFullScreenSvg } from './AssetSvg';
import { Subject } from 'rxjs';
export const AssetActionSubject = new Subject();
const AssetAction = (props) => { const AssetAction = (props) => {
const { id, dirId, action, terms, onChange, readOnly = false, form, onMetadataChange, onElementsChange, reference = AssetManageReference } = props; const { id, dirId, action, terms, onChange, readOnly = false, form, onMetadataChange, onElementsChange, reference = AssetManageReference } = props;
...@@ -81,7 +85,8 @@ const AssetAction = (props) => { ...@@ -81,7 +85,8 @@ const AssetAction = (props) => {
type: 'assetmanage.listElements', type: 'assetmanage.listElements',
payload: { payload: {
params: { params: {
range: getAssetRange(reference) range: getAssetRange(reference),
dataAssetType: getAssetType(reference),
} }
}, },
callback: data => { callback: data => {
...@@ -120,7 +125,8 @@ const AssetAction = (props) => { ...@@ -120,7 +125,8 @@ const AssetAction = (props) => {
type: 'assetmanage.listUserElements', type: 'assetmanage.listUserElements',
payload: { payload: {
params: { params: {
range: getAssetRange(reference) range: getAssetRange(reference),
dataAssetType: getAssetType(reference)
} }
}, },
callback: data => { callback: data => {
...@@ -228,25 +234,18 @@ const AssetAction = (props) => { ...@@ -228,25 +234,18 @@ const AssetAction = (props) => {
} }
const jumpToRelation = (relation) => { const jumpToRelation = (relation) => {
if (!readOnly) { const timestamp = new Date().getTime();
let event = new Event('storage');
event.key = 'assetRelationOnClickEvent';
event.relation = relation;
window?.dispatchEvent(event);
} else {
const timestamp = new Date().getTime();
if (relation.resourceType==='innerSource'||relation.resourceType==='outerSource') { if (relation.resourceType==='innerSource'||relation.resourceType==='outerSource') {
if (checkMenuAdmit('asset-resource-browse')) { if (checkMenuAdmit('asset-resource-browse')) {
window.open(`/center-home/menu/asset-resource-browse?${AnchorId}=${relation?.dataAssetId}&${AnchorDirId}=${relation?.dirId}&timestamp=${timestamp}`); window.open(`/center-home/menu/asset-resource-browse?${AnchorId}=${relation?.dataAssetId}&${AnchorDirId}=${relation?.dirId}&timestamp=${timestamp}`);
} }
} else if (relation.resourceType==='dataAsset') { } else if (relation.resourceType==='dataAsset') {
if (checkMenuAdmit('asset-browse')) { if (checkMenuAdmit('asset-browse')) {
window.open(`/center-home/menu/asset-browse?${AnchorId}=${relation?.dataAssetId}&${AnchorDirId}=${relation?.dirId}&timestamp=${timestamp}`); window.open(`/center-home/menu/asset-browse?${AnchorId}=${relation?.dataAssetId}&${AnchorDirId}=${relation?.dirId}&timestamp=${timestamp}`);
}
} else {
showMessage('warn', '资产类型不是资源也不是资产!');
} }
} else {
showMessage('warn', '资产类型不是资源也不是资产!');
} }
} }
...@@ -261,12 +260,8 @@ const AssetAction = (props) => { ...@@ -261,12 +260,8 @@ const AssetAction = (props) => {
} }
}); });
const params = { let params = {
dirId, dirIds: dirId,
}
if ((metadataId||'')!=='') {
params.metadataId = metadataId;
} }
setConfirmLoading(true); setConfirmLoading(true);
...@@ -282,7 +277,7 @@ const AssetAction = (props) => { ...@@ -282,7 +277,7 @@ const AssetAction = (props) => {
showMessage('warn', '已存在相同的资产编号,请重新输入'); showMessage('warn', '已存在相同的资产编号,请重新输入');
} else { } else {
dispatch({ dispatch({
type: 'assetmanage.addOrUpdateDataAsset', type: (reference===ResourceManageReference)?'assetmanage.addOrUpdateResource':'assetmanage.addOrUpdateDataAsset',
payload: { payload: {
params, params,
data: action==='add' ? { elements: newElements } : { ...assets, elements: newElements } data: action==='add' ? { elements: newElements } : { ...assets, elements: newElements }
...@@ -293,6 +288,9 @@ const AssetAction = (props) => { ...@@ -293,6 +288,9 @@ const AssetAction = (props) => {
getAsset(); getAsset();
showMessage("success",(action==='add')?"新增成功":"修改成功"); showMessage("success",(action==='add')?"新增成功":"修改成功");
onChange && onChange(); onChange && onChange();
if (action !== 'add') {
AssetActionSubject.next({ type: 'asset-change' })
}
}, },
error: () => { error: () => {
setConfirmLoading(false); setConfirmLoading(false);
...@@ -535,8 +533,6 @@ const AssetAction = (props) => { ...@@ -535,8 +533,6 @@ const AssetAction = (props) => {
setMetadataId(state.data?.metadataId||''); setMetadataId(state.data?.metadataId||'');
onMetadataChange && onMetadataChange(state.data?.metadataId||''); onMetadataChange && onMetadataChange(state.data?.metadataId||'');
form?.setFieldsValue({ '资产项': state.data?.metadataInfoJson||'' });
if ((state.data?.metadataId||'') !== '') { if ((state.data?.metadataId||'') !== '') {
fillElementValueBeforeCreate(state.data?.metadataId||''); fillElementValueBeforeCreate(state.data?.metadataId||'');
} }
...@@ -552,7 +548,7 @@ const AssetAction = (props) => { ...@@ -552,7 +548,7 @@ const AssetAction = (props) => {
key={_index} key={_index}
style={{ marginBottom: (_index===sameAttributeElements.length-1)? 0 : 15 }} style={{ marginBottom: (_index===sameAttributeElements.length-1)? 0 : 15 }}
> >
{ (element.name==='资产项') ? <MetadataInfo /> : <Input disabled={element.manualMaintain==='否'} /> } <ElementItem type='edit' element={element} reference={reference} />
</Form.Item> </Form.Item>
); );
}) })
...@@ -564,9 +560,7 @@ const AssetAction = (props) => { ...@@ -564,9 +560,7 @@ const AssetAction = (props) => {
(sameAttributeElements||[]).map((item, index) => { (sameAttributeElements||[]).map((item, index) => {
return ( return (
<Descriptions.Item label={<div className='title-common' style={{ textAlign: 'right', width: 60 }}>{item.name||''}</div>} key={index} style={{ paddingBottom: (index===sameAttributeElements.length-1)? 0 : 10 }}> <Descriptions.Item label={<div className='title-common' style={{ textAlign: 'right', width: 60 }}>{item.name||''}</div>} key={index} style={{ paddingBottom: (index===sameAttributeElements.length-1)? 0 : 10 }}>
{ <ElementItem element={item} value={item.value} terms={terms} />
item.name==='资产项' ? <MetadataInfo config={false} value={item.value||''} /> : <span className='text-color'>{highlightSearchContentByTerms(item.value||'', terms)}</span>
}
</Descriptions.Item> </Descriptions.Item>
); );
}) })
...@@ -590,4 +584,79 @@ const AssetAction = (props) => { ...@@ -590,4 +584,79 @@ const AssetAction = (props) => {
) )
} }
export default AssetAction; export default AssetAction;
\ No newline at end of file
export const MultipleItem = ({ value, onChange, element }) => {
return (
<Select
value={value?value.split(','):undefined}
mode="multiple"
disabled={element?.manualMaintain==='否'}
onChange={(val) => {
onChange?.((val??[]).length === 0 ? undefined : val.toString())
}}
dropdownRender={(originNode) => (
<div
onClick={e => {
e.stopPropagation()
}}
>
{originNode}
</div>
)}
>
{
(typeof(element?.optional) === 'string') && (element.optional??'').split(',').map((item, index) => <Select.Option key={index} value={item}>{item}</Select.Option>)
}
</Select>
)
}
export const ElementItem = ({ type = 'detail', element, reference = AssetManageReference, ...restProps }) => {
const { value, terms } = restProps
const inputItem = () => {
if (element?.metadataItem === '是') {
if (getAssetType(reference) === 'dataAsset') {
return <AssetItem readonly={(type==='detail')} {...restProps} />
} else if (getAssetType(reference) === 'resource') {
return <ResourceItem readonly={(type==='detail')} {...restProps} />
}
}
if (type === 'detail') {
return <span className='text-color'>{highlightSearchContentByTerms(value, terms)}</span>
} else {
if (element?.selectMode === '单选') {
return <Select
allowClear
disabled={element?.manualMaintain==='否'}
dropdownRender={(originNode) => (
<div
onClick={e => {
e.stopPropagation()
}}
>
{originNode}
</div>
)}
{...restProps}
>
{
(typeof(element?.optional) === 'string') && (element?.optional??'').split(',').map((item, index) => <Select.Option key={index} value={item}>{item}</Select.Option>)
}
</Select>
} else if (element?.selectMode === '多选') {
return <MultipleItem element={element} {...restProps}/>
}
return <Input disabled={element?.manualMaintain==='否'} {...restProps} />
}
}
return (
<React.Fragment>
{inputItem()}
</React.Fragment>
)
}
\ No newline at end of file
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import { Spin, Descriptions, Divider } from "antd"; import { Spin, Descriptions, Divider } from "antd";
import MetadataInfo from './MetadataInfo'; import { getAssetRange, getAssetType, highlightSearchContentByTerms } from '../../../../util';
import { getAssetRange, highlightSearchContentByTerms } from '../../../../util';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { ElementItem } from "./AssetAction";
import { AssetManageReference } from "../../../../util/constant";
const AssetDetail = (props)=>{ const AssetDetail = (props)=>{
...@@ -71,7 +72,8 @@ const AssetDetail = (props)=>{ ...@@ -71,7 +72,8 @@ const AssetDetail = (props)=>{
type: 'assetmanage.listUserElements', type: 'assetmanage.listUserElements',
payload: { payload: {
params: { params: {
range: getAssetRange(reference) range: getAssetRange(reference),
dataAssetType: getAssetType(reference)
} }
}, },
callback: data => { callback: data => {
...@@ -143,9 +145,7 @@ const AssetDetail = (props)=>{ ...@@ -143,9 +145,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}>
{ <ElementItem type={AssetManageReference} element={item} value={item.value} terms={terms} />
item.name==='资产项' ? <MetadataInfo config={false} value={item.value||''} terms={terms} /> : <span>{highlightSearchContentByTerms(item.value||'', terms)}</span>
}
</Descriptions.Item> </Descriptions.Item>
); );
}) })
......
...@@ -2,20 +2,24 @@ import React, { useEffect, useState } from 'react'; ...@@ -2,20 +2,24 @@ import React, { useEffect, useState } from 'react';
import { Spin, Tooltip, Typography, Dropdown, Menu } from 'antd'; import { Spin, Tooltip, Typography, Dropdown, Menu } from 'antd';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { AssetBrowseReference, AssetManageReference, ResourceBrowseReference } from '../../../../util/constant'; import { AssetBrowseReference, AssetManageReference, ResourceBrowseReference, ResourceManageReference } from '../../../../util/constant';
import ImportElement from './ImportElement'; import ImportElement from './ImportElement';
import AttributeRelationModal from "./AttributeRelationModal"; import AttributeRelationModal from "./AttributeRelationModal";
import FilterElementModal from './FilterElementModal'; import FilterElementModal from './FilterElementModal';
import { showNotifaction, getAssetRange } from '../../../../util'; import ChangeElementValue from './change-element-value';
import { showNotifaction, getAssetRange, getAssetType } from '../../../../util';
import { MoreSvg } from './AssetSvg'; import { MoreSvg } from './AssetSvg';
import Separate from './Separate'; import Separate from './Separate';
import record from '../Assets/record.png'; import record from '../Assets/record.png';
import PermissionMenuItem from '../../../../util/Component/PermissionMenuItem'; import PermissionMenuItem from '../../../../util/Component/PermissionMenuItem';
import './AssetDirectory.less'; import './AssetDirectory.less';
import { Subject } from 'rxjs';
const { Paragraph, Text } = Typography; const { Paragraph, Text } = Typography;
export const AssetDirectorySubject = new Subject();
const AssetDirectory = (props) => { const AssetDirectory = (props) => {
const { id, directoryChanged, assetCount, reference = AssetManageReference, onElementsChange, nodeType } = props; const { id, directoryChanged, assetCount, reference = AssetManageReference, onElementsChange, nodeType } = props;
const [ dir, setDir ] = useState(null); const [ dir, setDir ] = useState(null);
...@@ -25,10 +29,16 @@ const AssetDirectory = (props) => { ...@@ -25,10 +29,16 @@ const AssetDirectory = (props) => {
const [ filterElementVisible, setFilterElementVisible ] = useState(false); const [ filterElementVisible, setFilterElementVisible ] = useState(false);
const [ resourceState, setResourceState ] = useState(null); const [ resourceState, setResourceState ] = useState(null);
const [ permissions, setPermissions ] = useState([]); const [ permissions, setPermissions ] = useState([]);
const [changeElementValueParams, setChangeElementValueParams] = useState({
visible: false,
type: undefined
})
useEffect(() => { useEffect(() => {
getPermissions(); getPermissions()
}, [])
useEffect(() => {
const storageChange = (e) => { const storageChange = (e) => {
if (e.key === 'assetResourceChange') { if (e.key === 'assetResourceChange') {
getResourceState(); getResourceState();
...@@ -108,7 +118,7 @@ const AssetDirectory = (props) => { ...@@ -108,7 +118,7 @@ const AssetDirectory = (props) => {
} }
const onExportElementBtnClick = () => { const onExportElementBtnClick = () => {
window.open('/api/dataassetmanager/elementApi/export'); window.open(`/api/dataassetmanager/elementApi/export?dataAssetType=${getAssetType(reference)}`);
} }
const onFilterElementClick = () => { const onFilterElementClick = () => {
...@@ -119,11 +129,19 @@ const AssetDirectory = (props) => { ...@@ -119,11 +129,19 @@ const AssetDirectory = (props) => {
setAttributeRelationModalVisible(true); setAttributeRelationModalVisible(true);
} }
const onChangeElementValueClick = () => {
setChangeElementValueParams({
visible: true,
type: reference
})
}
const onImportElementCancel = (visible = false, change = false, tip = '') => { const onImportElementCancel = (visible = false, change = false, tip = '') => {
setImportElementVisible(visible); setImportElementVisible(visible);
if (change) { if (change) {
onElementsChange && onElementsChange(); onElementsChange && onElementsChange();
AssetDirectorySubject.next({ type: 'element-change' })
} }
if (tip && tip!== '') { if (tip && tip!== '') {
...@@ -148,6 +166,8 @@ const AssetDirectory = (props) => { ...@@ -148,6 +166,8 @@ const AssetDirectory = (props) => {
onFilterElementClick(); onFilterElementClick();
} else if (key === 'attributeRelate') { } else if (key === 'attributeRelate') {
onAttributeRelationBtnClick(); onAttributeRelationBtnClick();
} else if (key === 'elementValueChangeManage') {
onChangeElementValueClick();
} }
} }
...@@ -189,6 +209,16 @@ const AssetDirectory = (props) => { ...@@ -189,6 +209,16 @@ const AssetDirectory = (props) => {
资产属性关联 资产属性关联
</div> </div>
</PermissionMenuItem> </PermissionMenuItem>
<PermissionMenuItem
defaultPermission='true'
key='elementValueChangeManage'
permissionKey='elementValueChangeManage'
permissions={permissions}
>
<div className='text-center'>
属性值变更管理
</div>
</PermissionMenuItem>
</Menu> </Menu>
); );
...@@ -224,7 +254,7 @@ const AssetDirectory = (props) => { ...@@ -224,7 +254,7 @@ const AssetDirectory = (props) => {
</Tooltip> </Tooltip>
</Paragraph> </Paragraph>
</div> </div>
<div className={(reference===AssetManageReference)?'mb-common':''}> <div className={(reference===ResourceManageReference||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}>
...@@ -235,7 +265,7 @@ const AssetDirectory = (props) => { ...@@ -235,7 +265,7 @@ const AssetDirectory = (props) => {
</Paragraph> </Paragraph>
</div> </div>
{ {
(reference===AssetManageReference) && <div className='flex'> (reference===ResourceManageReference||reference===AssetManageReference) && <div className='flex'>
<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}>
...@@ -302,7 +332,7 @@ const AssetDirectory = (props) => { ...@@ -302,7 +332,7 @@ const AssetDirectory = (props) => {
</div> </div>
{ {
(reference===AssetManageReference) && <Dropdown overlay={elementManageMenu} placement="bottomCenter"> (reference===ResourceManageReference||reference===AssetManageReference) && <Dropdown overlay={elementManageMenu} placement="bottomCenter">
<div <div
className='flex more-container' className='flex more-container'
style={{ style={{
...@@ -322,6 +352,7 @@ const AssetDirectory = (props) => { ...@@ -322,6 +352,7 @@ const AssetDirectory = (props) => {
<ImportElement <ImportElement
visible={importElementVisible} visible={importElementVisible}
type={reference}
onCancel={onImportElementCancel} onCancel={onImportElementCancel}
/> />
...@@ -332,9 +363,21 @@ const AssetDirectory = (props) => { ...@@ -332,9 +363,21 @@ const AssetDirectory = (props) => {
/> />
<AttributeRelationModal <AttributeRelationModal
type={reference}
visible={ attributeRelationModalVisible } visible={ attributeRelationModalVisible }
onCancel={ onAttributeRelationModalCancel } onCancel={ onAttributeRelationModalCancel }
/> />
<ChangeElementValue
{...changeElementValueParams}
onCancel={(refresh) => {
setChangeElementValueParams({
visible: false,
type: undefined
})
refresh && AssetDirectorySubject.next({ type: 'element-value-change' })
}}
/>
</Spin> </Spin>
); );
} }
......
import React from 'react';
import { Row, Col, Typography } from 'antd';
import MetadataInfo from './MetadataInfo';
import './AssetItem.less';
const AssetItem = (props) => {
const { data } = props;
return (
<div className='asset-item'>
{
(data.elementsGroup||[]).map((elementGroup, index) => {
const _type = elementGroup.type||'';
return (
<div key={index}>
<div className='flex' style={{ alignItems: 'center', padding: '15px 0' }}>
<div style={{ width: 3, height: 14, backgroundColor: '#0069AC', marginRight: 5 }} />
<span style={{ fontWeight: 'bold', color: '#464646' }}>{_type||''}</span>
</div>
<Row>
{
elementGroup && elementGroup.elements && elementGroup.elements.map((element, _index) => {
return (
<Col className='mb-3' key={_index} md={8}>
<Typography.Paragraph title={ `${element.name||''}: ${element.value||''}` } style={{ color: '#464646' }} ellipsis>
{ `${element.name||''}: `}
{ element.name==='资产项'?<MetadataInfo config={false} value={element.value||''} />:`${element.value||''}` }
</Typography.Paragraph>
</Col>
);
})
}
</Row>
<div style={{ width: '100%', height: 2, backgroundColor: '#ededed' }} />
</div>
)
})
}
</div>
);
}
export default AssetItem;
\ No newline at end of file
.asset-item {
margin: 0px 0px 0px 30px;
.yy-divider-horizontal {
margin: 0 !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 - 40px - 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
...@@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react'; ...@@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react';
import { Modal, Form, TreeSelect, Select, Space, Button, Row, Col, } from 'antd'; import { Modal, Form, TreeSelect, Select, Space, Button, Row, Col, } from 'antd';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { AssetManageReference, ResourceManageReference } from '../../../../util/constant';
import { getAssetType } from '../../../../util';
const MetaModelSelect = ({ value = {}, metaModelTreeData = [], onChange, ...restProps }) => { const MetaModelSelect = ({ value = {}, metaModelTreeData = [], onChange, ...restProps }) => {
const [ attributes, setAttributes ] = useState([]); const [ attributes, setAttributes ] = useState([]);
...@@ -99,7 +101,7 @@ const MetaModelSelect = ({ value = {}, metaModelTreeData = [], onChange, ...rest ...@@ -99,7 +101,7 @@ const MetaModelSelect = ({ value = {}, metaModelTreeData = [], onChange, ...rest
} }
const AttributeRelationModal = (props) => { const AttributeRelationModal = (props) => {
const { visible, onCancel } = props; const { visible, onCancel, type = AssetManageReference } = props;
const [ confirmLoading, setConfirmLoading ] = useState(false); const [ confirmLoading, setConfirmLoading ] = useState(false);
const [ metadataModelTreeData, setMetadataModelTreeData ] = useState([]); const [ metadataModelTreeData, setMetadataModelTreeData ] = useState([]);
...@@ -146,6 +148,9 @@ const AttributeRelationModal = (props) => { ...@@ -146,6 +148,9 @@ const AttributeRelationModal = (props) => {
const loadElementWithoutCustom = () => { const loadElementWithoutCustom = () => {
dispatch({ dispatch({
type: 'assetmanage.loadElementWithoutCustom', type: 'assetmanage.loadElementWithoutCustom',
payload: {
dataAssetType: getAssetType(type)
},
callback: data => { callback: data => {
setElements(data||[]); setElements(data||[]);
getRelAttrByModel(); getRelAttrByModel();
...@@ -159,6 +164,11 @@ const AttributeRelationModal = (props) => { ...@@ -159,6 +164,11 @@ const AttributeRelationModal = (props) => {
const getRelAttrByModel = () => { const getRelAttrByModel = () => {
dispatch({ dispatch({
type: 'assetmanage.getRelAttrByModel', type: 'assetmanage.getRelAttrByModel',
payload: {
params: {
dataAssetType: getAssetType(type),
}
},
callback: data => { callback: data => {
let _fieldsValue = {}; let _fieldsValue = {};
(data||[]).forEach(item => { (data||[]).forEach(item => {
...@@ -191,7 +201,10 @@ const AttributeRelationModal = (props) => { ...@@ -191,7 +201,10 @@ const AttributeRelationModal = (props) => {
dispatch({ dispatch({
type: 'assetmanage.saveEleAndAttrRel', type: 'assetmanage.saveEleAndAttrRel',
payload: { payload: {
data: newRels data: newRels,
params: {
dataAssetType: getAssetType(type)
}
}, },
callback: data => { callback: data => {
reset(); reset();
......
...@@ -7,14 +7,17 @@ import update from 'immutability-helper'; ...@@ -7,14 +7,17 @@ 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 { AssetManageReference, AssetBrowseReference, ResourceBrowseReference, ResourceManageReference } from '../../../../util/constant';
import { showMessage } from '../../../../util'; import { getAssetType, showMessage } from '../../../../util';
const resourceTypes = [ const resourceTypes = [
{ key: 'innerSource', name: '内部资源' }, { key: 'innerSource', name: '内部资源' },
{ key: 'outerSource', name: '外部资源' }, { key: 'outerSource', name: '外部资源' },
{ key: 'dataAsset', name: '资产' }, ]
const assetTypes = [
{ key: 'dataAsset', name: '资产' }
] ]
const CustomDirectoryModal = (props) => { const CustomDirectoryModal = (props) => {
...@@ -49,6 +52,9 @@ const CustomDirectoryModal = (props) => { ...@@ -49,6 +52,9 @@ const CustomDirectoryModal = (props) => {
const getAllElementsThenGetCurrentDirectory = () => { const getAllElementsThenGetCurrentDirectory = () => {
dispatch({ dispatch({
type: 'assetmanage.listCustomElements', type: 'assetmanage.listCustomElements',
payload: {
dataAssetType: getAssetType(reference)
},
callback: elements => { callback: elements => {
setData(elements||[]); setData(elements||[]);
setFilterData((elements||[]).filter(item => (item.name||'').indexOf(keyword)!==-1)); setFilterData((elements||[]).filter(item => (item.name||'').indexOf(keyword)!==-1));
...@@ -81,11 +87,15 @@ const CustomDirectoryModal = (props) => { ...@@ -81,11 +87,15 @@ const CustomDirectoryModal = (props) => {
let url = 'assetmanage.previewTreeByCustomElements'; let url = 'assetmanage.previewTreeByCustomElements';
let payload = { let payload = {
data: checkedValues data: checkedValues,
params: {
dataAssetType: getAssetType(reference)
}
} }
if (reference===AssetManageReference) { if (reference===ResourceManageReference || reference===AssetManageReference) {
payload.params = { payload.params = {
...payload.params,
resourceTypes: (form.getFieldValue('resourceTypes')||[]).join(',') resourceTypes: (form.getFieldValue('resourceTypes')||[]).join(',')
}; };
} }
...@@ -94,6 +104,7 @@ const CustomDirectoryModal = (props) => { ...@@ -94,6 +104,7 @@ const CustomDirectoryModal = (props) => {
url = 'assetmanage.previewTreeByCustomElementsAndResourceType'; url = 'assetmanage.previewTreeByCustomElementsAndResourceType';
payload.params = { payload.params = {
...payload.params,
resourceType: (reference===ResourceBrowseReference)?'resource':'dataAsset', resourceType: (reference===ResourceBrowseReference)?'resource':'dataAsset',
} }
} }
...@@ -155,7 +166,10 @@ const CustomDirectoryModal = (props) => { ...@@ -155,7 +166,10 @@ const CustomDirectoryModal = (props) => {
let payload = { let payload = {
data: checkedValues, data: checkedValues,
params: row params: {
...row,
dataAssetType: getAssetType(reference)
}
} }
if (action === 'edit') { if (action === 'edit') {
...@@ -164,10 +178,10 @@ const CustomDirectoryModal = (props) => { ...@@ -164,10 +178,10 @@ const CustomDirectoryModal = (props) => {
let url = 'assetmanage.saveTreeByCustomElements'; let url = 'assetmanage.saveTreeByCustomElements';
if (reference===AssetManageReference) { if (reference===ResourceManageReference || reference===AssetManageReference) {
payload.params = { payload.params = {
...payload.params, ...payload.params,
resourceTypes: (row.resourceTypes||[]).join(',') resourceTypes: (row.resourceTypes||[]).join(','),
} }
} }
...@@ -304,7 +318,7 @@ const CustomDirectoryModal = (props) => { ...@@ -304,7 +318,7 @@ const CustomDirectoryModal = (props) => {
<Input /> <Input />
</Form.Item> </Form.Item>
{ {
reference===AssetManageReference && <Form.Item (reference===ResourceManageReference) && <Form.Item
label='数据范围' label='数据范围'
name='resourceTypes' name='resourceTypes'
> >
...@@ -317,6 +331,20 @@ const CustomDirectoryModal = (props) => { ...@@ -317,6 +331,20 @@ const CustomDirectoryModal = (props) => {
</Select> </Select>
</Form.Item> </Form.Item>
} }
{
(reference===AssetManageReference) && <Form.Item
label='数据范围'
name='resourceTypes'
>
<Select mode="multiple" allowClear>
{
assetTypes.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'
......
...@@ -3,7 +3,7 @@ import { Row, Col, Checkbox, Typography, Button, Switch, Modal } from 'antd'; ...@@ -3,7 +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 { getAssetRange } from '../../../../util'; import { getAssetRange, getAssetType } from '../../../../util';
//type //type
//global 全局设置 //global 全局设置
...@@ -27,21 +27,31 @@ const FilterElementModal = (props) => { ...@@ -27,21 +27,31 @@ const FilterElementModal = (props) => {
}, [visible]); }, [visible]);
const getAllFilterElementIdsThenGetAllElements = () => { const getAllFilterElementIdsThenGetAllElements = () => {
let url = '';
if (type === 'global') { if (type === 'global') {
url = 'assetmanage.listFilterElementIdsConfig'; dispatch({
type: 'assetmanage.listFilterElementIdsConfig',
payload: {
params: {
dataAssetType: getAssetType(reference)
}
},
callback: data => {
setSelectedKeys(data||[]);
getAllElements();
}
})
} else { } else {
url = 'assetmanage.listFilterElementIds'; dispatch({
type: 'assetmanage.listFilterElementIds',
payload: {
dataAssetType: getAssetType(reference)
},
callback: data => {
setSelectedKeys(data||[]);
getAllElements();
}
})
} }
dispatch({
type: url,
callback: data => {
setSelectedKeys(data||[]);
getAllElements();
}
})
} }
const getAllElements = () => { const getAllElements = () => {
...@@ -57,7 +67,8 @@ const FilterElementModal = (props) => { ...@@ -57,7 +67,8 @@ const FilterElementModal = (props) => {
type: url, type: url,
payload: { payload: {
params: { params: {
range: getAssetRange(reference) range: getAssetRange(reference),
dataAssetType: getAssetType(reference)
} }
}, },
callback: data => { callback: data => {
...@@ -129,7 +140,10 @@ const FilterElementModal = (props) => { ...@@ -129,7 +140,10 @@ const FilterElementModal = (props) => {
dispatch({ dispatch({
type: url, type: url,
payload: { payload: {
data: selectedKeys data: selectedKeys,
params: {
dataAssetType: getAssetType(reference)
}
}, },
callback: () => { callback: () => {
reset(); reset();
......
...@@ -3,10 +3,11 @@ import { Button, Upload, Drawer, Table, Pagination, Divider, Form } from 'antd'; ...@@ -3,10 +3,11 @@ import { Button, Upload, Drawer, Table, Pagination, Divider, Form } from 'antd';
import { UploadOutlined, DownloadOutlined } from '@ant-design/icons'; import { UploadOutlined, DownloadOutlined } from '@ant-design/icons';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { showMessage, formatDate } from '../../../../util'; import { showMessage, formatDate, getAssetType } from '../../../../util';
import { AssetManageReference } from '../../../../util/constant';
const ImportAssetDrawer = (props) => { const ImportAssetDrawer = (props) => {
const { onCancel, onSuccess, visible, nodeId } = props; const { onCancel, onSuccess, visible, nodeId, reference = AssetManageReference } = props;
const [ fileList, setFileList ] = useState([]); const [ fileList, setFileList ] = useState([]);
const [ confirmLoading, setConfirmLoading ] = useState(false); const [ confirmLoading, setConfirmLoading ] = useState(false);
...@@ -76,7 +77,7 @@ const ImportAssetDrawer = (props) => { ...@@ -76,7 +77,7 @@ const ImportAssetDrawer = (props) => {
}, [visible]) }, [visible])
const downloadTemplate = () => { const downloadTemplate = () => {
window.open("/api/dataassetmanager/dataAssetApi/getImportTemplate"); window.open(`/api/dataassetmanager/dataAssetApi/getImportTemplate?dataAssetType=${getAssetType(reference)}`);
} }
const getLogs = (p = 1, s = 20) => { const getLogs = (p = 1, s = 20) => {
...@@ -84,6 +85,7 @@ const ImportAssetDrawer = (props) => { ...@@ -84,6 +85,7 @@ const ImportAssetDrawer = (props) => {
dispatch({ dispatch({
type: 'assetmanage.importLogs', type: 'assetmanage.importLogs',
payload: { payload: {
dataAssetType: getAssetType(reference),
page: p, page: p,
pageSize: s pageSize: s
}, },
...@@ -134,7 +136,8 @@ const ImportAssetDrawer = (props) => { ...@@ -134,7 +136,8 @@ const ImportAssetDrawer = (props) => {
dispatch({ dispatch({
type: 'assetmanage.getDirectoryById', type: 'assetmanage.getDirectoryById',
payload: { payload: {
dirId: nodeId dirId: nodeId,
dataAssetType: getAssetType(reference)
}, },
callback: data => { callback: data => {
console.log('path', data.path); console.log('path', data.path);
......
...@@ -3,10 +3,11 @@ import { Modal, Form, Upload, Button, Radio, Space } from 'antd'; ...@@ -3,10 +3,11 @@ import { Modal, Form, Upload, Button, Radio, Space } from 'antd';
import { UploadOutlined } from '@ant-design/icons'; import { UploadOutlined } from '@ant-design/icons';
import { dispatch } from '../../../../model'; import { dispatch } from '../../../../model';
import { showNotifaction } from '../../../../util'; import { getAssetType, showNotifaction } from '../../../../util';
import { AssetManageReference } from '../../../../util/constant';
const ImportDirectory = (props) => { const ImportDirectory = (props) => {
const { visible, onCancel, dirId } = props; const { visible, onCancel, dirId, reference = AssetManageReference } = props;
const [ uploading, setUploading ] = useState(false); const [ uploading, setUploading ] = useState(false);
const [ fileList, setFileList ] = useState([]); const [ fileList, setFileList ] = useState([]);
const [ form ] = Form.useForm(); const [ form ] = Form.useForm();
...@@ -32,7 +33,8 @@ const ImportDirectory = (props) => { ...@@ -32,7 +33,8 @@ const ImportDirectory = (props) => {
dispatch({ dispatch({
type: 'assetmanage.getDirectoryById', type: 'assetmanage.getDirectoryById',
payload: { payload: {
dirId dirId,
dataAssetType: getAssetType(reference)
}, },
callback: data => { callback: data => {
setDir(data); setDir(data);
...@@ -55,7 +57,8 @@ const ImportDirectory = (props) => { ...@@ -55,7 +57,8 @@ const ImportDirectory = (props) => {
if (row.type === 'root') { if (row.type === 'root') {
payload = { payload = {
params: { params: {
ignoreRepeatPath ignoreRepeatPath,
dataAssetType: getAssetType(reference)
}, },
fileList: fileList, fileList: fileList,
}; };
...@@ -63,7 +66,8 @@ const ImportDirectory = (props) => { ...@@ -63,7 +66,8 @@ const ImportDirectory = (props) => {
payload = { payload = {
params: { params: {
ignoreRepeatPath, ignoreRepeatPath,
parentPath: dir.path parentPath: dir.path,
dataAssetType: getAssetType(reference)
}, },
fileList: fileList fileList: fileList
}; };
......
...@@ -3,10 +3,11 @@ import { Button, Upload, Modal } from 'antd'; ...@@ -3,10 +3,11 @@ import { Button, Upload, Modal } from 'antd';
import { DownloadOutlined, UploadOutlined } from '@ant-design/icons'; import { DownloadOutlined, UploadOutlined } from '@ant-design/icons';
import { dispatchLatest } from '../../../../model'; import { dispatchLatest } from '../../../../model';
import { showMessage } from '../../../../util'; import { getAssetType, showMessage } from '../../../../util';
import { AssetManageReference } from '../../../../util/constant';
const ImportElement = (props) => { const ImportElement = (props) => {
const { onCancel, visible } = props; const { onCancel, visible, type = AssetManageReference } = props;
const [ fileList, setFileList ] = useState([]); const [ fileList, setFileList ] = useState([]);
const [ confirmLoading, setConfirmLoading ] = useState(false); const [ confirmLoading, setConfirmLoading ] = useState(false);
...@@ -42,7 +43,12 @@ const ImportElement = (props) => { ...@@ -42,7 +43,12 @@ const ImportElement = (props) => {
setConfirmLoading(true); setConfirmLoading(true);
dispatchLatest({ dispatchLatest({
type: 'assetmanage.importElement', type: 'assetmanage.importElement',
payload: { fileList }, payload: {
params: {
dataAssetType: getAssetType(type)
},
fileList,
},
callback: data => { callback: data => {
setConfirmLoading(false); setConfirmLoading(false);
reset(); reset();
......
import React from 'react';
import { Button } from 'antd';
import { SettingFilled } from '@ant-design/icons';
import { highlightSearchContentByTerms } from '../../../../util';
import { AppContext } from '../../../../App';
const MetadataInfo = ({ value = '', config = true, terms = [] }) => {
let metadata = {};
try {
metadata = JSON.parse(value);
} catch(error) {
metadata = value;
}
return (
<AppContext.Consumer>
{
value => <div className='flex'>
{
(typeof metadata==='string') ? <span style={{ marginRight: 5 }}>{highlightSearchContentByTerms(metadata||'', terms)}</span> : <div className='flex' style={{ flexDirection: 'column' }}>
<a onClick={() => {
value?.setGlobalState && value?.setGlobalState({
message: 'data-govern-show-metadata-message',
data: metadata
})
}} style={{ marginRight: 5, marginTop: config?5:0 }}>{highlightSearchContentByTerms(metadata?.tableName||'',terms)}
</a>
{
(metadata?.columnItems||[]).map((item, index) => {
let _content = '';
if ((item.metadataColumnCnName||'')!=='') {
_content = item.metadataColumnCnName + '/';
}
_content += item.metadataColumnName||'';
return <span key={index}>{highlightSearchContentByTerms(_content,terms)}</span>
})
}
</div>
}
{
config && <Button icon={<SettingFilled />} onClick={() => {
value?.setGlobalState && value?.setGlobalState({
message: 'data-govern-show-metadata-list-message',
data: (typeof metadata==='string') ? {} : metadata
})
}} />
}
</div>
}
</AppContext.Consumer>
);
}
export default MetadataInfo;
\ No newline at end of file
import React, { useEffect, useState } from 'react';
import { Modal, Form, Input, Space, Button, Radio, Select } from 'antd';
import { dispatch } from '../../../../model';
import { showMessage } from '../../../../util';
const resourceTypes = [
{ key: 'innerSource', name: '内部资源' },
{ key: 'outerSource', name: '外部资源' },
{ key: 'dataAsset', name: '资产' },
{ key: 'custom', name: '自定义' },
]
const UpdateDirectoryModal = (props) => {
const { visible, onCancel, dirId, action } = props;
const [ form ] = Form.useForm();
const [ dir, setDir ] = useState(null);
const [ confirmLoading, setConfirmLoading ] = useState(false);
const [ isThemeAdd, setIsThemeAdd ] = useState(false);
useEffect(() => {
if (visible) {
setDir(null);
form.resetFields();
if ((dirId||'')!=='') {
getDirectory();
}
}
//eslint-disable-next-line react-hooks/exhaustive-deps
}, [ visible ])
const getDirectory = () => {
setDir(null);
dispatch({
type: 'assetmanage.getDirectoryById',
payload: {
dirId
},
callback: data => {
setDir(data);
if (action !== 'add') {
form.setFieldsValue({ code: data?.code, name: data?.name||'', desc: data?.desc||'', remarks: data?.remarks||'', resourceType: data?.resourceType });
}
}
})
}
const onOk = async () => {
try {
const row = await form.validateFields();
setConfirmLoading(true);
let payload = {
data: {
code: row.code,
name: row.name,
desc: row.desc,
remarks: row.remarks,
resourceType: row.resourceType
}
};
if (action === 'add') {
if (row.type === 'directory') {
if (dir === null) {
showMessage('warn', '资产目录节点信息正在加载中...');
return;
}
payload = { ...payload, params: {
parentPath: dir.path||''
}};
} else {
payload.data.resourceType = row.resourceType;
}
} else {
if (dir === null) {
showMessage('warn', '资产目录节点信息正在加载中...');
return;
}
payload.data = { ...payload.data, ...{ order: dir.order, id: dirId } };
const parentPath = dir.path.substring(0, dir.path.lastIndexOf("/"));;
payload = { ...payload, params: {
parentPath
}};
}
dispatch({
type: 'assetmanage.addOrUpdateDirectory',
payload: payload,
callback: data => {
setConfirmLoading(false);
onCancel && onCancel(true, data?.id||'');
},
error: () => {
setConfirmLoading(false);
}
})
} catch (errInfo) {
console.log('Validate Failed:', errInfo);
}
}
const onReset = () => {
if(action === 'add') {
setIsThemeAdd(false);
form.resetFields();
} else {
if (dir === null) {
showMessage('warn', '资产目录节点信息正在加载中...');
return;
}
form.resetFields();
}
}
const onValuesChange = (changedValues, allValues) => {
if (action==='add') {
if (changedValues.type === 'theme') {
setIsThemeAdd(true);
} else if (changedValues.type === 'directory') {
setIsThemeAdd(false);
}
}
}
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 5 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 17 },
},
};
return (
<Modal
forceRender
title={'资产目录信息'}
visible={visible}
width={600}
onCancel={() => { onCancel && onCancel() }}
footer={
<Space>
<Button type="primary" onClick={onOk} loading={confirmLoading}>提交</Button>
<Button onClick={onReset} >重置</Button>
<Button onClick={() => onCancel && onCancel() }>返回</Button>
</Space>
}
>
<Form {...formItemLayout} form={form} onValuesChange={onValuesChange}>
{
action==='add' && <Form.Item
label="类型"
name="type"
rules={[{ required: true, message: '必填项' }]}
>
<Radio.Group>
<Radio value='theme'>栏目</Radio>
<Radio value='directory' disabled={ dirId===null }>目录</Radio>
</Radio.Group>
</Form.Item>
}
{
((action==='add'&&isThemeAdd) || action!=='add') && <Form.Item
label="资产类型"
name="resourceType"
rules={[{ required: false }]}
>
<Select allowClear>
{
resourceTypes.map((item,index) => {
return <Select.Option key={item.key}>{item.name}</Select.Option>
})
}
</Select>
</Form.Item>
}
<Form.Item
label="编号"
name="code"
rules={[{ required: true, message: '必填项' }]}
>
<Input placeholder="请输入编号" />
</Form.Item>
<Form.Item
label="名称"
name="name"
rules={[{ required: true, message: '必填项' }]}
>
<Input placeholder="请输入名称" />
</Form.Item>
{
action !== 'add' && (
<Form.Item
label="路径"
name="path"
>
<span>{ dir ? (dir.path||''):'' }</span>
</Form.Item>
)
}
<Form.Item
label="描述"
name="desc"
>
<Input.TextArea placeholder="请输入描述" autoSize={{ minRows: 4, maxRows: 4 }} />
</Form.Item>
<Form.Item
label="备注"
name="remarks"
>
<Input.TextArea placeholder="请输入备注" autoSize={{ minRows: 4, maxRows: 4 }} />
</Form.Item>
</Form>
</Modal>
);
}
export default UpdateDirectoryModal;
\ No newline at end of file
import React from "react"
import { Modal, Button, Spin, Form, Select } from "antd"
import { dispatch } from '../../../../model'
import { getAssetRange, getAssetType } from '../../../../util'
import { ElementItem } from "./AssetAction"
const FC = (props) => {
const { type, visible, onCancel } = props
const [loading, setLoading] = React.useState(false)
const [waiting, setWaiting] = React.useState(false)
const [elements, setElements] = React.useState()
const basicRef = React.useRef()
React.useEffect(() => {
if (visible) {
getElements()
}
}, [visible])
const getElements = () => {
setLoading(true)
dispatch({
type: 'assetmanage.listElements',
payload: {
params: {
range: getAssetRange(type),
dataAssetType: getAssetType(type)
}
},
callback: data => {
setLoading(false)
setElements((data??[]).filter(item => item.supportBatchEdit==='是'))
},
error: () => {
setLoading(false)
}
})
}
const close = (refresh = false) => {
setLoading(false)
setWaiting(false)
onCancel?.(refresh)
}
const save = async () => {
try {
const rows = await basicRef.current?.validate()
setWaiting(true)
dispatch({
type: 'assetmanage.changeElementValue',
payload: {
params: {
dataAssetType: getAssetType(type),
...rows
}
},
callback: data => {
setWaiting(false)
close(true)
},
error: () => {
setWaiting(false)
}
})
} catch(e) {
}
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button disabled={waiting} key={'save'} type='primary'
onClick={() => save()}
>确定</Button>
]
}, [close, save, waiting])
return (
<Modal
visible={visible}
footer={footer}
width={520}
bodyStyle={{ padding: '15px 15px 0px 15px', overflowX: 'auto', maxHeight: '80vh' }}
title='属性值变更管理'
centered destroyOnClose
onCancel={() => { close() }}
>
<Spin spinning={loading||waiting} >
<Basic ref={basicRef} type={type} elements={elements} />
</Spin>
</Modal>
)
}
export default FC
export const Basic = React.forwardRef(function ({ type, elements }, ref) {
const [form] = Form.useForm()
const [loadingSources, setLoadingSources] = React.useState(false)
const [sources, setSources] = React.useState()
const [currentElement, setCurrentElement] = React.useState()
React.useImperativeHandle(ref, () => ({
validate: async () => {
return await form.validateFields()
},
}), [form])
const marginBottom = React.useMemo(() => {
return 15
}, [])
const getSources = (elementId) => {
setLoadingSources(true)
dispatch({
type: 'assetmanage.getDistinctValuesByElementId',
payload: {
dataAssetType: getAssetType(type),
elementId
},
callback: data => {
setLoadingSources(false)
setSources(data)
},
error: () => {
setLoadingSources(false)
}
})
}
const onValuesChange = (changedValues, allValues) => {
if (changedValues.hasOwnProperty('elementId')) {
const index = (elements??[]).findIndex(item => item.id === changedValues.elementId)
if (index !== -1) {
setCurrentElement(elements[index])
}
getSources(changedValues.elementId)
}
}
return (
<Form
form={form}
labelCol={{ span: 5 }}
wrapperCol={{ span: 17 }}
autoComplete="off"
onValuesChange={onValuesChange}
>
<Form.Item
label="属性"
name="elementId"
rules={[{ required: true, message: '请选择属性!' }]}
style={{ marginBottom }}
>
<Select placeholder='请选择属性'>
{
(elements??[]).map((item,index) =>
<Select.Option key={item.id} value={item.id}>{item.name}</Select.Option>
)
}
</Select>
</Form.Item>
<Form.Item
label="原属性值"
name="source"
rules={[{ required: true, message: '请选择原属性值!' }]}
style={{ marginBottom }}
>
<Select loading={loadingSources} placeholder='请选择属性'>
{
(sources??[]).map((item,index) =>
<Select.Option key={item} value={item}>{item}</Select.Option>
)
}
</Select>
</Form.Item>
<Form.Item
label="替换属性值"
name="target"
rules={[{ required: true, message: '请选择替换属性值!' }]}
style={{ marginBottom }}
>
<ElementItem type='edit' element={currentElement} />
</Form.Item>
</Form>
)
})
\ No newline at end of file
.add-resources {
.tree {
height: calc(80vh - 30px);
overflow: auto;
}
}
\ No newline at end of file
//资产项
import React from 'react'
import { Button, Tooltip } from 'antd'
import { AppContext } from '../../../App'
import { highlightSearchContentByTerms, IsArr } from '../../../util'
import { MetadataColumnTooltipTitle } from '../AssetResourceManage/table'
import AddResources from './add-resources'
import { dispatch } from '../../../model'
const FC = ({ value, onChange, readonly = true, terms = [] }) => {
const [decodeData, setDecodeData] = React.useState()
const [addResourcesParams, setAddResourcesParams] = React.useState({
visible: false,
})
const app = React.useContext(AppContext)
React.useMemo(() => {
if (value) {
try {
setDecodeData(JSON.parse(value))
} catch(error) {
setDecodeData(value)
}
} else {
setDecodeData()
}
}, [value])
const onAddResourcesOk = (resources) => {
dispatch({
type: 'assetmanage.getMetadataItems',
payload: {
params: {
resourceIds: (resources??[]).map(item => item.id).toString()
}
},
callback: data => {
if (typeof decodeData === 'string') {
onChange?.(JSON.stringify(data??[]))
} else {
const newData = [...decodeData??[]]
for (const item of data??[]) {
const _index = (newData??[]).findIndex(_item => item.metadataId ===_item.metadataId)
if (_index === -1) {
newData.push(item)
}
}
onChange?.(JSON.stringify(newData))
}
},
})
}
return (
<div>
{
!readonly && <Button onClick={() => {
setAddResourcesParams({
visible: true
})
}}>添加资源</Button>
}
{
(typeof decodeData === 'string') && <div className='flex' style={{ alignItems: 'center', marginTop: readonly?0:5 }}>
<span style={{ marginRight: 5 }}>
{highlightSearchContentByTerms(decodeData, terms)}
</span>
{
!readonly && <Button size='small' onClick={() => {
onChange?.()
}}>删除</Button>
}
</div>
}
{
IsArr(decodeData) && <div>
{
//资源可能没有资源项
(decodeData??[]).filter(item => item.metadataId).map((item, index) => <div key={index} className='flex' style={{ alignItems: 'center', marginTop: readonly?0:5 }}>
<span>
<Tooltip
overlayClassName='tooltip-common'
title={<MetadataColumnTooltipTitle data={[item]} />}
>
<a onClick={() => {
app?.setGlobalState?.({
message: 'data-govern-show-metadata-message',
data: item
})
}}
style={{ marginRight: 5 }}
>
{highlightSearchContentByTerms(item.enName, terms)}
</a>
</Tooltip>
</span>
{
!readonly && <Button size='small' onClick={() => {
const newData = [...decodeData]
const _index = (newData??[]).findIndex(_item => item.metadataId ===_item.metadataId)
if (_index !== -1) {
newData.splice(_index, 1)
onChange?.(JSON.stringify(newData))
}
}}>删除</Button>
}
</div>
)
}
</div>
}
<AddResources
{...addResourcesParams}
onCancel={(refresh) => {
setAddResourcesParams({
visible: false
})
}}
onOk={onAddResourcesOk}
/>
</div>
)
}
export default FC
\ No newline at end of file
import React from 'react'
import { Button, Modal, Spin, Tree, AutoComplete } from 'antd'
import { dispatch } from '../../../model'
import produce from 'immer'
import { highlightSearchContentByTerms, showMessage, showNotifaction } from '../../../util'
import { generateList } from '../AssetResourceManage/tree'
const FC = (props) => {
const { visible, items, onCancel } = props
const [waiting, setWaiting] = React.useState(false)
const basicRef = React.useRef()
const close = (refresh = false) => {
setWaiting(false)
onCancel?.(refresh)
}
const save = () => {
const checkedKeys = basicRef.current?.getCheckedKeys()
if ((checkedKeys??[]).length === 0) {
showMessage('warn', '请先选择资源目录')
return
}
setWaiting(true)
dispatch({
type: 'assetmanage.loadDataAssets',
payload: {
params: {
dirId: checkedKeys.join(","),
},
data: (items??[]).map(item => item.id)
},
callback: data => {
setWaiting(false)
if (data?.message) {
showNotifaction('提示', data?.message, 5)
}
onCancel?.(true)
},
error: () => {
setWaiting(false)
}
})
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button key={'save'} type='primary'
disabled={waiting}
onClick={() => save()}
>保存</Button>
]
}, [close, save, waiting])
return (
<Modal
visible={visible}
footer={footer}
width='400px'
bodyStyle={{ padding: '15px 15px 0px 15px', overflowX: 'auto', maxHeight: '80vh', height: 500 }}
title='变更目录'
centered destroyOnClose
onCancel={() => { close() }}
>
<Spin spinning={waiting}>
<Basic ref={basicRef} items={items} />
</Spin>
</Modal>
)
}
export default FC
export const Basic = React.forwardRef(function ({ items, onCheck }, ref) {
const [data, setData] = React.useState()
const [dataList, setDataList] = React.useState()
const [loading, setLoading] = React.useState(false)
const [checkedKeys, setCheckedKeys] = React.useState()
const [expandedKeys, setExpandedKeys] = React.useState([])
const [autoExpandParent, setAutoExpandParent] = React.useState(false)
const [options, setOptions] = React.useState()
const [keyword, setKeyword] = React.useState()
React.useImperativeHandle(ref, () => ({
getCheckedKeys: () => checkedKeys
}), [checkedKeys])
React.useEffect(() => {
getTreeData()
getAssetPaths()
}, [])
const treeData = React.useMemo(() => {
if (data) {
const newTreeData = produce(data, draft => {
const setNode = (g) => {
g.key = g.nodeId
g.title = g.text
g.children?.forEach((child) => {
setNode(child)
})
}
draft.forEach((child) => {
setNode(child)
})
})
return newTreeData
}
return []
}, [data])
const getAssetPaths = () => {
if ((items??[]).length > 0) {
dispatch({
type: 'assetmanage.getAssetPaths',
payload: {
dataAssetId: items[0].id,
},
callback: data => {
setCheckedKeys((data??[]).map(item => item.dirId))
}
})
}
}
const getTreeData = () => {
setLoading(true)
dispatch({
type: 'assetmanage.queryDataAssetManageTree',
callback: data => {
setLoading(false)
const newData = (data??[]).filter(item => item.resourceType !== 'custom')
setData(newData)
if ((newData??[]).length > 0) {
const newDataList = []
generateList(newData, newDataList)
setDataList(newDataList)
const firstNode = newData[0]
setExpandedKeys([firstNode.nodeId])
setAutoExpandParent(true)
}
},
error: () => {
setLoading(false)
}
})
}
const onTreeExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys)
setAutoExpandParent(false)
}
const onTreeCheck = (values, e) => {
//同一主题下只能挂载一个目录
if (e.node?.level === 1) {
showMessage('warn', '栏目不允许勾选')
return
}
const newCheckedKeys = values.checked??[]
if (e.checked) {
const index = (dataList??[]).findIndex(item => item.nodeId === e.node?.key)
if (index !== -1) {
const currentSubjectNodeId = dataList[index].subjectNodeId
const filterChecktedKeys = newCheckedKeys.filter(key => {
if (key !== e.node?.key) {
const index = (dataList??[]).findIndex(item => item.nodeId === key)
if (index !== -1) {
return (dataList[index].subjectNodeId !== currentSubjectNodeId)
} else {
return false
}
}
return true
})
setCheckedKeys(filterChecktedKeys)
onCheck?.(filterChecktedKeys)
}
} else {
setCheckedKeys(newCheckedKeys)
onCheck?.(newCheckedKeys)
}
}
const onAutoCompleteSearch = (searchText) => {
setKeyword(searchText)
setOptions(!searchText?[]:(dataList||[]).filter(item => item.value.indexOf(searchText)!==-1))
}
const onAutoCompleteSelect = (value, option) => {
const paths = value.split('/')
setKeyword(paths[paths.length-1])
const newExpandedKeys = [...expandedKeys, option.key]
setExpandedKeys(Array.from(new Set(newExpandedKeys)))
setAutoExpandParent(true)
}
return (
<Spin spinning={loading}>
<AutoComplete
allowClear
value={keyword}
style={{ marginBottom: 10, width: '100%' }}
onSelect={onAutoCompleteSelect}
onSearch={onAutoCompleteSearch}
onClear={() => {
setKeyword()
}}
>
{
(options||[]).map((item, index) => {
return (
<AutoComplete.Option key={item.key} value={item.value}>
<div style={{ whiteSpace: 'normal' }}>
{highlightSearchContentByTerms(item.value, [keyword])}
</div>
</AutoComplete.Option>
);
})
}
</AutoComplete>
<Tree
checkable
checkStrictly
showLine
showIcon={false}
treeData={treeData}
autoExpandParent={autoExpandParent}
expandedKeys={expandedKeys}
checkedKeys={checkedKeys}
onExpand={onTreeExpand}
onCheck={onTreeCheck}
/>
</Spin>
)
})
\ No newline at end of file
import React, { useState } from 'react'; import React from "react"
import classNames from 'classnames'; import classNames from 'classnames'
import { Form } from 'antd'; import { ResizableBox } from 'react-resizable'
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons'; import { Form } from "antd"
import { ResizableBox } from 'react-resizable'; import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons'
import AssetTree from './Component/AssetManageTree'; import Tree from './tree'
import AssetDirectory from './Component/AssetDirectory'; import Separate from './Component/Separate'
import AssetTable from './Component/AssetTable'; import NodeDetail from './Component/AssetDirectory'
import AssetAction from './Component/AssetAction'; import AssetList from './table'
import Separate from './Component/Separate'; import AssetDetail from './Component/AssetAction'
import { AssetManageReference } from "../../../util/constant"
import { AssetManageReference } from '../../../util/constant';
import './index.less'
import './index.less';
const FC = (props) => {
const AssetManage = (props) => { const [collapseTree, setCollapseTree] = React.useState(false)
const [node, setNode] = React.useState()
const [ nodeId, setNodeId ] = useState(''); const [asset, setAsset] = React.useState()
const [ nodeType, setNodeType ] = useState(''); const [assetListFullScreen, setAssetListFullScreen] = React.useState(false)
const [ nodeLevel, setNodeLevel ] = useState(null); const [directoryChanged, setDirectoryChanged] = React.useState(false)
const [ assetParams, setAssetParams ] = useState({ assetId: '', assetDirId: '' })
const [ expandTree, setExpandTree ] = useState(true); const [form] = Form.useForm()
const [ assetFullScreen, setAssetFullScreen ] = useState(false);
const onTreeClick = (value) => {
const [ assetCount, setAssetCount ] = useState(0); setDirectoryChanged(!directoryChanged)
const [ directoryChanged, setDirectoryChanged ] = useState(false); setNode(value)
const [ elementsChanged, setElementsChanged ] = useState(false);
const [ assetActionChanged, setAssetActionChanged ] = useState(false);
const [ form ] = Form.useForm();
const { assetId, assetDirId } = assetParams;
const onTreeSelect = (value, type, level) => {
setNodeId(value||'');
setNodeType(type);
setNodeLevel(level);
} }
const onTableSelect = (id, did) => { const onAssetListClick = (value) => {
setAssetParams({ assetId: id, assetDirId: did }); setAsset(value)
} }
const treeToggleClick = () => { const onAssetListFullScreenChange = (value) => {
setExpandTree(!expandTree); setAssetListFullScreen(value)
} }
const onElementsChange = () => { const treeToggleClick = () => {
setElementsChanged(!elementsChanged); setCollapseTree(!collapseTree)
}
const onDirectoryChange = () => {
setDirectoryChanged(!directoryChanged);
}
const onAssetActionChange = () => {
setAssetActionChanged(!assetActionChanged);
}
const onAssetCountChange = (count) => {
setAssetCount(count);
}
const onFullScreenChange = (value) => {
setAssetFullScreen(value);
} }
const classes = classNames('asset-manage', { const rootClasses = classNames('asset-manage', {
'asset-manage-collapse': !expandTree 'asset-manage-collapse': collapseTree
}); })
const middleClasses = classNames('middle', { const middleClasses = classNames('middle', {
'middle-fullscreen': assetFullScreen 'middle-fullscreen': assetListFullScreen
}); })
return ( return (
<div className={classes}> <div className={rootClasses}>
<ResizableBox <ResizableBox
className='left' className='left'
width={230} width={230}
height={Infinity} height={Infinity}
axis='x' axis='x'
minConstraints={[230, Infinity]} maxConstraints={[Infinity, Infinity]} minConstraints={[230, Infinity]}
maxConstraints={[Infinity, Infinity]}
> >
<AssetTree onSelect={onTreeSelect} onDirectoryChange={onDirectoryChange} {...props} /> <Tree onClick={onTreeClick} {...props} />
</ResizableBox> </ResizableBox>
{ {
expandTree && <Separate width={15} /> !collapseTree && <Separate width={15} />
} }
<div className={middleClasses}> <div className={middleClasses}>
<AssetDirectory id={nodeId} assetCount={assetCount} directoryChanged={directoryChanged} onElementsChange={onElementsChange} /> <NodeDetail
reference={AssetManageReference}
id={node?.nodeId}
assetCount={node?.dataAssetAndSubDirCount}
directoryChanged={directoryChanged}
/>
<Separate height={15} /> <Separate height={15} />
<AssetTable nodeId={nodeId} nodeType={nodeType} nodeLevel={nodeLevel} reference={AssetManageReference} elementsChanged={elementsChanged} assetActionChanged={assetActionChanged} onSelect={onTableSelect} onCountChange={onAssetCountChange} onFullScreenChange={onFullScreenChange} {...props} /> <AssetList
node={node}
onClick={onAssetListClick}
onFullScreenChange={onAssetListFullScreenChange}
{...props}
/>
<div className='tree-toggle' onClick={treeToggleClick}> <div className='tree-toggle' onClick={treeToggleClick}>
{ expandTree ? <CaretLeftOutlined /> : <CaretRightOutlined /> } { !collapseTree ? <CaretLeftOutlined /> : <CaretRightOutlined /> }
</div> </div>
</div> </div>
<Separate width='15px' /> <Separate width='15px' />
<div className='right'> <div className='right'>
<AssetAction form={form} id={assetId} dirId={assetDirId} action='detail' reference={AssetManageReference} onChange={onAssetActionChange} /> <AssetDetail
form={form}
id={asset?.id}
dirId={asset?.dirId}
action='detail'
reference={AssetManageReference}
/>
</div> </div>
</div> </div>
) )
} }
export default AssetManage; export default FC
\ No newline at end of file \ No newline at end of file
@import '../../../../variables.less'; @import '../../../variables.less';
.asset-list { .asset-list {
background-color: #fff; background-color: #fff;
......
import React from 'react'
import { Modal, Button, Spin, Form, Input, Radio, Select, Space, TreeSelect, Row, Col, Checkbox } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { dispatch } from '../../../model'
import { getAssetType, getValidString, showMessage } from '../../../util'
import { AssetManageReference } from '../../../util/constant'
const resourceTypes = [
{ key: 'dataAsset', name: '资产' },
{ key: 'custom', name: '自定义' },
]
const FC = (props) => {
const { id, action, visible, onCancel } = props
const [loading, setLoading] = React.useState(false)
const [waiting, setWaiting] = React.useState(false)
const [node, setNode] = React.useState()
const basicRef = React.useRef()
React.useEffect(() => {
if (visible && id) {
getDetail()
}
}, [visible, id])
const getDetail = () => {
setLoading(true)
dispatch({
type: 'assetmanage.getDirectoryById',
payload: {
dirId: id
},
callback: data => {
setLoading(false)
setNode(data)
},
error: () => {
setLoading(false)
}
})
}
const close = (refresh = false) => {
setLoading(false)
setWaiting(false)
setNode()
onCancel?.(refresh)
}
const save = async() => {
try {
const rows = await basicRef.current?.validate()
setWaiting(true)
let parentPath = ''
if (action === 'add') {
if (basicRef.current?.getType === 'child') {
parentPath = node?.path
rows.resourceType = node?.resourceType
}
} else {
parentPath = node?.path.substring(0, node?.path.lastIndexOf("/"))
}
dispatch({
type: 'assetmanage.addOrUpdateDirectory',
payload: {
data: (action === 'add')?rows:{...node??{}, ...rows},
params: {
parentPath,
dataAssetType: getAssetType(AssetManageReference)
}
},
callback: data => {
setWaiting(false)
onCancel?.(true, data?.id)
},
error: () => {
setWaiting(false)
}
})
} catch (e) {
}
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button key={'save'} type='primary'
onClick={() => save()}
>确定</Button>
]
}, [close, save])
return (
<Modal
visible={visible}
footer={footer}
width='600px'
bodyStyle={{ padding: '15px 15px 0px 15px', overflowX: 'auto', maxHeight: '80vh' }}
title='资产目录信息'
centered destroyOnClose
onCancel={() => { close() }}
>
<Spin spinning={loading||waiting} >
<Basic
ref={basicRef}
node={node}
action={action}
/>
</Spin>
</Modal>
)
}
export default FC
export const Basic = React.forwardRef(function ({ node, action }, ref) {
const [type, setType] = React.useState('root')
const [currentResourceType, setCurrentResourceType] = React.useState()
const [form] = Form.useForm()
React.useImperativeHandle(ref, () => ({
getType: type,
validate: async () => {
return await form.validateFields()
},
}), [type, form])
React.useEffect(() => {
if (node) {
const index = resourceTypes.findIndex(item => item.key === node?.resourceType)
if (index !== -1) {
setCurrentResourceType(resourceTypes[index].name)
}
if (action !== 'add') {
form.setFieldsValue(node)
}
}
}, [action, node])
const allowChangeResourceType = React.useMemo(() => {
return (action==='add' && type==='root')
}, [action, type])
const onValuesChange = (changedValues, allValues) => {
}
return (
<Form
form={form}
labelCol={{ span: 5 }}
wrapperCol={{ span: 17 }}
autoComplete="off"
onValuesChange={onValuesChange}
>
{
action==='add' && <Form.Item
label="类型"
rules={[{ required: true, message: '请选择类型!' }]}
>
<Radio.Group value={type} onChange={(e) => {
setType(e.target.value)
}}>
<Radio value='root'>栏目</Radio>
<Radio value='child' disabled={!node?.id}>目录</Radio>
</Radio.Group>
</Form.Item>
}
<Form.Item
label="资产类型"
name="resourceType"
rules={[{ required: allowChangeResourceType?true:false, message: '请选择资产类型!' }]}
>
{
allowChangeResourceType ? <Select allowClear>
{
resourceTypes.map((item,index) => {
return <Select.Option key={item.key} value={item.key}>{item.name}</Select.Option>
})
}
</Select> : <span>{currentResourceType}</span>
}
</Form.Item>
<Form.Item
label="编号"
name="code"
rules={[{ required: true, message: '必填项' }]}
>
<Input placeholder="请输入编号" />
</Form.Item>
<Form.Item
label="名称"
name="name"
rules={[{ required: true, message: '必填项' }]}
>
<Input placeholder="请输入名称" />
</Form.Item>
{
action !== 'add' && (
<Form.Item
label="路径"
name="path"
>
<span>{node?.path}</span>
</Form.Item>
)
}
<Form.Item
label="描述"
name="desc"
>
<Input placeholder="请输入描述" />
</Form.Item>
<Form.Item
label="备注"
name="remarks"
>
<Input placeholder="请输入备注" />
</Form.Item>
</Form>
)
})
.asset-operation {
height: 100%;
overflow: auto;
.yy-tabs-nav::before {
border: none;
}
.yy-tabs-nav-wrap {
justify-content: flex-end;
}
}
\ No newline at end of file
import React, { useState } from "react";
import { Modal } from "antd";
import { dispatch } from '../../../../model';
import AssetTree from '../../AssetManage/Component/AssetManageTree';
import { showMessage, showNotifaction } from '../../../../util';
import { AssetManageReference, AssetRecycleReference, AssetMountReference } from "../../../../util/constant";
const AssetMount = (props) => {
const { onCancel, visible, ids, reference = AssetManageReference } = props;
const [ dirIds, setDirIds ] = useState([]);
const [ confirmLoading, setConfirmLoading ] = useState(false);
const onCheck = (values) => {
setDirIds(values||[]);
}
const onOk = () => {
if ((dirIds||[]).length === 0) {
showMessage('warn', '请先选择资产目录');
return;
}
setConfirmLoading(true);
dispatch({
type: 'assetmanage.loadDataAssets',
payload: {
params: {
dirId: dirIds.join(","),
},
data: ids
},
callback: data => {
setConfirmLoading(false);
if (data?.message) {
showNotifaction('提示', data?.message, 5);
}
reset();
onCancel && onCancel(true);
},
error: () => {
setConfirmLoading(false);
}
})
}
const reset = () => {
setConfirmLoading(false);
}
return(
<Modal
title={(reference===AssetRecycleReference)?'挂载目录详情':'变更目录详情'}
visible={ visible }
width={ 400 }
confirmLoading={ confirmLoading }
onCancel={()=>{
reset();
onCancel && onCancel()
}}
onOk={ onOk }
>
<AssetTree
checkable={true}
onCheck={onCheck}
tableId={(reference===AssetManageReference&&(ids||[].length>0))?ids[0]:''}
reference={AssetMountReference}
/>
</Modal>
)
}
export default AssetMount;
\ No newline at end of file
import React from 'react'
import { Button, Modal, Spin, Tree, AutoComplete } from 'antd'
import { dispatch } from '../../../model'
import produce from 'immer'
import { highlightSearchContentByTerms, showMessage, showNotifaction } from '../../../util'
import { generateList } from '../AssetResourceManage/tree'
const FC = (props) => {
const { visible, items, onCancel } = props
const [waiting, setWaiting] = React.useState(false)
const basicRef = React.useRef()
const close = (refresh = false) => {
setWaiting(false)
onCancel?.(refresh)
}
const save = () => {
const checkedKeys = basicRef.current?.getCheckedKeys()
if ((checkedKeys??[]).length === 0) {
showMessage('warn', '请先选择资源目录')
return
}
setWaiting(true)
dispatch({
type: 'assetmanage.loadDataAssets',
payload: {
params: {
dirId: (checkedKeys??[]).toString(),
},
data: (items??[]).map(item => item.id)
},
callback: data => {
setWaiting(false)
if (data?.message) {
showNotifaction('提示', data?.message, 5)
}
onCancel?.(true)
},
error: () => {
setWaiting(false)
}
})
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button key={'save'} type='primary'
disabled={waiting}
onClick={() => save()}
>保存</Button>
]
}, [close, save, waiting])
return (
<Modal
visible={visible}
footer={footer}
width='400px'
bodyStyle={{ padding: '15px 15px 0px 15px', overflowX: 'auto', maxHeight: '80vh', height: 500 }}
title='变更目录'
centered destroyOnClose
onCancel={() => { close() }}
>
<Spin spinning={waiting}>
<Basic ref={basicRef} items={items} />
</Spin>
</Modal>
)
}
export default FC
export const Basic = React.forwardRef(function ({ items, onCheck }, ref) {
const [data, setData] = React.useState()
const [dataList, setDataList] = React.useState()
const [loading, setLoading] = React.useState(false)
const [checkedKeys, setCheckedKeys] = React.useState()
const [expandedKeys, setExpandedKeys] = React.useState([])
const [autoExpandParent, setAutoExpandParent] = React.useState(false)
const [options, setOptions] = React.useState()
const [keyword, setKeyword] = React.useState()
React.useImperativeHandle(ref, () => ({
getCheckedKeys: () => checkedKeys
}), [checkedKeys])
React.useEffect(() => {
getTreeData()
}, [])
const treeData = React.useMemo(() => {
if (data) {
const newTreeData = produce(data, draft => {
const setNode = (g) => {
g.key = g.nodeId
g.title = g.text
g.children?.forEach((child) => {
setNode(child)
})
}
draft.forEach((child) => {
setNode(child)
})
})
return newTreeData
}
return []
}, [data])
const getTreeData = () => {
setLoading(true)
dispatch({
type: 'assetmanage.queryDataAssetManageTree',
callback: data => {
setLoading(false)
const newData = (data??[]).filter(item => item.resourceType !== 'custom')
setData(newData)
if ((newData??[]).length > 0) {
const newDataList = []
generateList(newData, newDataList)
setDataList(newDataList)
const firstNode = newData[0]
setExpandedKeys([firstNode.nodeId])
setAutoExpandParent(true)
}
},
error: () => {
setLoading(false)
}
})
}
const onTreeExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys)
setAutoExpandParent(false)
}
const onTreeCheck = (values, e) => {
//同一主题下只能挂载一个目录
if (e.node?.level === 1) {
showMessage('warn', '栏目不允许勾选')
return
}
const newCheckedKeys = values.checked??[]
if (e.checked) {
const index = (dataList??[]).findIndex(item => item.nodeId === e.node?.key)
if (index !== -1) {
const currentSubjectNodeId = dataList[index].subjectNodeId
const filterChecktedKeys = newCheckedKeys.filter(key => {
if (key !== e.node?.key) {
const index = (dataList??[]).findIndex(item => item.nodeId === key)
if (index !== -1) {
return (dataList[index].subjectNodeId !== currentSubjectNodeId)
} else {
return false
}
}
return true
})
setCheckedKeys(filterChecktedKeys)
onCheck?.(filterChecktedKeys)
}
} else {
setCheckedKeys(newCheckedKeys)
onCheck?.(newCheckedKeys)
}
}
const onAutoCompleteSearch = (searchText) => {
setKeyword(searchText)
setOptions(!searchText?[]:(dataList||[]).filter(item => item.value.indexOf(searchText)!==-1))
}
const onAutoCompleteSelect = (value, option) => {
const paths = value.split('/')
setKeyword(paths[paths.length-1])
const newExpandedKeys = [...expandedKeys, option.key]
setExpandedKeys(Array.from(new Set(newExpandedKeys)))
setAutoExpandParent(true)
}
return (
<Spin spinning={loading}>
<AutoComplete
allowClear
value={keyword}
style={{ marginBottom: 10, width: '100%' }}
onSelect={onAutoCompleteSelect}
onSearch={onAutoCompleteSearch}
onClear={() => {
setKeyword()
}}
>
{
(options||[]).map((item, index) => {
return (
<AutoComplete.Option key={item.key} value={item.value}>
<div style={{ whiteSpace: 'normal' }}>
{highlightSearchContentByTerms(item.value, [keyword])}
</div>
</AutoComplete.Option>
);
})
}
</AutoComplete>
<Tree
checkable
checkStrictly
showLine
showIcon={false}
treeData={treeData}
autoExpandParent={autoExpandParent}
expandedKeys={expandedKeys}
checkedKeys={checkedKeys}
onExpand={onTreeExpand}
onCheck={onTreeCheck}
/>
</Spin>
)
})
\ No newline at end of file
import React from 'react'; import React from 'react';
import AssetTable from '../AssetManage/Component/AssetTable'; import AssetTable from './table';
import { AssetRecycleReference } from '../../../util/constant'; import { AssetRecycleReference } from '../../../util/constant';
const AssetRecycle = (props) => { const AssetRecycle = (props) => {
......
import React from 'react'; import React, { useState } from 'react';
import classNames from 'classnames';
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons';
import { ResizableBox } from 'react-resizable';
import AssetBrowse from '../AssetBrowse'; import AssetTree from '../AssetManage/Component/AssetTree';
import AssetDirectory from '../AssetManage/Component/AssetDirectory';
import RelationContainer from '../AssetBrowse/Component/RelationContainer';
import AssetTable from "./table";
import Separate from '../AssetManage/Component/Separate';
import { ResourceBrowseReference } from '../../../util/constant'; import { ResourceBrowseReference } from '../../../util/constant';
const AssetResourceBrowse = (props) => { import '../AssetBrowse/index.less';
const FC = (props) => {
const [ nodeParams, setNodeParams ] = useState({ centerId: '', expandId: '', nodeType: '' });
const [ expandTree, setExpandTree ] = useState(true);
const [ expandRelation, setExpandRelation ] = useState(true);
const [ assetCount, setAssetCount ] = useState(0);
const [ resizeRelation, setResizeRelation ] = useState(false);
const [ assetFullScreen, setAssetFullScreen ] = useState(false);
const { centerId, expandId } = nodeParams;
const onTreeSelect = (value, type) => {
setNodeParams({ centerId: value||'', expandId: '', nodeType: type });
}
const treeToggleClick = () => {
setExpandTree(!expandTree);
setResizeRelation(!resizeRelation);
}
const relationToggleClick = () => {
setExpandRelation(!expandRelation);
setResizeRelation(!resizeRelation);
}
const onRelationChange = (data) => {
setNodeParams(data);
}
const onAssetCountChange = (count) => {
setAssetCount(count);
}
const onFullScreenChange = (value) => {
setAssetFullScreen(value);
}
let nodeId = '';
if ((expandId||'') !== '') {
nodeId = expandId;
} else {
nodeId = centerId;
}
const classes = classNames('asset-browse', {
'asset-browse-tree-collapse': !expandTree,
'asset-browse-relation-collapse': !expandRelation,
});
const rightClasses = classNames('right', {
'right-fullscreen': assetFullScreen
});
return ( return (
<AssetBrowse reference={ResourceBrowseReference} {...props} /> <div className={classes}>
<ResizableBox
className='left'
width={230}
height={Infinity}
axis='x'
minConstraints={[230, Infinity]} maxConstraints={[Infinity, Infinity]}
>
<AssetTree centerId={centerId} onSelect={onTreeSelect} reference={ResourceBrowseReference} {...props} />
</ResizableBox>
{
expandTree && <Separate width={15} />
}
<div className={rightClasses}>
<AssetDirectory id={nodeId} assetCount={assetCount} reference={ResourceBrowseReference} nodeType={nodeParams.nodeType} />
<Separate height={15} />
<div className='flex' style={{ flex: 1, height: '100%', overflow: 'hidden' }}>
{
expandRelation && <React.Fragment>
<div style={{ flex: 1, height: '100%', overflow: 'hidden' }}>
<RelationContainer reference={ResourceBrowseReference} nodeParams={nodeParams} onChange={onRelationChange} resize={resizeRelation} />
</div>
<Separate width={15} />
</React.Fragment>
}
<div style={{ flex: 1, overflow: 'hidden' }}>
<AssetTable node={{ nodeId, type: nodeParams.nodeType }} onFullScreenChange={onFullScreenChange} {...props} />
</div>
</div>
<div className='tree-toggle' onClick={treeToggleClick}>
{ expandTree ? <CaretLeftOutlined /> : <CaretRightOutlined /> }
</div>
<div className='relation-toggle' onClick={relationToggleClick}>
{ expandRelation ? <CaretLeftOutlined /> : <CaretRightOutlined /> }
</div>
</div>
</div>
) )
} }
export default AssetResourceBrowse; export default FC;
\ No newline at end of file \ No newline at end of file
.add-to-asset {
.tree {
height: calc(80vh - 150px);
overflow: auto;
}
}
\ No newline at end of file
import React from "react"
import { Modal, Button, Spin, Form } from "antd"
import { getAssetRange, showMessage } from "../../../util"
import { ResourceManageReference } from "../../../util/constant"
import { dispatch } from '../../../model'
const FC = (props) => {
const { args, node, visible, onCancel } = props
const [waiting, setWaiting] = React.useState(false)
const basicRef = React.useRef()
const close = (refresh = false) => {
setWaiting(false)
onCancel?.(refresh)
}
const save = async() => {
const departments = basicRef.current?.departments
if ((departments??[]).length === 0) {
showMessage('warn', '没有所属部门')
return
}
let [recursive, dirId] = [true, node?.nodeId]
if (args.params.catalogType === 'current') {
recursive = false
}
if (args.params.catalogType === 'fullSearch') {
dirId = ''
}
setWaiting(true)
dispatch({
type: 'assetmanage.autoDistributeTask',
payload: {
data: args.params.elementValueFilters??[],
params: {
dirId,
keyword: args.params.keyword,
range: getAssetRange(ResourceManageReference),
resourceStatus: args.params.resourceStatus,
sortingStatus: args.params.sortingStatus,
recursive,
filterTodo: args.params.onlyPending,
departments: (departments??[]).toString()
}
},
callback: () => {
setWaiting(false)
onCancel(true)
},
error: () => {
setWaiting(false)
}
})
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button key={'save'} type='primary'
onClick={() => save()}
>发起流程</Button>
]
}, [close, save])
return (
<Modal
visible={visible}
footer={footer}
width='800px'
bodyStyle={{ padding: '15px', overflowX: 'auto', maxHeight: '80vh' }}
title='自动分配任务'
centered destroyOnClose
onCancel={() => { close() }}
>
<Spin spinning={waiting}>
<Basic ref={basicRef} node={node} args={args} />
</Spin>
</Modal>
)
}
export default FC
export const Basic = React.forwardRef(function ({ node, args }, ref) {
const [departments, setDepartments] = React.useState()
const [form] = Form.useForm()
React.useImperativeHandle(ref, () => ({
departments
}), [departments])
React.useEffect(() => {
if (node && args) {
getDepartments()
}
}, [node, args])
const getDepartments = () => {
let [recursive, dirId] = [true, node?.nodeId]
if (args.params.catalogType === 'current') {
recursive = false
}
if (args.params.catalogType === 'fullSearch') {
dirId = ''
}
dispatch({
type: 'assetmanage.listAutoDistributeUserDepartments',
payload: {
data: args.params.elementValueFilters??[],
params: {
dirId,
keyword: args.params.keyword,
range: getAssetRange(ResourceManageReference),
resourceStatus: args.params.resourceStatus,
sortingStatus: args.params.sortingStatus,
recursive,
filterTodo: args.params.onlyPending,
}
},
callback: (data) => {
setDepartments(data)
},
error: () => {
}
})
}
return (
<Form
form={form}
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
autoComplete="off"
>
<Form.Item
label='所属部门'
extra="发起流程后,自动将筛选结果中未梳理状态的资源,分配到部门资产管理员进行梳理"
>
<span>{(departments??[]).toString()}</span>
</Form.Item>
</Form>
)
})
\ No newline at end of file
import React from 'react'
import { Button, Modal, Spin, Tree, AutoComplete } from 'antd'
import { dispatch } from '../../../model'
import { generateList } from './tree'
import produce from 'immer'
import { highlightSearchContentByTerms, showMessage, showNotifaction } from '../../../util'
const FC = (props) => {
const { visible, items, onCancel } = props
const [waiting, setWaiting] = React.useState(false)
const basicRef = React.useRef()
const close = (refresh = false) => {
setWaiting(false)
onCancel?.(refresh)
}
const save = () => {
const checkedKeys = basicRef.current?.getCheckedKeys()
if ((checkedKeys??[]).length === 0) {
showMessage('warn', '请先选择资源目录')
return
}
setWaiting(true)
dispatch({
type: 'assetmanage.loadDataAssets',
payload: {
params: {
dirId: checkedKeys.join(","),
},
data: (items??[]).map(item => item.id)
},
callback: data => {
setWaiting(false)
if (data?.message) {
showNotifaction('提示', data?.message, 5)
}
onCancel?.(true)
},
error: () => {
setWaiting(false)
}
})
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button key={'save'} type='primary'
disabled={waiting}
onClick={() => save()}
>保存</Button>
]
}, [close, save, waiting])
return (
<Modal
visible={visible}
footer={footer}
width='400px'
bodyStyle={{ padding: '15px 15px 0px 15px', overflowX: 'auto', maxHeight: '80vh', height: 500 }}
title='变更目录'
centered destroyOnClose
onCancel={() => { close() }}
>
<Spin spinning={waiting}>
<Basic ref={basicRef} items={items} />
</Spin>
</Modal>
)
}
export default FC
export const Basic = React.forwardRef(function ({ items, onCheck }, ref) {
const [data, setData] = React.useState()
const [dataList, setDataList] = React.useState()
const [loading, setLoading] = React.useState(false)
const [checkedKeys, setCheckedKeys] = React.useState()
const [expandedKeys, setExpandedKeys] = React.useState([])
const [autoExpandParent, setAutoExpandParent] = React.useState(false)
const [options, setOptions] = React.useState()
const [keyword, setKeyword] = React.useState()
React.useImperativeHandle(ref, () => ({
getCheckedKeys: () => checkedKeys
}), [checkedKeys])
React.useEffect(() => {
getTreeData()
getAssetPaths()
}, [])
const treeData = React.useMemo(() => {
if (data) {
const newTreeData = produce(data, draft => {
const setNode = (g) => {
g.key = g.nodeId
g.title = g.text
g.children?.forEach((child) => {
setNode(child)
})
}
draft.forEach((child) => {
setNode(child)
})
})
return newTreeData
}
return []
}, [data])
const getAssetPaths = () => {
if ((items??[]).length > 0) {
dispatch({
type: 'assetmanage.getAssetPaths',
payload: {
dataAssetId: items[0].id,
},
callback: data => {
setCheckedKeys((data??[]).map(item => item.dirId))
}
})
}
}
const getTreeData = () => {
setLoading(true)
dispatch({
type: 'assetmanage.queryResourceManageTree',
callback: data => {
setLoading(false)
const newData = (data??[]).filter(item => item.resourceType !== 'custom')
setData(newData)
if ((newData??[]).length > 0) {
const newDataList = []
generateList(newData, newDataList)
setDataList(newDataList)
const firstNode = newData[0]
setExpandedKeys([firstNode.nodeId])
setAutoExpandParent(true)
}
},
error: () => {
setLoading(false)
}
})
}
const onTreeExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys)
setAutoExpandParent(false)
}
const onTreeCheck = (values, e) => {
//同一主题下只能挂载一个目录
if (e.node?.level === 1) {
showMessage('warn', '栏目不允许勾选')
return
}
const newCheckedKeys = values.checked??[]
if (e.checked) {
const index = (dataList??[]).findIndex(item => item.nodeId === e.node?.key)
if (index !== -1) {
const currentSubjectNodeId = dataList[index].subjectNodeId
const filterChecktedKeys = newCheckedKeys.filter(key => {
if (key !== e.node?.key) {
const index = (dataList??[]).findIndex(item => item.nodeId === key)
if (index !== -1) {
return (dataList[index].subjectNodeId !== currentSubjectNodeId)
} else {
return false
}
}
return true
})
setCheckedKeys(filterChecktedKeys)
onCheck?.(filterChecktedKeys)
}
} else {
setCheckedKeys(newCheckedKeys)
onCheck?.(newCheckedKeys)
}
}
const onAutoCompleteSearch = (searchText) => {
setKeyword(searchText)
setOptions(!searchText?[]:(dataList||[]).filter(item => item.value.indexOf(searchText)!==-1))
}
const onAutoCompleteSelect = (value, option) => {
const paths = value.split('/')
setKeyword(paths[paths.length-1])
const newExpandedKeys = [...expandedKeys, option.key]
setExpandedKeys(Array.from(new Set(newExpandedKeys)))
setAutoExpandParent(true)
}
return (
<Spin spinning={loading}>
<AutoComplete
allowClear
value={keyword}
style={{ marginBottom: 10, width: '100%' }}
onSelect={onAutoCompleteSelect}
onSearch={onAutoCompleteSearch}
onClear={() => {
setKeyword()
}}
>
{
(options||[]).map((item, index) => {
return (
<AutoComplete.Option key={item.key} value={item.value}>
<div style={{ whiteSpace: 'normal' }}>
{highlightSearchContentByTerms(item.value, [keyword])}
</div>
</AutoComplete.Option>
);
})
}
</AutoComplete>
<Tree
checkable
checkStrictly
showLine
showIcon={false}
treeData={treeData}
autoExpandParent={autoExpandParent}
expandedKeys={expandedKeys}
checkedKeys={checkedKeys}
onExpand={onTreeExpand}
onCheck={onTreeCheck}
/>
</Spin>
)
})
\ No newline at end of file
import React from 'react'
import { Modal, Button, Spin, Form, Radio } from 'antd'
import { dispatch } from '../../../model'
import { checkMenuAdmit } from '../../../util'
import { AnchorDirId, AnchorId } from '../../../util/constant'
import ResourceRelateAssetDetail from './resource-relate-asset-detal'
const FC = (props) => {
const { items, visible, onCancel, type = 'single' } = props
const [waiting, setWaiting] = React.useState(false)
const basicRef = React.useRef()
const close = (refresh = false) => {
setWaiting(false)
onCancel?.(refresh)
}
const save = async() => {
try {
const rows = await basicRef.current?.validate()
setWaiting(true)
dispatch({
type: 'assetmanage.checkResources',
payload: {
params: {
resourceIds: (items??[]).map(item => item.id).toString(),
status: rows.status
},
},
callback: () => {
setWaiting(false)
onCancel(true)
},
error: () => {
setWaiting(false)
}
})
} catch (e) {
}
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button key={'save'} type='primary'
onClick={() => save()}
>确定</Button>
]
}, [close, save])
return (
<Modal
visible={visible}
footer={footer}
width={520}
bodyStyle={{ padding: '15px 15px 0px 15px', overflowX: 'auto', maxHeight: '80vh' }}
title='复核确认'
centered destroyOnClose
onCancel={() => { close() }}
>
<Spin spinning={waiting} >
<Basic ref={basicRef} items={items} type={type} />
</Spin>
</Modal>
)
}
export default FC
export const Basic = React.forwardRef(function ({ items, type }, ref) {
const [relations, setRelations] = React.useState([])
const [assetDetailParams, setAssetDetailParams] = React.useState({
visible: false,
id: undefined
})
const [form] = Form.useForm()
React.useImperativeHandle(ref, () => ({
validate: async () => {
return await form.validateFields()
},
}), [form])
React.useEffect(() => {
if (type === 'single') {
getRelations()
}
}, [])
const checkInfo = React.useMemo(() => {
const toBeCheckCount = (items??[]).filter(item => (item.allowButtons??[]).findIndex(item => item==='check') !== -1).length
const noNeedToBeCheckCount = (items??[]).filter(item => (item.allowButtons??[]).findIndex(item => item==='check') === -1).length
return `已选数据:${(items??[]).length} 无需复核:${noNeedToBeCheckCount} 待复核:${toBeCheckCount}`
}, [items])
const getRelations = () => {
if ((items??[]).length > 0) {
dispatch({
type: 'assetmanage.getResourceRelateDataAssetsWhenChecking',
payload: {
resourceId: items[0].id,
},
callback: data => {
setRelations(data??[])
}
})
}
}
const onValuesChange = (changedValues, allValues) => {
console.log('all values', allValues)
}
return (
<React.Fragment>
<Form
form={form}
labelCol={{ span: 4 }}
wrapperCol={{ span: 20 }}
autoComplete="off"
onValuesChange={onValuesChange}
>
{
type === 'multiple' && <Form.Item style={{ marginBottom: 5 }}>
<span>{checkInfo}</span>
</Form.Item>
}
<Form.Item
name='status'
rules={[{ required: true, message: '请选择复核方式!' }]}
style={{ marginBottom: (type === 'single')?5:15 }}
>
<Radio.Group>
<Radio value="checked"> 验证通过 </Radio>
<Radio value="changeToNotAsset"> 转为非资产 </Radio>
</Radio.Group>
</Form.Item>
{
type === 'single' && <Form.Item label='关联资产' style={{ marginBottom: 5 }}>
<div className='flex' style={{ flexDirection: 'column', lineHeight: '32px' }}>
{
(relations??[]).map((item, index) => {
return (
<a key={index} onClick={() => {
setAssetDetailParams({
visible: true,
id: item.dataAssetId
})
}}>{item.dataAssetName}</a>
);
})
}
</div>
</Form.Item>
}
</Form>
<ResourceRelateAssetDetail
{...assetDetailParams}
onCancel={() => {
setAssetDetailParams({
visible: false,
id: undefined
})
}}
/>
</React.Fragment>
)
})
\ No newline at end of file
import React from "react"
import { Modal, Button, Form, Select, Spin, Checkbox } from "antd"
import { debounceTime, Subject } from 'rxjs'
import produce from "immer"
import { dispatch } from '../../../model'
const FC = (props) => {
const { visible, items, onCancel } = props
const [waiting, setWaiting] = React.useState(false)
const basicRef = React.useRef()
const close = (refresh = false) => {
setWaiting(false)
onCancel?.(refresh)
}
const save = async() => {
try {
const rows = await basicRef.current?.validate()
setWaiting(true)
dispatch({
type: 'assetmanage.distributeTask',
payload: {
params: {
resourceIds: (items??[]).map(item => item.id).toString(),
},
data: rows
},
callback: () => {
setWaiting(false)
onCancel(true)
},
error: () => {
setWaiting(false)
}
})
} catch (e) {
}
}
const footer = React.useMemo(() => {
return [
<Button key={'cancel'}
onClick={() => close()}
>取消</Button>,
<Button key={'save'} type='primary'
onClick={() => save()}
>发起流程</Button>
]
}, [close, save])
return (
<Modal
visible={visible}
footer={footer}
width='800px'
bodyStyle={{ padding: '15px', overflowX: 'auto', maxHeight: '80vh' }}
title='任务分配'
centered destroyOnClose
onCancel={() => { close() }}
>
<Spin spinning={waiting}>
<Basic ref={basicRef} />
</Spin>
</Modal>
)
}
export default FC
export const Basic = React.forwardRef(function ({ items }, ref) {
const [noticeTypes, setNoticeTypes] = React.useState()
const [form] = Form.useForm()
React.useImperativeHandle(ref, () => ({
validate: async () => {
return await form.validateFields()
},
}), [form])
React.useEffect(() => {
getNoticeTypes()
}, [])
const getNoticeTypes = () => {
dispatch({
type: 'assetmanage.getNoticeTypes',
callback: (data) => {
const newData = produce(data, (draft) => {
draft?.forEach(item => {
item.label = item.desc
item.value = item.type
})
})
setNoticeTypes(newData)
},
error: () => {
}
})
}
const onValuesChange = (changedValues, allValues) => {
console.log('all values', allValues)
}
return (
<Form
form={form}
labelCol={{ span: 3 }}
wrapperCol={{ span: 21 }}
autoComplete="off"
onValuesChange={onValuesChange}
>
<Form.Item
label='分配用户'
name='users'
rules={[{ required: true, message: '请选择用户!' }]}
>
<HandlersItem />
</Form.Item>
<Form.Item
label='通知方式'
name='noticeTypes'
rules={[{ required: true, message: '请选择通知方式!' }]}
>
<Checkbox.Group options={noticeTypes} />
</Form.Item>
</Form>
)
})
export const HandlersItem = ({ value, onChange }) => {
const $keyword = React.useMemo(() => new Subject(), [])
const [keyword, setKeyword] = React.useState()
const [loading, setLoading] = React.useState(false)
const [users, setUsers] = React.useState()
const [options, setOptions] = React.useState([])
React.useEffect(() => {
const $$keyword = $keyword.pipe(debounceTime(1000)).subscribe((keyword) => {
setKeyword(keyword)
})
return () => {
$$keyword.unsubscribe()
}
}, [])
React.useEffect(() => {
if (keyword) {
getHandlers()
}
}, [keyword])
const getHandlers = () => {
setLoading(true)
dispatch({
type: 'assetmanage.listDistributeAbleUsersByName',
payload: {
keyword,
pageNum: 1,
pageSize: 1000
},
callback: (data) => {
setLoading(false)
setUsers(data?.data)
const newOptions = produce(data?.data, (draft) => {
draft?.forEach(item => {
item.label = item.name
item.value = item.id
})
})
setOptions(newOptions)
},
error: () => {
setLoading(false)
}
})
}
const onHandleChange = (val) => {
onChange?.((users??[]).filter(item => (val??[]).includes(item.id)))
}
return (
<Select
placeholder='请选择用户'
loading={loading}
value={value?value.map(item => item.id):undefined}
onChange={onHandleChange}
onSearch={(val) => {
$keyword.next(val)
}}
allowClear
mode='multiple'
filterOption={false}
notFoundContent={loading ? <Spin size="small" /> : null}
options={options}
/>
)
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment