Files
art-design/src/views/system/role/index.vue
T
2025-07-21 11:16:16 +08:00

368 lines
11 KiB
Vue

<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="id" />
<ElTableColumn label="描述" prop="desc" />
<ElTableColumn label="启用" prop="enable">
<template #default="scope">
<ElTag :type="scope.row.status ? 'primary' : 'info'">
{{ scope.row.status ? '启用' : '禁用' }}
</ElTag>
</template>
</ElTableColumn>
<ElTableColumn label="创建时间" prop="created_at">
</ElTableColumn>
<ElTableColumn fixed="right" label="操作" width="200px">
<template #default="scope">
<ElRow>
<el-button link @click="showPermissionDialog()"> 菜单权限 </el-button>
<el-button link @click="showDialog('edit', scope.row)"> 编辑 </el-button>
<el-button link @click="deleteRole()"> 删除 </el-button>
<!-- <ArtButtonMore
:list="[
{ key: 'permission', label: '菜单权限' },
{ key: 'edit', label: '编辑角色' },
{ key: 'delete', label: '删除角色' }
]"
@click="buttonMoreClick($event, scope.row)"
/> -->
</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="roleName">
<ElInput v-model="form.roleName" />
</ElFormItem>
<ElFormItem label="角色编码" prop="roleCode">
<ElInput v-model="form.roleCode" />
</ElFormItem>
<ElFormItem label="描述" prop="roleStatus">
<ElInput v-model="form.des" type="textarea" :rows="3" />
</ElFormItem>
<ElFormItem label="启用">
<ElSwitch v-model="form.enable" />
</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="name"
:default-expand-all="isExpandAll"
:default-checked-keys="[1, 2, 3]"
: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 { useMenuStore } from '@/store/modules/menu'
import { ElMessage, ElMessageBox } from 'element-plus'
import type { FormInstance, FormRules } from 'element-plus'
import { formatMenuTitle } from '@/router/utils/utils'
import { UserService } from '@/api/usersApi'
// 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)
const { menuList } = storeToRefs(useMenuStore())
const treeRef = ref()
const isExpandAll = ref(true)
const isSelectAll = ref(false)
const pagination = reactive({
currentPage: 1,
pageSize: 10,
total: 0
})
// 处理菜单数据,将 authList 转换为子节点
const processedMenuList = computed(() => {
const processNode = (node: any) => {
const processed = { ...node }
// 如果有 authList,将其转换为子节点
if (node.meta && node.meta.authList && node.meta.authList.length) {
const authNodes = node.meta.authList.map((auth: any) => ({
id: `${node.id}_${auth.auth_mark}`,
name: `${node.name}_${auth.auth_mark}`,
label: auth.title,
auth_mark: auth.auth_mark,
isAuth: true,
checked: auth.checked || false
}))
processed.children = processed.children ? [...processed.children, ...authNodes] : authNodes
}
// 递归处理子节点
if (processed.children) {
processed.children = processed.children.map(processNode)
}
return processed
}
return menuList.value.map(processNode)
})
const formRef = ref<FormInstance>()
const rules = reactive<FormRules>({
name: [
{ required: true, message: '请输入角色名称', trigger: 'blur' },
{ min: 2, max: 20, message: '长度在 2 到 20 个字符', trigger: 'blur' }
],
des: [{ required: true, message: '请输入角色描述', trigger: 'blur' }]
})
const form = reactive<Role>({
roleName: '',
roleCode: '',
des: '',
date: '',
enable: true
})
const roleList = ref<Role[]>([])
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 UserService.getRoleList({
current: currentPage,
size: pageSize
})
roleList.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 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.roleName = row.roleName
form.roleCode = row.roleCode
form.des = row.des
form.date = row.date
form.enable = row.enable
} else {
form.roleName = ''
form.roleCode = ''
form.des = ''
form.date = ''
form.enable = true
}
}
const showPermissionDialog = () => {
permissionDialog.value = true
}
const defaultProps = {
children: 'children',
label: (data: any) => formatMenuTitle(data.meta?.title) || ''
}
const deleteRole = () => {
ElMessageBox.confirm('确定删除该角色吗?', '删除确认', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'error'
}).then(() => {
ElMessage.success('删除成功')
})
}
const handleSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid) => {
if (valid) {
const message = dialogType.value === 'add' ? '新增成功' : '修改成功'
ElMessage.success(message)
dialogVisible.value = false
formEl.resetFields()
}
})
}
const savePermission = () => {
ElMessage.success('权限保存成功')
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[]): string[] => {
const keys: string[] = []
const traverse = (nodeList: any[]) => {
nodeList.forEach((node) => {
if (node.name) {
keys.push(node.name)
}
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 formatDate = (date: string) => {
return new Date(date)
.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
})
.replace(/\//g, '-')
}
</script>
<style lang="scss" scoped>
.page-content {
.svg-icon {
width: 1.8em;
height: 1.8em;
overflow: hidden;
vertical-align: -8px;
fill: currentcolor;
}
}
</style>