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

@@ -1,4 +1,8 @@
import { usePermission } from '../permission';
import { type Station } from '@/apis';
import { PERMISSION_TYPE_LITERALS, type PermissionType } from '@/enums';
import { objectEntries } from '@vueuse/core';
import type { CheckboxProps } from 'naive-ui';
import { computed, ref, watch, type Ref } from 'vue';
type BatchActionKey = 'export-icmp' | 'export-record' | 'sync-camera' | 'sync-nvr';
@@ -6,29 +10,36 @@ type BatchActionKey = 'export-icmp' | 'export-record' | 'sync-camera' | 'sync-nv
type BatchAction = {
label: string;
key: BatchActionKey;
permission: PermissionType;
active: boolean;
};
export const useBatchActions = (stations: Ref<Station[]>, abortController?: Ref<AbortController | undefined>) => {
const { hasPermission } = usePermission();
const batchActions = ref<BatchAction[]>([
{
label: '导出设备状态',
key: 'export-icmp',
permission: PERMISSION_TYPE_LITERALS.VIEW,
active: false,
},
{
label: '导出录像诊断',
key: 'export-record',
permission: PERMISSION_TYPE_LITERALS.VIEW,
active: false,
},
{
label: '同步摄像机',
key: 'sync-camera',
permission: PERMISSION_TYPE_LITERALS.OPERATION,
active: false,
},
{
label: '同步录像机通道',
key: 'sync-nvr',
permission: PERMISSION_TYPE_LITERALS.OPERATION,
active: false,
},
]);
@@ -39,11 +50,33 @@ export const useBatchActions = (stations: Ref<Station[]>, abortController?: Ref<
const selectableStations = computed(() => {
if (!selectedAction.value) return [];
return stations.value;
const result: Station[] = [];
if (selectedAction.value.permission === PERMISSION_TYPE_LITERALS.VIEW) {
result.push(...stations.value.filter((station) => hasPermission(station.code, PERMISSION_TYPE_LITERALS.VIEW)));
}
if (selectedAction.value.permission === PERMISSION_TYPE_LITERALS.OPERATION) {
result.push(...stations.value.filter((station) => hasPermission(station.code, PERMISSION_TYPE_LITERALS.OPERATION)));
}
return result;
});
const stationSelection = ref<Record<Station['code'], boolean>>({});
const selectionProps = computed<CheckboxProps>(() => {
const selectableStationsLength = selectableStations.value.length;
const selectedStationsLength = objectEntries(stationSelection.value).filter(([, selected]) => selected).length;
const disabled = selectableStationsLength === 0;
const checked = selectableStationsLength > 0 && selectedStationsLength === selectableStationsLength;
const indeterminate = selectableStationsLength > 0 && selectedStationsLength > 0 && selectedStationsLength < selectableStationsLength;
return {
disabled,
checked,
indeterminate,
};
});
const toggleSelectAction = (action: BatchAction) => {
batchActions.value.forEach((batchAction) => {
if (batchAction.key === action.key) {
@@ -95,6 +128,8 @@ export const useBatchActions = (stations: Ref<Station[]>, abortController?: Ref<
selectableStations,
stationSelection,
selectionProps,
toggleSelectAction,
toggleSelectAllStations,