Commit 1f70f741 by zhaochengxiang

主数据

parent b63df5cd
......@@ -38,6 +38,10 @@ export const routes = [
{
name: 'asset-recycle',
text: '未挂载资产',
},
{
name: 'data-master',
text: '主数据'
}
]
}
......
import { useMemo } from 'react';
import ResizeableTable from '../../ResizeableTable';
import { expandedTableData } from './Mock';
import './DataMasterExpandedTable.less';
const DataMasterExpandedTable = (props) => {
const columns = useMemo(() => {
return ([
{
title: '序号',
dataIndex: 'key',
render: (text, record, index) => {
return (index+1).toString();
},
width: 60,
ellipsis: true,
},
{
title: '属性1',
dataIndex: 'attr1',
width: 200,
ellipsis: true,
},
{
title: '属性2',
dataIndex: 'attr2',
width: 200,
ellipsis: true,
},
{
title: '属性3',
dataIndex: 'attr3',
width: 200,
ellipsis: true,
},
{
title: '属性4',
dataIndex: 'attr4',
width: 200,
ellipsis: true,
},
{
title: '属性5',
dataIndex: 'attr5',
width: 200,
ellipsis: true,
},
{
title: '属性6',
dataIndex: 'attr6',
width: 200,
ellipsis: true,
},
]);
}, []);
return (
<div className='p-1'>
<ResizeableTable
rowKey='id'
columns={columns}
dataSource={expandedTableData}
pagination={false}
/>
</div>
);
}
export default DataMasterExpandedTable;
\ No newline at end of file
import { useMemo, useState } from 'react';
import { Space, Button, Input } from 'antd';
import ResizeableTable from '../../ResizeableTable';
import DebounceInput from '../../Model/Component/DebounceInput';
import { inputWidth } from '../../../../util';
import DataMasterExpandedTable from './DataMasterExpandedTable';
import { tableData } from './Mock';
import './DataMasterTable.less';
const InputDebounce = DebounceInput(300)(Input);
const DataMasterTable = (props) => {
const [keyword, setKeyword] = useState('');
const [checkedKeys, setCheckedKeys] = useState([]);
const columns = useMemo(() => {
return ([
{
title: '序号',
dataIndex: 'key',
render: (text, record, index) => {
return (index+1).toString();
},
width: 60,
ellipsis: true,
},
{
title: '模版名称',
dataIndex: 'name',
width: 200,
ellipsis: true,
},
{
title: '模版英文名称',
dataIndex: 'cnName',
width: 200,
ellipsis: true,
},
{
title: '创建人',
dataIndex: 'creator',
width: 200,
ellipsis: true,
},
{
title: '创建时间',
dataIndex: 'createTime',
width: 200,
ellipsis: true,
},
{
title: '修改人',
dataIndex: 'modifier',
width: 200,
ellipsis: true,
},
{
title: '修改时间',
dataIndex: 'modifyTime',
width: 200,
ellipsis: true,
},
]);
}, []);
const onAddClick = () => {
}
const onBatchDeleteClick = () => {
}
const onSearchInputChange = (value) => {
setKeyword(value);
}
const onTableSelectChange = keys => {
setCheckedKeys(keys);
};
const rowSelection = {
selectedRowKeys: checkedKeys,
onChange: onTableSelectChange,
};
return (
<div className='data-master-table'>
<div className='data-master-header px-3'>
<Space>
<Space>
<Button onClick={onAddClick}>新建</Button>
</Space>
<Space>
<Button onClick={onBatchDeleteClick}>删除</Button>
</Space>
</Space>
<InputDebounce
placeholder="通过主数据模版名称搜索"
allowClear
value={keyword}
onChange={onSearchInputChange}
style={{ width: inputWidth, marginLeft: 'auto' }}
/>
</div>
<div className='data-master-content p-3'>
<ResizeableTable
rowKey='id'
rowSelection={rowSelection}
columns={columns}
dataSource={tableData}
pagination={false}
expandable={{
expandedRowRender: record => <DataMasterExpandedTable />,
rowExpandable: record => true,
}}
scroll={{ y: 'calc(100vh - 94px - 37px - 57px - 24px - 32px)' }}
/>
</div>
</div>
);
}
export default DataMasterTable;
\ No newline at end of file
.data-master-table {
height: 100%;
.data-master-header {
display: flex;
flex: none;
height: 57px;
border-bottom: 1px solid #EFEFEF;
justify-content: space-between;
align-items: center;
}
}
\ No newline at end of file
import {useEffect, useMemo, useState} from 'react';
import {Tooltip, Spin, AutoComplete, Tree} from 'antd';
import {PlusOutlined, ReloadOutlined} from '@ant-design/icons';
import {highlightSearchContentByTerms} from '../../../../util';
import {treeData} from './Mock';
import './DataMasterTree.less';
const {Option} = AutoComplete;
const DataMasterTree = (props) => {
const {onClick} = props;
const [loading, setLoading] = useState(false);
const [options, setOptions] = useState([]);
const [keyword, setKeyword] = useState('');
const [expandedKeys, setExpandedKeys] = useState(['0-0']);
const [selectedKeys, setSelectedKeys] = useState(['0-0']);
const [autoExpandParent, setAutoExpandParent] = useState(false);
useEffect(() => {
onTreeSelect(['0-0']);
}, [])
const treeList = useMemo(() => {
const generateList = (data, list, path = null) => {
for (let i = 0; i < data.length; i++) {
const node = data[i];
const { key, title } = node;
const currentPath = path ? `${path}/${title}` : title;
list.push({ key, title: currentPath });
if (node.children) {
generateList(node.children, list, currentPath);
}
}
};
const newTreeList = [];
generateList(treeData, newTreeList);
return newTreeList;
}, [treeData])
const onAddClick = () => {
}
const onRefreshClick = () => {
}
const onAutoCompleteSearch = (searchText) => {
setKeyword(searchText);
setOptions(treeList.filter(item => item.title.indexOf(searchText)!==-1));
};
const onAutoCompleteSelect = (value, option) => {
const paths = value.split('/');
setKeyword(paths[paths.length-1]);
onTreeSelect([option.key]);
setExpandedKeys(Array.from(new Set([...expandedKeys, option.key])));
setAutoExpandParent(true);
};
const onAutoCompleteClear = () => {
setKeyword('');
}
const onTreeExpand = (expandedKeys) => {
setExpandedKeys(expandedKeys);
setAutoExpandParent(false);
}
const onTreeSelect = (selectedKeys) => {
if (selectedKeys.length === 0) {
return;
}
setSelectedKeys(selectedKeys);
onClick && onClick(selectedKeys[0]);
}
return (
<div className='data-master-tree'>
<div className='header p-3'>
<Tooltip title="新增目录">
<PlusOutlined
className='default'
onClick={onAddClick}
style={{
fontSize:16,
cursor:'pointer',
flex: 1
}}
/>
</Tooltip>
<Tooltip title="刷新目录" className='ml-2'>
<ReloadOutlined
className='default'
onClick={onRefreshClick}
style={{
fontSize:16,
cursor:'pointer',
flex: 1
}}
/>
</Tooltip>
<div style={{flex: 3}} />
</div>
<div className='content p-3'>
<Spin spinning={loading}>
<AutoComplete
className='content-search'
allowClear
value={keyword}
onSelect={onAutoCompleteSelect}
onSearch={onAutoCompleteSearch}
onClear={onAutoCompleteClear}
>
{
(options||[]).map((item, index) => {
return (
<Option key={item.key} value={item.title}>
<div style={{ whiteSpace: 'normal' }}>
{highlightSearchContentByTerms(item.title, [keyword])}
</div>
</Option>
);
})
}
</AutoComplete>
<Tree
className='content-tree'
showLine
showIcon={false}
autoExpandParent={autoExpandParent}
treeData={treeData}
onExpand={onTreeExpand}
onSelect={onTreeSelect}
expandedKeys={expandedKeys}
selectedKeys={selectedKeys}
/>
</Spin>
</div>
</div>
);
}
export default DataMasterTree;
\ No newline at end of file
@import '../../../../variables.less';
.data-master-tree {
height: 100%;
.header {
display: inline-flex;
flex: none;
width: 100%;
height: 57px;
justify-content: flex-start;
align-items: center;
border-bottom: 1px solid #EFEFEF;
}
.content-search {
margin-bottom: 10px;
width: 100%;
}
.content-tree {
height: calc(100vh - @header-height - @breadcrumb-height - 25px - 57px - 66px);
overflow: auto;
}
}
\ No newline at end of file
export const treeData = [
{
title: 'parent 1',
key: '0-0',
children: [
{
title: 'parent 1-0',
key: '0-0-0',
children: [
{
title: 'leaf1',
key: '0-0-0-0',
},
{
title: 'leaf2',
key: '0-0-0-1',
},
{
title: 'leaf3',
key: '0-0-0-2',
},
],
},
{
title: 'parent 1-1',
key: '0-0-1',
children: [
{
title: 'leaf',
key: '0-0-1-0',
},
],
},
{
title: 'parent 1-2',
key: '0-0-2',
children: [
{
title: 'leaf1',
key: '0-0-2-0',
},
{
title: 'leaf2',
key: '0-0-2-1',
},
],
},
{
title: 'parent 1-3',
key: '0-0-3',
children: [
{
title: 'leaf1',
key: '0-0-3-0',
},
{
title: 'leaf2',
key: '0-0-3-1',
},
],
},
{
title: 'parent 1-4',
key: '0-0-4',
children: [
{
title: 'leaf1',
key: '0-0-4-0',
},
{
title: 'leaf2',
key: '0-0-4-1',
},
],
},
{
title: 'parent 1-5',
key: '0-0-5',
children: [
{
title: 'leaf1',
key: '0-0-5-0',
},
{
title: 'leaf2',
key: '0-0-5-1',
},
],
},
],
},
];
export const tableData = [
{
id: '1',
name: '模版1',
cnName: '模版1',
creator: 'demotest',
createTime: '2022-07-13 12:00:00',
modifier: 'demotest',
modifyTime: '2022-07-13 12:00:00',
},
{
id: '2',
name: '模版2',
cnName: '模版2',
creator: 'demotest',
createTime: '2022-07-13 12:00:00',
modifier: 'demotest',
modifyTime: '2022-07-13 12:00:00',
},
{
id: '3',
name: '模版3',
cnName: '模版3',
creator: 'demotest',
createTime: '2022-07-13 12:00:00',
modifier: 'demotest',
modifyTime: '2022-07-13 12:00:00',
},
{
id: '4',
name: '模版4',
cnName: '模版4',
creator: 'demotest',
createTime: '2022-07-13 12:00:00',
modifier: 'demotest',
modifyTime: '2022-07-13 12:00:00',
},
{
id: '5',
name: '模版5',
cnName: '模版5',
creator: 'demotest',
createTime: '2022-07-13 12:00:00',
modifier: 'demotest',
modifyTime: '2022-07-13 12:00:00',
},
];
export const expandedTableData = [
{
id: '1',
attr1: 'attr1',
attr2: 'attr2',
attr3: 'attr3',
attr4: 'attr4',
attr5: 'attr5',
attr6: 'attr6',
},
{
id: '2',
attr1: 'attr1',
attr2: 'attr2',
attr3: 'attr3',
attr4: 'attr4',
attr5: 'attr5',
attr6: 'attr6',
},
];
\ No newline at end of file
import { useMemo, useState } from 'react';
import classNames from 'classnames';
import { ResizableBox } from 'react-resizable';
import { CaretLeftOutlined, CaretRightOutlined } from '@ant-design/icons';
import DataMasterTree from './Component/DataMasterTree';
import './index.less';
import DataMasterTable from './Component/DataMasterTable';
const DataMaster = (props) => {
const [collapse, setCollapse] = useState(false);
const classes = useMemo(() => {
return classNames('data-master', {
'data-master-collapse': collapse,
});
}, [collapse]);
const onCollapseClick = () => {
setCollapse(!collapse);
}
return (
<div className={classes}>
<ResizableBox
className='left-wrap'
width={230}
height={Infinity}
axis='x'
minConstraints={[230, Infinity]} maxConstraints={[Infinity, Infinity]}
>
<DataMasterTree />
</ResizableBox>
<div className='left-collapse-wrap'>
<div className='left-collapse' onClick={onCollapseClick}>
{ collapse ? <CaretRightOutlined /> : <CaretLeftOutlined /> }
</div>
</div>
<div className='right-wrap'>
<DataMasterTable />
</div>
</div>
)
}
export default DataMaster;
\ No newline at end of file
.data-master {
display: flex;
flex: auto;
height: 100%;
background-color: #fff;
.left-wrap {
flex: none;
overflow: hidden;
height: 100%;
border-right: 1px solid #EFEFEF;
}
.left-collapse-wrap {
flex: none;
position: relative;
width: 20px;
height: 100%;
.left-collapse {
display: inline-flex;
justify-content: center;
align-items: center;
left: 0;
right: 0;
background: #f2f5fc;
position: absolute;
top: calc(50% - 40px);
width: 12px;
height: 80px;
border-radius: 0 12px 12px 0;
-ms-transform: translateY(-50%);
transform: translateY(-50%);
cursor: pointer;
}
}
.right-wrap {
flex: 1;
overflow: hidden;
height: 100%;
}
}
.data-master-collapse {
.left-wrap {
width: 0 !important;
}
}
\ No newline at end of file
import { useEffect, useMemo, useState } from 'react';
import { Table } from 'antd';
import { Resizable } from 'react-resizable';
const ResizeableHeaderCell = props => {
const { onResize, width, onClick, ...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
onClick={onClick}
{...restProps}
/>
</Resizable>
);
};
const ResizeableTable = (props) => {
const { columns, ...restProps } = props;
const [_columns, setColumns] = useState([]);
useEffect(() => {
setColumns([...columns, { title: '', dataIndex: 'auto' }]);
}, [columns])
const handleResize = index => (e, { size }) => {
const nextColumns = [..._columns];
nextColumns[index] = {
...nextColumns[index],
width: size.width,
};
setColumns(nextColumns);
};
return (
<Table
components={{
header: {
cell: ResizeableHeaderCell,
}
}}
columns={
_columns.map((column, index) => {
return {
...column,
onHeaderCell: column => ({
width: column.width,
onResize: handleResize(index),
}),
};
})
}
{ ...restProps }
/>
);
}
export default ResizeableTable;
\ No newline at end of file
......@@ -12,6 +12,7 @@ import AssetManage from './AssetManage';
import AssetResourceBrowse from './AssetResourceBrowse';
import AssetBrowse from './AssetBrowse';
import AssetRecycle from './AssetRecycle';
import DataMaster from "./DataMaster";
class Manage extends Component {
......@@ -33,6 +34,7 @@ class Manage extends Component {
<Route path={`${match.path}/asset-resource-browse`} component={AssetResourceBrowse} />
<Route path={`${match.path}/asset-browse`} component={AssetBrowse} />
<Route path={`${match.path}/asset-recycle`} component={AssetRecycle} />
<Route path={`${match.path}/data-master`} component={DataMaster} />
</Switch>
) : (
<GetSession {...this.props} />
......
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