feat: 移除mock并接入真实权限控制
This commit is contained in:
+107
-37
@@ -9,12 +9,12 @@ import {
|
||||
import {
|
||||
createRole,
|
||||
deleteRole,
|
||||
listRoles,
|
||||
listRolePage,
|
||||
updateRole,
|
||||
type Role,
|
||||
type RolePayload
|
||||
} from "@/api/access";
|
||||
import { hasPerms } from "@/utils/auth";
|
||||
import { hasMenuAction } from "@/utils/auth";
|
||||
|
||||
import Plus from "~icons/ep/plus";
|
||||
import Search from "~icons/ep/search";
|
||||
@@ -40,7 +40,16 @@ const formRef = ref<FormInstance>();
|
||||
const roles = ref<Role[]>([]);
|
||||
|
||||
const query = reactive({
|
||||
keyword: ""
|
||||
keyword: "",
|
||||
isSystem: undefined as boolean | undefined,
|
||||
page: 1,
|
||||
pageSize: 20
|
||||
});
|
||||
|
||||
/** 角色管理列表由后端分页,这里只记录当前筛选结果的分页摘要。 */
|
||||
const pagination = reactive({
|
||||
total: 0,
|
||||
totalPages: 0
|
||||
});
|
||||
|
||||
const form = reactive<RoleFormState>({
|
||||
@@ -72,26 +81,15 @@ const describedCount = computed(
|
||||
() => roles.value.filter(item => Boolean(item.description)).length
|
||||
);
|
||||
const systemRoleCount = computed(
|
||||
() => roles.value.filter(item => item.code === "admin").length
|
||||
() => roles.value.filter(item => item.isSystem).length
|
||||
);
|
||||
const dialogTitle = computed(() => (form.id ? "编辑角色" : "新增角色"));
|
||||
const canManageRoles = computed(() => hasPerms("role:manage"));
|
||||
|
||||
function applyRoleQuery(items: Role[]) {
|
||||
const keyword = query.keyword.trim().toLowerCase();
|
||||
|
||||
if (keyword.length === 0) {
|
||||
return items;
|
||||
}
|
||||
|
||||
return items.filter(role => {
|
||||
return (
|
||||
role.code.toLowerCase().includes(keyword) ||
|
||||
role.name.toLowerCase().includes(keyword) ||
|
||||
(role.description ?? "").toLowerCase().includes(keyword)
|
||||
);
|
||||
});
|
||||
}
|
||||
const canCreateRole = computed(() => hasMenuAction("roles", "create"));
|
||||
const canUpdateRole = computed(() => hasMenuAction("roles", "update"));
|
||||
const canDeleteRole = computed(() => hasMenuAction("roles", "delete"));
|
||||
const canOperateRole = computed(
|
||||
() => canUpdateRole.value || canDeleteRole.value
|
||||
);
|
||||
|
||||
function getErrorMessage(error: unknown, fallback: string) {
|
||||
const message = (
|
||||
@@ -134,12 +132,19 @@ function buildPayload(): RolePayload {
|
||||
};
|
||||
}
|
||||
|
||||
/** 角色查询必须走接口,避免搜索条件只在前端过滤当前缓存。 */
|
||||
/** 角色筛选、分页必须走接口,避免查询条件只在前端过滤当前缓存。 */
|
||||
async function fetchRoles() {
|
||||
tableLoading.value = true;
|
||||
try {
|
||||
const result = await listRoles();
|
||||
roles.value = applyRoleQuery(result.data);
|
||||
const result = await listRolePage({
|
||||
keyword: query.keyword.trim() || undefined,
|
||||
isSystem: query.isSystem,
|
||||
page: query.page,
|
||||
pageSize: query.pageSize
|
||||
});
|
||||
roles.value = result.data.items;
|
||||
pagination.total = result.data.pagination.total;
|
||||
pagination.totalPages = result.data.pagination.totalPages;
|
||||
} catch (error) {
|
||||
ElMessage.error(getErrorMessage(error, "加载角色列表失败"));
|
||||
} finally {
|
||||
@@ -149,22 +154,37 @@ async function fetchRoles() {
|
||||
|
||||
function handleReset() {
|
||||
query.keyword = "";
|
||||
query.isSystem = undefined;
|
||||
query.page = 1;
|
||||
query.pageSize = 20;
|
||||
fetchRoles();
|
||||
}
|
||||
|
||||
function handleSearch() {
|
||||
query.keyword = query.keyword.trim();
|
||||
query.page = 1;
|
||||
fetchRoles();
|
||||
}
|
||||
|
||||
function handlePageChange(page: number) {
|
||||
query.page = page;
|
||||
fetchRoles();
|
||||
}
|
||||
|
||||
function handleSizeChange(pageSize: number) {
|
||||
query.page = 1;
|
||||
query.pageSize = pageSize;
|
||||
fetchRoles();
|
||||
}
|
||||
|
||||
function openCreateDialog() {
|
||||
if (!canManageRoles.value) return;
|
||||
if (!canCreateRole.value) return;
|
||||
resetFormState();
|
||||
dialogVisible.value = true;
|
||||
}
|
||||
|
||||
function openEditDialog(row: Role) {
|
||||
if (!canManageRoles.value || row.isSystem) return;
|
||||
if (!canUpdateRole.value || row.isSystem) return;
|
||||
Object.assign(form, {
|
||||
id: row.id,
|
||||
code: row.code,
|
||||
@@ -176,7 +196,7 @@ function openEditDialog(row: Role) {
|
||||
}
|
||||
|
||||
async function submitForm() {
|
||||
if (!canManageRoles.value) return;
|
||||
if (form.id ? !canUpdateRole.value : !canCreateRole.value) return;
|
||||
await formRef.value?.validate();
|
||||
submitLoading.value = true;
|
||||
|
||||
@@ -201,7 +221,7 @@ async function submitForm() {
|
||||
}
|
||||
|
||||
async function removeRole(row: Role) {
|
||||
if (!canManageRoles.value || row.isSystem) return;
|
||||
if (!canDeleteRole.value || row.isSystem) return;
|
||||
try {
|
||||
await ElMessageBox.confirm(
|
||||
`删除后角色「${row.name}」无法再绑定员工,确认继续?`,
|
||||
@@ -214,6 +234,10 @@ async function removeRole(row: Role) {
|
||||
);
|
||||
await deleteRole(row.id);
|
||||
ElMessage.success("角色已删除");
|
||||
|
||||
if (roles.value.length === 1 && query.page > 1) {
|
||||
query.page -= 1;
|
||||
}
|
||||
fetchRoles();
|
||||
} catch (error) {
|
||||
if (error !== "cancel") {
|
||||
@@ -233,7 +257,7 @@ onMounted(fetchRoles);
|
||||
<h1>角色管理</h1>
|
||||
</div>
|
||||
<el-button
|
||||
v-if="canManageRoles"
|
||||
v-if="canCreateRole"
|
||||
type="primary"
|
||||
:icon="Plus"
|
||||
@click="openCreateDialog"
|
||||
@@ -245,14 +269,14 @@ onMounted(fetchRoles);
|
||||
<div class="summary-strip">
|
||||
<div class="summary-item">
|
||||
<span>总角色</span>
|
||||
<strong>{{ roles.length }}</strong>
|
||||
<strong>{{ pagination.total }}</strong>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span>已配置说明</span>
|
||||
<span>当前页有说明</span>
|
||||
<strong>{{ describedCount }}</strong>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
<span>系统角色</span>
|
||||
<span>当前页系统角色</span>
|
||||
<strong>{{ systemRoleCount }}</strong>
|
||||
</div>
|
||||
<div class="summary-item">
|
||||
@@ -262,6 +286,16 @@ onMounted(fetchRoles);
|
||||
</div>
|
||||
|
||||
<div class="toolbar">
|
||||
<el-select
|
||||
v-model="query.isSystem"
|
||||
clearable
|
||||
placeholder="全部类型"
|
||||
class="toolbar-control"
|
||||
@change="handleSearch"
|
||||
>
|
||||
<el-option label="系统内置" :value="true" />
|
||||
<el-option label="自定义角色" :value="false" />
|
||||
</el-select>
|
||||
<el-input
|
||||
v-model="query.keyword"
|
||||
clearable
|
||||
@@ -305,14 +339,14 @@ onMounted(fetchRoles);
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
v-if="canManageRoles"
|
||||
v-if="canOperateRole"
|
||||
label="操作"
|
||||
width="170"
|
||||
fixed="right"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-button
|
||||
v-if="!row.isSystem"
|
||||
v-if="canUpdateRole && !row.isSystem"
|
||||
link
|
||||
type="primary"
|
||||
:icon="EditPen"
|
||||
@@ -321,7 +355,7 @@ onMounted(fetchRoles);
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="!row.isSystem"
|
||||
v-if="canDeleteRole && !row.isSystem"
|
||||
link
|
||||
type="danger"
|
||||
:icon="Delete"
|
||||
@@ -333,6 +367,22 @@ onMounted(fetchRoles);
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<div class="pagination-row">
|
||||
<span
|
||||
>共 {{ pagination.total }} 条,{{ pagination.totalPages }} 页</span
|
||||
>
|
||||
<el-pagination
|
||||
v-model:current-page="query.page"
|
||||
v-model:page-size="query.pageSize"
|
||||
background
|
||||
layout="sizes, prev, pager, next"
|
||||
:total="pagination.total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
@current-change="handlePageChange"
|
||||
@size-change="handleSizeChange"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
@@ -391,9 +441,9 @@ onMounted(fetchRoles);
|
||||
|
||||
.page-heading {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px;
|
||||
|
||||
h1 {
|
||||
@@ -459,6 +509,10 @@ onMounted(fetchRoles);
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.toolbar-control {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.toolbar-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
@@ -474,6 +528,16 @@ onMounted(fetchRoles);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pagination-row {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 14px 16px 0;
|
||||
font-size: 13px;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.role-cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -510,8 +574,8 @@ onMounted(fetchRoles);
|
||||
}
|
||||
|
||||
.page-heading {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.summary-strip {
|
||||
@@ -519,6 +583,7 @@ onMounted(fetchRoles);
|
||||
}
|
||||
|
||||
.keyword-input,
|
||||
.toolbar-control,
|
||||
.toolbar-actions {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
@@ -528,6 +593,11 @@ onMounted(fetchRoles);
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.pagination-row {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user