import React, {Component} from 'react'
|
import PropTypes from 'prop-types'
|
import { is, fromJS } from 'immutable'
|
import { notification, Spin, Tabs, Tree, Row, Col, Card, Input, Empty } from 'antd'
|
import { FolderOpenOutlined, FolderOutlined, FileOutlined } from '@ant-design/icons'
|
|
import Api from '@/api'
|
import zhCN from '@/locales/zh-CN/main.js'
|
import enUS from '@/locales/en-US/main.js'
|
import Utils from '@/utils/utils.js'
|
import UtilsDM from '@/utils/utils-datamanage.js'
|
import MKEmitter from '@/utils/events.js'
|
import asyncComponent from '@/utils/asyncComponent'
|
import asyncSpinComponent from '@/utils/asyncSpinComponent'
|
import MkIcon from '@/components/mk-icon'
|
import NotFount from '@/components/404'
|
import './index.scss'
|
|
const SubTable = asyncSpinComponent(() => import('@/tabviews/subtable'))
|
const SettingComponent = asyncComponent(() => import('@/tabviews/zshare/settingcomponent'))
|
const PagemsgComponent = asyncComponent(() => import('@/tabviews/zshare/pageMessage'))
|
|
const { TabPane } = Tabs
|
const { TreeNode } = Tree
|
const { Search } = Input
|
|
class TreePage extends Component {
|
static propTpyes = {
|
param: PropTypes.string, // 其他页面传递的参数
|
MenuID: PropTypes.string, // 菜单Id
|
MenuNo: PropTypes.string, // 菜单参数
|
MenuName: PropTypes.string // 菜单名称
|
}
|
|
state = {
|
dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
|
ContainerId: Utils.getuuid(), // 菜单外层html Id
|
loadingview: true, // 页面加载中
|
BID: null, // 页面跳转时携带ID
|
viewlost: false, // 页面丢失:1、未获取到配置-页面丢失;2、页面未启用
|
lostmsg: '', // 页面丢失时的提示信息
|
config: {}, // 页面配置信息,包括按钮、搜索、显示列、标签等
|
setting: null, // 页面全局设置:数据源、按钮及显示列固定、主键等
|
treedata: null, // 列表数据集
|
treeNodes: null, // 列表数据集
|
loading: false, // 列表数据加载中
|
BIDs: {}, // 上级表id
|
visible: false, // 弹框显示隐藏控制
|
confirmLoading: false,// 自定义设置模态框加载中
|
revertLoading: false, // 恢复默认设置
|
expandedKeys: [], // 展开的树节点
|
selectedKeys: [], // 选中的树节点
|
shortcuts: null, // 快捷键
|
searchKey: ''
|
}
|
|
/**
|
* @description 获取页面配置信息
|
*/
|
async loadconfig () {
|
const { param, MenuName, MenuID } = this.props
|
|
let _param = {
|
func: 'sPC_Get_LongParam',
|
MenuID: MenuID
|
}
|
let result = await Api.getCacheConfig(_param)
|
|
if (result.status) {
|
let config = ''
|
let shortcuts = []
|
|
try { // 配置信息解析
|
config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
|
config.MenuID = MenuID
|
config.MenuName = MenuName
|
config.setting.$name = MenuName
|
} catch (e) {
|
console.warn('Parse Failure')
|
config = ''
|
}
|
|
if (result.LongParamUser) {
|
try { // 配置信息解析
|
let userConfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParamUser)))
|
if (userConfig) {
|
shortcuts = userConfig.action
|
userConfig.printers.forEach(item => {
|
window.GLOB.UserCacheMap.set(item.parentId + item.uuid, item)
|
})
|
}
|
} catch (e) {
|
console.warn('Parse Failure')
|
}
|
}
|
|
// 页面配置解析错误时提示
|
if (!config) {
|
this.setState({
|
loadingview: false,
|
viewlost: true
|
})
|
return
|
}
|
|
// 页面未启用时,显示未启用页面
|
if (!config.enabled) {
|
this.setState({
|
loadingview: false,
|
viewlost: true,
|
lostmsg: this.state.dict['main.view.unenabled']
|
})
|
return
|
}
|
|
// 权限过滤
|
config.tabgroups.forEach(group => {
|
group.sublist = group.sublist.filter(tab => {
|
if (tab.supMenu === 'mainTable' || (!tab.supMenu && tab.level === 0)) {
|
tab.isTreeNode = true
|
}
|
if (tab.supMenu === 'mainTable') {
|
tab.supMenu = MenuID
|
}
|
return window.GLOB.mkActions[tab.linkTab]}
|
)
|
})
|
|
let _tabgroups = []
|
|
config.tabgroups.forEach(group => {
|
let _group = fromJS(group).toJS()
|
_group.sublist = _group.sublist.filter(tab => tab.level === 0)
|
|
if (_group.sublist.length > 0) {
|
_tabgroups.push(_group)
|
}
|
})
|
|
// 数据源信息预处理
|
config.setting.laypage = false // 是否分页,转为boolean 统一格式
|
config.setting.execute = config.setting.default !== 'false' // 默认sql是否执行,转为boolean 统一格式
|
config.setting.customScript = '' // 自定义脚本
|
|
// 数据源
|
if (config.setting.interType === 'inner' && !config.setting.innerFunc) {
|
config.setting.interType = 'system'
|
}
|
|
if (config.setting.interType === 'system') {
|
if (config.setting.scripts && config.setting.scripts.length > 0) {
|
let _customScript = ''
|
config.setting.scripts.forEach(item => {
|
if (item.status === 'false') return
|
_customScript += `
|
${item.sql}
|
`
|
})
|
config.setting.customScript = _customScript
|
}
|
|
if (!config.setting.execute) { // 默认sql 不执行时 置空
|
config.setting.dataresource = ''
|
} else {
|
config.setting.dataresource = config.setting.dataresource || ''
|
}
|
if (/\s/.test(config.setting.dataresource)) {
|
config.setting.dataresource = '(' + config.setting.dataresource + ') tb'
|
}
|
|
if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
|
config.setting.dataresource = config.setting.dataresource.replace(/\$@/ig, '/*')
|
config.setting.dataresource = config.setting.dataresource.replace(/@\$/ig, '*/')
|
config.setting.customScript = config.setting.customScript.replace(/\$@/ig, '/*')
|
config.setting.customScript = config.setting.customScript.replace(/@\$/ig, '*/')
|
} else {
|
config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
|
config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
|
}
|
|
let userName = sessionStorage.getItem('User_Name') || ''
|
let fullName = sessionStorage.getItem('Full_Name') || ''
|
|
if (sessionStorage.getItem('isEditState') === 'true') {
|
userName = sessionStorage.getItem('CloudUserName') || ''
|
fullName = sessionStorage.getItem('CloudFullName') || ''
|
}
|
|
let regs = [
|
{ reg: /@userName@/ig, value: `'${userName}'` },
|
{ reg: /@fullName@/ig, value: `'${fullName}'` }
|
]
|
|
regs.forEach(cell => {
|
config.setting.dataresource = config.setting.dataresource.replace(cell.reg, cell.value)
|
config.setting.customScript = config.setting.customScript.replace(cell.reg, cell.value)
|
})
|
}
|
|
this.setState({
|
BID: param && param.$BID ? param.$BID : '',
|
loadingview: false,
|
config: config,
|
setting: config.setting,
|
tabgroups: _tabgroups,
|
shortcuts
|
}, () => {
|
this.loadmaindata()
|
this.setShortcut()
|
})
|
} else {
|
this.setState({
|
loadingview: false,
|
viewlost: true
|
})
|
notification.warning({
|
top: 92,
|
message: result.message,
|
duration: 5
|
})
|
}
|
}
|
|
setShortcut = () => {
|
const { shortcuts } = this.state
|
|
if (!shortcuts || shortcuts.length === 0) {
|
document.onkeydown = () => {}
|
return
|
}
|
|
document.onkeydown = (event) => {
|
let e = event || window.event
|
let keyCode = e.keyCode || e.which || e.charCode
|
let preKey = ''
|
|
if (e.ctrlKey) {
|
preKey = 'ctrl'
|
} else if (e.shiftKey) {
|
preKey = 'shift'
|
} else if (e.altKey) {
|
preKey = 'alt'
|
}
|
|
if (!preKey || !keyCode) return
|
|
let _shortcut = `${preKey}+${keyCode}`
|
|
shortcuts.some(item => {
|
if (item.$shortcut === _shortcut) {
|
MKEmitter.emit('triggerBtnId', item.uuid)
|
|
let element = item.parentId ? document.getElementById(item.parentId) : '' // 标签切换
|
if (element && element.click) {
|
element.click()
|
}
|
|
return true
|
}
|
return false
|
})
|
}
|
}
|
|
/**
|
* @description 主表数据加载
|
*/
|
async loadmaindata () {
|
const { setting, searchKey, BID } = this.state
|
|
this.setState({
|
loading: true
|
})
|
|
let arr_field = `${setting.valueField},${setting.labelField},${setting.parentField}`
|
let param = UtilsDM.getQueryDataParams(setting, arr_field, [], setting.order, '', '', BID)
|
|
let result = await Api.genericInterface(param)
|
if (result.status) {
|
let parentNodes = []
|
let _options = []
|
result.data.forEach(item => {
|
let pval = item[setting.parentField]
|
let val = item[setting.valueField]
|
|
if (!val) return
|
|
if (pval === setting.mark) {
|
parentNodes.push({
|
title: item[setting.labelField] || '',
|
key: val,
|
parentId: '',
|
level: 1
|
})
|
} else if (pval) {
|
_options.push({
|
title: item[setting.labelField] || '',
|
key: val,
|
parentId: pval
|
})
|
}
|
})
|
let _treedata = this.getTree(parentNodes, _options)
|
|
let _treeNodes = []
|
|
if (!searchKey) {
|
_treeNodes = fromJS(_treedata).toJS()
|
} else {
|
_treeNodes = this.getFilterTree(fromJS(_treedata).toJS(), searchKey.toLowerCase())
|
}
|
|
this.setState({
|
treedata: _treedata,
|
treeNodes: _treeNodes,
|
loading: false
|
})
|
} else {
|
this.setState({
|
loading: false,
|
treeNodes: [],
|
treedata: []
|
})
|
notification.error({
|
top: 92,
|
message: result.message,
|
duration: 10
|
})
|
}
|
}
|
|
/**
|
* @description 获取结构树信息
|
*/
|
getTree = (parents, options) => {
|
parents.forEach(parent => {
|
parent.children = []
|
// 添加菜单的子元素
|
options = options.filter(option => {
|
if (option.parentId === parent.key) {
|
option.level = parent.level + 1
|
|
parent.children.push(option)
|
return false
|
}
|
return true
|
})
|
|
if (parent.children.length === 0) {
|
parent.children = null
|
} else {
|
parent.children = this.getTree(parent.children, options)
|
}
|
})
|
return parents
|
}
|
|
/**
|
* @description 获取树节点
|
*/
|
renderTreeNodes = (nodes) => {
|
return nodes.map(item => {
|
if (item.children) {
|
return (
|
<TreeNode icon={<span><FolderOpenOutlined /><FolderOutlined /></span>} title={item.title} key={item.key} dataRef={item}>
|
{this.renderTreeNodes(item.children)}
|
</TreeNode>
|
)
|
}
|
return <TreeNode icon={<FileOutlined />} key={item.key} title={item.title} dataRef={item} isLeaf />
|
})
|
}
|
|
treeFilter = (value) => {
|
const { treedata } = this.state
|
|
let _treeNodes = []
|
|
if (!value) {
|
_treeNodes = fromJS(treedata).toJS()
|
} else {
|
_treeNodes = this.getFilterTree(fromJS(treedata).toJS(), value.toLowerCase())
|
}
|
|
this.setState({
|
searchKey: value,
|
treeNodes: _treeNodes
|
})
|
}
|
|
/**
|
* @description 获取结构树信息
|
*/
|
getFilterTree = (parents, searchKey) => {
|
return parents.filter(node => {
|
if (!node.children) {
|
return (node.title.toLowerCase().indexOf(searchKey) >= 0 || node.key.toLowerCase().indexOf(searchKey) >= 0)
|
} else {
|
if (node.title.toLowerCase().indexOf(searchKey) >= 0 || node.key.toLowerCase().indexOf(searchKey) >= 0) {
|
return true
|
}
|
|
node.children = this.getFilterTree(node.children, searchKey)
|
if (node.children.length === 0) {
|
return false
|
} else {
|
return true
|
}
|
}
|
})
|
}
|
|
selectTreeNode = (selectedKeys, {selected, node}) => {
|
const { config, ContainerId } = this.state
|
let _expandedKeys = fromJS(this.state.expandedKeys).toJS()
|
let _data = fromJS(node.props.dataRef).toJS()
|
|
if (_expandedKeys.indexOf(_data.key) >= 0) {
|
_expandedKeys = _expandedKeys.filter(key => key !== _data.key)
|
} else {
|
if (_data.children) {
|
_expandedKeys.push(_data.key)
|
_expandedKeys = Array.from(new Set(_expandedKeys))
|
}
|
}
|
|
if (selected) {
|
let _tabgroups = []
|
|
config.tabgroups.forEach(group => {
|
let _group = fromJS(group).toJS()
|
_group.sublist = _group.sublist.filter(tab => (!tab.level && tab.level !== 0) || tab.level === _data.level)
|
|
if (_group.sublist.length > 0) {
|
_tabgroups.push(_group)
|
}
|
})
|
|
delete _data.children
|
|
MKEmitter.emit('changeTableLine', ContainerId, this.props.MenuID, _data.key, _data)
|
|
this.setState({
|
tabgroups: _tabgroups,
|
expandedKeys: _expandedKeys,
|
selectedKeys: [_data.key]
|
})
|
} else {
|
this.setState({
|
expandedKeys: _expandedKeys,
|
selectedKeys: [_data.key]
|
})
|
}
|
}
|
|
/**
|
* @description 页面刷新,重新获取配置
|
*/
|
reloadview = () => {
|
this.setState({
|
loadingview: true,
|
viewlost: false,
|
config: {},
|
setting: null,
|
treedata: null,
|
treeNodes: null,
|
loading: false,
|
BIDs: {},
|
shortcuts: null,
|
expandedKeys: [],
|
selectedKeys: [],
|
searchKey: ''
|
}, () => {
|
this.loadconfig()
|
})
|
}
|
|
reloadData = (menuId) => {
|
const { MenuID } = this.props
|
|
if (MenuID !== menuId) return
|
|
this.loadmaindata()
|
}
|
|
reloadMenuView = (menuId) => {
|
const { MenuID } = this.props
|
|
if (MenuID !== menuId) return
|
|
this.reloadview()
|
}
|
|
resetActiveMenu = (menuId) => {
|
const { MenuID } = this.props
|
|
if (MenuID !== menuId) return
|
|
this.setShortcut()
|
}
|
|
changeTableLine = (ContainerId, tableId, id, data) => {
|
if (this.state.ContainerId !== ContainerId) return
|
|
this.setState({
|
BIDs: {...this.state.BIDs, [tableId]: id, [tableId + 'data']: data}
|
})
|
}
|
|
UNSAFE_componentWillMount () {
|
// 组件加载时,获取菜单数据
|
this.loadconfig()
|
}
|
|
shouldComponentUpdate (nextProps, nextState) {
|
return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
|
}
|
|
componentDidMount () {
|
MKEmitter.addListener('reloadData', this.reloadData)
|
MKEmitter.addListener('reloadMenuView', this.reloadMenuView)
|
MKEmitter.addListener('resetActiveMenu', this.resetActiveMenu)
|
MKEmitter.addListener('changeTableLine', this.changeTableLine)
|
}
|
|
/**
|
* @description 组件销毁,清除state更新,清除快捷键设置
|
*/
|
componentWillUnmount () {
|
this.setState = () => {
|
return
|
}
|
document.onkeydown = () => {}
|
MKEmitter.removeListener('reloadData', this.reloadData)
|
MKEmitter.removeListener('reloadMenuView', this.reloadMenuView)
|
MKEmitter.removeListener('resetActiveMenu', this.resetActiveMenu)
|
MKEmitter.removeListener('changeTableLine', this.changeTableLine)
|
}
|
|
changeExpandedKeys = (expandedKeys) => {
|
this.setState({
|
expandedKeys: expandedKeys
|
})
|
}
|
|
// 右键展开节点下的全部分支
|
changeExpandedAllKeys = ({event, node}) => {
|
const { expandedKeys } = this.state
|
let _node = node.props.dataRef
|
event.stopPropagation()
|
|
let keys = []
|
this.getExpandKeys(_node, keys)
|
|
this.setState({
|
expandedKeys: Array.from(new Set([...keys, ...expandedKeys])),
|
})
|
}
|
|
getExpandKeys = (node, keys) => {
|
if (node.children) {
|
keys.push(node.key)
|
node.children.forEach(_node => {
|
this.getExpandKeys(_node, keys)
|
})
|
}
|
}
|
|
render() {
|
const { setting, loadingview, viewlost, config, tabgroups, treeNodes, treedata, expandedKeys, selectedKeys, shortcuts } = this.state
|
|
return (
|
<div className="tree-page" id={this.state.ContainerId}>
|
{loadingview && <Spin size="large" />}
|
{setting ? <Row gutter={16}>
|
<Col span={setting.width}>
|
<Card
|
className="tree-card"
|
title={
|
<span className="tree-title">
|
<span className="title">{setting.title}</span>
|
{setting.searchable !== 'false' ? <Search allowClear onSearch={this.treeFilter} /> : null}
|
</span>
|
}
|
bordered={false}
|
>
|
{treeNodes && treeNodes.length > 0 ? <div className="tree-box">
|
<Tree
|
blockNode
|
onSelect={this.selectTreeNode}
|
expandedKeys={expandedKeys}
|
selectedKeys={selectedKeys}
|
onRightClick={this.changeExpandedAllKeys}
|
onExpand={this.changeExpandedKeys}
|
showIcon={setting.showIcon === 'true'}
|
showLine={setting.showLine === 'true'}
|
>
|
{this.renderTreeNodes(treeNodes)}
|
</Tree>
|
</div> : null}
|
{treeNodes && treeNodes.length === 0 ? <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> : null}
|
{!treedata ? <Spin /> : null}
|
</Card>
|
</Col>
|
<Col span={24 - setting.width}>
|
{tabgroups.map(group => (
|
<Tabs key={group.uuid} >
|
{group.sublist.map(_tab => {
|
return (
|
<TabPane tab={
|
<span id={_tab.uuid}>
|
{_tab.icon ? <MkIcon type={_tab.icon} /> : null}
|
{_tab.label}
|
</span>
|
} key={_tab.uuid}>
|
{_tab.type === 'SubTable' ?
|
<SubTable
|
Tab={_tab}
|
MenuID={_tab.linkTab}
|
mainSearch={null}
|
SupMenuID={this.props.MenuID}
|
ContainerId={this.state.ContainerId}
|
BID={this.state.BIDs[_tab.supMenu] || ''}
|
BData={this.state.BIDs[_tab.supMenu + 'data'] || ''}
|
/> : null}
|
</TabPane>
|
)
|
})}
|
</Tabs>)
|
)}
|
</Col>
|
</Row> : null}
|
{!window.GLOB.mkHS && window.GLOB.systemType !== 'production' ? <PagemsgComponent menu={{MenuName: this.props.MenuName, MenuNo: this.props.MenuNo}} config={config} dict={this.state.dict} /> : null}
|
{!window.GLOB.mkHS && shortcuts ? <SettingComponent config={config} dict={this.state.dict} shortcuts={shortcuts}/> : null}
|
{viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
|
</div>
|
)
|
}
|
}
|
|
export default TreePage
|