update 强化菜单

This commit is contained in:
2021-06-28 17:23:47 +08:00
parent f1ae3d5b2a
commit 6dceac060d
14 changed files with 491 additions and 243 deletions

View File

@@ -7,29 +7,31 @@ import { api } from 'common/api'
import { EMPTY_ID } from 'util/global'
const initialValues = {
type: '1',
openType: '1',
type: 1,
openType: 1,
weight: '2',
visible: true,
sort: 100
sort: 100,
}
export default class form extends Component {
state = {
// 加载状态
loading: true,
codes: {
menuType: [],
openType: []
openType: [],
menuWeight: [],
},
options: {
appList: [],
parentTreeData: []
parentTreeData: [],
},
addType: [],
type: initialValues.type,
openType: initialValues.openType,
icon: ''
icon: '',
}
// 表单实例
@@ -51,45 +53,49 @@ export default class form extends Component {
* 填充数据
* 可以在设置this.record之后对其作出数据结构调整
* [异步,必要]
* @param {*} params
* @param {*} params
*/
async fillData(params) {
const form = this.form.current
this.record = cloneDeep(params.record)
//#region 从后端转换成前段所需格式
const { menuType, openType } = await getDictData('menu_type', 'open_type')
const codes = await getDictData('menu_type', 'open_type', 'menu_weight')
const appList = await this.onLoadSysApplist()
let parentTreeData = []
if (params.isParent) {
parentTreeData = await this.onLoadMenuTree(params.parent.application)
} else if (params.record) {
}
if (params.record) {
parentTreeData = await this.onLoadMenuTree(params.record.application)
} else {
this.setState({ addType: params.addType })
if (params.addType.length) {
form.setFieldsValue({
type: params.addType[0],
})
}
}
const icon = params.record && params.record.icon
this.setState({
codes: {
menuType,
openType
},
codes,
options: {
appList,
parentTreeData
parentTreeData,
},
icon
icon,
})
//#endregion
const form = this.form.current
if (params.isParent) {
form.setFieldsValue({
pid: params.parent.id,
application: params.parent.application
application: params.parent.application,
})
} else {
form.setFieldsValue(this.record)
}
this.setState({
loading: false
})
this.setState({ loading: false })
this.onTypeChange()
}
@@ -98,7 +104,7 @@ export default class form extends Component {
* 获取数据
* 可以对postData进行数据结构调整
* [异步,必要]
* @returns
* @returns
*/
async getData() {
const form = this.form.current
@@ -123,30 +129,31 @@ export default class form extends Component {
async onLoadMenuTree(application) {
const { data } = await api.getMenuTree({ application })
return [{
id: EMPTY_ID,
parentId: undefined,
title: '顶级',
value: EMPTY_ID,
pid: undefined,
children: data,
}]
return [
{
id: EMPTY_ID,
parentId: undefined,
title: '顶级',
value: EMPTY_ID,
pid: undefined,
children: data,
},
]
}
onTypeChange() {
this.onTypeChangeGroup()
const form = this.form.current
const { type } = form.getFieldsValue()
if (['0', '2'].includes(type)) {
form.setFieldsValue({
openType: '0'
})
} else {
form.setFieldsValue({
openType: '1'
})
}
// const form = this.form.current
// const { type } = form.getFieldsValue()
// if ([0, 2].includes(type)) {
// form.setFieldsValue({
// openType: 0,
// })
// } else {
// form.setFieldsValue({
// openType: 1,
// })
// }
}
onOpenTypeChange() {
@@ -168,178 +175,221 @@ export default class form extends Component {
this.setState({
type,
openType
openType,
})
}
async onApplicationChange(value) {
this.setState({
loading: true
loading: true,
})
const parentTreeData = await this.onLoadMenuTree(value)
this.setState({
loading: false,
options: {
...this.state.options,
parentTreeData
}
parentTreeData,
},
})
this.form.current.setFieldsValue({
pid: undefined
pid: undefined,
})
}
onSelectIcon(icon) {
this.form.current.setFieldsValue({
icon
icon,
})
this.setState({ icon })
}
//#endregion
render() {
const { loading, codes, options, addType, type, openType, icon } = this.state
return (
<Form
initialValues={initialValues}
ref={this.form}
className="yo-form"
>
<Spin spinning={this.state.loading} indicator={<AntIcon type="loading" />}>
<Form initialValues={initialValues} ref={this.form} className="yo-form">
<Spin spinning={loading} indicator={<AntIcon type="loading" />}>
<div className="yo-form-group">
<h3 className="h3">基本信息</h3>
<div className="yo-form-group">
<Form.Item
label="菜单类型"
name="type"
help={
tooltip={
<>
目录默认添加在顶级
<br />菜单
<br />按钮
目录一级菜单默认添加在顶级
<br />
菜单二级菜单
<br />
按钮菜单中对应到接口的功能
</>
}
rules={[{ required: true, message: '请选择菜单类型' }]}
>
<Radio.Group onChange={(e) => this.onTypeChange(e)}>
{
this.state.codes.menuType.map(item => {
return (
<Radio.Button
key={item.code}
value={item.code}
>{item.value}</Radio.Button>
)
})
}
<Radio.Group onChange={e => this.onTypeChange(e)}>
{codes.menuType.map(item => {
return (
<Radio.Button
key={item.code}
value={+item.code}
disabled={!addType.includes(+item.code)}
>
{item.value}
</Radio.Button>
)
})}
</Radio.Group>
</Form.Item>
<Form.Item label="名称" name="name" rules={[{ required: true, message: '请输入名称' }]}>
<Form.Item
label="名称"
name="name"
rules={[{ required: true, message: '请输入名称' }]}
>
<Input autoComplete="off" placeholder="请输入名称" />
</Form.Item>
<Form.Item label="唯一编码" name="code">
<Input autoComplete="off" placeholder="请输入唯一编码" />
</Form.Item>
<Form.Item label="所属应用" name="application" rules={[{ required: true, message: '请选择所属应用' }]}>
<Select placeholder="请选择所属应用" onChange={(value) => this.onApplicationChange(value)}>
{
this.state.options.appList.map(item => {
return (
<Select.Option
key={item.code}
value={item.code}
>{item.name}</Select.Option>
)
})
}
<Form.Item
label="所属应用"
name="application"
rules={[{ required: true, message: '请选择所属应用' }]}
>
<Select
placeholder="请选择所属应用"
onChange={value => this.onApplicationChange(value)}
>
{options.appList.map(item => {
return (
<Select.Option key={item.code} value={item.code}>
{item.name}
</Select.Option>
)
})}
</Select>
</Form.Item>
{
this.state.type != 0 &&
<Form.Item label="父级菜单" name="pid" rules={[{ required: true, message: '请选择父级' }]}>
{type != 0 && (
<Form.Item
label="父级菜单"
name="pid"
rules={[{ required: true, message: '请选择父级' }]}
>
<TreeSelect
dropdownStyle={{ maxHeight: '300px', overflow: 'auto' }}
treeData={this.state.options.parentTreeData}
treeData={options.parentTreeData}
placeholder="请选择父级菜单"
/>
</Form.Item>
}
)}
<Form.Item
label="权重"
name="weight"
tooltip={
<>
系统权重菜单/功能任何角色可用
<br />
业务权重菜单/功能为超级管理员不可用可防止管理员误操作
</>
}
rules={[{ required: true, message: '请选择权重' }]}
>
<Radio.Group>
{codes.menuWeight.map(item => {
return (
<Radio.Button key={item.code} value={item.code}>
{item.value}
</Radio.Button>
)
})}
</Radio.Group>
</Form.Item>
</div>
<h3 className="h3">扩展信息</h3>
<div className="yo-form-group">
{
this.state.type == 1 &&
{type == 1 && (
<Form.Item label="打开方式" name="openType">
<Radio.Group onChange={(e) => this.onOpenTypeChange(e)}>
{
this.state.codes.openType.map(item => {
return (
<Radio.Button
key={item.code}
value={item.code}
>{item.value}</Radio.Button>
)
})
}
<Radio.Group onChange={e => this.onOpenTypeChange(e)}>
{codes.openType.map(item => {
return (
<Radio.Button key={item.code} value={+item.code}>
{item.value}
</Radio.Button>
)
})}
</Radio.Group>
</Form.Item>
}
{
this.state.type == 1 && this.state.openType == 1 &&
<Form.Item label="前端组件" name="component" rules={[{ required: true, message: '请输入前端组件' }]}>
)}
{type == 1 && openType == 1 && (
<Form.Item
label="前端组件"
name="component"
tooltip="打开新页签并渲染前端组件"
rules={[{ required: true, message: '请输入前端组件' }]}
>
<Input autoComplete="off" placeholder="请输入前端组件" />
</Form.Item>
}
{
this.state.type == 1 && this.state.openType == 2 &&
<Form.Item label="内链地址" name="router" rules={[{ required: true, message: '请输入内链地址' }]}>
)}
{type == 1 && openType == 2 && (
<Form.Item
label="内链地址"
name="link"
tooltip="打开新页签并使用iframe加载页面"
rules={[{ required: true, message: '请输入内链地址' }]}
>
<Input autoComplete="off" placeholder="请输入内链地址" />
</Form.Item>
}
{
this.state.type == 1 && this.state.openType == 3 &&
<Form.Item label="外链地址" name="link" rules={[{ required: true, message: '请输入外链地址' }]}>
)}
{type == 1 && openType == 3 && (
<Form.Item
label="外链地址"
name="redirect"
tooltip="打开新的浏览器窗口"
rules={[{ required: true, message: '请输入外链地址' }]}
>
<Input autoComplete="off" placeholder="请输入外链地址" />
</Form.Item>
}
{
this.state.type == 2 &&
<Form.Item label="权限标识" name="permission" rules={[{ required: true, message: '请输入权限标识' }]}>
)}
{type == 2 && (
<Form.Item
label="权限标识"
name="permission"
rules={[{ required: true, message: '请输入权限标识' }]}
>
<Input autoComplete="off" placeholder="请输入权限标识" />
</Form.Item>
}
{
this.state.type == 2 &&
<Form.Item label="关联上级菜单显示" name="visibleParent" valuePropName="checked">
)}
{type == 2 && (
<Form.Item
label="关联上级菜单显示"
name="visibleParent"
valuePropName="checked"
>
<Switch />
</Form.Item>
}
)}
<Form.Item label="可见性" name="visible" valuePropName="checked">
<Switch />
</Form.Item>
{
this.state.type != 2 &&
{type != 2 && (
<Form.Item label="图标" name="icon">
<Input
disabled
placeholder="请选择图标"
addonBefore={
this.state.icon &&
<AntIcon type={this.state.icon} />
}
addonBefore={icon && <AntIcon type={icon} />}
addonAfter={
<AntIcon
type="setting"
onClick={() =>
this
.iconSelector
.current
.open(this.form.current.getFieldValue('icon'))
this.iconSelector.current.open(
this.form.current.getFieldValue('icon')
)
}
/>
}
/>
</Form.Item>
}
)}
<Form.Item label="排序" name="sort">
<InputNumber
max={1000}
@@ -355,7 +405,7 @@ export default class form extends Component {
</div>
</Spin>
<IconSelector ref={this.iconSelector} onSelect={(icon) => this.onSelectIcon(icon)} />
<IconSelector ref={this.iconSelector} onSelect={icon => this.onSelectIcon(icon)} />
</Form>
)
}

View File

@@ -1,5 +1,5 @@
import React, { Component } from 'react'
import { Button, Table, Card, Popconfirm, message as Message, Row, Col, Tooltip } from 'antd'
import { Button, Table, Card, Popconfirm, message as Message, Row, Col, Tooltip, Tag } from 'antd'
import { isEqual } from 'lodash'
import { AntIcon, Auth, Container, ModalForm, QueryTable, QueryTableActions } from 'components'
import { api } from 'common/api'
@@ -24,6 +24,7 @@ export default class index extends Component {
codes: {
menuType: [],
menuWeight: [],
openType: [],
},
}
@@ -55,9 +56,36 @@ export default class index extends Component {
render: text => text && <AntIcon type={text} />,
},
{
title: '前端组件',
title: '连接',
width: 220,
dataIndex: 'component',
dataIndex: 'openType',
render: (text, record) => {
switch (text) {
case 1:
return (
<>
<Tag color="green">{this.bindCodeValue(text, 'open_type')}</Tag>{' '}
{record.component}
</>
)
case 2:
return (
<>
<Tag color="orange">{this.bindCodeValue(text, 'open_type')}</Tag>{' '}
{record.link}
</>
)
case 3:
return (
<>
<Tag color="red">{this.bindCodeValue(text, 'open_type')}</Tag>{' '}
{record.redirect}
</>
)
default:
return ''
}
},
},
{
title: '排序',
@@ -83,7 +111,9 @@ export default class index extends Component {
render: (text, record) => (
<QueryTableActions>
<Auth auth="sysMenu:edit">
<a onClick={() => this.onOpen(this.editForm, record)}>编辑</a>
<a onClick={() => this.onOpen({ modal: this.editForm, record })}>
编辑
</a>
</Auth>
<Auth auth="sysMenu:delete">
<Popconfirm
@@ -96,7 +126,16 @@ export default class index extends Component {
</Auth>
{record.type < 2 && (
<Auth auth="sysMenu:add">
<a onClick={() => this.onOpen(this.addForm, record, true)}>
<a
onClick={() =>
this.onOpen({
modal: this.addForm,
record,
isParent: true,
addType: record.type == 0 ? [1] : [2],
})
}
>
{record.type == 0 ? '新增子菜单' : '新增功能'}
</a>
</Auth>
@@ -125,7 +164,7 @@ export default class index extends Component {
*/
componentDidMount() {
this.table.current.onLoading()
getDictData('menu_type', 'menu_weight').then(res => {
getDictData('menu_type', 'menu_weight', 'open_type').then(res => {
this.setState(
{
codes: res,
@@ -162,7 +201,7 @@ export default class index extends Component {
name = toCamelCase(name)
const codes = this.state.codes[name]
if (codes) {
const c = codes.find(p => p.code === code)
const c = codes.find(p => p.code == code)
if (c) {
return c.value
}
@@ -175,15 +214,17 @@ export default class index extends Component {
* @param {*} modal
* @param {*} record
*/
onOpen(modal, record, isParent = false) {
onOpen({ modal, record, isParent = false, addType = [] }) {
const params = isParent
? {
parent: record,
isParent,
addType,
}
: {
record,
isParent,
addType,
}
modal.current.open(params)
@@ -246,7 +287,9 @@ export default class index extends Component {
<Tooltip title="编辑">
<a
className="link-gray"
onClick={() => this.onOpen(this.editForm, item)}
onClick={() =>
this.onOpen({ modal: this.editForm, record: item })
}
>
<AntIcon type="edit" />
</a>
@@ -280,9 +323,12 @@ export default class index extends Component {
if (isFunction) {
grids.push(
<Card.Grid
key={0}
style={{ padding: '18px 12px', cursor: 'pointer' }}
className="text-center"
onClick={() => this.onOpen(this.addForm, record, true)}
onClick={() =>
this.onOpen({ modal: this.addForm, record, isParent: true, addType: [2] })
}
>
<div>
<AntIcon type="plus" className="text-normal h2" />
@@ -331,9 +377,11 @@ export default class index extends Component {
<Auth auth="sysMenu:add">
<Button
icon={<AntIcon type="plus" />}
onClick={() => this.onOpen(this.addForm)}
onClick={() =>
this.onOpen({ modal: this.addForm, addType: [0, 1] })
}
>
新增{name}
新增目录/菜单
</Button>
</Auth>
}