提交 9a269f8d 作者: 郁骅焌

菜单管理

上级 d7cb6d09
......@@ -5,5 +5,5 @@
NODE_ENV=development
# api接口地址
# VITE_APP_BASE_URL='http://139.196.169.103:9003'
VITE_APP_BASE_URL=''
VITE_APP_BASE_URL='http://139.196.169.103:9003'
# VITE_APP_BASE_URL=''
......@@ -15,6 +15,8 @@ declare global {
const $sub: typeof import('../../../src/hooks/index')['$sub']
const $unsub: typeof import('../../../src/hooks/index')['$unsub']
const EffectScope: typeof import('vue')['EffectScope']
const ElLoading: typeof import('element-plus/es')['ElLoading']
const ElMessage: typeof import('element-plus/es')['ElMessage']
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
......
......@@ -35,6 +35,7 @@ declare module 'vue' {
DepartmentManagementEdit: typeof import('./../../../src/views/setting/departmentManagement/vabAutoComponents/DepartmentManagementEdit.vue')['default']
Develop: typeof import('./../../../src/views/index/vabAutoComponents/Develop.vue')['default']
DictionaryManagementEdit: typeof import('./../../../src/views/setting/dictionaryManagement/vabAutoComponents/DictionaryManagementEdit.vue')['default']
DictTag: typeof import('./../../components/DictTag/index.vue')['default']
DrawerBasicUsage: typeof import('./../../../src/views/vab/drawer/vabAutoComponents/DrawerBasicUsage.vue')['default']
DrawerCustomizationContent: typeof import('./../../../src/views/vab/drawer/vabAutoComponents/DrawerCustomizationContent.vue')['default']
DrawerCustomizationHeader: typeof import('./../../../src/views/vab/drawer/vabAutoComponents/DrawerCustomizationHeader.vue')['default']
......@@ -140,6 +141,7 @@ declare module 'vue' {
InfiniteScrollDisableLoading: typeof import('./../../../src/views/vab/infiniteScroll/vabAutoComponents/InfiniteScrollDisableLoading.vue')['default']
LoginContainer: typeof import('./../../../src/views/login/vabAutoComponents/LoginContainer.vue')['default']
MenuManagementEdit: typeof import('./../../../src/views/setting/menuManagement/vabAutoComponents/MenuManagementEdit.vue')['default']
MenuManagementEdit2: typeof import('./../../../src/views/system/menuManagement/vabAutoComponents/MenuManagementEdit2.vue')['default']
NodePanel: typeof import('./../../../src/views/other/workflow/vabAutoComponents/lFComponents/NodePanel.vue')['default']
PageHeader: typeof import('./../../../src/views/index/vabAutoComponents/PageHeader.vue')['default']
Pending: typeof import('./../../../src/views/index/vabAutoComponents/Pending.vue')['default']
......@@ -196,6 +198,7 @@ declare module 'vue' {
UploadPhotoWall: typeof import('./../../../src/views/vab/upload/vabAutoComponents/UploadPhotoWall.vue')['default']
User: typeof import('./../../../src/views/other/workflow/vabAutoComponents/propertySetting/User.vue')['default']
UserManagementEdit: typeof import('./../../../src/views/setting/userManagement/vabAutoComponents/UserManagementEdit.vue')['default']
UserManagementEdit2: typeof import('./../../../src/views/system/userManagement/vabAutoComponents/UserManagementEdit2.vue')['default']
VabAlert: typeof import('./../../components/VabAlert/index.vue')['default']
VabApp: typeof import('./../../components/VabApp/index.vue')['default']
VabAppMain: typeof import('./../../components/VabAppMain/index.vue')['default']
......
<template>
<div>
<template v-for="(item, index) in options">
<template v-if="values.includes(item.value)">
<span
v-if="(item.elTagType == 'default' || item.elTagType == '') && (item.elTagClass == '' || item.elTagClass == null)"
:key="item.value"
:class="item.elTagClass"
:index="index"
>
{{ item.label + ' ' }}
</span>
<el-tag v-else :key="item.value + ''" :class="item.elTagClass" :disable-transitions="true" :index="index" :type="item.elTagType">
{{ item.label + ' ' }}
</el-tag>
</template>
</template>
<template v-if="unmatch && showValue">
{{ handledUnmatchArray }}
</template>
</div>
</template>
<script setup>
// 记录未匹配的项
const unmatchArray = ref([])
const props = defineProps({
// 数据
options: {
type: Array,
default: null,
},
// 当前的值
value: [Number, String, Array],
// 当未找到匹配的数据时,显示value
showValue: {
type: Boolean,
default: true,
},
separator: {
type: String,
default: ',',
},
})
const values = computed(() => {
if (props.value === null || props.value === undefined || props.value === '') return []
return Array.isArray(props.value) ? props.value.map(String) : String(props.value).split(props.separator)
})
const unmatch = computed(() => {
unmatchArray.value = []
// 没有value不显示
if (
props.value === null ||
props.value === undefined ||
props.value === '' ||
!Array.isArray(props.options) ||
props.options.length === 0
)
return false
// 传入值为数组
let unmatch = false // 添加一个标志来判断是否有未匹配项
values.value.forEach((item) => {
if (!props.options.some((v) => v.value === item)) {
unmatchArray.value.push(item)
unmatch = true // 如果有未匹配项,将标志设置为true
}
})
return unmatch // 返回标志的值
})
const handledUnmatchArray = computed(() => {
if (unmatchArray.value.length === 0) return ''
return unmatchArray.value.reduce((pre, cur) => {
return `${pre} ${cur}`
})
})
</script>
<style scoped>
.el-tag + .el-tag {
margin-left: 10px;
}
</style>
......@@ -100,7 +100,7 @@ export default [
},
},
{
url: '/system/dept/treeselect',
url: '/system/user/deptTree',
method: 'get',
response: () => {
return {
......
......@@ -1216,9 +1216,9 @@ const list: VabRouteRecord[] = [
{
path: 'userManagement',
name: 'UserManagement',
component: '/@/views/setting/userManagement/index.vue',
component: '/@views/setting/userManagement/index.vue',
meta: {
title: '用户管理1',
title: '用户管理',
icon: 'user-3-line',
},
},
......
......@@ -93,7 +93,7 @@ const List = [
export default [
{
url: '/userManagement/getList',
url: '/system/user/list',
method: 'get',
response({ query }: any) {
const { username, pageNo = 1, pageSize = 20 } = query
......@@ -129,8 +129,8 @@ export default [
},
},
{
url: '/userManagement/doDelete',
method: 'post',
url: '/system/user/:userId',
method: 'delete',
response() {
return {
code: 200,
......
......@@ -33,6 +33,7 @@
"@logicflow/extension": "^2.0.12",
"@lucky-canvas/vue": "^0.1.11",
"@opentiny/vue": "3.18.0",
"@types/file-saver": "^2.0.7",
"@vueuse/core": "^12.0.0",
"@vueuse/head": "^2.0.0",
"@wangeditor/editor": "^5.1.23",
......@@ -42,6 +43,7 @@
"disable-devtool": "^0.3.8",
"echarts": "^5.5.1",
"element-plus": "^2.8.8",
"file-saver": "2.0.5",
"jsencrypt": "^3.3.2",
"lodash-es": "^4.17.21",
"mitt": "^3.0.1",
......
......@@ -27,7 +27,7 @@ export const doDelete = (data: any) => {
// 查询部门下拉树结构
export function deptTreeSelect() {
return request({
url: '/system/dept/treeselect',
url: '/system/user/deptTree',
method: 'get',
})
}
import request from '/@/utils/request'
// 查询菜单列表
export function listMenu(params?: any) {
return request({
url: '/system/menu/list',
method: 'get',
params,
})
}
export function getTree(params?: any) {
return request({
url: '/menuManagement/getTree',
......@@ -8,18 +17,36 @@ export function getTree(params?: any) {
})
}
export const doEdit = (data: any) => {
/** 新增菜单 */
export const doAdd = (data: any) => {
return request({
url: '/menuManagement/doEdit',
url: '/system/menu',
method: 'post',
data,
})
}
export const doDelete = (data: any) => {
/** 修改菜单 */
export const doEdit = (data: any) => {
return request({
url: '/menuManagement/doDelete',
method: 'post',
url: '/system/menu',
method: 'put',
data,
})
}
/** 删除菜单 */
export const doDelete = (menuId: any) => {
return request({
url: `/system/menu/${menuId}`,
method: 'delete',
})
}
// 查询菜单详细
export function getMenu(menuId: any) {
return request({
url: `/system/menu/${menuId}`,
method: 'get',
})
}
......@@ -3,7 +3,7 @@ import request from '/@/utils/request'
export function getList(params?: any) {
return request({
url: '/userManagement/getList',
url: '/system/user/list',
method: 'get',
params,
})
......@@ -25,11 +25,10 @@ export const doEdit = (data: any) => {
})
}
export const doDelete = (data: any) => {
export const doDelete = (userId: any) => {
return request({
url: '/userManagement/doDelete',
method: 'post',
data,
url: `/system/user/${userId}`,
method: 'delete',
})
}
......@@ -40,3 +39,16 @@ export function getUser(userId: any) {
method: 'get',
})
}
// 用户状态修改
export function changeUserStatus(userId: any, status: any) {
const data = {
userId,
status,
}
return request({
url: '/system/user/changeStatus',
method: 'put',
data,
})
}
......@@ -5,17 +5,20 @@ import { setupRouter } from '/@/router'
import { setupStore } from '/@/store'
// 全局方法
import { addDateRange, resetForm, useDict } from '/@/utils/index'
import { useDict } from './utils/dict'
import { download } from '/@/utils/download'
import { addDateRange, handleTree, resetForm } from '/@/utils/index'
// svg图标
import elementIcons from '/@/icon/elementIcon'
const app = createApp(App)
// 全局方法挂载
app.config.globalProperties.download = download
app.config.globalProperties.useDict = useDict
app.config.globalProperties.resetForm = resetForm
app.config.globalProperties.addDateRange = addDateRange
app.config.globalProperties.handleTree = handleTree
setupVab(app)
setupI18n(app)
......
......@@ -14,11 +14,19 @@
</vab-query-form-top-panel>
</vab-query-form>
</el-col>
<el-col v-for="(item, index) in queryIcon" :key="index" :span="6">
<!-- <el-col v-for="(item, index) in queryIcon" :key="index" :span="6">
<vab-card @click="handleIcon(item)">
<vab-icon :icon="item" />
</vab-card>
</el-col>
</el-col> -->
<div class="icon-layout">
<div v-for="(item, index) in queryIcon" :key="index" class="icon-item">
<vab-card @click="handleIcon(item)">
<vab-icon :icon="item" />
</vab-card>
</div>
</div>
<el-col :span="24">
<vab-pagination
:current-page="queryForm.pageNo"
......@@ -34,7 +42,8 @@
<script lang="ts" setup>
import { Search } from '@element-plus/icons-vue'
import { getIconList } from '/@/api/icon'
// import { getIconList } from '/@/api/icon'
import IconList from '/@/icon/list'
defineOptions({
name: 'VabIconSelector',
......@@ -48,7 +57,7 @@ const total = ref<number>(0)
const queryIcon = ref<any>([])
const queryForm = reactive<any>({
pageNo: 1,
pageSize: 20,
pageSize: 30,
title: '',
})
......@@ -69,9 +78,13 @@ const queryData = () => {
}
const fetchData = async () => {
const { data } = await getIconList(queryForm)
queryIcon.value = data.list
total.value = data.total
// const { data } = await getIconList(queryForm)
const { title, pageNo = 1, pageSize = 72 } = queryForm
const mockList = IconList.filter((item) => !(title && !item.includes(title)))
const list = mockList.filter((item, index) => index < pageSize * pageNo && index >= pageSize * (pageNo - 1))
queryIcon.value = list
total.value = mockList.length
}
const handleIcon = (item: any) => {
......@@ -86,7 +99,7 @@ onBeforeMount(() => {
<style lang="scss">
.icon-selector-popper {
width: 302px !important;
// width: 302px !important;
.vab-query-form {
margin-top: calc(var(--el-margin) / 2);
......@@ -117,5 +130,28 @@ onBeforeMount(() => {
.el-pagination {
margin-top: calc(0 - var(--el-margin)) !important;
}
.icon-layout {
display: flex;
flex-wrap: wrap;
gap: 10px;
justify-content: flex-start;
padding: 10px;
.icon-item {
.vab-card {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
cursor: pointer;
.vab-icon {
font-size: 24px;
}
}
}
}
}
</style>
......@@ -6,6 +6,7 @@ import type { RouteRecordName, RouteRecordRaw } from 'vue-router'
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
import { authentication, base, disableRouterWarning, isHashRouterMode } from '/@/config'
import { setupPermissions } from '/@/router/permissions'
import { isHttp } from '/@/utils/validate'
import Layout from '/@vab/layouts/index.vue'
export const constantRoutes: VabRouteRecord[] = [
......@@ -247,7 +248,9 @@ const fatteningRoutes = (routes: VabRouteRecord[]): VabRouteRecord[] => {
const addRouter = (routes: VabRouteRecord[]) => {
routes.forEach((route: VabRouteRecord) => {
if (!router.hasRoute(route.name)) router.addRoute(route as RouteRecordRaw)
if (!router.hasRoute(route.name) && !isHttp(route.path)) {
router.addRoute(route as RouteRecordRaw)
}
if (route.children) addRouter(route.children)
})
}
......
export default {
200: '服务器成功返回请求数据',
201: '新建或修改数据成功',
202: '一个请求已经进入后台排队(异步任务)',
204: '删除数据成功',
205: '后端code指令强制开启锁屏',
400: '发出信息有误',
401: '用户没有权限(令牌失效、用户名、密码错误、登录过期)',
402: '令牌过期',
403: '用户得到授权,但是访问是被禁止的',
404: '访问资源不存在',
406: '请求格式不可得',
410: '请求资源被永久删除,且不会被看到',
500: '服务器发生错误',
502: '网关错误',
503: '服务不可用,服务器暂时过载或维护',
504: '网关超时',
default: '系统未知错误,请反馈给管理员',
}
import { ElLoading, ElMessage } from 'element-plus'
import { saveAs } from 'file-saver'
import CODE_MESSAGE from '/@/utils/codeMessage'
import { blobValidate, tansParams } from '/@/utils/index'
import request from '/@/utils/request'
// 通用下载方法
export function download(url: string, params: any, filename: any, config: any) {
let downloadLoadingInstance = ElLoading.service({ text: '正在下载数据,请稍候', background: 'rgba(0, 0, 0, 0.7)' })
return request
.post(url, params, {
transformRequest: [
(params) => {
return tansParams(params)
},
],
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
responseType: 'blob',
...config,
})
.then(async (data: any) => {
const isBlob = blobValidate(data)
if (isBlob) {
const blob = new Blob([data as any])
saveAs(blob, filename)
} else {
const resText = await data.text()
const rspObj: { code: keyof typeof CODE_MESSAGE; msg: string } = JSON.parse(resText)
const errMsg = CODE_MESSAGE[rspObj.code] || rspObj.msg || CODE_MESSAGE['default']
ElMessage.error(errMsg)
}
downloadLoadingInstance.close()
})
.catch((error) => {
console.error(error)
ElMessage.error('下载文件出现错误,请联系管理员!')
downloadLoadingInstance.close()
})
}
......@@ -244,3 +244,85 @@ export function parseStrEmpty(str: any) {
}
return str
}
/**
* 参数处理
* @param {*} params 参数
*/
export function tansParams(params: any) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName]
const part = `${encodeURIComponent(propName)}=`
if (value !== null && value !== '' && value !== undefined) {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && value[key] !== '' && value[key] !== undefined) {
let params = `${propName}[${key}]`
const subPart = `${encodeURIComponent(params)}=`
result += `${subPart}${encodeURIComponent(value[key])}&`
}
}
} else {
result += `${part}${encodeURIComponent(value)}&`
}
}
}
return result
}
// 验证是否为blob格式
export function blobValidate(data: any) {
return data.type !== 'application/json'
}
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
*/
export function handleTree(data: any, id: any, parentId: any, children: any) {
let config = {
id: id || 'id',
parentId: parentId || 'parentId',
childrenList: children || 'children',
}
const childrenListMap: any = {}
const nodeIds: any = {}
const tree = []
for (let d of data) {
let parentId = d[config.parentId]
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = []
}
nodeIds[d[config.id]] = d
childrenListMap[parentId].push(d)
}
for (let d of data) {
let parentId = d[config.parentId]
if (nodeIds[parentId] == null) {
tree.push(d)
}
}
for (let t of tree) {
adaptToChildrenList(t)
}
function adaptToChildrenList(o: any) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]]
}
if (o[config.childrenList]) {
for (let c of o[config.childrenList]) {
adaptToChildrenList(c)
}
}
}
return tree
}
......@@ -4,6 +4,7 @@ import { contentType, debounce, messageName, statusName, successCode, timeout }
import router from '/@/router'
import { useSettingsStore } from '/@/store/modules/settings'
import { useUserStore } from '/@/store/modules/user'
import CODE_MESSAGE from '/@/utils/codeMessage'
import { isArray } from '/@/utils/validate'
import { addErrorLog, needErrorLog } from '/@vab/plugins/errorLog'
import { gp } from '/@vab/plugins/vab'
......@@ -17,24 +18,24 @@ let requests: any[] = []
// 操作正常Code数组
const codeVerificationArray = isArray(successCode) ? [...successCode] : [successCode]
const CODE_MESSAGE: any = {
200: '服务器成功返回请求数据',
201: '新建或修改数据成功',
202: '一个请求已经进入后台排队(异步任务)',
204: '删除数据成功',
205: '后端code指令强制开启锁屏',
400: '发出信息有误',
401: '用户没有权限(令牌失效、用户名、密码错误、登录过期)',
402: '令牌过期',
403: '用户得到授权,但是访问是被禁止的',
404: '访问资源不存在',
406: '请求格式不可得',
410: '请求资源被永久删除,且不会被看到',
500: '服务器发生错误',
502: '网关错误',
503: '服务不可用,服务器暂时过载或维护',
504: '网关超时',
}
// const CODE_MESSAGE: any = {
// 200: '服务器成功返回请求数据',
// 201: '新建或修改数据成功',
// 202: '一个请求已经进入后台排队(异步任务)',
// 204: '删除数据成功',
// 205: '后端code指令强制开启锁屏',
// 400: '发出信息有误',
// 401: '用户没有权限(令牌失效、用户名、密码错误、登录过期)',
// 402: '令牌过期',
// 403: '用户得到授权,但是访问是被禁止的',
// 404: '访问资源不存在',
// 406: '请求格式不可得',
// 410: '请求资源被永久删除,且不会被看到',
// 500: '服务器发生错误',
// 502: '网关错误',
// 503: '服务不可用,服务器暂时过载或维护',
// 504: '网关超时',
// }
/**
* axios请求拦截器配置
......
......@@ -15,8 +15,10 @@ export const convertRouter = (asyncRoutes: VabRouteRecord[]) => {
if (route.component === 'Layout') route.component = () => import('/@vab/layouts/index.vue')
else {
const index = route.component.indexOf('views')
const path = index > 0 ? route.component.slice(index) : `${route.component}`
console.log(path)
let path = index > 0 ? route.component.slice(index) : `${route.component}`
if (!path.includes('.vue')) {
path += '.vue'
}
route.component = routeAllPathToCompMap[`../${path}`]
}
if (route.children && route.children.length > 0) route.children = convertRouter(route.children)
......
......@@ -206,3 +206,12 @@ export const isEnglish = (value: string) => {
const reg = /^[A-Za-z]+$/
return reg.test(value)
}
/**
* 判断url是否是http或https
* @param {string} url
* @returns {Boolean}
*/
export function isHttp(url: any) {
return url.includes('http://') || url.includes('https://')
}
<template>
<div class="comprehensive-table-container auto-height-container" :class="{ 'fullscreen-container': isFullscreen }">
<vab-query-form>
<vab-query-form-top-panel>
<el-form ref="queryRef" inline label-width="70px" :model="queryForm" @submit.prevent>
<el-form-item label="菜单名称" prop="menuName">
<el-input v-model="queryForm.menuName" clearable placeholder="请输入菜单名称" style="width: 200px" @keyup.enter="handleQuery" />
</el-form-item>
<el-form-item v-show="!fold" label="状态" prop="status">
<el-select v-model="queryForm.status" clearable placeholder="菜单状态" style="width: 200px">
<el-option v-for="dict in sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
<el-form-item>
<el-button icon="Search" :loading="listLoading" native-type="submit" type="primary" @click="handleQuery">查询</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
<el-button class="hidden-xs-only" text type="primary" @click="handleFold">
<span v-if="fold">展开</span>
<span v-else>合并</span>
<vab-icon class="vab-dropdown" :class="{ 'vab-dropdown-active': fold }" icon="arrow-up-s-line" />
</el-button>
</el-form-item>
</el-form>
</vab-query-form-top-panel>
<vab-query-form-left-panel>
<el-button icon="Plus" type="primary" @click="handleAdd">添加</el-button>
</vab-query-form-left-panel>
<vab-query-form-right-panel>
<div class="custom-table-right-tools">
<el-button @click="handleQuery">
<vab-icon icon="refresh-line" />
</el-button>
<el-button @click="clickFullScreen">
<vab-icon :icon="isFullscreen ? 'fullscreen-exit-fill' : 'fullscreen-fill'" />
</el-button>
</div>
</vab-query-form-right-panel>
</vab-query-form>
<el-table
ref="tableRef"
v-loading="listLoading"
border
:data="list"
row-key="menuId"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
>
<el-table-column label="菜单名称" prop="menuName" :show-overflow-tooltip="true" width="160" />
<el-table-column align="center" label="图标" prop="icon" width="160" />
<el-table-column label="排序" prop="orderNum" width="60" />
<el-table-column label="权限标识" prop="perms" :show-overflow-tooltip="true" />
<el-table-column label="组件路径" prop="component" :show-overflow-tooltip="true" />
<el-table-column label="状态" prop="status" width="80">
<template #default="scope">
<dict-tag :options="sys_normal_disable" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column align="center" label="创建时间" prop="createTime" width="160" />
<el-table-column align="center" fixed="right" label="操作" min-width="150">
<template #default="scope">
<el-button icon="Edit" link type="primary" @click="handleUpdate(scope.row)">修改</el-button>
<el-button icon="Plus" link type="primary" @click="handleAdd(scope.row)">新增</el-button>
<el-button icon="Delete" link type="primary" @click="handleDelete(scope.row)">删除</el-button>
</template>
</el-table-column>
<template #empty>
<el-empty class="vab-data-empty" description="暂无数据" />
</template>
</el-table>
<menu-management-edit2 ref="editRef" @fetch-data="fetchData" />
</div>
</template>
<script lang="ts" setup>
import type { TableInstance } from 'element-plus'
import { doDelete, listMenu } from '/@/api/menuManagement'
defineOptions({
name: 'MenuManagement',
})
const { proxy } = getCurrentInstance() as any
const { sys_normal_disable } = proxy.useDict('sys_normal_disable')
const { exit, enter, isFullscreen: _isFullscreen } = useFullscreen()
const isFullscreen = ref<boolean>(false)
const tableRef = ref<TableInstance>()
const fold = ref<boolean>(true)
const editRef = ref<any>(null)
const list = ref<any>([])
const listLoading = ref<boolean>(true)
const queryForm = reactive<any>({
menuName: undefined,
visible: undefined,
})
watch(
_isFullscreen,
() => {
if (_isFullscreen.value) isFullscreen.value = true
else isFullscreen.value = false
},
{ immediate: true }
)
onActivated(() => {
tableRef.value?.doLayout()
})
onBeforeMount(() => {
fetchData()
})
/** 点击全屏 */
const clickFullScreen = () => {
isFullscreen.value = !isFullscreen.value
isFullscreen.value ? enter() : exit()
}
/** 搜索条件折叠 */
const handleFold = () => {
fold.value = !fold.value
}
/** 查询菜单列表 */
const fetchData = async () => {
listLoading.value = true
const pp = Object.assign({}, queryForm)
const { data } = (await listMenu(pp)) as any
list.value = proxy.handleTree(data, 'menuId')
listLoading.value = false
}
/** 搜索按钮操作 */
function handleQuery() {
fetchData()
}
/** 重置按钮操作 */
function resetQuery() {
proxy.resetForm('queryRef')
handleQuery()
}
/** 新增按钮操作 */
const handleAdd = (row: any = {}) => {
editRef.value.showAdd(row)
}
/** 修改按钮操作 */
const handleUpdate = (row: any = {}) => {
editRef.value.showEdit(row)
}
/** 删除按钮操作 */
const handleDelete = (row: any = {}) => {
if (row.menuId) {
$baseConfirm(`是否确认删除名称为"${row.menuName}"的数据项?`, null, async () => {
const { msg }: any = await doDelete(row.menuId)
$baseMessage(msg, 'success', 'hey')
await fetchData()
})
}
}
</script>
<template>
<vab-dialog v-model="dialogFormVisible" append-to-body :title="title" width="600px" @close="close">
<el-form ref="formRef" label-width="80px" :model="form" :rules="rules">
<el-row>
<el-col :span="12">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" maxlength="30" placeholder="请输入用户昵称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<el-tree-select
v-model="form.deptId"
check-strictly
:data="deptOptions"
placeholder="请选择归属部门"
:props="{ value: 'id', label: 'label', children: 'children' }"
value-key="id"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" maxlength="11" placeholder="请输入手机号码" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" maxlength="50" placeholder="请输入邮箱" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-input v-model="form.userName" maxlength="30" placeholder="请输入用户名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" maxlength="20" placeholder="请输入用户密码" show-password type="password" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择">
<el-option v-for="dict in sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in sys_normal_disable" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择">
<el-option
v-for="item in postOptions"
:key="item.postId"
:disabled="item.status == 1"
:label="item.postName"
:value="item.postId"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择">
<el-option
v-for="item in roleOptions"
:key="item.roleId"
:disabled="item.status == 1"
:label="item.roleName"
:value="item.roleId"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" placeholder="请输入内容" type="textarea" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<el-button type="primary" @click="save">确定</el-button>
<el-button @click="cancel">取 消</el-button>
</template>
</vab-dialog>
</template>
<script lang="ts" setup>
import type { FormInstance } from 'element-plus'
import { doAdd, doEdit, getUser } from '/@/api/userManagement'
defineOptions({
name: 'UserManagementEdit2',
})
const { proxy } = getCurrentInstance() as any
const { sys_normal_disable, sys_user_sex } = proxy.useDict('sys_normal_disable', 'sys_user_sex')
const emit = defineEmits(['fetch-data'])
defineProps({
deptOptions: {
type: Array,
default: () => [],
},
})
const postOptions = ref<any>([])
const roleOptions = ref<any>([])
const formRef = ref<FormInstance>()
const form = ref<any>({
userId: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: '0',
remark: undefined,
postIds: [],
roleIds: [],
})
const rules = reactive<any>({
userName: [
{ required: true, message: '用户名称不能为空', trigger: 'blur' },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' },
],
nickName: [{ required: true, message: '用户昵称不能为空', trigger: 'blur' }],
password: [
{ required: true, message: '用户密码不能为空', trigger: 'blur' },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: '不能包含非法字符:< > " \' \\\ |', trigger: 'blur' },
],
email: [{ type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }],
phonenumber: [{ pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, message: '请输入正确的手机号码', trigger: 'blur' }],
})
const title = ref<string>('')
const dialogFormVisible = ref<boolean>(false)
const showEdit = async (row: any) => {
reset()
const { posts, roles, data, postIds, roleIds } = (await getUser(row?.userId)) as any
postOptions.value = posts
roleOptions.value = roles
dialogFormVisible.value = true
nextTick(() => {
if (row) {
title.value = '编辑'
form.value = data
form.value.postIds = postIds
form.value.roleIds = roleIds
} else {
title.value = '添加'
}
})
}
defineExpose({
showEdit,
})
onMounted(async () => {})
/** 重置操作表单 */
function reset() {
form.value = {
userId: undefined,
deptId: undefined,
userName: undefined,
nickName: undefined,
password: undefined,
phonenumber: undefined,
email: undefined,
sex: undefined,
status: '0',
remark: undefined,
postIds: [],
roleIds: [],
}
proxy.resetForm('userRef')
}
const close = () => {
formRef.value?.clearValidate()
formRef.value?.resetFields()
emit('fetch-data')
}
const cancel = () => {
close()
dialogFormVisible.value = false
}
const save = () => {
formRef.value?.validate(async (valid: any) => {
if (valid) {
if (form.value.userId) {
await doEdit(form.value)
await $baseMessage('修改成功', 'success', 'hey')
} else {
await doAdd(form.value)
await $baseMessage('添加成功', 'success', 'hey')
}
cancel()
}
})
}
</script>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论