Files
ndm-web-platform/src/composables/station/use-batch-actions.ts
yangsy 0c1fb418bd feat: 添加权限查询和管理机制
- 新增权限管理页面
- 改进轮询链,引入权限查询
- 支持订阅权限变更或轮询权限检测变更
- 应用权限到页面和组件
2026-01-22 10:34:37 +08:00

140 lines
4.0 KiB
TypeScript

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';
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,
},
]);
const selectedAction = computed(() => {
return batchActions.value.find((action) => action.active);
});
const selectableStations = computed(() => {
if (!selectedAction.value) return [];
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) {
if (batchAction.active) stationSelection.value = {};
batchAction.active = !batchAction.active;
} else {
batchAction.active = false;
}
});
};
const toggleSelectAllStations = (checked: boolean) => {
if (!checked) {
stationSelection.value = {};
return;
}
selectableStations.value.forEach((station) => {
stationSelection.value[station.code] = checked;
});
};
watch(selectedAction, () => {
toggleSelectAllStations(false);
});
const confirmAction = (callbacks: Record<BatchActionKey, () => void>) => {
const { key } = selectedAction.value ?? {};
if (!key) return;
const noStationSeleted = !Object.values(stationSelection.value).some((selected) => selected);
if (noStationSeleted) {
window.$message.warning('请选择车站');
return;
}
callbacks[key]();
};
const cancelAction = () => {
abortController?.value?.abort();
stationSelection.value = {};
batchActions.value.forEach((batchAction) => {
batchAction.active = false;
});
};
return {
batchActions,
selectedAction,
selectableStations,
stationSelection,
selectionProps,
toggleSelectAction,
toggleSelectAllStations,
confirmAction,
cancelAction,
};
};