添加菜单 权限 等页面
This commit is contained in:
@@ -153,4 +153,26 @@ export class manageService {
|
|||||||
// showErrorMessage: false // 不显示错误消息
|
// showErrorMessage: false // 不显示错误消息
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
//用户设置角色
|
||||||
|
static userSetRole(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/user/authorize',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//用户菜单权限设置
|
||||||
|
static userMenuAuth(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/user/set/resources',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//清除缓存
|
||||||
|
static clearCache() {
|
||||||
|
return request.get<any>({
|
||||||
|
url: '/common/preset/cache/clear'
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -1,6 +1,7 @@
|
|||||||
import { menuDataToRouter } from '@/router/utils/menuToRouter'
|
import { menuDataToRouter } from '@/router/utils/menuToRouter'
|
||||||
import { AppRouteRecord } from '@/types/router'
|
import { AppRouteRecord } from '@/types/router'
|
||||||
import { useUserStore } from '@/store/modules/user'
|
import { useUserStore } from '@/store/modules/user'
|
||||||
|
import { UserService } from '@/api/usersApi'
|
||||||
interface MenuResponse {
|
interface MenuResponse {
|
||||||
menuList: AppRouteRecord[]
|
menuList: AppRouteRecord[]
|
||||||
}
|
}
|
||||||
@@ -13,14 +14,16 @@ export const menuService = {
|
|||||||
if (!userStore.isLogin) {
|
if (!userStore.isLogin) {
|
||||||
throw new Error('用户未登录')
|
throw new Error('用户未登录')
|
||||||
}
|
}
|
||||||
|
const { menu } = await UserService.getMenuList()
|
||||||
|
const menuData = menu
|
||||||
|
// const userStore = useUserStore()
|
||||||
// 模拟接口返回的菜单数据
|
// 模拟接口返回的菜单数据
|
||||||
const menuData = userStore.info.menu
|
|
||||||
// 验证菜单数据
|
// 验证菜单数据
|
||||||
if (!menuData || !Array.isArray(menuData) || menuData.length === 0) {
|
if (!menuData || !Array.isArray(menuData) || menuData.length === 0) {
|
||||||
ElMessage.error('暂无系统菜单权限')
|
ElMessage.error('暂无系统菜单权限')
|
||||||
return { menuList: [] }
|
return { menuList: [] }
|
||||||
}
|
}
|
||||||
|
console.log('menuData', menuData)
|
||||||
// 处理菜单数据
|
// 处理菜单数据
|
||||||
const menuList = menuData.map((route: any) => menuDataToRouter(route))
|
const menuList = menuData.map((route: any) => menuDataToRouter(route))
|
||||||
// 验证处理后的菜单列表
|
// 验证处理后的菜单列表
|
||||||
|
|||||||
@@ -0,0 +1,219 @@
|
|||||||
|
import request from '@/utils/http'
|
||||||
|
|
||||||
|
export class systemService {
|
||||||
|
//系统列表
|
||||||
|
static getSystemList(params: Api.Common.PaginatingParams) {
|
||||||
|
return request.get<Api.Common.CommonListData>({
|
||||||
|
url: '/admin/systems/list',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//系统添加
|
||||||
|
static systemAdd(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/systems/store',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//系统详情
|
||||||
|
static systemDetail(params: any) {
|
||||||
|
return request.get<any>({
|
||||||
|
url: '/admin/systems/show',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//系统编辑
|
||||||
|
static systemEdit(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/systems/update',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//系统删除
|
||||||
|
static systemDelete(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/systems/destroy',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//飞书应用列表
|
||||||
|
static getFeishuAppList(params: Api.Common.PaginatingParams) {
|
||||||
|
return request.get<Api.Common.CommonListData>({
|
||||||
|
url: '/admin/corp/feishu/list',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//飞书应用添加
|
||||||
|
static feishuAppAdd(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/corp/feishu/store',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//飞书应用详情
|
||||||
|
static feishuAppDetail(params: any) {
|
||||||
|
return request.get<any>({
|
||||||
|
url: '/admin/corp/feishu/show',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//飞书应用编辑
|
||||||
|
static feishuAppEdit(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/corp/feishu/update',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//飞书应用删除
|
||||||
|
static feishuAppDelete(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/corp/feishu/destroy',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//公司列表
|
||||||
|
static getCompanyList(params: Api.Common.PaginatingParams) {
|
||||||
|
return request.get<Api.Common.CommonListData>({
|
||||||
|
url: '/admin/corp/list',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//公司添加
|
||||||
|
static companyAdd(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/corp/store',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//公司详情
|
||||||
|
static companyDetail(params: any) {
|
||||||
|
return request.get<any>({
|
||||||
|
url: '/admin/corp/show',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//公司编辑
|
||||||
|
static companyEdit(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/corp/update',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//公司删除
|
||||||
|
static companyDelete(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/corp/destroy',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//角色列表
|
||||||
|
static getRoleList(params: Api.Common.PaginatingParams) {
|
||||||
|
return request.get<Api.Common.CommonListData>({
|
||||||
|
url: '/admin/role/list',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//角色添加
|
||||||
|
static roleAdd(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/role/store',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//角色详情
|
||||||
|
static roleDetail(params: any) {
|
||||||
|
return request.get<any>({
|
||||||
|
url: '/admin/role/show',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//角色编辑
|
||||||
|
static roleEdit(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/role/update',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//角色删除
|
||||||
|
static roleDelete(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/role/destroy',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//角色权限设置
|
||||||
|
static roleAuth(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/role/menu/resource',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//角色下拉框
|
||||||
|
static getRoleSelectList() {
|
||||||
|
return request.get<Api.Common.CommonListData>({
|
||||||
|
url: '/common/preset/roles'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//菜单列表
|
||||||
|
static getMenutreeList() {
|
||||||
|
return request.get<any>({
|
||||||
|
url: '/admin/resources/list/tree'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
static getMenuList() {
|
||||||
|
return request.get<Api.Common.CommonListData>({
|
||||||
|
url: '/admin/resources/list/menu'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//菜单添加
|
||||||
|
static menuAdd(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/resources/store',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//菜单详情
|
||||||
|
static menuDetail(params: any) {
|
||||||
|
return request.get<any>({
|
||||||
|
url: '/admin/resources/show',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//菜单编辑
|
||||||
|
static menuEdit(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/resources/update',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//菜单删除
|
||||||
|
static menuDelete(params: any) {
|
||||||
|
return request.post<Api.Common.AddResponse>({
|
||||||
|
url: '/admin/resources/destroy',
|
||||||
|
params
|
||||||
|
// showErrorMessage: false // 不显示错误消息
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//权限菜单
|
||||||
|
static getPermissionMenuList(params: any) {
|
||||||
|
return request.get<Api.Common.CommonListData>({
|
||||||
|
url: '/admin/resources/list/menu/tree',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,4 +72,10 @@ export class UserService {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
//获取菜单
|
||||||
|
static getMenuList() {
|
||||||
|
return request.get<Api.User.UserInfo>({
|
||||||
|
url: '/common/preset/menus'
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,7 +54,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div> -->
|
</div> -->
|
||||||
|
<div class="btn-box screen-box" @click="clearCachefn">
|
||||||
|
<div class="btn">
|
||||||
|
<i class="iconfont-sys"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- 全屏按钮 -->
|
<!-- 全屏按钮 -->
|
||||||
<div class="btn-box screen-box" @click="toggleFullScreen">
|
<div class="btn-box screen-box" @click="toggleFullScreen">
|
||||||
<div
|
<div
|
||||||
@@ -215,6 +219,7 @@
|
|||||||
import { mittBus } from '@/utils/sys'
|
import { mittBus } from '@/utils/sys'
|
||||||
import { useMenuStore } from '@/store/modules/menu'
|
import { useMenuStore } from '@/store/modules/menu'
|
||||||
import AppConfig from '@/config'
|
import AppConfig from '@/config'
|
||||||
|
import { manageService } from '@/api/adminApi'
|
||||||
import { languageOptions } from '@/locales'
|
import { languageOptions } from '@/locales'
|
||||||
const isWindows = navigator.userAgent.includes('Windows')
|
const isWindows = navigator.userAgent.includes('Windows')
|
||||||
const { locale } = useI18n()
|
const { locale } = useI18n()
|
||||||
@@ -275,7 +280,14 @@
|
|||||||
const toggleFullScreen = () => {
|
const toggleFullScreen = () => {
|
||||||
toggleFullscreen()
|
toggleFullscreen()
|
||||||
}
|
}
|
||||||
|
const clearCachefn = () => {
|
||||||
|
manageService.clearCache().then((res) => {
|
||||||
|
ElMessage.success(res.data?.message || '成功!')
|
||||||
|
// setTimeout(() => {
|
||||||
|
window.location.reload()
|
||||||
|
// }, 5000)
|
||||||
|
})
|
||||||
|
}
|
||||||
const topBarWidth = (): string => {
|
const topBarWidth = (): string => {
|
||||||
const { TOP, DUAL_MENU, TOP_LEFT } = MenuTypeEnum
|
const { TOP, DUAL_MENU, TOP_LEFT } = MenuTypeEnum
|
||||||
const { getMenuOpenWidth } = settingStore
|
const { getMenuOpenWidth } = settingStore
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export interface RouteMeta extends Record<string | number | symbol, unknown> {
|
|||||||
authList?: Array<{
|
authList?: Array<{
|
||||||
title: string
|
title: string
|
||||||
auth_mark: string
|
auth_mark: string
|
||||||
|
authMark?: string // 兼容旧版
|
||||||
}>
|
}>
|
||||||
/** 是否为一级菜单 */
|
/** 是否为一级菜单 */
|
||||||
isFirstLevel?: boolean
|
isFirstLevel?: boolean
|
||||||
|
|||||||
Vendored
+4
@@ -51,6 +51,10 @@ declare namespace Api {
|
|||||||
code: string
|
code: string
|
||||||
message: string
|
message: string
|
||||||
}
|
}
|
||||||
|
interface CommonListDatad1 {
|
||||||
|
data: never[]
|
||||||
|
message: string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 认证类型 */
|
/** 认证类型 */
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-content">
|
||||||
|
<div v-if="!isMobile">
|
||||||
|
<ElRow>
|
||||||
|
<div style="width: 12px"></div>
|
||||||
|
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||||
|
<ElButton @click="showDialog('add')" v-ripple>新增</ElButton>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
<ArtTable
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
|
:data="tableData"
|
||||||
|
:currentPage="pagination.currentPage"
|
||||||
|
:pageSize="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn label="ID" prop="id" />
|
||||||
|
<ElTableColumn label="公司名称" prop="name" />
|
||||||
|
<ElTableColumn label="状态" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElTag :type="scope.row.status ? 'primary' : 'info'">
|
||||||
|
{{ scope.row.status ? '启用' : '禁用' }}
|
||||||
|
</ElTag>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
<ElTableColumn label="创建时间" prop="created_at" />
|
||||||
|
<ElTableColumn fixed="right" label="操作" width="200px">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElRow>
|
||||||
|
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
|
||||||
|
<el-button link @click="deleteRole(scope.row)"> 删除 </el-button>
|
||||||
|
</ElRow>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
<ElDialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="dialogType === 'add' ? '新增' : '编辑'"
|
||||||
|
width="40%"
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<ElForm ref="formRef" :model="form" :rules="rules" label-width="160px">
|
||||||
|
<ElFormItem label="公司名称" prop="name">
|
||||||
|
<ElInput v-model="form.name" />
|
||||||
|
</ElFormItem>
|
||||||
|
</ElForm>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||||
|
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
</div>
|
||||||
|
<div v-else class="mobile-hide-tip">
|
||||||
|
<p>该页面暂不支持移动端访问</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { Ordertype} from '@/mock/temp/formData'
|
||||||
|
import { systemService } from '@/api/systemApi'
|
||||||
|
defineOptions({ name: 'Type ' })
|
||||||
|
const loading = ref(false)
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const typeList = ref<any[]>([])
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const { width } = useWindowSize()
|
||||||
|
const isMobile = computed(() => width.value < 500)
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
name: [{ required: true, message: '请输入公司名称', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = reactive<Ordertype>({
|
||||||
|
name: '',
|
||||||
|
id:''
|
||||||
|
})
|
||||||
|
const pagination = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
// 表格数据
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
|
||||||
|
// 表格实例引用
|
||||||
|
const tableRef = ref()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getWorkList()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取列表数据
|
||||||
|
const getWorkList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const { currentPage, pageSize } = pagination
|
||||||
|
|
||||||
|
const { records, current, size, total } = await systemService.getCompanyList({
|
||||||
|
current: currentPage,
|
||||||
|
size: pageSize
|
||||||
|
})
|
||||||
|
tableData.value = records.map((item: any) => ({
|
||||||
|
...item
|
||||||
|
}))
|
||||||
|
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialogType = ref('add')
|
||||||
|
|
||||||
|
const showDialog = (type: string, row?: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogType.value = type
|
||||||
|
|
||||||
|
if (type === 'edit' && row) {
|
||||||
|
form.name = row.name
|
||||||
|
form.id = row.id
|
||||||
|
} else {
|
||||||
|
form.name = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const deleteRole = (row?: any) => {
|
||||||
|
ElMessageBox.confirm('确定删除该分类吗?', '删除确认', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'error'
|
||||||
|
}).then(async () => {
|
||||||
|
const { message } = await systemService.companyDelete({
|
||||||
|
id: row.id,
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
getWorkList()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
if (dialogType.value === 'add') {
|
||||||
|
const { message } = await systemService.companyAdd({
|
||||||
|
name: form.name
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
dialogVisible.value = false
|
||||||
|
getWorkList()
|
||||||
|
} else {
|
||||||
|
const { message } = await systemService.companyEdit({
|
||||||
|
name: form.name,
|
||||||
|
id: form.id
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
dialogVisible.value = false
|
||||||
|
getWorkList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-table__empty-block) {
|
||||||
|
height: 100% !important;
|
||||||
|
min-height: 200px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.page-content {
|
||||||
|
.svg-icon {
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: -8px;
|
||||||
|
fill: currentcolor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-content">
|
||||||
|
<div v-if="!isMobile">
|
||||||
|
<ElRow>
|
||||||
|
<!-- <ElCol :xs="24" :sm="12" :lg="6">
|
||||||
|
<ElInput placeholder="名称"></ElInput>
|
||||||
|
</ElCol> -->
|
||||||
|
<div style="width: 12px"></div>
|
||||||
|
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||||
|
<!-- <ElButton v-ripple>搜索</ElButton> -->
|
||||||
|
<ElButton @click="showDialog('add')" v-ripple>新增</ElButton>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
|
||||||
|
<ArtTable
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
|
:data="tableData"
|
||||||
|
:currentPage="pagination.currentPage"
|
||||||
|
:pageSize="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn label="ID" prop="id" />
|
||||||
|
<ElTableColumn label="分类名称" prop="name" />
|
||||||
|
<ElTableColumn label="状态" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElTag :type="scope.row.status ? 'primary' : 'info'">
|
||||||
|
{{ scope.row.status ? '启用' : '禁用' }}
|
||||||
|
</ElTag>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
<ElTableColumn label="创建时间" prop="created_at" />
|
||||||
|
<ElTableColumn fixed="right" label="操作" width="200px">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElRow>
|
||||||
|
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
|
||||||
|
<el-button link @click="deleteRole(scope.row)"> 删除 </el-button>
|
||||||
|
</ElRow>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
|
||||||
|
<ElDialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="dialogType === 'add' ? '新增' : '编辑'"
|
||||||
|
width="40%"
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<ElForm ref="formRef" :model="form" :rules="rules" label-width="160px">
|
||||||
|
<ElFormItem label="分类名称" prop="name">
|
||||||
|
<ElInput v-model="form.name" />
|
||||||
|
</ElFormItem>
|
||||||
|
</ElForm>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||||
|
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
</div>
|
||||||
|
<div v-else class="mobile-hide-tip">
|
||||||
|
<p>该页面暂不支持移动端访问</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { Ordertype} from '@/mock/temp/formData'
|
||||||
|
import { systemService } from '@/api/systemApi'
|
||||||
|
defineOptions({ name: 'Type ' })
|
||||||
|
const loading = ref(false)
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const typeList = ref<any[]>([])
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const { width } = useWindowSize()
|
||||||
|
const isMobile = computed(() => width.value < 500)
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入分类名称', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = reactive<Ordertype>({
|
||||||
|
name: '',
|
||||||
|
id:''
|
||||||
|
})
|
||||||
|
const pagination = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
// 表格数据
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
|
||||||
|
// 表格实例引用
|
||||||
|
const tableRef = ref()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getWorkList()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取列表数据
|
||||||
|
const getWorkList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const { currentPage, pageSize } = pagination
|
||||||
|
|
||||||
|
const { records, current, size, total } = await systemService.getFeishuAppList({
|
||||||
|
current: currentPage,
|
||||||
|
size: pageSize
|
||||||
|
})
|
||||||
|
tableData.value = records.map((item: any, index: number) => ({
|
||||||
|
...item
|
||||||
|
}))
|
||||||
|
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialogType = ref('add')
|
||||||
|
|
||||||
|
const showDialog = (type: string, row?: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogType.value = type
|
||||||
|
|
||||||
|
if (type === 'edit' && row) {
|
||||||
|
form.name = row.name
|
||||||
|
form.id = row.id
|
||||||
|
} else {
|
||||||
|
form.name = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const deleteRole = (row?: any) => {
|
||||||
|
ElMessageBox.confirm('确定删除该分类吗?', '删除确认', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'error'
|
||||||
|
}).then(async () => {
|
||||||
|
const { message } = await systemService.feishuAppDelete({
|
||||||
|
id: row.id,
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
getWorkList()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
if (dialogType.value === 'add') {
|
||||||
|
const { message } = await systemService.feishuAppAdd({
|
||||||
|
name: form.name
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
dialogVisible.value = false
|
||||||
|
getWorkList()
|
||||||
|
} else {
|
||||||
|
const { message } = await systemService.feishuAppEdit({
|
||||||
|
name: form.name,
|
||||||
|
id: form.id
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
dialogVisible.value = false
|
||||||
|
getWorkList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-table__empty-block) {
|
||||||
|
height: 100% !important;
|
||||||
|
min-height: 200px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.page-content {
|
||||||
|
.svg-icon {
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: -8px;
|
||||||
|
fill: currentcolor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,696 @@
|
|||||||
|
<template>
|
||||||
|
<ArtTableFullScreen>
|
||||||
|
<div class="menu-page" id="table-full-screen">
|
||||||
|
<!-- 搜索栏 -->
|
||||||
|
<ArtSearchBar
|
||||||
|
v-model:filter="formFilters"
|
||||||
|
:items="formItems"
|
||||||
|
:showExpand="false"
|
||||||
|
@reset="handleReset"
|
||||||
|
@search="handleSearch"
|
||||||
|
></ArtSearchBar>
|
||||||
|
|
||||||
|
<ElCard shadow="never" class="art-table-card">
|
||||||
|
<!-- 表格头部 -->
|
||||||
|
<ArtTableHeader :showZebra="false" v-model:columns="columnChecks" @refresh="handleRefresh">
|
||||||
|
<template #left>
|
||||||
|
<!-- 按钮权限:后端控制模式,使用自定义指令 -->
|
||||||
|
<ElButton v-auth="'system@menu_add'" @click="showModel('menu', null)" v-ripple>
|
||||||
|
添加菜单
|
||||||
|
</ElButton>
|
||||||
|
<ElButton @click="toggleExpand" v-ripple>
|
||||||
|
{{ isExpanded ? '收起' : '展开' }}
|
||||||
|
</ElButton>
|
||||||
|
<!-- 按钮权限:前端控制模式,使用 hasAuth 方法 -->
|
||||||
|
<!-- <ElButton v-if="hasAuth('B_CODE1')" @click="showModel('menu', null, true)" v-ripple>
|
||||||
|
添加菜单
|
||||||
|
</ElButton> -->
|
||||||
|
</template>
|
||||||
|
</ArtTableHeader>
|
||||||
|
<!-- 表格 -->
|
||||||
|
<ArtTable
|
||||||
|
rowKey="path"
|
||||||
|
ref="tableRef"
|
||||||
|
:loading="loading"
|
||||||
|
:data="filteredTableData"
|
||||||
|
:marginTop="10"
|
||||||
|
:stripe="false"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn v-for="col in columns" :key="col.prop || col.type" v-bind="col" />
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
|
||||||
|
<ElDialog :title="dialogTitle" v-model="dialogVisible" width="700px" align-center>
|
||||||
|
<ElForm ref="formRef" :model="form" :rules="rules" label-width="85px">
|
||||||
|
<ElRow :gutter="20">
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="资源类型" prop="type">
|
||||||
|
<el-select v-model="form.type">
|
||||||
|
<el-option label="目录" value="directory" />
|
||||||
|
<el-option label="菜单" value="menu" />
|
||||||
|
<el-option label="权限" value="permission" />
|
||||||
|
</el-select>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="资源名称" prop="name">
|
||||||
|
<ElInput v-model="form.name" placeholder="资源名称"></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
<ElRow :gutter="20">
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="权限标识" prop="code">
|
||||||
|
<ElInput v-model="form.code" placeholder="权限标识"></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="图标" prop="icon">
|
||||||
|
<ArtIconSelector v-model="form.icon" :iconType="iconType" width="100%" />
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
<ElRow :gutter="20" v-if="form.type !== 'permission'">
|
||||||
|
<ElCol :span="12" v-if="form.type !== 'permission'">
|
||||||
|
<ElFormItem label="路由地址" prop="url">
|
||||||
|
<ElInput v-model="form.url" placeholder="路由地址"></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="打开方式" prop="open_type">
|
||||||
|
<ElSelect v-model="form.open_type" class="account-select">
|
||||||
|
<el-option label="内部" value="internal" />
|
||||||
|
<el-option label="外部" value="external" />
|
||||||
|
<el-option label="嵌入" value="iframe" />
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
<ElRow :gutter="20" v-if="form.type !== 'permission'">
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="资源排序" prop="sort" style="width: 100%">
|
||||||
|
<ElInputNumber
|
||||||
|
v-model="form.sort"
|
||||||
|
style="width: 100%"
|
||||||
|
@change="handleChange"
|
||||||
|
:min="1"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="外部链接" prop="link">
|
||||||
|
<ElInput
|
||||||
|
v-model="form.link"
|
||||||
|
placeholder="外部链接/内嵌地址(https://www.baidu.com)"
|
||||||
|
></ElInput>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
<ElRow :gutter="20">
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="系统" prop="system_id">
|
||||||
|
<ElSelect v-model="form.system_id" class="account-select">
|
||||||
|
<ElOption
|
||||||
|
v-for="account in systemsList"
|
||||||
|
:key="account.id"
|
||||||
|
:label="account.name"
|
||||||
|
:value="account.id"
|
||||||
|
>
|
||||||
|
<span>{{ account.name }}</span>
|
||||||
|
</ElOption>
|
||||||
|
</ElSelect>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="12">
|
||||||
|
<ElFormItem label="父级" prop="parent_id">
|
||||||
|
<el-tree-select
|
||||||
|
v-model="form.parent_id"
|
||||||
|
:data="parentList"
|
||||||
|
:props="{
|
||||||
|
value: 'id',
|
||||||
|
label: 'name',
|
||||||
|
children: 'children'
|
||||||
|
}"
|
||||||
|
check-strictly
|
||||||
|
:render-after-expand="false"
|
||||||
|
style="width: 240px"
|
||||||
|
/>
|
||||||
|
<!-- <ElSelect v-model="form.parent_id" class="account-select">
|
||||||
|
<ElOption
|
||||||
|
v-for="account in parentList"
|
||||||
|
:key="account.id"
|
||||||
|
:label="account.name"
|
||||||
|
:value="account.id"
|
||||||
|
>
|
||||||
|
<span>{{ account.name }}</span>
|
||||||
|
</ElOption>
|
||||||
|
</ElSelect> -->
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
|
||||||
|
<ElRow :gutter="20" v-if="form.type !== 'permission'">
|
||||||
|
<ElCol :span="5">
|
||||||
|
<ElFormItem label="是否启用" prop="status">
|
||||||
|
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0"></ElSwitch>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="5">
|
||||||
|
<ElFormItem label="页面缓存" prop="keep_alive">
|
||||||
|
<ElSwitch
|
||||||
|
v-model="form.keep_alive"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
></ElSwitch>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="5">
|
||||||
|
<ElFormItem label="是否隐藏" prop="is_hide">
|
||||||
|
<ElSwitch v-model="form.is_hide" :active-value="1" :inactive-value="0"></ElSwitch>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="5">
|
||||||
|
<ElFormItem label="标签页是否隐藏" prop="is_hide_tab" label-width="120px">
|
||||||
|
<ElSwitch
|
||||||
|
v-model="form.is_hide_tab"
|
||||||
|
:active-value="1"
|
||||||
|
:inactive-value="0"
|
||||||
|
></ElSwitch>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<!-- <ElCol :span="5">
|
||||||
|
<ElFormItem label="是否内嵌" prop="isMenu">
|
||||||
|
<ElSwitch v-model="form.isIframe"></ElSwitch>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol> -->
|
||||||
|
</ElRow>
|
||||||
|
<ElRow :gutter="20" v-if="form.type !== 'permission'">
|
||||||
|
<ElCol :span="5">
|
||||||
|
<ElFormItem label="是否首页" prop="is_home">
|
||||||
|
<ElSwitch v-model="form.is_home" :active-value="1" :inactive-value="0"></ElSwitch>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
<ElCol :span="10">
|
||||||
|
<ElFormItem label="不需要认证" prop="no_auth" label-width="120px">
|
||||||
|
<ElSwitch v-model="form.no_auth" :active-value="1" :inactive-value="0"></ElSwitch>
|
||||||
|
</ElFormItem>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
</ElForm>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<ElButton @click="dialogVisible = false">取 消</ElButton>
|
||||||
|
<ElButton type="primary" @click="submitForm()">确 定</ElButton>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
</ElCard>
|
||||||
|
</div>
|
||||||
|
</ArtTableFullScreen>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import { IconTypeEnum } from '@/enums/appEnum'
|
||||||
|
import { formatMenuTitle } from '@/router/utils/utils'
|
||||||
|
import ArtButtonTable from '@/components/core/forms/ArtButtonTable.vue'
|
||||||
|
import { useCheckedColumns } from '@/composables/useCheckedColumns'
|
||||||
|
import { ElPopover, ElButton } from 'element-plus'
|
||||||
|
import { AppRouteRecord } from '@/types/router'
|
||||||
|
import { useAuth } from '@/composables/useAuth'
|
||||||
|
import { SearchFormItem } from '@/types'
|
||||||
|
import { systemService } from '@/api/systemApi'
|
||||||
|
import { UserService } from '@/api/usersApi'
|
||||||
|
|
||||||
|
defineOptions({ name: 'Menus' })
|
||||||
|
|
||||||
|
const { hasAuth } = useAuth()
|
||||||
|
|
||||||
|
// const { menuList } = storeToRefs(useMenuStore())
|
||||||
|
const menuList = ref<any[]>([])
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
//系统
|
||||||
|
const systemsList = ref<any>()
|
||||||
|
const getsystemsList = async () => {
|
||||||
|
const response = await UserService.getsystemsList()
|
||||||
|
systemsList.value = response || []
|
||||||
|
}
|
||||||
|
//父级
|
||||||
|
const parentList = ref<any>()
|
||||||
|
const getparentList = async () => {
|
||||||
|
const response = await systemService.getMenuList()
|
||||||
|
parentList.value = response || []
|
||||||
|
}
|
||||||
|
// 定义表单搜索初始值
|
||||||
|
const initialSearchState = {
|
||||||
|
name: '',
|
||||||
|
route: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应式表单数据
|
||||||
|
const formFilters = reactive({ ...initialSearchState })
|
||||||
|
|
||||||
|
// 增加实际应用的搜索条件状态
|
||||||
|
const appliedFilters = reactive({ ...initialSearchState })
|
||||||
|
|
||||||
|
// 重置表单
|
||||||
|
const handleReset = () => {
|
||||||
|
Object.assign(formFilters, { ...initialSearchState })
|
||||||
|
Object.assign(appliedFilters, { ...initialSearchState })
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索处理
|
||||||
|
const handleSearch = () => {
|
||||||
|
// 将当前输入的筛选条件应用到实际搜索
|
||||||
|
Object.assign(appliedFilters, { ...formFilters })
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单配置项
|
||||||
|
const formItems: SearchFormItem[] = [
|
||||||
|
{
|
||||||
|
label: '菜单名称',
|
||||||
|
prop: 'name',
|
||||||
|
type: 'input',
|
||||||
|
config: {
|
||||||
|
clearable: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '路由地址',
|
||||||
|
prop: 'route',
|
||||||
|
type: 'input',
|
||||||
|
config: {
|
||||||
|
clearable: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// 构建菜单类型标签
|
||||||
|
const buildMenuTypeTag = (row: AppRouteRecord) => {
|
||||||
|
if (row.children && row.children.length > 0) {
|
||||||
|
return 'info'
|
||||||
|
} else if (row.meta?.link && row.meta?.isIframe) {
|
||||||
|
return 'success'
|
||||||
|
} else if (row.path) {
|
||||||
|
return 'primary'
|
||||||
|
} else if (row.meta?.link) {
|
||||||
|
return 'warning'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建菜单类型文本
|
||||||
|
const buildMenuTypeText = (row: AppRouteRecord) => {
|
||||||
|
if (row.children && row.children.length > 0) {
|
||||||
|
return '目录'
|
||||||
|
} else if (row.meta?.link && row.meta?.isIframe) {
|
||||||
|
return '内嵌'
|
||||||
|
} else if (row.path) {
|
||||||
|
return '菜单'
|
||||||
|
} else if (row.meta?.link) {
|
||||||
|
return '外链'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态列配置
|
||||||
|
const { columnChecks, columns } = useCheckedColumns(() => [
|
||||||
|
{
|
||||||
|
prop: 'meta.title',
|
||||||
|
label: '菜单名称',
|
||||||
|
minWidth: 120,
|
||||||
|
formatter: (row: AppRouteRecord) => {
|
||||||
|
return formatMenuTitle(row.meta?.title)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'type',
|
||||||
|
label: '菜单类型',
|
||||||
|
formatter: (row: AppRouteRecord) => {
|
||||||
|
return h(ElTag, { type: buildMenuTypeTag(row) }, () => buildMenuTypeText(row))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'path',
|
||||||
|
label: '路由',
|
||||||
|
formatter: (row: AppRouteRecord) => {
|
||||||
|
return row.meta?.link || row.path || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'meta.authList',
|
||||||
|
label: '可操作权限',
|
||||||
|
formatter: (row: AppRouteRecord) => {
|
||||||
|
return h(
|
||||||
|
'div',
|
||||||
|
{},
|
||||||
|
row.meta.authList?.map((item: { title: string; auth_mark: string }, index: number) => {
|
||||||
|
return h(
|
||||||
|
ElPopover,
|
||||||
|
{
|
||||||
|
placement: 'top-start',
|
||||||
|
title: '操作',
|
||||||
|
width: 200,
|
||||||
|
trigger: 'click',
|
||||||
|
key: index
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () =>
|
||||||
|
h('div', { style: 'margin: 0; text-align: right' }, [
|
||||||
|
h(
|
||||||
|
ElButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'primary',
|
||||||
|
onClick: () => showModel('button', item, false, row)
|
||||||
|
},
|
||||||
|
{ default: () => '编辑' }
|
||||||
|
),
|
||||||
|
h(
|
||||||
|
ElButton,
|
||||||
|
{
|
||||||
|
size: 'small',
|
||||||
|
type: 'danger',
|
||||||
|
onClick: () => deleteAuth(item)
|
||||||
|
},
|
||||||
|
{ default: () => '删除' }
|
||||||
|
)
|
||||||
|
]),
|
||||||
|
reference: () => h(ElButton, { class: 'small-btn' }, { default: () => item.title })
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'date',
|
||||||
|
label: '编辑时间',
|
||||||
|
formatter: () => '2022-3-12 12:00:00'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'status',
|
||||||
|
label: '隐藏菜单',
|
||||||
|
formatter: (row) => {
|
||||||
|
return h(ElTag, { type: row.meta.isHide ? 'danger' : 'info' }, () =>
|
||||||
|
row.meta.isHide ? '是' : '否'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prop: 'operation',
|
||||||
|
label: '操作',
|
||||||
|
width: 180,
|
||||||
|
formatter: (row: AppRouteRecord) => {
|
||||||
|
return h('div', [
|
||||||
|
// 后端模式权限标识
|
||||||
|
hasAuth('system@menu_add') &&
|
||||||
|
h(ArtButtonTable, {
|
||||||
|
type: 'add',
|
||||||
|
onClick: () => showModel('menu', row, true)
|
||||||
|
}),
|
||||||
|
hasAuth('system@menu_update') &&
|
||||||
|
h(ArtButtonTable, {
|
||||||
|
type: 'edit',
|
||||||
|
onClick: () => showDialog('edit', row)
|
||||||
|
}),
|
||||||
|
hasAuth('system@menu_destroy') &&
|
||||||
|
h(ArtButtonTable, {
|
||||||
|
type: 'delete',
|
||||||
|
onClick: () => deleteMenu(row)
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const handleRefresh = () => {
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const form = reactive({
|
||||||
|
// 菜单
|
||||||
|
system_id: '',
|
||||||
|
type: 'menu', // 资源类型
|
||||||
|
parent_id: '',
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
code: '',
|
||||||
|
icon: '',
|
||||||
|
status: 1,
|
||||||
|
sort: 1,
|
||||||
|
is_home: 0,
|
||||||
|
keep_alive: 1,
|
||||||
|
is_hide: 0,
|
||||||
|
is_hide_tab: 0,
|
||||||
|
no_auth: 0,
|
||||||
|
link: '',
|
||||||
|
open_type: 'internal'
|
||||||
|
})
|
||||||
|
const iconType = ref(IconTypeEnum.UNICODE)
|
||||||
|
|
||||||
|
// const labelPosition = ref('menu')
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入菜单名称', trigger: 'blur' },
|
||||||
|
{ min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
system_id: [{ required: true, message: '请选择系统', trigger: 'blur' }],
|
||||||
|
type: [{ required: true, message: '请选择资源类型', trigger: 'blur' }],
|
||||||
|
code: [{ required: true, message: '输入权限标识', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
const tableData = ref<AppRouteRecord[]>([])
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getTableData()
|
||||||
|
})
|
||||||
|
|
||||||
|
const getTableData = async () => {
|
||||||
|
loading.value = true
|
||||||
|
// const { res } = await systemService.getMenutreeList()
|
||||||
|
await systemService.getMenutreeList().then((res) => {
|
||||||
|
console.log(res)
|
||||||
|
menuList.value = res
|
||||||
|
})
|
||||||
|
// console.log(res)
|
||||||
|
// menuList.value = data
|
||||||
|
|
||||||
|
// 基于 appliedFilters 在这里进行过滤,并将结果赋值给 tableData
|
||||||
|
const searchName = appliedFilters.name?.toLowerCase().trim() || ''
|
||||||
|
const searchRoute = appliedFilters.route?.toLowerCase().trim() || ''
|
||||||
|
|
||||||
|
const filterMenus = (items: AppRouteRecord[]): AppRouteRecord[] => {
|
||||||
|
return items.reduce((acc: AppRouteRecord[], item: AppRouteRecord) => {
|
||||||
|
// 浅拷贝节点,避免直接修改原数据
|
||||||
|
const copy: AppRouteRecord = { ...item }
|
||||||
|
if (copy.children && copy.children.length > 0) {
|
||||||
|
copy.children = filterMenus(copy.children)
|
||||||
|
}
|
||||||
|
|
||||||
|
const menuTitle = formatMenuTitle(copy.meta?.title || '').toLowerCase()
|
||||||
|
const menuPath = (copy.path || '').toLowerCase()
|
||||||
|
const nameMatch = !searchName || menuTitle.includes(searchName)
|
||||||
|
const routeMatch = !searchRoute || menuPath.includes(searchRoute)
|
||||||
|
const hasChildren = Array.isArray(copy.children) && copy.children.length > 0
|
||||||
|
|
||||||
|
if (hasChildren || (nameMatch && routeMatch)) {
|
||||||
|
acc.push(copy)
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
tableData.value = filterMenus(menuList.value)
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤后的表格数据改为来源于 getTableData 的结果
|
||||||
|
const filteredTableData = computed(() => tableData.value)
|
||||||
|
|
||||||
|
const isEdit = ref(false)
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const dialogTitle = computed(() => {
|
||||||
|
// const type = labelPosition.value === 'menu' ? '菜单' : '权限'
|
||||||
|
return isEdit.value ? `编辑资源` : `新建资源`
|
||||||
|
})
|
||||||
|
|
||||||
|
const showDialog = (type: string, row: AppRouteRecord) => {
|
||||||
|
showModel('menu', row)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleChange = () => {}
|
||||||
|
|
||||||
|
const submitForm = async () => {
|
||||||
|
if (!formRef.value) return
|
||||||
|
|
||||||
|
await formRef.value.validate(async (valid) => {
|
||||||
|
if (valid) {
|
||||||
|
try {
|
||||||
|
if (isEdit.value) {
|
||||||
|
const payload = { ...form, id: itemid.value }
|
||||||
|
await systemService.menuEdit(payload as any)
|
||||||
|
} else {
|
||||||
|
await systemService.menuAdd(form)
|
||||||
|
}
|
||||||
|
|
||||||
|
ElMessage.success(`${isEdit.value ? '编辑' : '新增'}成功`)
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 刷新表格数据
|
||||||
|
getTableData()
|
||||||
|
} catch {
|
||||||
|
ElMessage.error(`${isEdit.value ? '编辑' : '新增'}失败`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const itemid = ref('')
|
||||||
|
const showModel = (type: string, row?: any, padd: boolean = false, data?: any) => {
|
||||||
|
getsystemsList()
|
||||||
|
getparentList()
|
||||||
|
dialogVisible.value = true
|
||||||
|
// labelPosition.value = type
|
||||||
|
isEdit.value = false
|
||||||
|
// lockMenuType.value = lock
|
||||||
|
resetForm()
|
||||||
|
itemid.value = ''
|
||||||
|
if (data) {
|
||||||
|
isEdit.value = true
|
||||||
|
form.type = 'permission'
|
||||||
|
form.system_id = data.meta.systemId
|
||||||
|
form.parent_id = data.id
|
||||||
|
form.name = row.title
|
||||||
|
form.code = row.authMark
|
||||||
|
itemid.value = row.id
|
||||||
|
} else if (padd) {
|
||||||
|
nextTick(() => {
|
||||||
|
form.parent_id = row.id
|
||||||
|
form.system_id = row.meta.systemId
|
||||||
|
})
|
||||||
|
} else if (row && !padd) {
|
||||||
|
isEdit.value = true
|
||||||
|
nextTick(() => {
|
||||||
|
// 回显数据
|
||||||
|
itemid.value = row.id
|
||||||
|
form.system_id = row.meta.systemId
|
||||||
|
form.parent_id = row.meta.parentId == 0 ? '' : row.meta.parentId
|
||||||
|
form.name = row.name
|
||||||
|
form.type = row.meta.type
|
||||||
|
form.url = row.path
|
||||||
|
form.code = row.meta.code
|
||||||
|
form.icon = row.meta.icon
|
||||||
|
form.sort = row.meta.sort
|
||||||
|
form.is_home = row.meta.isHome
|
||||||
|
form.keep_alive = row.meta.keepAlive
|
||||||
|
form.is_hide = row.meta.isHide
|
||||||
|
form.is_hide_tab = row.meta.isHideTab
|
||||||
|
form.no_auth = row.meta.noAuth
|
||||||
|
form.status = row.meta.status
|
||||||
|
form.link = row.meta.link
|
||||||
|
form.open_type = row.meta.openType
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
formRef.value?.resetFields()
|
||||||
|
Object.assign(form, {
|
||||||
|
// 菜单
|
||||||
|
system_id: '',
|
||||||
|
type: 'menu', // 资源类型
|
||||||
|
parent_id: '',
|
||||||
|
name: '',
|
||||||
|
url: '',
|
||||||
|
code: '',
|
||||||
|
icon: '',
|
||||||
|
status: 1,
|
||||||
|
sort: 1,
|
||||||
|
is_home: 0,
|
||||||
|
keep_alive: 1,
|
||||||
|
is_hide: 0,
|
||||||
|
is_hide_tab: 0,
|
||||||
|
no_auth: 0,
|
||||||
|
link: '',
|
||||||
|
open_type: 'internal'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteMenu = async (item: any) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('确定要删除该菜单吗?删除后无法恢复', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
const res = await systemService.menuDelete({ id: item.id })
|
||||||
|
ElMessage.success(res?.message || '删除成功!')
|
||||||
|
// 刷新表格数据
|
||||||
|
getTableData()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
ElMessage.error('删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteAuth = async (item: any) => {
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm('确定要删除该权限吗?删除后无法恢复', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
})
|
||||||
|
const res = await systemService.menuDelete({ id: item.id })
|
||||||
|
ElMessage.success(res?.message || '删除成功!')
|
||||||
|
// 刷新表格数据
|
||||||
|
getTableData()
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== 'cancel') {
|
||||||
|
ElMessage.error('删除失败')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 添加一个控制变量
|
||||||
|
// const lockMenuType = ref(false)
|
||||||
|
|
||||||
|
const isExpanded = ref(false)
|
||||||
|
const tableRef = ref()
|
||||||
|
|
||||||
|
const toggleExpand = () => {
|
||||||
|
isExpanded.value = !isExpanded.value
|
||||||
|
nextTick(() => {
|
||||||
|
if (tableRef.value) {
|
||||||
|
tableRef.value[isExpanded.value ? 'expandAll' : 'collapseAll']()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.menu-page {
|
||||||
|
.svg-icon {
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: -8px;
|
||||||
|
fill: currentcolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.small-btn) {
|
||||||
|
height: 22px !important;
|
||||||
|
padding: 0 5px !important;
|
||||||
|
font-size: 10px !important;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
:deep(.el-dialog__footer) {
|
||||||
|
z-index: inherit;
|
||||||
|
.el-button > span {
|
||||||
|
z-index: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,425 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-content">
|
||||||
|
<ElRow>
|
||||||
|
<ElCol :xs="24" :sm="12" :lg="6">
|
||||||
|
<ElInput placeholder="角色名称"></ElInput>
|
||||||
|
</ElCol>
|
||||||
|
<div style="width: 12px"></div>
|
||||||
|
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||||
|
<ElButton v-ripple>搜索</ElButton>
|
||||||
|
<ElButton @click="showDialog('add')" v-ripple>新增角色</ElButton>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
|
||||||
|
<ArtTable
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
|
:data="roleList"
|
||||||
|
:currentPage="pagination.currentPage"
|
||||||
|
:pageSize="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
@size-change="handleSizeChange"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn label="角色名称" prop="name" />
|
||||||
|
<ElTableColumn label="描述" prop="desc" />
|
||||||
|
<ElTableColumn label="启用" prop="enable">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElTag :type="scope.row.status == 1 ? 'primary' : 'info'">
|
||||||
|
{{ scope.row.status == 1 ? '启用' : '禁用' }}
|
||||||
|
</ElTag>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
<ElTableColumn label="创建时间" prop="created_at"></ElTableColumn>
|
||||||
|
<ElTableColumn fixed="right" label="操作" width="200px">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElRow>
|
||||||
|
<el-button link @click="showPermissionDialog(scope.row)"> 菜单权限 </el-button>
|
||||||
|
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
|
||||||
|
<el-button link @click="deleteRole(scope.row)"> 删除 </el-button>
|
||||||
|
</ElRow>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
|
||||||
|
<ElDialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="dialogType === 'add' ? '新增角色' : '编辑角色'"
|
||||||
|
width="30%"
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<ElForm ref="formRef" :model="form" :rules="rules" label-width="120px">
|
||||||
|
<ElFormItem label="角色名称" prop="name">
|
||||||
|
<ElInput v-model="form.name" />
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="描述" prop="desc">
|
||||||
|
<ElInput v-model="form.desc" type="textarea" :rows="3" />
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="排序" prop="sort">
|
||||||
|
<ElInput type="number" v-model="form.sort" />
|
||||||
|
</ElFormItem>
|
||||||
|
<ElFormItem label="启用">
|
||||||
|
<ElSwitch v-model="form.status" :active-value="1" :inactive-value="0" />
|
||||||
|
</ElFormItem>
|
||||||
|
</ElForm>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||||
|
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
|
||||||
|
<ElDialog
|
||||||
|
v-model="permissionDialog"
|
||||||
|
title="菜单权限"
|
||||||
|
width="520px"
|
||||||
|
align-center
|
||||||
|
class="el-dialog-border"
|
||||||
|
>
|
||||||
|
<ElScrollbar height="70vh">
|
||||||
|
<ElTree
|
||||||
|
ref="treeRef"
|
||||||
|
:data="processedMenuList"
|
||||||
|
show-checkbox
|
||||||
|
node-key="id"
|
||||||
|
:default-expand-all="isExpandAll"
|
||||||
|
:props="defaultProps"
|
||||||
|
@check="handleTreeCheck"
|
||||||
|
>
|
||||||
|
<template #default="{ data }">
|
||||||
|
<div style="display: flex; align-items: center">
|
||||||
|
<span v-if="data.isAuth">
|
||||||
|
{{ data.label }}
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ defaultProps.label(data) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElTree>
|
||||||
|
</ElScrollbar>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<ElButton @click="toggleExpandAll">{{ isExpandAll ? '全部收起' : '全部展开' }}</ElButton>
|
||||||
|
<ElButton @click="toggleSelectAll" style="margin-left: 8px">{{
|
||||||
|
isSelectAll ? '取消全选' : '全部选择'
|
||||||
|
}}</ElButton>
|
||||||
|
<ElButton type="primary" @click="savePermission">保存</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { formatMenuTitle } from '@/router/utils/utils'
|
||||||
|
import { systemService } from '@/api/systemApi'
|
||||||
|
// import { ButtonMoreItem } from '@/components/core/forms/ArtButtonMore.vue'
|
||||||
|
// import { Role, ROLE_LIST_DATA } from '@/mock/temp/formData'
|
||||||
|
const loading = ref(false)
|
||||||
|
defineOptions({ name: 'Role' })
|
||||||
|
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const permissionDialog = ref(false)
|
||||||
|
// 权限树数据(来自接口 getPermissionMenuList)
|
||||||
|
const permissionMenuList = ref<any[]>([])
|
||||||
|
const treeRef = ref()
|
||||||
|
const isExpandAll = ref(true)
|
||||||
|
const isSelectAll = ref(false)
|
||||||
|
const pagination = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
name: [{ required: true, message: '请输入角色名称', trigger: 'blur' }],
|
||||||
|
des: [{ required: true, message: '请输入角色描述', trigger: 'blur' }]
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = reactive<any>({
|
||||||
|
id: '',
|
||||||
|
name: '',
|
||||||
|
desc: '',
|
||||||
|
sort: 0,
|
||||||
|
status: 1
|
||||||
|
})
|
||||||
|
|
||||||
|
const roleList = ref<any[]>([])
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getTableData()
|
||||||
|
})
|
||||||
|
|
||||||
|
// const getTableData = () => {
|
||||||
|
// roleList.value = ROLE_LIST_DATA
|
||||||
|
// }
|
||||||
|
// 获取列表数据
|
||||||
|
const getTableData = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const { currentPage, pageSize } = pagination
|
||||||
|
|
||||||
|
const { records, current, size, total } = await systemService.getRoleList({
|
||||||
|
current: currentPage,
|
||||||
|
size: pageSize
|
||||||
|
})
|
||||||
|
roleList.value = records.map((item: any) => ({
|
||||||
|
...item
|
||||||
|
}))
|
||||||
|
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取用户列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 处理表格分页变化
|
||||||
|
const handleSizeChange = (newPageSize: number) => {
|
||||||
|
pagination.pageSize = newPageSize
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCurrentChange = (newCurrentPage: number) => {
|
||||||
|
pagination.currentPage = newCurrentPage
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
const dialogType = ref('add')
|
||||||
|
|
||||||
|
const showDialog = (type: string, row?: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogType.value = type
|
||||||
|
|
||||||
|
if (type === 'edit' && row) {
|
||||||
|
form.id = row.id
|
||||||
|
form.name = row.name
|
||||||
|
form.desc = row.desc
|
||||||
|
form.sort = row.sort
|
||||||
|
form.status = row.status
|
||||||
|
} else {
|
||||||
|
form.name = ''
|
||||||
|
form.desc = ''
|
||||||
|
form.sort = 0
|
||||||
|
form.status = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const roleId = ref('')
|
||||||
|
const showPermissionDialog = async (row: any) => {
|
||||||
|
permissionDialog.value = true
|
||||||
|
roleId.value = row.id
|
||||||
|
try {
|
||||||
|
const res = await systemService.getPermissionMenuList({ role_id: row.id })
|
||||||
|
// 兼容不同返回结构(data/records/直接数组)
|
||||||
|
const list = (res as any)?.data ?? (res as any)?.records ?? (res as any)
|
||||||
|
permissionMenuList.value = Array.isArray(list) ? list : []
|
||||||
|
// 根据接口返回的 selected 字段设置默认选中
|
||||||
|
nextTick(() => {
|
||||||
|
const keys = buildDefaultCheckedKeys(permissionMenuList.value)
|
||||||
|
treeRef.value?.setCheckedKeys(keys)
|
||||||
|
handleTreeCheck()
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
permissionMenuList.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 构建默认选中的 key 列表(与 node-key="id" 一致)
|
||||||
|
const buildDefaultCheckedKeys = (source: any[]): Array<string | number> => {
|
||||||
|
const keys: Array<string | number> = []
|
||||||
|
const walk = (node: any) => {
|
||||||
|
if (node?.meta?.selected) {
|
||||||
|
keys.push(node.id)
|
||||||
|
}
|
||||||
|
if (Array.isArray(node?.meta?.authList)) {
|
||||||
|
node.meta.authList.forEach((auth: any) => {
|
||||||
|
if (auth?.selected) {
|
||||||
|
keys.push(`${node.id}__auth__${auth.authMark}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (Array.isArray(node?.children)) node.children.forEach(walk)
|
||||||
|
}
|
||||||
|
source.forEach(walk)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
// 处理菜单数据,将 authList 转换为子节点
|
||||||
|
const processedMenuList = computed(() => {
|
||||||
|
const processNode = (node: any) => {
|
||||||
|
// 规范化 id,确保树节点唯一键与 node-key 对应
|
||||||
|
const processed: any = { ...node, id: node.id }
|
||||||
|
|
||||||
|
// 如果有 authList,将其转换为子节点
|
||||||
|
if (node.meta && node.meta.authList && node.meta.authList.length) {
|
||||||
|
const authNodes = node.meta.authList.map((auth: any) => ({
|
||||||
|
// 为权限子节点提供稳定唯一 id(数字+字符串),与 node-key="id" 匹配
|
||||||
|
id: `${node.id}__auth__${auth.authMark}`,
|
||||||
|
name: `${node.name}_${auth.authMark}`,
|
||||||
|
label: auth.title,
|
||||||
|
auth_mark: auth.authMark,
|
||||||
|
auth_id: auth.id,
|
||||||
|
isAuth: true,
|
||||||
|
checked: auth.selected || false
|
||||||
|
}))
|
||||||
|
|
||||||
|
processed.children = processed.children ? [...processed.children, ...authNodes] : authNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归处理子节点
|
||||||
|
if (processed.children) {
|
||||||
|
processed.children = processed.children.map(processNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return processed
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = permissionMenuList.value || []
|
||||||
|
return source.map(processNode)
|
||||||
|
})
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
children: 'children',
|
||||||
|
label: (data: any) => formatMenuTitle(data.meta?.title) || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const deleteRole = async (row: any) => {
|
||||||
|
ElMessageBox.confirm('确定删除该角色吗?', '删除确认', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'error'
|
||||||
|
}).then(async () => {
|
||||||
|
const res = await systemService.roleDelete({ id: row.id })
|
||||||
|
ElMessage.success(res?.message || '删除成功!')
|
||||||
|
getTableData()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
|
||||||
|
if (dialogType.value === 'add') {
|
||||||
|
// 新增角色逻辑
|
||||||
|
const res = await systemService.roleAdd(form)
|
||||||
|
ElMessage.success(res?.message || '提交成功!')
|
||||||
|
getTableData()
|
||||||
|
} else {
|
||||||
|
// 编辑角色逻辑
|
||||||
|
const res = await systemService.roleEdit(form)
|
||||||
|
ElMessage.success(res?.message || '提交成功!')
|
||||||
|
getTableData()
|
||||||
|
}
|
||||||
|
dialogVisible.value = false
|
||||||
|
formEl.resetFields()
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSelectedIds = () => {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (!tree) return { menuIds: [], authIds: [] }
|
||||||
|
|
||||||
|
const checkedNodes = tree.getCheckedNodes?.(false) || []
|
||||||
|
const halfCheckedNodes = tree.getHalfCheckedNodes?.() || []
|
||||||
|
const allNodes = [...checkedNodes, ...halfCheckedNodes]
|
||||||
|
|
||||||
|
const menuIds = Array.from(
|
||||||
|
new Set(
|
||||||
|
allNodes
|
||||||
|
.filter((n: any) => !n.isAuth && n.id !== undefined && n.id !== null)
|
||||||
|
.map((n: any) => n.id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
const authIds = Array.from(
|
||||||
|
new Set(
|
||||||
|
checkedNodes.filter((n: any) => n.isAuth && n.auth_id != null).map((n: any) => n.auth_id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const ids = Array.from(new Set([...(menuIds as any[]), ...(authIds as any[])]))
|
||||||
|
return { menuIds, authIds, ids }
|
||||||
|
}
|
||||||
|
|
||||||
|
const savePermission = async () => {
|
||||||
|
const { ids } = getSelectedIds()
|
||||||
|
// console.log('选中的菜单ID:', menuIds)
|
||||||
|
// console.log('选中的权限ID:', authIds)
|
||||||
|
// console.log('合并后的全部ID:', ids)
|
||||||
|
|
||||||
|
const res = await systemService.roleAuth({
|
||||||
|
role_id: roleId.value,
|
||||||
|
resources: ids
|
||||||
|
})
|
||||||
|
ElMessage.success(res?.message || '权限保存成功')
|
||||||
|
permissionDialog.value = false
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleExpandAll = () => {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (!tree) return
|
||||||
|
|
||||||
|
// 使用store.nodesMap直接控制所有节点的展开状态
|
||||||
|
const nodes = tree.store.nodesMap
|
||||||
|
for (const node in nodes) {
|
||||||
|
nodes[node].expanded = !isExpandAll.value
|
||||||
|
}
|
||||||
|
|
||||||
|
isExpandAll.value = !isExpandAll.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSelectAll = () => {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (!tree) return
|
||||||
|
|
||||||
|
if (!isSelectAll.value) {
|
||||||
|
// 全选:获取所有节点的key并设置为选中
|
||||||
|
const allKeys = getAllNodeKeys(processedMenuList.value)
|
||||||
|
tree.setCheckedKeys(allKeys)
|
||||||
|
} else {
|
||||||
|
// 取消全选:清空所有选中
|
||||||
|
tree.setCheckedKeys([])
|
||||||
|
}
|
||||||
|
|
||||||
|
isSelectAll.value = !isSelectAll.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const getAllNodeKeys = (nodes: any[]): Array<string | number> => {
|
||||||
|
const keys: Array<string | number> = []
|
||||||
|
const traverse = (nodeList: any[]) => {
|
||||||
|
nodeList.forEach((node) => {
|
||||||
|
if (node.id !== undefined && node.id !== null) {
|
||||||
|
keys.push(node.id)
|
||||||
|
}
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
traverse(node.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
traverse(nodes)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTreeCheck = () => {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (!tree) return
|
||||||
|
|
||||||
|
// 使用树组件的getCheckedKeys方法获取选中的节点
|
||||||
|
const checkedKeys = tree.getCheckedKeys()
|
||||||
|
const allKeys = getAllNodeKeys(processedMenuList.value)
|
||||||
|
|
||||||
|
// 判断是否全选:选中的节点数量等于总节点数量
|
||||||
|
isSelectAll.value = checkedKeys.length === allKeys.length && allKeys.length > 0
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.page-content {
|
||||||
|
.svg-icon {
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: -8px;
|
||||||
|
fill: currentcolor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,194 @@
|
|||||||
|
<template>
|
||||||
|
<div class="page-content">
|
||||||
|
<div v-if="!isMobile">
|
||||||
|
<ElRow>
|
||||||
|
<!-- <ElCol :xs="24" :sm="12" :lg="6">
|
||||||
|
<ElInput placeholder="名称"></ElInput>
|
||||||
|
</ElCol> -->
|
||||||
|
<div style="width: 12px"></div>
|
||||||
|
<ElCol :xs="24" :sm="12" :lg="6" class="el-col2">
|
||||||
|
<!-- <ElButton v-ripple>搜索</ElButton> -->
|
||||||
|
<ElButton @click="showDialog('add')" v-ripple>新增</ElButton>
|
||||||
|
</ElCol>
|
||||||
|
</ElRow>
|
||||||
|
|
||||||
|
<ArtTable
|
||||||
|
ref="tableRef"
|
||||||
|
row-key="id"
|
||||||
|
:loading="loading"
|
||||||
|
:data="tableData"
|
||||||
|
:currentPage="pagination.currentPage"
|
||||||
|
:pageSize="pagination.pageSize"
|
||||||
|
:total="pagination.total"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<ElTableColumn label="ID" prop="id" />
|
||||||
|
<ElTableColumn label="分类名称" prop="name" />
|
||||||
|
<ElTableColumn label="状态" prop="status">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElTag :type="scope.row.status ? 'primary' : 'info'">
|
||||||
|
{{ scope.row.status ? '启用' : '禁用' }}
|
||||||
|
</ElTag>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
<ElTableColumn label="创建时间" prop="created_at" />
|
||||||
|
<ElTableColumn fixed="right" label="操作" width="200px">
|
||||||
|
<template #default="scope">
|
||||||
|
<ElRow>
|
||||||
|
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
|
||||||
|
<el-button link @click="deleteRole(scope.row)"> 删除 </el-button>
|
||||||
|
</ElRow>
|
||||||
|
</template>
|
||||||
|
</ElTableColumn>
|
||||||
|
</template>
|
||||||
|
</ArtTable>
|
||||||
|
|
||||||
|
<ElDialog
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="dialogType === 'add' ? '新增' : '编辑'"
|
||||||
|
width="40%"
|
||||||
|
align-center
|
||||||
|
>
|
||||||
|
<ElForm ref="formRef" :model="form" :rules="rules" label-width="160px">
|
||||||
|
<ElFormItem label="分类名称" prop="name">
|
||||||
|
<ElInput v-model="form.name" />
|
||||||
|
</ElFormItem>
|
||||||
|
</ElForm>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<ElButton @click="dialogVisible = false">取消</ElButton>
|
||||||
|
<ElButton type="primary" @click="handleSubmit(formRef)">提交</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
</div>
|
||||||
|
<div v-else class="mobile-hide-tip">
|
||||||
|
<p>该页面暂不支持移动端访问</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
|
import type { FormInstance, FormRules } from 'element-plus'
|
||||||
|
import { Ordertype} from '@/mock/temp/formData'
|
||||||
|
import { systemService } from '@/api/systemApi'
|
||||||
|
defineOptions({ name: 'Type ' })
|
||||||
|
const loading = ref(false)
|
||||||
|
const dialogVisible = ref(false)
|
||||||
|
const typeList = ref<any[]>([])
|
||||||
|
const formRef = ref<FormInstance>()
|
||||||
|
const { width } = useWindowSize()
|
||||||
|
const isMobile = computed(() => width.value < 500)
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
name: [
|
||||||
|
{ required: true, message: '请输入分类名称', trigger: 'blur' }
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
const form = reactive<Ordertype>({
|
||||||
|
name: '',
|
||||||
|
id:''
|
||||||
|
})
|
||||||
|
const pagination = reactive({
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0
|
||||||
|
})
|
||||||
|
// 表格数据
|
||||||
|
const tableData = ref<any[]>([])
|
||||||
|
|
||||||
|
// 表格实例引用
|
||||||
|
const tableRef = ref()
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
getWorkList()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取列表数据
|
||||||
|
const getWorkList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
const { currentPage, pageSize } = pagination
|
||||||
|
|
||||||
|
const { records, current, size, total } = await systemService.getSystemList({
|
||||||
|
current: currentPage,
|
||||||
|
size: pageSize
|
||||||
|
})
|
||||||
|
tableData.value = records.map((item: any, index: number) => ({
|
||||||
|
...item
|
||||||
|
}))
|
||||||
|
Object.assign(pagination, { currentPage: current, pageSize: size, total })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取列表失败:', error)
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const dialogType = ref('add')
|
||||||
|
|
||||||
|
const showDialog = (type: string, row?: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogType.value = type
|
||||||
|
|
||||||
|
if (type === 'edit' && row) {
|
||||||
|
form.name = row.name
|
||||||
|
form.id = row.id
|
||||||
|
} else {
|
||||||
|
form.name = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const deleteRole = (row?: any) => {
|
||||||
|
ElMessageBox.confirm('确定删除该分类吗?', '删除确认', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'error'
|
||||||
|
}).then(async () => {
|
||||||
|
const { message } = await systemService.systemDelete({
|
||||||
|
id: row.id,
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
getWorkList()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSubmit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return
|
||||||
|
if (dialogType.value === 'add') {
|
||||||
|
const { message } = await systemService.systemAdd({
|
||||||
|
name: form.name
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
dialogVisible.value = false
|
||||||
|
getWorkList()
|
||||||
|
} else {
|
||||||
|
const { message } = await systemService.systemEdit({
|
||||||
|
name: form.name,
|
||||||
|
id:form.id
|
||||||
|
})
|
||||||
|
ElMessage.success(message)
|
||||||
|
dialogVisible.value = false
|
||||||
|
getWorkList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-table__empty-block) {
|
||||||
|
height: 100% !important;
|
||||||
|
min-height: 200px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.page-content {
|
||||||
|
.svg-icon {
|
||||||
|
width: 1.8em;
|
||||||
|
height: 1.8em;
|
||||||
|
overflow: hidden;
|
||||||
|
vertical-align: -8px;
|
||||||
|
fill: currentcolor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+327
-12
@@ -3,16 +3,16 @@
|
|||||||
<!-- 顶部操作栏 -->
|
<!-- 顶部操作栏 -->
|
||||||
<div class="customer-toolbar boxshadow">
|
<div class="customer-toolbar boxshadow">
|
||||||
<div class="customer-search-group">
|
<div class="customer-search-group">
|
||||||
<el-input v-model="keyword" placeholder="请输入关键字" />
|
<el-form-item label="关键字:" label-width="70px">
|
||||||
<el-select
|
<el-input style="min-width: 120px" v-model="keyword" placeholder="请输入关键字" />
|
||||||
v-model="selectValue"
|
</el-form-item>
|
||||||
style="min-width: 120px"
|
<el-form-item label="状态:" label-width="50px">
|
||||||
filterable
|
<el-select v-model="selectValue" style="min-width: 120px">
|
||||||
placeholder="请选择用户"
|
<el-option label="全部" value="" />
|
||||||
>
|
<el-option label="正常" value="1" />
|
||||||
<el-option v-for="v in userOptions" :key="v.id" :label="v.name" :value="v.id">
|
<el-option label="离职" value="2" />
|
||||||
</el-option>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="boxshadow">
|
<div class="boxshadow">
|
||||||
@@ -57,6 +57,24 @@
|
|||||||
<el-table-column prop="customer_count" label="客户数量" align="center" />
|
<el-table-column prop="customer_count" label="客户数量" align="center" />
|
||||||
<el-table-column fixed="right" label="操作" width="200px" align="center">
|
<el-table-column fixed="right" label="操作" width="200px" align="center">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
<el-link
|
||||||
|
type="success"
|
||||||
|
underline="never"
|
||||||
|
style="margin-right: 8px"
|
||||||
|
@click="showPermissionDialog(scope.row)"
|
||||||
|
v-if="hasAuth('user@direct_perm')"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i>直接授权
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
type="warning"
|
||||||
|
underline="never"
|
||||||
|
style="margin-right: 8px"
|
||||||
|
@click="showroleDialog(scope.row)"
|
||||||
|
v-if="hasAuth('user@role_system')"
|
||||||
|
>
|
||||||
|
<i class="iconfont-sys"></i>角色&系统
|
||||||
|
</el-link>
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
underline="never"
|
underline="never"
|
||||||
@@ -185,7 +203,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 图片预览组件 -->
|
<!-- 图片预览组件 -->
|
||||||
<ElImageViewer
|
<ElImageViewer
|
||||||
v-if="showImageViewer"
|
v-if="showImageViewer"
|
||||||
@@ -193,6 +210,97 @@
|
|||||||
:hide-on-click-modal="true"
|
:hide-on-click-modal="true"
|
||||||
@close="showImageViewer = false"
|
@close="showImageViewer = false"
|
||||||
/>
|
/>
|
||||||
|
<ElDialog
|
||||||
|
v-model="permissionDialog"
|
||||||
|
title="菜单权限"
|
||||||
|
width="520px"
|
||||||
|
align-center
|
||||||
|
class="el-dialog-border"
|
||||||
|
>
|
||||||
|
<ElScrollbar height="70vh">
|
||||||
|
<ElTree
|
||||||
|
ref="treeRef"
|
||||||
|
:data="processedMenuList"
|
||||||
|
show-checkbox
|
||||||
|
node-key="id"
|
||||||
|
:default-expand-all="isExpandAll"
|
||||||
|
:props="defaultProps"
|
||||||
|
@check="handleTreeCheck"
|
||||||
|
>
|
||||||
|
<template #default="{ data }">
|
||||||
|
<div style="display: flex; align-items: center">
|
||||||
|
<span v-if="data.isAuth">
|
||||||
|
{{ data.label }}
|
||||||
|
</span>
|
||||||
|
<span v-else>{{ defaultProps.label(data) }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElTree>
|
||||||
|
</ElScrollbar>
|
||||||
|
<template #footer>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<ElButton @click="toggleExpandAll">{{ isExpandAll ? '全部收起' : '全部展开' }}</ElButton>
|
||||||
|
<ElButton @click="toggleSelectAll" style="margin-left: 8px">{{
|
||||||
|
isSelectAll ? '取消全选' : '全部选择'
|
||||||
|
}}</ElButton>
|
||||||
|
<ElButton type="primary" @click="savePermission">保存</ElButton>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ElDialog>
|
||||||
|
<el-dialog
|
||||||
|
title="角色&系统设置"
|
||||||
|
v-model="roleDialogVisible"
|
||||||
|
width="700px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<el-form :model="roleForm" ref="addFormRef" label-width="80px" class="add-form">
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="角色" prop="status">
|
||||||
|
<ElSelect
|
||||||
|
v-model="roleForm.role_ids"
|
||||||
|
multiple
|
||||||
|
class="account-select"
|
||||||
|
placeholder="请选择角色"
|
||||||
|
>
|
||||||
|
<ElOption
|
||||||
|
v-for="account in roleOptions"
|
||||||
|
:key="account.id"
|
||||||
|
:label="account.name"
|
||||||
|
:value="account.id"
|
||||||
|
>
|
||||||
|
<span>{{ account.name }}</span>
|
||||||
|
</ElOption>
|
||||||
|
</ElSelect>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="24">
|
||||||
|
<el-form-item label="系统" prop="status">
|
||||||
|
<ElSelect
|
||||||
|
v-model="roleForm.system_ids"
|
||||||
|
multiple
|
||||||
|
class="account-select"
|
||||||
|
placeholder="请选择系统"
|
||||||
|
>
|
||||||
|
<ElOption
|
||||||
|
v-for="account in systemsList"
|
||||||
|
:key="account.id"
|
||||||
|
:label="account.name"
|
||||||
|
:value="account.id"
|
||||||
|
>
|
||||||
|
<span>{{ account.name }}</span>
|
||||||
|
</ElOption>
|
||||||
|
</ElSelect>
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<div class="form-submit-row">
|
||||||
|
<el-button type="primary" size="large" style="width: 70%" @click="handleRoleSubmit"
|
||||||
|
>提交</el-button
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</el-form>
|
||||||
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -200,6 +308,9 @@
|
|||||||
import { ElImageViewer } from 'element-plus'
|
import { ElImageViewer } from 'element-plus'
|
||||||
import { manageService } from '@/api/adminApi'
|
import { manageService } from '@/api/adminApi'
|
||||||
import { useAuth } from '@/composables/useAuth'
|
import { useAuth } from '@/composables/useAuth'
|
||||||
|
import { systemService } from '@/api/systemApi'
|
||||||
|
import { formatMenuTitle } from '@/router/utils/utils'
|
||||||
|
import { UserService } from '@/api/usersApi'
|
||||||
const { hasAuth } = useAuth()
|
const { hasAuth } = useAuth()
|
||||||
const selectValue = ref<string[]>([])
|
const selectValue = ref<string[]>([])
|
||||||
const keyword = ref<string>('')
|
const keyword = ref<string>('')
|
||||||
@@ -208,6 +319,13 @@
|
|||||||
const detailDialogVisible = ref(false)
|
const detailDialogVisible = ref(false)
|
||||||
const plzyDialogVisible = ref(false)
|
const plzyDialogVisible = ref(false)
|
||||||
const AddDialogVisible = ref(false)
|
const AddDialogVisible = ref(false)
|
||||||
|
const permissionDialog = ref(false)
|
||||||
|
const roleDialogVisible = ref(false)
|
||||||
|
// 权限树数据(来自接口 getPermissionMenuList)
|
||||||
|
const permissionMenuList = ref<any[]>([])
|
||||||
|
const treeRef = ref()
|
||||||
|
const isExpandAll = ref(true)
|
||||||
|
const isSelectAll = ref(false)
|
||||||
const pagination = reactive({
|
const pagination = reactive({
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
@@ -232,7 +350,24 @@
|
|||||||
phone: '',
|
phone: '',
|
||||||
status: ''
|
status: ''
|
||||||
})
|
})
|
||||||
|
const roleForm = reactive({
|
||||||
|
user_id: '',
|
||||||
|
role_ids: '',
|
||||||
|
system_ids: ''
|
||||||
|
})
|
||||||
const userOptions = ref<any>()
|
const userOptions = ref<any>()
|
||||||
|
//系统
|
||||||
|
const systemsList = ref<any>()
|
||||||
|
const getsystemsList = async () => {
|
||||||
|
const response = await UserService.getsystemsList()
|
||||||
|
systemsList.value = response || []
|
||||||
|
}
|
||||||
|
//角色下拉框
|
||||||
|
const roleOptions = ref<any>()
|
||||||
|
const getroleOptions = async () => {
|
||||||
|
const response = await systemService.getRoleSelectList()
|
||||||
|
roleOptions.value = response || []
|
||||||
|
}
|
||||||
const getuserList = async () => {
|
const getuserList = async () => {
|
||||||
// 这里调用获取用户列表的接口
|
// 这里调用获取用户列表的接口
|
||||||
const res = await manageService.presetusers()
|
const res = await manageService.presetusers()
|
||||||
@@ -260,7 +395,7 @@
|
|||||||
size: pageSize
|
size: pageSize
|
||||||
}
|
}
|
||||||
if (selectValue.value) {
|
if (selectValue.value) {
|
||||||
params.id = selectValue.value
|
params.status = selectValue.value
|
||||||
}
|
}
|
||||||
if (keyword.value) {
|
if (keyword.value) {
|
||||||
params.keyword = keyword.value
|
params.keyword = keyword.value
|
||||||
@@ -327,6 +462,187 @@
|
|||||||
zyForm.customer_id = row.id
|
zyForm.customer_id = row.id
|
||||||
detailDialogVisible.value = true
|
detailDialogVisible.value = true
|
||||||
}
|
}
|
||||||
|
// 显示角色&系统对话框
|
||||||
|
const showroleDialog = (row: any) => {
|
||||||
|
getsystemsList()
|
||||||
|
getroleOptions()
|
||||||
|
roleDialogVisible.value = true
|
||||||
|
roleForm.user_id = row.id
|
||||||
|
roleForm.role_ids = row.role_ids || []
|
||||||
|
roleForm.system_ids = row.system_ids || []
|
||||||
|
}
|
||||||
|
// 提交角色&系统
|
||||||
|
const handleRoleSubmit = async () => {
|
||||||
|
const res = await manageService.userSetRole(roleForm)
|
||||||
|
ElMessage.success(res?.message || '角色&系统设置成功!')
|
||||||
|
roleDialogVisible.value = false
|
||||||
|
gettableList()
|
||||||
|
}
|
||||||
|
// 显示权限对话框
|
||||||
|
const userId = ref('')
|
||||||
|
const showPermissionDialog = async (row: any) => {
|
||||||
|
permissionDialog.value = true
|
||||||
|
userId.value = row.id
|
||||||
|
try {
|
||||||
|
const res = await systemService.getPermissionMenuList({ user_id: row.id })
|
||||||
|
// 兼容不同返回结构(data/records/直接数组)
|
||||||
|
const list = (res as any)?.data ?? (res as any)?.records ?? (res as any)
|
||||||
|
permissionMenuList.value = Array.isArray(list) ? list : []
|
||||||
|
// 根据接口返回的 selected 字段设置默认选中
|
||||||
|
nextTick(() => {
|
||||||
|
const keys = buildDefaultCheckedKeys(permissionMenuList.value)
|
||||||
|
treeRef.value?.setCheckedKeys(keys)
|
||||||
|
handleTreeCheck()
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
permissionMenuList.value = []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 构建默认选中的 key 列表(与 node-key="id" 一致)
|
||||||
|
const buildDefaultCheckedKeys = (source: any[]): Array<string | number> => {
|
||||||
|
const keys: Array<string | number> = []
|
||||||
|
const walk = (node: any) => {
|
||||||
|
if (node?.meta?.selected) {
|
||||||
|
keys.push(node.id)
|
||||||
|
}
|
||||||
|
if (Array.isArray(node?.meta?.authList)) {
|
||||||
|
node.meta.authList.forEach((auth: any) => {
|
||||||
|
if (auth?.selected) {
|
||||||
|
keys.push(`${node.id}__auth__${auth.authMark}`)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (Array.isArray(node?.children)) node.children.forEach(walk)
|
||||||
|
}
|
||||||
|
source.forEach(walk)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
// 处理菜单数据,将 authList 转换为子节点
|
||||||
|
const processedMenuList = computed(() => {
|
||||||
|
const processNode = (node: any) => {
|
||||||
|
// 规范化 id,确保树节点唯一键与 node-key 对应
|
||||||
|
const processed: any = { ...node, id: node.id }
|
||||||
|
|
||||||
|
// 如果有 authList,将其转换为子节点
|
||||||
|
if (node.meta && node.meta.authList && node.meta.authList.length) {
|
||||||
|
const authNodes = node.meta.authList.map((auth: any) => ({
|
||||||
|
// 为权限子节点提供稳定唯一 id(数字+字符串),与 node-key="id" 匹配
|
||||||
|
id: `${node.id}__auth__${auth.authMark}`,
|
||||||
|
name: `${node.name}_${auth.authMark}`,
|
||||||
|
label: auth.title,
|
||||||
|
auth_mark: auth.authMark,
|
||||||
|
auth_id: auth.id,
|
||||||
|
isAuth: true,
|
||||||
|
checked: auth.selected || false
|
||||||
|
}))
|
||||||
|
|
||||||
|
processed.children = processed.children ? [...processed.children, ...authNodes] : authNodes
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归处理子节点
|
||||||
|
if (processed.children) {
|
||||||
|
processed.children = processed.children.map(processNode)
|
||||||
|
}
|
||||||
|
|
||||||
|
return processed
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = permissionMenuList.value || []
|
||||||
|
return source.map(processNode)
|
||||||
|
})
|
||||||
|
|
||||||
|
const defaultProps = {
|
||||||
|
children: 'children',
|
||||||
|
label: (data: any) => formatMenuTitle(data.meta?.title) || ''
|
||||||
|
}
|
||||||
|
const toggleExpandAll = () => {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (!tree) return
|
||||||
|
|
||||||
|
// 使用store.nodesMap直接控制所有节点的展开状态
|
||||||
|
const nodes = tree.store.nodesMap
|
||||||
|
for (const node in nodes) {
|
||||||
|
nodes[node].expanded = !isExpandAll.value
|
||||||
|
}
|
||||||
|
|
||||||
|
isExpandAll.value = !isExpandAll.value
|
||||||
|
}
|
||||||
|
|
||||||
|
const toggleSelectAll = () => {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (!tree) return
|
||||||
|
|
||||||
|
if (!isSelectAll.value) {
|
||||||
|
// 全选:获取所有节点的key并设置为选中
|
||||||
|
const allKeys = getAllNodeKeys(processedMenuList.value)
|
||||||
|
tree.setCheckedKeys(allKeys)
|
||||||
|
} else {
|
||||||
|
// 取消全选:清空所有选中
|
||||||
|
tree.setCheckedKeys([])
|
||||||
|
}
|
||||||
|
|
||||||
|
isSelectAll.value = !isSelectAll.value
|
||||||
|
}
|
||||||
|
const getAllNodeKeys = (nodes: any[]): Array<string | number> => {
|
||||||
|
const keys: Array<string | number> = []
|
||||||
|
const traverse = (nodeList: any[]) => {
|
||||||
|
nodeList.forEach((node) => {
|
||||||
|
if (node.id !== undefined && node.id !== null) {
|
||||||
|
keys.push(node.id)
|
||||||
|
}
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
traverse(node.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
traverse(nodes)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
const handleTreeCheck = () => {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (!tree) return
|
||||||
|
|
||||||
|
// 使用树组件的getCheckedKeys方法获取选中的节点
|
||||||
|
const checkedKeys = tree.getCheckedKeys()
|
||||||
|
const allKeys = getAllNodeKeys(processedMenuList.value)
|
||||||
|
|
||||||
|
// 判断是否全选:选中的节点数量等于总节点数量
|
||||||
|
isSelectAll.value = checkedKeys.length === allKeys.length && allKeys.length > 0
|
||||||
|
}
|
||||||
|
const getSelectedIds = () => {
|
||||||
|
const tree = treeRef.value
|
||||||
|
if (!tree) return { menuIds: [], authIds: [] }
|
||||||
|
|
||||||
|
const checkedNodes = tree.getCheckedNodes?.(false) || []
|
||||||
|
const halfCheckedNodes = tree.getHalfCheckedNodes?.() || []
|
||||||
|
const allNodes = [...checkedNodes, ...halfCheckedNodes]
|
||||||
|
|
||||||
|
const menuIds = Array.from(
|
||||||
|
new Set(
|
||||||
|
allNodes
|
||||||
|
.filter((n: any) => !n.isAuth && n.id !== undefined && n.id !== null)
|
||||||
|
.map((n: any) => n.id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
const authIds = Array.from(
|
||||||
|
new Set(
|
||||||
|
checkedNodes.filter((n: any) => n.isAuth && n.auth_id != null).map((n: any) => n.auth_id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const ids = Array.from(new Set([...(menuIds as any[]), ...(authIds as any[])]))
|
||||||
|
return { menuIds, authIds, ids }
|
||||||
|
}
|
||||||
|
|
||||||
|
const savePermission = async () => {
|
||||||
|
const { ids } = getSelectedIds()
|
||||||
|
const res = await manageService.userMenuAuth({
|
||||||
|
user_id: userId.value,
|
||||||
|
resources: ids
|
||||||
|
})
|
||||||
|
ElMessage.success(res?.message || '权限保存成功')
|
||||||
|
permissionDialog.value = false
|
||||||
|
}
|
||||||
// 选中的行数据
|
// 选中的行数据
|
||||||
const selectedRows = ref<any[]>([])
|
const selectedRows = ref<any[]>([])
|
||||||
// 处理表格行选择变化
|
// 处理表格行选择变化
|
||||||
@@ -390,7 +706,6 @@
|
|||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
transition: opacity 0.2s;
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,11 +36,11 @@
|
|||||||
<div class="form">
|
<div class="form">
|
||||||
<!-- 登录方式切换 tab -->
|
<!-- 登录方式切换 tab -->
|
||||||
<div class="login-type-tabs">
|
<div class="login-type-tabs">
|
||||||
<!-- <span
|
<span
|
||||||
:class="{ active: activeLoginType === 'password' }"
|
:class="{ active: activeLoginType === 'password' }"
|
||||||
@click="activeLoginType = 'password'"
|
@click="activeLoginType = 'password'"
|
||||||
>账号密码登录</span
|
>账号密码登录</span
|
||||||
> -->
|
>
|
||||||
<span
|
<span
|
||||||
:class="{ active: activeLoginType === 'qrcode' }"
|
:class="{ active: activeLoginType === 'qrcode' }"
|
||||||
@click="activeLoginType = 'qrcode'"
|
@click="activeLoginType = 'qrcode'"
|
||||||
|
|||||||
@@ -151,7 +151,7 @@
|
|||||||
type="danger"
|
type="danger"
|
||||||
underline="never"
|
underline="never"
|
||||||
@click="delectfn(scope.row)"
|
@click="delectfn(scope.row)"
|
||||||
v-if="hasAuth('crm_customer@follow_delete')"
|
v-if="hasAuth('crm_customer@delete')"
|
||||||
>
|
>
|
||||||
<i class="iconfont-sys"></i> 删除
|
<i class="iconfont-sys"></i> 删除
|
||||||
</el-link>
|
</el-link>
|
||||||
|
|||||||
Reference in New Issue
Block a user