feat: 添加权限查询和管理机制

- 新增权限管理页面
- 改进轮询链,引入权限查询
- 支持订阅权限变更或轮询权限检测变更
- 应用权限到页面和组件
This commit is contained in:
yangsy
2026-01-22 10:34:37 +08:00
parent 82789c78a9
commit 0af52c62ce
53 changed files with 1129 additions and 131 deletions

View File

@@ -0,0 +1,184 @@
<script setup lang="ts">
import { pageBaseEmployeeApi, type BaseEmployeePageQuery, type BaseEmployeeResultVO } from '@/apis';
import { PermissionConfigModal } from '@/components';
import { parseErrorFeedback } from '@/utils';
import { useMutation } from '@tanstack/vue-query';
import { isCancel } from 'axios';
import { KeyIcon } from 'lucide-vue-next';
import { NButton, NDataTable, NFlex, NForm, NFormItemGi, NGrid, NGridItem, NInput, type DataTableColumns, type DataTableRowData, type PaginationProps } from 'naive-ui';
import { h, onBeforeUnmount, onMounted, reactive, ref, watch } from 'vue';
interface SearchFields extends BaseEmployeePageQuery {}
const searchFields = ref<SearchFields>({});
const resetSearchFields = () => {
searchFields.value = {
realName: '',
};
};
const getModelFields = (): BaseEmployeePageQuery => {
return {
realName: searchFields.value.realName,
};
};
const searchFieldsChanged = ref(false);
watch(searchFields, () => {
searchFieldsChanged.value = true;
});
const showPermissionConfigModal = ref(false);
const selectedEmployeeId = ref('');
const tableColumns: DataTableColumns<BaseEmployeeResultVO> = [
{ title: '姓名', key: 'realName', align: 'center' },
{ title: '创建时间', key: 'createdTime', align: 'center' },
{
title: '操作',
key: 'action',
align: 'center',
width: 150,
render: (rowData) => {
return h(
NButton,
{
secondary: true,
type: 'info',
size: 'small',
onClick: () => {
const { id } = rowData;
if (!id) return;
selectedEmployeeId.value = id;
showPermissionConfigModal.value = true;
},
},
{
icon: () => h(KeyIcon),
default: () => '配置权限',
},
);
},
},
];
const tableData = ref<DataTableRowData[]>([]);
const DEFAULT_PAGE_SIZE = 10;
const pagination = reactive<PaginationProps>({
showSizePicker: true,
page: 1,
pageSize: DEFAULT_PAGE_SIZE,
pageSizes: [5, 10, 20, 50, 80, 100],
itemCount: 0,
prefix: ({ itemCount }) => {
return h('div', {}, { default: () => `${itemCount}` });
},
onUpdatePage: (page: number) => {
pagination.page = page;
getTableData();
},
onUpdatePageSize: (pageSize: number) => {
pagination.pageSize = pageSize;
pagination.page = 1;
getTableData();
},
});
const abortController = ref(new AbortController());
const { mutate: getTableData, isPending: tableLoading } = useMutation({
mutationFn: async () => {
abortController.value.abort();
abortController.value = new AbortController();
const signal = abortController.value.signal;
const res = await pageBaseEmployeeApi(
{
model: getModelFields(),
extra: {},
current: pagination.page ?? 1,
size: pagination.pageSize ?? DEFAULT_PAGE_SIZE,
order: 'descending',
sort: 'id',
},
{
signal,
},
);
return res;
},
onSuccess: (res) => {
const { records, size, total } = res;
pagination.pageSize = parseInt(size);
pagination.itemCount = parseInt(total);
tableData.value = records;
},
onError: (error) => {
if (isCancel(error)) return;
console.error(error);
const errorFeedback = parseErrorFeedback(error);
window.$message.error(errorFeedback);
},
});
const onClickReset = () => {
resetSearchFields();
pagination.page = 1;
pagination.pageSize = DEFAULT_PAGE_SIZE;
pagination.itemCount = 0;
getTableData();
};
const onClickQuery = () => {
if (searchFieldsChanged.value) {
pagination.page = 1;
pagination.pageSize = DEFAULT_PAGE_SIZE;
searchFieldsChanged.value = false;
}
getTableData();
};
onMounted(() => {
getTableData();
});
onBeforeUnmount(() => {
abortController.value.abort();
});
</script>
<template>
<NFlex vertical :size="0" style="height: 100%">
<!-- 查询面板 -->
<NForm style="flex: 0 0 auto; padding: 8px">
<NGrid cols="3" :x-gap="24">
<NFormItemGi span="1" label="姓名" label-placement="left">
<NInput v-model:value="searchFields.realName" />
</NFormItemGi>
</NGrid>
<!-- 操作按钮 -->
<NGrid :cols="1">
<NGridItem>
<NFlex>
<NButton @click="onClickReset">重置</NButton>
<NButton type="primary" :loading="tableLoading" @click="onClickQuery">查询</NButton>
</NFlex>
</NGridItem>
</NGrid>
</NForm>
<!-- 数据表格工具栏 -->
<NFlex align="center" style="padding: 8px; flex: 0 0 auto">
<div style="font-size: medium">用户权限列表</div>
<NFlex style="margin-left: auto">
<!-- <NButton type="primary" :loading="exporting" @click="() => exportTableData()">导出</NButton> -->
</NFlex>
</NFlex>
<!-- 数据表格 -->
<NDataTable remote :columns="tableColumns" :data="tableData" :pagination="pagination" :loading="tableLoading" :single-line="false" flex-height style="height: 100%; padding: 8px; flex: 1 1 auto" />
</NFlex>
<PermissionConfigModal v-model:show="showPermissionConfigModal" :employee-id="selectedEmployeeId" />
</template>
<style scoped lang="scss"></style>