import React, {Component} from 'react'
|
import { fromJS } from 'immutable'
|
import { Spin, notification, Button, Table, Modal, ConfigProvider, Tree, Input, Empty } from 'antd'
|
import moment from 'moment'
|
import md5 from 'md5'
|
import zhCN from 'antd/es/locale/zh_CN'
|
import { ApiOutlined } from '@ant-design/icons'
|
|
import Api from '@/api'
|
import Utils from '@/utils/utils.js'
|
import asyncComponent from '@/utils/asyncComponent'
|
import './index.scss'
|
|
const { confirm } = Modal
|
const { TreeNode } = Tree
|
const { Search } = Input
|
|
const Header = asyncComponent(() => import('./header'))
|
const TransferForm = asyncComponent(() => import('@/templates/zshare/basetransferform'))
|
|
class RoleManage extends Component {
|
state = {
|
app: null,
|
loading: false,
|
menulist: [],
|
columns: [
|
{
|
title: '菜单名称', dataIndex: 'MenuName', key: 'MenuName', align: 'center', render: (text, record) => {
|
if (record.extra) {
|
return <span style={{color: '#1890ff'}}>{text}</span>
|
} else if (record.interfaces === 'true') {
|
return <span><ApiOutlined style={{color: 'orange', marginRight: '5px'}} title="菜单中使用了外部接口" />{text}</span>
|
}
|
return text
|
}
|
},
|
{
|
title: '菜单参数', dataIndex: 'MenuNo', key: 'MenuNo', align: 'center'
|
},
|
{
|
title: '操作',
|
key: 'action',
|
align: 'center',
|
render: (text, record) => (
|
<div>
|
{record.type !== 'none' ?
|
<Button type="link" onClick={() => this.deleteMenu(record)} style={{color: '#ff4d4f'}}>删除</Button> :
|
<Button type="link" onClick={() => {
|
notification.warning({
|
top: 92,
|
message: '当前系统菜单尚未创建。',
|
duration: 5
|
})
|
}} style={{color: '#ff4d4f', opacity: '0.5'}}>删除</Button>}
|
<Button type="link" onClick={() => this.jumpApp(record)} style={{color: '#1890ff', marginLeft: '5px'}}>编辑</Button>
|
</div>
|
),
|
},
|
],
|
selectApp: null,
|
selectSubApp: null,
|
visible: false,
|
thawmenulist: [],
|
confirmLoading: false,
|
targetKeys: [],
|
trees: null,
|
expandedKeys: [],
|
searchkey: '',
|
appViewList: []
|
}
|
|
oriTrees = null
|
|
UNSAFE_componentWillMount() {
|
document.body.className = ''
|
let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
|
|
this.setState({app: param}, () => {
|
this.getTreeList()
|
this.getMenuList()
|
this.getAppViewList()
|
})
|
}
|
|
/**
|
* @description 组件销毁,清除state更新
|
*/
|
componentWillUnmount () {
|
this.setState = () => {
|
return
|
}
|
}
|
|
getAppViewList = () => {
|
const { app } = this.state
|
|
Api.getCloudConfig({
|
func: 's_get_keyids',
|
bid: app.ID
|
}).then(result => {
|
if (!result.status) {
|
notification.warning({
|
top: 92,
|
message: result.message,
|
duration: 5
|
})
|
return
|
}
|
this.setState({appViewList: result.data || []})
|
})
|
}
|
|
getMenuList = (reset, resolve) => {
|
const { app } = this.state
|
let param = {
|
func: 's_get_app_menus',
|
TypeCharOne: app.kei_no,
|
typename: app.typename,
|
LText: `select '${window.GLOB.appkey}'`,
|
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
|
lang: app.lang
|
}
|
|
param.secretkey = Utils.encrypt(param.LText, param.timestamp)
|
|
if (!resolve) {
|
this.setState({
|
loading: true
|
})
|
}
|
|
Api.getCloudConfig(param).then(result => {
|
if (result.status) {
|
let ub = app.user_binding === 'true' && app.userbind ? false : true
|
let im = app.instantMessage ? false : true
|
|
let menus = result.menus.map(item => {
|
item.nodes = ''
|
item.type = 'view'
|
if (item.menus_rolelist) {
|
try {
|
let pageParam = JSON.parse(window.decodeURIComponent(window.atob(item.menus_rolelist)))
|
item.nodes = pageParam
|
item.interfaces = pageParam.interfaces || 'false'
|
|
if (pageParam.type) {
|
item.type = pageParam.type
|
}
|
|
if (pageParam.version !== '1.0') {
|
item.nodes = ''
|
} else if (pageParam.login || pageParam.pass) {
|
item.nodes = ''
|
} else if (pageParam.type === 'im') {
|
item.nodes = ''
|
}
|
} catch (e) {
|
item.nodes = ''
|
}
|
|
delete item.menus_rolelist
|
}
|
|
if (app.userbind === item.MenuID) {
|
item.extra = true
|
ub = true
|
}
|
if (app.instantMessage === item.MenuID) {
|
item.extra = true
|
im = true
|
}
|
|
return item
|
})
|
|
if (!im) {
|
menus.push({nodes: '', type: 'none', extra: true, MenuID: app.instantMessage, MenuName: '即时通信'})
|
}
|
if (!ub) {
|
menus.push({nodes: '', type: 'none', extra: true, MenuID: app.userbind, MenuName: '用户绑定'})
|
}
|
|
this.setState({
|
menulist: menus
|
}, () => {
|
if (resolve) {
|
this.initMenutree(resolve)
|
} else if (reset && (!this.oriTrees || this.oriTrees.length === 0)) {
|
this.initMenutree()
|
} else if (!reset && this.oriTrees && this.oriTrees.length === 0) {
|
this.initMenutree()
|
}
|
this.setState({loading: false})
|
})
|
} else {
|
this.setState({
|
loading: false
|
})
|
notification.warning({
|
top: 92,
|
message: result.message,
|
duration: 5
|
})
|
}
|
})
|
}
|
|
getTreeList = () => {
|
const { app } = this.state
|
let param = {
|
func: 's_get_menus_roles_tree',
|
typecharone: app.kei_no,
|
lang: app.lang
|
}
|
|
param.upid = md5(window.GLOB.appkey + app.kei_no + app.typename + app.lang)
|
|
Api.getCloudConfig(param).then(result => {
|
if (result.status) {
|
if (!result.data || result.data.length === 0) {
|
this.oriTrees = []
|
if (this.state.menulist.length > 0) {
|
this.initMenutree()
|
}
|
this.setState({trees: [], loading: false})
|
} else {
|
this.oriTrees = result.data
|
this.initTrees(result.data)
|
this.setState({loading: false})
|
}
|
} else {
|
this.setState({
|
loading: false
|
})
|
notification.warning({
|
top: 92,
|
message: result.message,
|
duration: 5
|
})
|
}
|
})
|
}
|
|
initTrees = (data) => {
|
let trees = []
|
let map = new Map()
|
let _data = data.sort((a, b) => {
|
return a.sort - b.sort
|
})
|
|
_data.forEach(menu => {
|
if (menu.ParentID === 'top') {
|
trees.push({
|
key: menu.MenuID,
|
title: menu.MenuName,
|
children: []
|
})
|
} else {
|
map.set(menu.MenuID, menu)
|
}
|
})
|
|
let reset = (m) => {
|
return m.map(n => {
|
[...map.keys()].forEach(key => {
|
if (map.get(key).ParentID === n.key) {
|
let c = map.get(key)
|
n.children.push({
|
key: c.MenuID,
|
title: c.MenuName,
|
children: []
|
})
|
map.delete(key)
|
}
|
})
|
if (n.children.length > 0) {
|
n.children = reset(n.children)
|
}
|
return n
|
})
|
}
|
|
trees = reset(trees)
|
|
let expandedKeys = this.getExpandedKeys(trees, 0, [])
|
|
this.setState({trees, expandedKeys})
|
}
|
|
getExpandedKeys = (trees, i, keys) => {
|
if (i >= 3 || !trees[0]) return keys
|
|
keys.push(trees[0].key)
|
|
i++
|
|
if (trees[0].children && trees[0].children.length > 0) {
|
keys = this.getExpandedKeys(trees[0].children, i, keys)
|
}
|
|
return keys
|
}
|
|
initMenutree = (resolve) => {
|
const { menulist } = this.state
|
|
if (!menulist || menulist.length === 0) {
|
this.setState({trees: [], expandedKeys: []}, () => {
|
if (resolve) {
|
this.execSave(resolve)
|
}
|
})
|
|
return
|
}
|
|
let navbars = []
|
let map = new Map()
|
|
fromJS(menulist).toJS().forEach(menu => {
|
if (!menu.nodes) return
|
|
if (menu.type === 'navbar') {
|
navbars.push(menu.nodes)
|
} else {
|
map.set(menu.MenuID, menu.nodes)
|
}
|
})
|
|
let data = []
|
|
if (navbars.length === 0) {
|
data = [...map.values()]
|
} else {
|
let reset = (m) => {
|
return m.map(n => {
|
if (n.children && n.children.length > 0) {
|
n.children = reset(n.children)
|
} else if (map.has(n.key)) {
|
let p = map.get(n.key)
|
if (p.children && p.children.length > 0) {
|
n.children = reset(p.children)
|
}
|
map.delete(n.key)
|
}
|
return n
|
})
|
}
|
|
data = reset(navbars)
|
data = [...data, ...map.values()]
|
}
|
|
let expandedKeys = this.getExpandedKeys(data, 0, [])
|
|
this.setState({trees: [], expandedKeys: []}, () => {
|
this.setState({trees: data, expandedKeys}, () => {
|
if (resolve) {
|
this.execSave(resolve)
|
}
|
})
|
})
|
}
|
|
getThawMenulist = () => {
|
const { app } = this.state
|
|
Api.getCloudConfig({
|
func: 'sPC_Get_FrozenMenu',
|
ParentID: 'mk_app',
|
TypeCharOne: app.kei_no,
|
typename: app.typename,
|
lang: app.lang
|
}).then(res => {
|
if (res.status) {
|
this.setState({
|
thawmenulist: res.data.map(menu => {
|
return {
|
key: menu.MenuID,
|
title: menu.MenuName
|
}
|
})
|
})
|
} else {
|
notification.warning({
|
top: 92,
|
message: res.message,
|
duration: 5
|
})
|
}
|
})
|
}
|
|
deleteMenu = (record) => {
|
const { app, appViewList } = this.state
|
const _this = this
|
|
let param = {
|
func: 'sPC_MainMenu_Del',
|
MenuID: record.MenuID,
|
TypeCharOne: app.kei_no,
|
typename: app.typename,
|
lang: app.lang
|
}
|
|
let _param = {
|
func: 's_kei_link_keyids_addupt',
|
BID: app.ID,
|
exec_type: 'y',
|
LText: ''
|
}
|
|
let _appViewList = appViewList.filter(item => item.keys_id !== record.MenuID)
|
|
if (appViewList.length !== _appViewList.length) {
|
_param.LText = _appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
|
_param.LText = _param.LText.join(' union all ')
|
_param.LText = Utils.formatOptions(_param.LText)
|
|
_param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
|
_param.secretkey = Utils.encrypt('', _param.timestamp)
|
} else {
|
_param = null
|
}
|
|
confirm({
|
content: '确定删除该菜单吗?',
|
onOk() {
|
return new Promise(resolve => {
|
Api.getCloudConfig(param).then(result => {
|
if (result.status) {
|
notification.success({
|
top: 92,
|
message: '操作成功!',
|
duration: 3
|
})
|
_this.getMenuList(true)
|
|
if (_param) {
|
Api.getCloudConfig(_param).then(res => {
|
if (!res.status) {
|
notification.warning({
|
top: 92,
|
message: res.message,
|
duration: 5
|
})
|
} else {
|
_this.setState({appViewList: _appViewList})
|
}
|
})
|
}
|
} else {
|
notification.warning({
|
top: 92,
|
message: result.message,
|
duration: 5
|
})
|
}
|
resolve()
|
}, () => {
|
resolve()
|
})
|
})
|
},
|
onCancel() {}
|
})
|
}
|
|
thawSubmit = () => {
|
const { targetKeys, app } = this.state
|
|
if (targetKeys.length === 0) {
|
notification.warning({
|
top: 92,
|
message: '请选择解除冻结的菜单!',
|
duration: 5
|
})
|
return
|
}
|
|
this.setState({
|
confirmLoading: true
|
})
|
|
Api.getCloudConfig({
|
func: 'sPC_MainMenu_ReDel',
|
MenuID: targetKeys.join(','),
|
TypeCharOne: app.kei_no,
|
typename: app.typename,
|
lang: app.lang
|
}).then(res => {
|
if (!res.status) {
|
notification.warning({
|
top: 92,
|
message: res.message,
|
duration: 2
|
})
|
this.setState({
|
confirmLoading: false
|
})
|
} else {
|
let param = {
|
func: 's_get_app_menus',
|
TypeCharOne: app.kei_no,
|
typename: app.typename,
|
LText: `select '${window.GLOB.appkey}'`,
|
timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
|
lang: app.lang
|
}
|
|
param.secretkey = Utils.encrypt(param.LText, param.timestamp)
|
|
Api.getCloudConfig(param).then(result => {
|
if (result.status) {
|
let list = []
|
this.setState({
|
menulist: result.menus.map(item => {
|
item.nodes = ''
|
item.type = 'view'
|
if (item.menus_rolelist) {
|
try {
|
let pageParam = JSON.parse(window.decodeURIComponent(window.atob(item.menus_rolelist)))
|
item.nodes = pageParam
|
|
if (pageParam.type) {
|
item.type = pageParam.type
|
}
|
|
if (pageParam.version !== '1.0') {
|
item.nodes = ''
|
} else if (pageParam.login || pageParam.pass) {
|
item.nodes = ''
|
} else if (pageParam.type === 'im') {
|
item.nodes = ''
|
}
|
} catch (e) {
|
item.nodes = ''
|
}
|
|
delete item.menus_rolelist
|
}
|
|
return item
|
})
|
}, () => {
|
if (!this.oriTrees || this.oriTrees.length === 0) {
|
this.initMenutree()
|
}
|
})
|
|
if (app.typename === 'pc' && list.length > 0) {
|
Api.getCloudConfig({
|
func: 'sPC_MainMenu_ReDel',
|
MenuID: list.join(','),
|
TypeCharOne: app.kei_no,
|
typename: app.typename,
|
lang: app.lang
|
}).then(response => {
|
if (!response.status) {
|
notification.warning({
|
top: 92,
|
message: response.message,
|
duration: 2
|
})
|
this.setState({
|
confirmLoading: false
|
})
|
} else {
|
this.setState({
|
confirmLoading: false,
|
visible: false,
|
targetKeys: []
|
})
|
}
|
})
|
} else {
|
this.setState({
|
confirmLoading: false,
|
visible: false,
|
targetKeys: []
|
})
|
}
|
} else {
|
this.setState({
|
confirmLoading: false
|
})
|
notification.warning({
|
top: 92,
|
message: result.message,
|
duration: 5
|
})
|
}
|
})
|
}
|
})
|
}
|
|
onDrop = info => {
|
const dropKey = info.node.props.eventKey
|
const dragKey = info.dragNode.props.eventKey
|
const dropPos = info.node.props.pos.split('-')
|
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
|
|
const loop = (data, key, callback) => {
|
data.forEach((item, index, arr) => {
|
if (item.key === key) {
|
return callback(item, index, arr)
|
}
|
if (item.children) {
|
return loop(item.children, key, callback)
|
}
|
})
|
}
|
const data = [...this.state.trees]
|
|
let dragObj
|
loop(data, dragKey, (item, index, arr) => {
|
arr.splice(index, 1)
|
dragObj = item
|
})
|
|
if (!info.dropToGap) {
|
loop(data, dropKey, item => {
|
item.children = item.children || []
|
|
item.children.push(dragObj)
|
})
|
} else if ((info.node.props.children || []).length > 0 && info.node.props.expanded && dropPosition === 1 ) {
|
loop(data, dropKey, item => {
|
item.children = item.children || []
|
|
item.children.unshift(dragObj)
|
})
|
} else {
|
let ar;
|
let i;
|
|
loop(data, dropKey, (item, index, arr) => {
|
ar = arr
|
i = index
|
})
|
|
if (dropPosition === -1) {
|
ar.splice(i, 0, dragObj)
|
} else {
|
ar.splice(i + 1, 0, dragObj)
|
}
|
}
|
|
this.setState({
|
trees: data
|
})
|
}
|
|
renderNode = data => {
|
return data.map(item => {
|
if (item.children && item.children.length) {
|
return (
|
<TreeNode key={item.key} title={item.title}>
|
{this.renderNode(item.children)}
|
</TreeNode>
|
)
|
}
|
return <TreeNode key={item.key} title={item.title} />
|
})
|
}
|
|
initTree = () => {
|
const _this = this
|
confirm({
|
content: '权限树会重新生成,确定执行吗?',
|
onOk() {
|
return new Promise(resolve => {
|
_this.getMenuList(true, resolve)
|
})
|
},
|
onCancel() {}
|
})
|
}
|
|
syncTree = () => {
|
const _this = this
|
|
confirm({
|
content: '同步会根据菜单删除或新增节点,确定执行吗?',
|
onOk() {
|
return new Promise(resolve => {
|
_this.syncMenutree(resolve)
|
})
|
},
|
onCancel() {}
|
})
|
}
|
|
saveTree = () => {
|
// const { trees } = this.state
|
const _this = this
|
|
// if (!trees || trees.length === 0) {
|
// notification.warning({
|
// top: 92,
|
// message: '未获取到权限信息!',
|
// duration: 5
|
// })
|
// return
|
// }
|
|
confirm({
|
content: '确定执行吗?',
|
onOk() {
|
return new Promise(resolve => {
|
_this.execSave(resolve)
|
})
|
},
|
onCancel() {}
|
})
|
}
|
|
syncMenutree = (resolve) => {
|
const { menulist } = this.state
|
|
if (menulist.length === 0) {
|
this.setState({trees: [], expandedKeys: []}, () => {
|
this.execSave(resolve)
|
})
|
|
return
|
}
|
|
let navbars = []
|
let map = new Map()
|
|
fromJS(menulist).toJS().forEach(menu => {
|
if (!menu.nodes) return
|
|
if (menu.type === 'navbar') {
|
navbars.push(menu.nodes)
|
} else {
|
map.set(menu.MenuID, menu.nodes)
|
}
|
})
|
|
let re = {}
|
this.oriTrees && this.oriTrees.forEach(item => {
|
if (item.ParentID === 'top') return
|
if (!re[item.ParentID]) {
|
re[item.ParentID] = []
|
}
|
re[item.ParentID].push(item.MenuID)
|
})
|
|
let data = []
|
|
if (navbars.length === 0) {
|
data = [...map.values()]
|
} else {
|
let reset = (m) => {
|
return m.map(n => {
|
if (n.children && n.children.length > 0) {
|
n.children = reset(n.children)
|
} else if (map.has(n.key)) {
|
let p = map.get(n.key)
|
if (p.children && p.children.length > 0) {
|
n.children = reset(p.children)
|
}
|
map.delete(n.key)
|
}
|
if (re[n.key]) {
|
n.children = n.children || []
|
re[n.key].forEach(c => {
|
if (map.has(c)) {
|
let p = map.get(c)
|
if (p.children && p.children.length > 0) {
|
p.children = reset(p.children)
|
}
|
map.delete(c)
|
n.children.push(p)
|
}
|
})
|
}
|
return n
|
})
|
}
|
|
data = reset(navbars)
|
data = [...data, ...map.values()]
|
}
|
|
let expandedKeys = this.getExpandedKeys(data, 0, [])
|
|
this.setState({trees: [], expandedKeys: []}, () => {
|
this.setState({trees: data, expandedKeys}, () => {
|
this.execSave(resolve)
|
})
|
})
|
}
|
|
execSave = (resolve) => {
|
const { trees, app } = this.state
|
|
let lines = []
|
let i = 0
|
let reset = (m) => {
|
m.children.forEach(n => {
|
lines.push(`'${n.key}','${n.title}','${m.key}',${i}`)
|
i++
|
if (n.children) {
|
reset(n)
|
}
|
})
|
}
|
|
trees.forEach(g => {
|
lines.push(`'${g.key}','${g.title}','top',${i}`)
|
i++
|
if (g.children) {
|
reset(g)
|
}
|
})
|
|
let param = {
|
func: 's_menus_roles_tree_adduptdel',
|
typecharone: app.kei_no,
|
typename: app.typename,
|
lang: app.lang
|
}
|
|
lines = lines.join(';')
|
|
param.upid = md5(window.GLOB.appkey + param.typecharone + param.typename + param.lang)
|
param.menus_roles_longtext = window.btoa(window.encodeURIComponent(lines))
|
|
Api.getCloudConfig(param).then(result => {
|
if (result.status) {
|
notification.success({
|
top: 92,
|
message: '操作成功!',
|
duration: 3
|
})
|
} else {
|
notification.warning({
|
top: 92,
|
message: result.message,
|
duration: 5
|
})
|
}
|
resolve()
|
}, () => {
|
resolve()
|
})
|
}
|
|
triggerThaw = () => {
|
this.getThawMenulist()
|
this.setState({ visible: true, targetKeys: [] })
|
}
|
|
jumpApp = (item) => {
|
const { app } = this.state
|
|
let route = 'mobdesign'
|
if (app.typename === 'pc') {
|
route = 'pcdesign'
|
}
|
if (item.type === 'navbar') {
|
notification.warning({
|
top: 92,
|
message: '导航栏不可单独编辑,请在含有导航栏的页面中修改。',
|
duration: 5
|
})
|
return
|
}
|
|
if (app.instantMessage && item.MenuID === app.instantMessage) {
|
route = 'imdesign'
|
}
|
|
window.open(window.location.href.replace(/#.+/ig, `#/${route}/${window.btoa(window.encodeURIComponent(JSON.stringify({...app, MenuID: item.MenuID, type: 'app'})))}`))
|
}
|
|
render () {
|
const { app, loading, columns, menulist, trees, searchkey } = this.state
|
let _menulist = menulist
|
|
if (searchkey) {
|
_menulist = _menulist.filter(item => item.MenuName.toLowerCase().indexOf(searchkey.toLowerCase()) > -1)
|
}
|
|
return (
|
<div className="mk-role-manage">
|
<ConfigProvider locale={zhCN}>
|
<Header app={app} />
|
{loading ?
|
<div className="loading-mask">
|
<Spin size="large" />
|
</div> : null
|
}
|
<div className="view-wrap">
|
<div className="left-view">
|
<div className="app-table">
|
<div className="app-action">
|
<Button className="mk-green" onClick={this.triggerThaw}>解冻菜单</Button>
|
<Search placeholder="综合搜索" onSearch={value => this.setState({ searchkey: value })} enterButton />
|
</div>
|
<Table
|
rowKey="MenuID"
|
columns={columns}
|
dataSource={_menulist}
|
pagination={false}
|
/>
|
</div>
|
</div>
|
<div className="right-view">
|
<div className="app-action">
|
<Button className="mk-primary" onClick={this.initTree}>重置</Button>
|
{/* <Button className="mk-purple" onClick={this.syncTree}>同步</Button> */}
|
<Button className="mk-green save" onClick={this.saveTree}>保存</Button>
|
</div>
|
{trees && trees.length ? <Tree
|
className="draggable-tree"
|
defaultExpandedKeys={this.state.expandedKeys}
|
// showLine
|
draggable
|
blockNode
|
onDrop={this.onDrop}
|
>
|
{this.renderNode(trees)}
|
</Tree> : <div className="empty">
|
<Empty />
|
</div>}
|
</div>
|
</div>
|
<Modal
|
title="解除冻结"
|
visible={this.state.visible}
|
width={600}
|
onOk={this.thawSubmit}
|
confirmLoading={this.state.confirmLoading}
|
onCancel={() => this.setState({visible: false, targetKeys: []})}
|
destroyOnClose
|
>
|
<TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>
|
</Modal>
|
</ConfigProvider>
|
</div>
|
)
|
}
|
}
|
|
export default RoleManage
|