293 lines
7.9 KiB
Vue
293 lines
7.9 KiB
Vue
<script setup lang="ts">
|
|
import { ref, onMounted, reactive, computed } from 'vue'
|
|
import { Button, Drawer, Form, Space, message } from 'ant-design-vue'
|
|
import { PlusOutlined, SearchOutlined } from '@ant-design/icons-vue'
|
|
import type { Permission } from '@/types'
|
|
import { getPermissions, createPermission, updatePermission, deletePermission } from '@/api/permission'
|
|
import {
|
|
TableToolbar,
|
|
TableActions,
|
|
Pagination
|
|
} from '@/components'
|
|
|
|
// 表格列定义
|
|
const columns = [
|
|
{ title: '权限编码', dataIndex: 'code', key: 'code', width: 160 },
|
|
{ title: '权限名称', dataIndex: 'name', key: 'name', width: 120 },
|
|
{ title: '类型', dataIndex: 'type', key: 'type', width: 90 },
|
|
{ title: '资源', dataIndex: 'resource', key: 'resource', width: 200, ellipsis: true },
|
|
{ title: '方法', dataIndex: 'method', key: 'method', width: 80 },
|
|
{ title: '描述', dataIndex: 'description', key: 'description', width: 180, ellipsis: true },
|
|
{ title: '操作', key: 'action', width: 140, fixed: 'right' as const }
|
|
]
|
|
|
|
const permissions = ref<Permission[]>([])
|
|
const loading = ref(false)
|
|
const drawerVisible = ref(false)
|
|
const drawerTitle = ref('')
|
|
const formRef = ref()
|
|
const submitting = ref(false)
|
|
const editingId = ref<string | null>(null)
|
|
|
|
// 搜索相关
|
|
const searchKeyword = ref('')
|
|
|
|
// 分页相关
|
|
const pagination = reactive({
|
|
current: 1,
|
|
pageSize: 10,
|
|
total: 0
|
|
})
|
|
|
|
// 分页后的数据
|
|
const paginatedData = computed(() => {
|
|
const start = (pagination.current - 1) * pagination.pageSize
|
|
const end = start + pagination.pageSize
|
|
return permissions.value.slice(start, end)
|
|
})
|
|
|
|
// 表单数据
|
|
const formState = reactive({
|
|
code: '',
|
|
name: '',
|
|
type: 'MENU',
|
|
resource: '',
|
|
method: 'GET',
|
|
description: ''
|
|
})
|
|
|
|
const typeOptions = [
|
|
{ value: 'MENU', label: '菜单' },
|
|
{ value: 'BUTTON', label: '按钮' },
|
|
{ value: 'API', label: '接口' }
|
|
]
|
|
|
|
const methodOptions = [
|
|
{ value: 'GET', label: 'GET' },
|
|
{ value: 'POST', label: 'POST' },
|
|
{ value: 'PUT', label: 'PUT' },
|
|
{ value: 'DELETE', label: 'DELETE' }
|
|
]
|
|
|
|
const fetchPermissions = async () => {
|
|
loading.value = true
|
|
try {
|
|
const res = await getPermissions()
|
|
permissions.value = res.data.data || []
|
|
pagination.total = permissions.value.length
|
|
} catch {
|
|
message.error('获取权限列表失败')
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const getTypeColor = (type: string) => {
|
|
const map: Record<string, string> = {
|
|
MENU: 'blue',
|
|
BUTTON: 'green',
|
|
API: 'purple'
|
|
}
|
|
return map[type] || 'default'
|
|
}
|
|
|
|
const getTypeLabel = (type: string) => {
|
|
const map: Record<string, string> = {
|
|
MENU: '菜单',
|
|
BUTTON: '按钮',
|
|
API: '接口'
|
|
}
|
|
return map[type] || type
|
|
}
|
|
|
|
const resetForm = () => {
|
|
formState.code = ''
|
|
formState.name = ''
|
|
formState.type = 'MENU'
|
|
formState.resource = ''
|
|
formState.method = 'GET'
|
|
formState.description = ''
|
|
editingId.value = null
|
|
}
|
|
|
|
const handleAdd = () => {
|
|
resetForm()
|
|
drawerTitle.value = '新建权限'
|
|
drawerVisible.value = true
|
|
}
|
|
|
|
const handleEdit = (record: Permission) => {
|
|
editingId.value = record.id
|
|
formState.code = record.code
|
|
formState.name = record.name
|
|
formState.type = record.type
|
|
formState.resource = record.resource || ''
|
|
formState.method = record.method || 'GET'
|
|
formState.description = record.description || ''
|
|
drawerTitle.value = '编辑权限'
|
|
drawerVisible.value = true
|
|
}
|
|
|
|
const handleDelete = async (id: string) => {
|
|
try {
|
|
await deletePermission(id)
|
|
message.success('删除成功')
|
|
fetchPermissions()
|
|
} catch {
|
|
message.error('删除失败')
|
|
}
|
|
}
|
|
|
|
const handleSubmit = async () => {
|
|
try {
|
|
await formRef.value.validate()
|
|
submitting.value = true
|
|
|
|
if (editingId.value) {
|
|
await updatePermission(editingId.value, formState)
|
|
message.success('更新成功')
|
|
} else {
|
|
await createPermission(formState)
|
|
message.success('创建成功')
|
|
}
|
|
|
|
drawerVisible.value = false
|
|
fetchPermissions()
|
|
} catch (error: any) {
|
|
if (error.errorFields) return
|
|
message.error('操作失败')
|
|
} finally {
|
|
submitting.value = false
|
|
}
|
|
}
|
|
|
|
const handleClose = () => {
|
|
formRef.value?.resetFields()
|
|
drawerVisible.value = false
|
|
}
|
|
|
|
const handlePageChange = (page: number, pageSize: number) => {
|
|
pagination.current = page
|
|
pagination.pageSize = pageSize
|
|
fetchPermissions()
|
|
}
|
|
|
|
const handleSearch = () => {
|
|
pagination.current = 1
|
|
fetchPermissions()
|
|
}
|
|
|
|
const handleReset = () => {
|
|
searchKeyword.value = ''
|
|
pagination.current = 1
|
|
fetchPermissions()
|
|
}
|
|
|
|
onMounted(fetchPermissions)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page-container">
|
|
<!-- 页面标题 -->
|
|
<div class="page-header">
|
|
<h2 class="page-title">权限管理</h2>
|
|
<div class="page-header-actions">
|
|
<Button type="primary" @click="handleAdd">
|
|
<PlusOutlined /> 新建权限
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 筛选区 -->
|
|
<div class="filter-bar">
|
|
<a-space>
|
|
<a-input
|
|
v-model:value="searchKeyword"
|
|
placeholder="搜索权限编码或名称"
|
|
style="width: 240px"
|
|
allow-clear
|
|
@press-enter="handleSearch"
|
|
/>
|
|
<a-button type="primary" @click="handleSearch">查询</a-button>
|
|
<a-button @click="handleReset">重置</a-button>
|
|
</a-space>
|
|
</div>
|
|
|
|
<!-- 表格 -->
|
|
<div class="table-card">
|
|
<TableToolbar @refresh="fetchPermissions" />
|
|
|
|
<a-table
|
|
:columns="columns"
|
|
:data-source="paginatedData"
|
|
:loading="loading"
|
|
:row-key="(record: Permission) => record.id"
|
|
:pagination="false"
|
|
>
|
|
<template #bodyCell="{ column, record }">
|
|
<template v-if="column.key === 'type'">
|
|
<a-tag :color="getTypeColor(record.type)">
|
|
{{ getTypeLabel(record.type) }}
|
|
</a-tag>
|
|
</template>
|
|
<template v-else-if="column.key === 'action'">
|
|
<TableActions @edit="handleEdit(record)" @delete="handleDelete(record.id)" />
|
|
</template>
|
|
</template>
|
|
</a-table>
|
|
|
|
<Pagination
|
|
v-model:current="pagination.current"
|
|
v-model:pageSize="pagination.pageSize"
|
|
:total="pagination.total"
|
|
@change="handlePageChange"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 抽屉 -->
|
|
<Drawer
|
|
v-model:open="drawerVisible"
|
|
:title="drawerTitle"
|
|
width="480px"
|
|
:footer-style="{ textAlign: 'right' }"
|
|
@close="handleClose"
|
|
>
|
|
<Form
|
|
ref="formRef"
|
|
:model="formState"
|
|
layout="vertical"
|
|
:rules="{
|
|
code: [{ required: true, message: '请输入权限代码' }],
|
|
name: [{ required: true, message: '请输入权限名称' }],
|
|
type: [{ required: true, message: '请选择类型' }]
|
|
}"
|
|
>
|
|
<Form.Item label="权限代码" name="code">
|
|
<a-input v-model:value="formState.code" placeholder="如: system:user:view" />
|
|
</Form.Item>
|
|
<Form.Item label="权限名称" name="name">
|
|
<a-input v-model:value="formState.name" placeholder="如: 查看用户" />
|
|
</Form.Item>
|
|
<Form.Item label="类型" name="type">
|
|
<a-select v-model:value="formState.type" :options="typeOptions" />
|
|
</Form.Item>
|
|
<Form.Item label="资源路径" name="resource">
|
|
<a-input v-model:value="formState.resource" placeholder="如: /api/users" />
|
|
</Form.Item>
|
|
<Form.Item label="请求方法" name="method">
|
|
<a-select v-model:value="formState.method" :options="methodOptions" />
|
|
</Form.Item>
|
|
<Form.Item label="描述" name="description">
|
|
<a-textarea v-model:value="formState.description" :rows="3" placeholder="权限描述" />
|
|
</Form.Item>
|
|
</Form>
|
|
<template #footer>
|
|
<Space>
|
|
<Button @click="handleClose">取消</Button>
|
|
<Button type="primary" :loading="submitting" @click="handleSubmit">确定</Button>
|
|
</Space>
|
|
</template>
|
|
</Drawer>
|
|
</div>
|
|
</template>
|