update 强化菜单
This commit is contained in:
@@ -300,6 +300,14 @@
|
||||
|
||||
opacity: 0;
|
||||
}
|
||||
>iframe {
|
||||
display: block;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,56 +3,62 @@ import { Button, Drawer, message as Message, Modal } from 'antd'
|
||||
import { cloneDeep, isEqual } from 'lodash'
|
||||
|
||||
/**
|
||||
* 渲染对话框
|
||||
* @param {*} props
|
||||
* @param {*} on
|
||||
* @param {*} childWithProps
|
||||
* @returns
|
||||
*/
|
||||
* 渲染对话框
|
||||
* @param {*} props
|
||||
* @param {*} on
|
||||
* @param {*} childWithProps
|
||||
* @returns
|
||||
*/
|
||||
function renderModal(props, on, childWithProps) {
|
||||
|
||||
on = {
|
||||
...on,
|
||||
onCancel: () => this.onClose()
|
||||
onCancel: () => this.onClose(),
|
||||
}
|
||||
|
||||
return <Modal className="yo-modal-form" {...props} {...on}>
|
||||
{childWithProps}
|
||||
</Modal>
|
||||
|
||||
return (
|
||||
<Modal className="yo-modal-form" {...props} {...on}>
|
||||
{childWithProps}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染抽屉
|
||||
* @param {*} props
|
||||
* @param {*} on
|
||||
* @param {*} childWithProps
|
||||
* @returns
|
||||
* @param {*} props
|
||||
* @param {*} on
|
||||
* @param {*} childWithProps
|
||||
* @returns
|
||||
*/
|
||||
function renderDrawer(props, on, childWithProps) {
|
||||
on = {
|
||||
...on,
|
||||
onClose: () => this.onClose()
|
||||
onClose: () => this.onClose(),
|
||||
}
|
||||
|
||||
return <Drawer className="yo-drawer-form" {...props} {...on}>
|
||||
<div class="yo-drawer-form--body">
|
||||
{childWithProps}
|
||||
</div>
|
||||
<div className="ant-drawer-footer">
|
||||
<Button onClick={on.onClose}>取消</Button>
|
||||
<Button loading={this.state.confirmLoading} onClick={on.onOk} type="primary">确定</Button>
|
||||
</div>
|
||||
</Drawer>
|
||||
// react在这里会对该组件不存在的props抛出异常
|
||||
;['action', 'onSuccess', 'onOk', 'confirmLoading'].forEach(p => {
|
||||
delete props[p]
|
||||
})
|
||||
|
||||
return (
|
||||
<Drawer className="yo-drawer-form" {...props} onClose={() => on.onClose()}>
|
||||
<div className="yo-drawer-form--body">{childWithProps}</div>
|
||||
<div className="ant-drawer-footer">
|
||||
<Button onClick={on.onClose}>取消</Button>
|
||||
<Button loading={this.state.confirmLoading} onClick={on.onOk} type="primary">
|
||||
确定
|
||||
</Button>
|
||||
</div>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
|
||||
export default class ModalForm extends Component {
|
||||
|
||||
state = {
|
||||
// 弹窗显示/隐藏
|
||||
visible: false,
|
||||
// 提交状态
|
||||
confirmLoading: false
|
||||
confirmLoading: false,
|
||||
}
|
||||
|
||||
// 子元素实例
|
||||
@@ -67,12 +73,11 @@ export default class ModalForm extends Component {
|
||||
snapshot = null
|
||||
|
||||
// 完成操作
|
||||
action = async () => { }
|
||||
action = async () => {}
|
||||
|
||||
// 是否在关闭时校验数据改变
|
||||
compareOnClose = true
|
||||
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
@@ -93,7 +98,7 @@ export default class ModalForm extends Component {
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
* @param {*} data
|
||||
* @param {*} data
|
||||
*/
|
||||
open = (data = {}) => {
|
||||
this.data = data
|
||||
@@ -110,7 +115,7 @@ export default class ModalForm extends Component {
|
||||
/**
|
||||
* 子元素创建后回调
|
||||
* 对子元素数据进行填充,(如需关闭时对比)之后再获取结构调整后的数据快照
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
onCreated = async () => {
|
||||
const body = this.childNode.current
|
||||
@@ -126,7 +131,7 @@ export default class ModalForm extends Component {
|
||||
/**
|
||||
* 取消编辑
|
||||
* (如需关闭时对比)获取当前数据结构与快照对比
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
onClose = async () => {
|
||||
const body = this.childNode.current
|
||||
@@ -143,7 +148,7 @@ export default class ModalForm extends Component {
|
||||
content: '当前内容已更改,是否确认不保存并且关闭',
|
||||
onOk: () => {
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -155,7 +160,7 @@ export default class ModalForm extends Component {
|
||||
/**
|
||||
* 完成编辑
|
||||
* 校验并获取结构调整后的数据,调用this.action进行操作
|
||||
* @returns
|
||||
* @returns
|
||||
*/
|
||||
onOk = async () => {
|
||||
const body = this.childNode.current
|
||||
@@ -175,39 +180,33 @@ export default class ModalForm extends Component {
|
||||
this.props.onSuccess(postData)
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
this.setState({ confirmLoading: false })
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
const props = {
|
||||
...this.props,
|
||||
visible: this.state.visible,
|
||||
destroyOnClose: true,
|
||||
|
||||
confirmLoading: this.state.confirmLoading
|
||||
confirmLoading: this.state.confirmLoading,
|
||||
}
|
||||
|
||||
const on = {
|
||||
onOk: () => this.onOk()
|
||||
onOk: () => this.onOk(),
|
||||
}
|
||||
|
||||
const childWithProps = React.cloneElement(
|
||||
React.Children.only(this.props.children),
|
||||
{
|
||||
created: childNode => {
|
||||
this.childNode.current = childNode
|
||||
this.onCreated()
|
||||
}
|
||||
}
|
||||
)
|
||||
const childWithProps = React.cloneElement(React.Children.only(this.props.children), {
|
||||
created: childNode => {
|
||||
this.childNode.current = childNode
|
||||
this.onCreated()
|
||||
},
|
||||
})
|
||||
|
||||
return this.type === 'modal' ?
|
||||
renderModal.call(this, props, on, childWithProps)
|
||||
:
|
||||
renderDrawer.call(this, props, on, childWithProps)
|
||||
return this.type === 'modal'
|
||||
? renderModal.call(this, props, on, childWithProps)
|
||||
: renderDrawer.call(this, props, on, childWithProps)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ class ComponentDynamic extends Component {
|
||||
if (this.props.onRef) {
|
||||
this.props.onRef(this)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -73,6 +72,40 @@ class ComponentDynamic extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
class Iframe extends Component {
|
||||
shouldComponentUpdate() {
|
||||
if (this.props.onRef) {
|
||||
this.props.onRef(this)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
if (this.props.onRef) {
|
||||
this.props.onRef(this)
|
||||
}
|
||||
this.loadComponent()
|
||||
}
|
||||
|
||||
loadComponent() {
|
||||
NProgress.start()
|
||||
const iframe = this.refs.content
|
||||
iframe.onload = () => {
|
||||
NProgress.done()
|
||||
}
|
||||
iframe.onerror = () => {
|
||||
NProgress.done()
|
||||
}
|
||||
iframe.src = this.props.src
|
||||
}
|
||||
|
||||
render() {
|
||||
const { title } = this.props
|
||||
|
||||
return <iframe ref="content" title={title} />
|
||||
}
|
||||
}
|
||||
|
||||
export default class index extends Component {
|
||||
state = {
|
||||
actived: '',
|
||||
@@ -191,14 +224,23 @@ export default class index extends Component {
|
||||
' yo-tab-external-tabpane'
|
||||
}
|
||||
>
|
||||
<ComponentDynamic
|
||||
path={pane.path}
|
||||
id={pane.key}
|
||||
key={pane.key}
|
||||
param={pane.param}
|
||||
paneActived={pane.key === actived}
|
||||
onRef={p => this.panes.push(p)}
|
||||
/>
|
||||
{pane.openType === 1 ? (
|
||||
<ComponentDynamic
|
||||
path={pane.path}
|
||||
id={pane.key}
|
||||
key={pane.key}
|
||||
param={pane.param}
|
||||
paneActived={pane.key === actived}
|
||||
onRef={p => this.panes.push(p)}
|
||||
/>
|
||||
) : pane.openType === 2 ? (
|
||||
<Iframe
|
||||
src={pane.path}
|
||||
title={pane.key}
|
||||
id={pane.key}
|
||||
onRef={p => this.panes.push(p)}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
|
||||
@@ -78,7 +78,7 @@ export default class search extends Component {
|
||||
}
|
||||
|
||||
onSelect(value, option) {
|
||||
const { id, meta, component } = option.menu
|
||||
const { id, meta, component, link, redirect, openType } = option.menu
|
||||
|
||||
// 选中时清空输入框内容,并失去焦点
|
||||
this.setState({ searchValue: '' })
|
||||
@@ -88,7 +88,19 @@ export default class search extends Component {
|
||||
key: id,
|
||||
title: meta.title,
|
||||
icon: meta.icon,
|
||||
path: component,
|
||||
path: (() => {
|
||||
switch (openType) {
|
||||
case 1:
|
||||
return component
|
||||
case 2:
|
||||
return link
|
||||
case 3:
|
||||
return redirect
|
||||
default:
|
||||
return null
|
||||
}
|
||||
})(),
|
||||
openType,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -50,11 +50,25 @@ export default class index extends Component {
|
||||
}
|
||||
|
||||
onOpenContentWindow = menu => {
|
||||
const { id, meta, component, link, redirect, openType } = menu
|
||||
|
||||
window.openContentWindow({
|
||||
key: menu.id,
|
||||
title: menu.meta.title,
|
||||
icon: menu.meta.icon,
|
||||
path: menu.component,
|
||||
key: id,
|
||||
title: meta.title,
|
||||
icon: meta.icon,
|
||||
path: (() => {
|
||||
switch (openType) {
|
||||
case 1:
|
||||
return component
|
||||
case 2:
|
||||
return link
|
||||
case 3:
|
||||
return redirect
|
||||
default:
|
||||
return null
|
||||
}
|
||||
})(),
|
||||
openType,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,31 @@ export default class index extends Component {
|
||||
return
|
||||
}
|
||||
|
||||
const path = settings.path.startsWith('/') ? settings.path : `/${settings.path}`
|
||||
let path = (p => {
|
||||
if (p.startsWith('http')) return p
|
||||
if (p.startsWith('/')) return p
|
||||
else return `/${p}`
|
||||
})(settings.path)
|
||||
|
||||
if ([2, 3].includes(settings.openType)) {
|
||||
const param = (p => {
|
||||
const arr = []
|
||||
if (p && p.constructor === Object) {
|
||||
Object.keys(p).forEach(key => {
|
||||
arr.push(`${key}=${(p[key] || '').toString()}`)
|
||||
})
|
||||
}
|
||||
return arr.join('&')
|
||||
})(settings.param)
|
||||
|
||||
path += param ? `?${param}` : ''
|
||||
|
||||
if (settings.openType === 3) {
|
||||
// 打开新的浏览器窗口
|
||||
window.open(path)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 向标签页队列中添加一个新的标签页
|
||||
@@ -120,7 +144,9 @@ export default class index extends Component {
|
||||
path,
|
||||
param: settings.param,
|
||||
loaded: false,
|
||||
openType: settings.openType || 1,
|
||||
}
|
||||
|
||||
this.setState({
|
||||
panes: [...this.state.panes, newPane],
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user