新功能:
1.部门显示组件
This commit is contained in:
@@ -26,7 +26,7 @@ class MenuFieldViewSet(CustomModelViewSet):
|
|||||||
"""
|
"""
|
||||||
列权限视图集
|
列权限视图集
|
||||||
"""
|
"""
|
||||||
queryset = MenuField.objects.all()
|
queryset = MenuField.objects.order_by('-model')
|
||||||
serializer_class = MenuFieldSerializer
|
serializer_class = MenuFieldSerializer
|
||||||
|
|
||||||
def list(self, request, *args, **kwargs):
|
def list(self, request, *args, **kwargs):
|
||||||
|
|||||||
28
web/src/components/dept-format/index.vue
Normal file
28
web/src/components/dept-format/index.vue
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
{{ data }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {defineProps,ref,watch} from 'vue'
|
||||||
|
import {useDeptInfoStore} from '/@/stores/modules/dept'
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue:{
|
||||||
|
type: Number || String
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const data = ref()
|
||||||
|
watch(()=>{
|
||||||
|
return props.modelValue
|
||||||
|
},async (newVal)=>{
|
||||||
|
const deptInfoStore = useDeptInfoStore()
|
||||||
|
const result = await deptInfoStore.getParentDeptById(newVal)
|
||||||
|
if(result?.nodes){
|
||||||
|
let name = ""
|
||||||
|
result.nodes.forEach((item:any,index:number)=>{
|
||||||
|
name += index>0?`/${item.name}`:item.name
|
||||||
|
})
|
||||||
|
data.value = name
|
||||||
|
}
|
||||||
|
},{immediate: true} )
|
||||||
|
</script>
|
||||||
@@ -13,7 +13,8 @@ import { useMenuApi } from '/@/api/menu/index';
|
|||||||
import { handleMenu } from '../utils/menu';
|
import { handleMenu } from '../utils/menu';
|
||||||
import { BtnPermissionStore } from '/@/plugin/permission/store.permission';
|
import { BtnPermissionStore } from '/@/plugin/permission/store.permission';
|
||||||
import {SystemConfigStore} from "/@/stores/systemConfig";
|
import {SystemConfigStore} from "/@/stores/systemConfig";
|
||||||
|
import {useDeptInfoStore} from "/@/stores/modules/dept";
|
||||||
|
import {DictionaryStore} from "/@/stores/dictionary";
|
||||||
const menuApi = useMenuApi();
|
const menuApi = useMenuApi();
|
||||||
|
|
||||||
const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}');
|
const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}');
|
||||||
@@ -112,6 +113,10 @@ export function getBackEndControlRoutes() {
|
|||||||
BtnPermissionStore().getBtnPermissionStore();
|
BtnPermissionStore().getBtnPermissionStore();
|
||||||
// 获取系统配置
|
// 获取系统配置
|
||||||
SystemConfigStore().getSystemConfigs()
|
SystemConfigStore().getSystemConfigs()
|
||||||
|
// 获取所有部门信息
|
||||||
|
useDeptInfoStore().requestDeptInfo()
|
||||||
|
// 获取字典信息
|
||||||
|
DictionaryStore().getSystemDictionarys()
|
||||||
return menuApi.getSystemMenu();
|
return menuApi.getSystemMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {Session} from '/@/utils/storage';
|
|||||||
import {notFoundAndNoPower,staticRoutes} from '/@/router/route';
|
import {notFoundAndNoPower,staticRoutes} from '/@/router/route';
|
||||||
import {initFrontEndControlRoutes} from '/@/router/frontEnd';
|
import {initFrontEndControlRoutes} from '/@/router/frontEnd';
|
||||||
import {initBackEndControlRoutes} from '/@/router/backEnd';
|
import {initBackEndControlRoutes} from '/@/router/backEnd';
|
||||||
|
import {useFrontendMenuStore} from "/@/stores/frontendMenu";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 1、前端控制路由时:isRequestRoutes 为 false,需要写 roles,需要走 setFilterRoute 方法。
|
* 1、前端控制路由时:isRequestRoutes 为 false,需要写 roles,需要走 setFilterRoute 方法。
|
||||||
@@ -107,6 +108,7 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
next('/home');
|
next('/home');
|
||||||
NProgress.done();
|
NProgress.done();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const storesRoutesList = useRoutesList(pinia);
|
const storesRoutesList = useRoutesList(pinia);
|
||||||
const {routesList} = storeToRefs(storesRoutesList);
|
const {routesList} = storeToRefs(storesRoutesList);
|
||||||
if (routesList.value.length === 0) {
|
if (routesList.value.length === 0) {
|
||||||
@@ -115,6 +117,8 @@ router.beforeEach(async (to, from, next) => {
|
|||||||
await initBackEndControlRoutes();
|
await initBackEndControlRoutes();
|
||||||
// 解决刷新时,一直跳 404 页面问题,关联问题 No match found for location with path 'xxx'
|
// 解决刷新时,一直跳 404 页面问题,关联问题 No match found for location with path 'xxx'
|
||||||
// to.query 防止页面刷新时,普通路由带参数时,参数丢失。动态路由(xxx/:id/:name")isDynamic 无需处理
|
// to.query 防止页面刷新时,普通路由带参数时,参数丢失。动态路由(xxx/:id/:name")isDynamic 无需处理
|
||||||
|
console.log("缓存的路由",routesList.value)
|
||||||
|
console.log("所有路由",router.getRoutes())
|
||||||
next({ path: to.path, query: to.query });
|
next({ path: to.path, query: to.query });
|
||||||
} else {
|
} else {
|
||||||
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
|
// https://gitee.com/lyt-top/vue-next-admin/issues/I5F1HP
|
||||||
|
|||||||
@@ -89,19 +89,11 @@ export const staticRoutes: Array<RouteRecordRaw> = [
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/operationLog',
|
path: '/demo',
|
||||||
name: 'operationLog',
|
name: 'demo',
|
||||||
component: () => import('/@/views/system/personal/index.vue'),
|
component: () => import('/@/views/system/demo/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: 'message.router.personal'
|
title: 'message.router.personal'
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
// {
|
|
||||||
// path: '/demo',
|
|
||||||
// name: 'demo',
|
|
||||||
// component: () => import('/@/views/system/demo/index.vue'),
|
|
||||||
// meta: {
|
|
||||||
// title: 'message.router.personal'
|
|
||||||
// },
|
|
||||||
// }
|
|
||||||
];
|
];
|
||||||
|
|||||||
159
web/src/stores/frontendMenu.ts
Normal file
159
web/src/stores/frontendMenu.ts
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
import {defineStore} from 'pinia';
|
||||||
|
import {FrontendMenu} from './interface';
|
||||||
|
import {Session} from '/@/utils/storage';
|
||||||
|
import {request} from '../utils/service';
|
||||||
|
import XEUtils from "xe-utils";
|
||||||
|
import {RouteRecordRaw} from "vue-router";
|
||||||
|
|
||||||
|
|
||||||
|
const layouModules: any = import.meta.glob('../layout/routerView/*.{vue,tsx}');
|
||||||
|
const viewsModules: any = import.meta.glob('../views/**/*.{vue,tsx}');
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取目录下的 .vue、.tsx 全部文件
|
||||||
|
* @method import.meta.glob
|
||||||
|
* @link 参考:https://cn.vitejs.dev/guide/features.html#json
|
||||||
|
*/
|
||||||
|
const dynamicViewsModules: Record<string, Function> = Object.assign({}, { ...layouModules }, { ...viewsModules });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 后端路由 component 转换函数
|
||||||
|
* @param dynamicViewsModules 获取目录下的 .vue、.tsx 全部文件
|
||||||
|
* @param component 当前要处理项 component
|
||||||
|
* @returns 返回处理成函数后的 component
|
||||||
|
*/
|
||||||
|
export function dynamicImport(dynamicViewsModules: Record<string, Function>, component: string) {
|
||||||
|
const keys = Object.keys(dynamicViewsModules);
|
||||||
|
const matchKeys = keys.filter((key) => {
|
||||||
|
const k = key.replace(/..\/views|../, '');
|
||||||
|
return k.startsWith(`${component}`) || k.startsWith(`/${component}`);
|
||||||
|
});
|
||||||
|
if (matchKeys?.length === 1) {
|
||||||
|
const matchKey = matchKeys[0];
|
||||||
|
return dynamicViewsModules[matchKey];
|
||||||
|
}
|
||||||
|
if (matchKeys?.length > 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: 处理后端菜单数据格式
|
||||||
|
* @param {Array} menuData
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
export const handleMenu = (menuData: Array<any>) => {
|
||||||
|
// 框架内路由
|
||||||
|
const frameInRoutes:Array<any> = []
|
||||||
|
// 框架外路由
|
||||||
|
const frameOutRoutes:Array<any> = []
|
||||||
|
// 先处理menu meta数据转换
|
||||||
|
const handleMeta = (item: any) => {
|
||||||
|
item.path = item.web_path
|
||||||
|
item.meta = {
|
||||||
|
title: item.title,
|
||||||
|
isLink: item.link_url,
|
||||||
|
isHide: !item.visible,
|
||||||
|
isKeepAlive: item.cache,
|
||||||
|
isAffix: item.is_affix,
|
||||||
|
isIframe: item.is_iframe,
|
||||||
|
roles: ['admin'],
|
||||||
|
icon: item.icon
|
||||||
|
}
|
||||||
|
item.component = dynamicImport(dynamicViewsModules, item.component as string)
|
||||||
|
if(item.is_catalog){
|
||||||
|
// 对目录的处理
|
||||||
|
item.component = dynamicImport(dynamicViewsModules, 'layout/routerView/parent')
|
||||||
|
}
|
||||||
|
if(item.is_link){
|
||||||
|
// 对外链接的处理
|
||||||
|
item.meta.isIframe = !item.is_iframe
|
||||||
|
if(item.is_iframe){
|
||||||
|
item.component = dynamicImport(dynamicViewsModules, 'layout/routerView/link')
|
||||||
|
}else {
|
||||||
|
item.component = dynamicImport(dynamicViewsModules, 'layout/routerView/iframes')
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(item.is_iframe){
|
||||||
|
const route = JSON.parse(JSON.stringify(item))
|
||||||
|
route.meta.isLink = ''
|
||||||
|
route.path = `${item.web_path}`
|
||||||
|
route.name = `${item.name}`
|
||||||
|
route.meta.isIframe = true
|
||||||
|
route.meta.isKeepAlive = false
|
||||||
|
route.meta.isIframeOpen = true
|
||||||
|
route.component = item.component
|
||||||
|
frameOutRoutes.push(route)
|
||||||
|
item.path = `${item.web_path}FrameOut`
|
||||||
|
item.name = `frameOut_${item.name}`
|
||||||
|
item.meta.isLink = item.web_path
|
||||||
|
item.meta.isIframe = !item.is_iframe
|
||||||
|
item.component = dynamicImport(dynamicViewsModules, 'layout/routerView/link.vue')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
item.children && handleMeta(item.children);
|
||||||
|
return item
|
||||||
|
}
|
||||||
|
menuData.forEach((val) => {
|
||||||
|
frameInRoutes.push(handleMeta(val))
|
||||||
|
})
|
||||||
|
const data = XEUtils.toArrayTree(frameInRoutes, {
|
||||||
|
parentKey: 'parent',
|
||||||
|
strict: true,
|
||||||
|
})
|
||||||
|
const dynamicRoutes = [
|
||||||
|
{
|
||||||
|
path: '/home', name: 'home',
|
||||||
|
component: '/system/home/index',
|
||||||
|
meta: {
|
||||||
|
title: 'message.router.home',
|
||||||
|
isLink: '',
|
||||||
|
isHide: false,
|
||||||
|
isKeepAlive: true,
|
||||||
|
isAffix: true,
|
||||||
|
isIframe: false,
|
||||||
|
roles: ['admin'],
|
||||||
|
icon: 'iconfont icon-shouye'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
...data
|
||||||
|
]
|
||||||
|
return {frameIn:dynamicRoutes,frameOut:frameOutRoutes}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useFrontendMenuStore = defineStore('frontendMenu',{
|
||||||
|
state: (): FrontendMenu => ({
|
||||||
|
arrayRouter: [],
|
||||||
|
treeRouter: [],
|
||||||
|
frameInRoutes:[],
|
||||||
|
frameOutRoutes:[]
|
||||||
|
}),
|
||||||
|
actions:{
|
||||||
|
async requestMenu(){
|
||||||
|
return request({
|
||||||
|
url: '/api/system/menu/web_router/',
|
||||||
|
method: 'get',
|
||||||
|
params:{},
|
||||||
|
}).then((res:any)=>{
|
||||||
|
return res.data
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async handleRouter(){
|
||||||
|
const menuData = await this.requestMenu();
|
||||||
|
this.arrayRouter = menuData
|
||||||
|
const {frameIn,frameOut} = handleMenu(menuData);
|
||||||
|
this.treeRouter = [...frameIn,...frameOut]
|
||||||
|
this.frameInRoutes=frameIn
|
||||||
|
this.frameOutRoutes=frameOut
|
||||||
|
},
|
||||||
|
async getRouter(){
|
||||||
|
await this.handleRouter()
|
||||||
|
return {
|
||||||
|
frameInRoutes:this.frameInRoutes,
|
||||||
|
frameOutRoutes:this.frameOutRoutes,
|
||||||
|
treeRouter:this.treeRouter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
* 定义接口来定义对象的类型
|
* 定义接口来定义对象的类型
|
||||||
* `stores` 全部类型定义在这里
|
* `stores` 全部类型定义在这里
|
||||||
*/
|
*/
|
||||||
|
import {useFrontendMenuStore} from "/@/stores/frontendMenu";
|
||||||
|
|
||||||
// 用户信息
|
// 用户信息
|
||||||
export interface UserInfosState {
|
export interface UserInfosState {
|
||||||
@@ -102,3 +103,12 @@ export interface DictionaryStates {
|
|||||||
export interface ConfigStates {
|
export interface ConfigStates {
|
||||||
systemConfig: any;
|
systemConfig: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FrontendMenu {
|
||||||
|
arrayRouter: Array<any>;
|
||||||
|
treeRouter:Array<any>;
|
||||||
|
|
||||||
|
frameOutRoutes:Array<any>;
|
||||||
|
|
||||||
|
frameInRoutes:Array<any>;
|
||||||
|
}
|
||||||
|
|||||||
30
web/src/stores/modules/dept.ts
Normal file
30
web/src/stores/modules/dept.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import {defineStore} from "pinia";
|
||||||
|
import {request} from "/@/utils/service";
|
||||||
|
import XEUtils from "xe-utils";
|
||||||
|
import {toRaw} from 'vue'
|
||||||
|
export const useDeptInfoStore = defineStore('deptInfo', {
|
||||||
|
state:()=>(
|
||||||
|
{
|
||||||
|
list:[],
|
||||||
|
tree:[],
|
||||||
|
}
|
||||||
|
),
|
||||||
|
actions:{
|
||||||
|
async requestDeptInfo() {
|
||||||
|
// 请求部门信息
|
||||||
|
const ret = await request({
|
||||||
|
url: '/api/system/dept/all_dept/'
|
||||||
|
})
|
||||||
|
this.list = ret.data
|
||||||
|
this.tree = XEUtils.toArrayTree(ret.data,{parentKey:'parent',strict:true})
|
||||||
|
},
|
||||||
|
async getDeptById(id:any){
|
||||||
|
|
||||||
|
},
|
||||||
|
async getParentDeptById(id: any){
|
||||||
|
const tree = toRaw(this.tree)
|
||||||
|
const obj = XEUtils.findTree(tree, item => item.id == id)
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import { dict } from "@fast-crud/fast-crud";
|
import { dict } from "@fast-crud/fast-crud";
|
||||||
|
import {shallowRef} from 'vue'
|
||||||
|
import deptFormat from "/@/components/dept-format/index.vue";
|
||||||
export const commonCrudConfig = (options = {
|
export const commonCrudConfig = (options = {
|
||||||
create_datetime: {
|
create_datetime: {
|
||||||
form: false,
|
form: false,
|
||||||
@@ -32,6 +34,48 @@ export const commonCrudConfig = (options = {
|
|||||||
},
|
},
|
||||||
}) => {
|
}) => {
|
||||||
return {
|
return {
|
||||||
|
dept_belong_id: {
|
||||||
|
title: '所属部门',
|
||||||
|
type: 'dict-cascader',
|
||||||
|
search: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
dict: dict({
|
||||||
|
url: '/api/system/dept/all_dept/',
|
||||||
|
isTree: true,
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
children: 'children',
|
||||||
|
}),
|
||||||
|
column: {
|
||||||
|
align: 'center',
|
||||||
|
width: 200,
|
||||||
|
show: options.dept_belong_id?.table || false,
|
||||||
|
component:{
|
||||||
|
name: shallowRef(deptFormat),
|
||||||
|
vModel: "modelValue",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: options.dept_belong_id?.form || false,
|
||||||
|
component: {
|
||||||
|
multiple: false,
|
||||||
|
clearable: true,
|
||||||
|
props: {
|
||||||
|
showAllLevels:false,
|
||||||
|
props: {
|
||||||
|
// 为什么这里要写两层props
|
||||||
|
// 因为props属性名与fs的动态渲染的props命名冲突,所以要多写一层
|
||||||
|
label: "name",
|
||||||
|
value: "id",
|
||||||
|
checkStrictly: true,
|
||||||
|
emitPath:false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
helper: "默认不填则为当前创建用户的部门ID"
|
||||||
|
}
|
||||||
|
},
|
||||||
description: {
|
description: {
|
||||||
title: '备注',
|
title: '备注',
|
||||||
search: {
|
search: {
|
||||||
@@ -39,15 +83,19 @@ export const commonCrudConfig = (options = {
|
|||||||
},
|
},
|
||||||
type: 'textarea',
|
type: 'textarea',
|
||||||
column: {
|
column: {
|
||||||
|
width: 100,
|
||||||
show: options.description?.table || false,
|
show: options.description?.table || false,
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
component: {
|
|
||||||
show: options.description?.form || false,
|
show: options.description?.form || false,
|
||||||
|
component: {
|
||||||
placeholder: '请输入内容',
|
placeholder: '请输入内容',
|
||||||
showWordLimit: true,
|
showWordLimit: true,
|
||||||
maxlength: '200',
|
maxlength: '200',
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
viewForm: {
|
||||||
|
show: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier_name: {
|
modifier_name: {
|
||||||
@@ -58,6 +106,28 @@ export const commonCrudConfig = (options = {
|
|||||||
column: {
|
column: {
|
||||||
width: 100,
|
width: 100,
|
||||||
show: options.modifier_name?.table || false,
|
show: options.modifier_name?.table || false,
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
viewForm: {
|
||||||
|
show: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
creator_name: {
|
||||||
|
title: '创建人',
|
||||||
|
search: {
|
||||||
|
show: options.creator_name?.search || false
|
||||||
|
},
|
||||||
|
column: {
|
||||||
|
width: 100,
|
||||||
|
show: options.creator_name?.table || false,
|
||||||
|
},
|
||||||
|
form: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
viewForm: {
|
||||||
|
show: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
update_datetime: {
|
update_datetime: {
|
||||||
@@ -69,16 +139,12 @@ export const commonCrudConfig = (options = {
|
|||||||
column: {
|
column: {
|
||||||
width: 160,
|
width: 160,
|
||||||
show: options.update_datetime?.table || false,
|
show: options.update_datetime?.table || false,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
creator_name: {
|
form: {
|
||||||
title: '创建人',
|
show: false,
|
||||||
search: {
|
|
||||||
show: options.creator_name?.search || false
|
|
||||||
},
|
},
|
||||||
column: {
|
viewForm: {
|
||||||
width: 100,
|
show: true
|
||||||
show: options.creator_name?.table || false,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
create_datetime: {
|
create_datetime: {
|
||||||
@@ -90,40 +156,12 @@ export const commonCrudConfig = (options = {
|
|||||||
column: {
|
column: {
|
||||||
width: 160,
|
width: 160,
|
||||||
show: options.create_datetime?.table || false,
|
show: options.create_datetime?.table || false,
|
||||||
}
|
|
||||||
},
|
|
||||||
dept_belong_id: {
|
|
||||||
title: '所属部门',
|
|
||||||
type: 'dict-tree',
|
|
||||||
search: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
dict: dict({
|
|
||||||
url: '/api/system/dept/all_dept/',
|
|
||||||
isTree: true,
|
|
||||||
value: 'id',
|
|
||||||
label: 'name',
|
|
||||||
children: 'children' // 数据字典中children字段的属性名
|
|
||||||
}),
|
|
||||||
column: {
|
|
||||||
width: 150,
|
|
||||||
show: options.dept_belong_id?.table || false,
|
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
component: {
|
show: false,
|
||||||
show: options.dept_belong_id?.form || false,
|
|
||||||
multiple: false,
|
|
||||||
clearable: true,
|
|
||||||
props: {
|
|
||||||
props: {
|
|
||||||
// 为什么这里要写两层props
|
|
||||||
// 因为props属性名与fs的动态渲染的props命名冲突,所以要多写一层
|
|
||||||
label: "name",
|
|
||||||
value: "id",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
helper: "默认不填则为当前创建用户的部门ID"
|
viewForm: {
|
||||||
|
show: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user