From 0af52c62ce5555a0c940d9b74e0eb71afdada1e6 Mon Sep 17 00:00:00 2001 From: yangsy Date: Thu, 22 Jan 2026 10:34:37 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=9D=83=E9=99=90?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=92=8C=E7=AE=A1=E7=90=86=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增权限管理页面 - 改进轮询链,引入权限查询 - 支持订阅权限变更或轮询权限检测变更 - 应用权限到页面和组件 --- src/apis/domain/biz/station/station.ts | 1 + src/apis/model/base/base-employee.ts | 21 ++ src/apis/model/base/index.ts | 1 + src/apis/model/biz/entity/other/index.ts | 1 + .../model/biz/entity/other/ndm-permission.ts | 34 ++ src/apis/model/index.ts | 1 + src/apis/request/base/base-employee.ts | 21 ++ src/apis/request/base/index.ts | 1 + src/apis/request/biz/other/index.ts | 1 + src/apis/request/biz/other/ndm-permission.ts | 83 +++++ src/apis/request/index.ts | 1 + .../ndm-alarm-host/alarm-host-card.vue | 6 +- .../device-card/ndm-camera/camera-card.vue | 6 +- .../device-card/ndm-decoder/decoder-card.vue | 6 +- .../ndm-keyboard/keyboard-card.vue | 6 +- .../device/device-card/ndm-nvr/nvr-card.vue | 6 +- .../ndm-security-box/security-box-card.vue | 6 +- .../device-card/ndm-server/server-card.vue | 6 +- .../device-card/ndm-switch/switch-card.vue | 6 +- .../device/device-tree/device-tree.vue | 21 +- .../settings-drawer/settings-drawer.vue | 53 +-- src/components/index.ts | 1 + src/components/permission/index.ts | 6 + .../permission/permission-config-modal.vue | 302 ++++++++++++++++++ .../station/station-card/station-card.vue | 10 +- .../sync-camera-result-modal.vue | 7 +- .../alarm/use-alarm-action-column.ts | 51 +-- src/composables/index.ts | 1 + src/composables/permission/index.ts | 1 + src/composables/permission/use-permission.ts | 14 + src/composables/query/index.ts | 1 + .../query/use-line-alarms-query.ts | 8 +- .../query/use-line-devices-query.ts | 8 +- .../query/use-line-stations-query.ts | 13 +- .../query/use-user-permission-query.ts | 67 ++++ src/composables/station/use-batch-actions.ts | 37 ++- src/composables/stomp/use-stomp-client.ts | 16 +- src/constants/query.ts | 1 + src/constants/stomp.ts | 2 +- src/constants/store.ts | 1 + src/enums/index.ts | 1 + src/enums/permission-type.ts | 13 + src/layouts/app-layout.vue | 17 +- src/pages/alarm/alarm-ignore-page.vue | 31 +- src/pages/alarm/alarm-log-page.vue | 29 +- src/pages/device/device-page.vue | 9 +- src/pages/log/call-log-page.vue | 17 +- src/pages/log/vimp-log-page.vue | 17 +- src/pages/permission/permission-page.vue | 184 +++++++++++ src/pages/station/station-page.vue | 20 +- src/router/index.ts | 9 + src/stores/index.ts | 1 + src/stores/permission.ts | 77 +++++ 53 files changed, 1129 insertions(+), 131 deletions(-) create mode 100644 src/apis/model/base/base-employee.ts create mode 100644 src/apis/model/base/index.ts create mode 100644 src/apis/model/biz/entity/other/ndm-permission.ts create mode 100644 src/apis/request/base/base-employee.ts create mode 100644 src/apis/request/base/index.ts create mode 100644 src/apis/request/biz/other/ndm-permission.ts create mode 100644 src/components/permission/index.ts create mode 100644 src/components/permission/permission-config-modal.vue create mode 100644 src/composables/permission/index.ts create mode 100644 src/composables/permission/use-permission.ts create mode 100644 src/composables/query/use-user-permission-query.ts create mode 100644 src/enums/permission-type.ts create mode 100644 src/pages/permission/permission-page.vue create mode 100644 src/stores/permission.ts diff --git a/src/apis/domain/biz/station/station.ts b/src/apis/domain/biz/station/station.ts index 5113778..6666509 100644 --- a/src/apis/domain/biz/station/station.ts +++ b/src/apis/domain/biz/station/station.ts @@ -3,4 +3,5 @@ export interface Station { name: string; online: boolean; ip: string; + occ?: boolean; // 是否为控制中心 } diff --git a/src/apis/model/base/base-employee.ts b/src/apis/model/base/base-employee.ts new file mode 100644 index 0000000..11561c4 --- /dev/null +++ b/src/apis/model/base/base-employee.ts @@ -0,0 +1,21 @@ +import type { BaseModel, ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO } from '@/apis'; +import type { Nullable, Optional } from '@/types'; + +export interface BaseEmployee extends BaseModel { + userId: string; + realName: string; + defUser: Nullable< + { + username: string; + nickName: string; + } & BaseModel + >; +} + +export type BaseEmployeeResultVO = Nullable; + +export type BaseEmployeeSaveVO = Partial>; + +export type BaseEmployeeUpdateVO = Optional>; + +export type BaseEmployeePageQuery = Partial>; diff --git a/src/apis/model/base/index.ts b/src/apis/model/base/index.ts new file mode 100644 index 0000000..a174b11 --- /dev/null +++ b/src/apis/model/base/index.ts @@ -0,0 +1 @@ +export * from './base-employee'; diff --git a/src/apis/model/biz/entity/other/index.ts b/src/apis/model/biz/entity/other/index.ts index 7ac828d..7006bdc 100644 --- a/src/apis/model/biz/entity/other/index.ts +++ b/src/apis/model/biz/entity/other/index.ts @@ -1,2 +1,3 @@ +export * from './ndm-permission'; export * from './ndm-security-box'; export * from './ndm-switch'; diff --git a/src/apis/model/biz/entity/other/ndm-permission.ts b/src/apis/model/biz/entity/other/ndm-permission.ts new file mode 100644 index 0000000..c0cc862 --- /dev/null +++ b/src/apis/model/biz/entity/other/ndm-permission.ts @@ -0,0 +1,34 @@ +import type { BaseModel, ReduceForPageQuery, ReduceForSaveVO, ReduceForUpdateVO, Station } from '@/apis'; +import type { PermissionType } from '@/enums'; +import type { Nullable, Optional } from '@/types'; + +export interface NdmPermission extends BaseModel { + /** + * 员工ID + */ + employeeId: string; + /** + * 服务器IP地址 + */ + ipAddress: string; + /** + * 站号 + */ + stationCode: Station['code']; + /** + * 站名 + */ + name: string; + /** + * 权限类型 + */ + type: PermissionType; +} + +export type NdmPermissionResultVO = Nullable; + +export type NdmPermissionSaveVO = Partial>; + +export type NdmPermissionUpdateVO = Optional>; + +export type NdmPermissionPageQuery = Partial>; diff --git a/src/apis/model/index.ts b/src/apis/model/index.ts index 4391f12..42ee35a 100644 --- a/src/apis/model/index.ts +++ b/src/apis/model/index.ts @@ -1,3 +1,4 @@ +export * from './base'; export * from './biz'; export * from './common'; export * from './schema'; diff --git a/src/apis/request/base/base-employee.ts b/src/apis/request/base/base-employee.ts new file mode 100644 index 0000000..fcd4fc7 --- /dev/null +++ b/src/apis/request/base/base-employee.ts @@ -0,0 +1,21 @@ +import type { BaseEmployeePageQuery, BaseEmployeeResultVO, PageParams, PageResult } from '@/apis'; +import { userClient } from '@/apis/client'; +import { unwrapResponse } from '@/utils'; + +export const pageBaseEmployeeApi = async (pageQuery: PageParams, options?: { signal?: AbortSignal }) => { + const { signal } = options ?? {}; + const client = userClient; + const endpoint = '/api/base/baseEmployee/page'; + const resp = await client.post>(endpoint, pageQuery, { signal }); + const data = unwrapResponse(resp); + return data; +}; + +export const detailBaseEmployeeApi = async (id: string, options?: { signal?: AbortSignal }) => { + const { signal } = options ?? {}; + const client = userClient; + const endpoint = `/api/base/baseEmployee/detail`; + const resp = await client.get(endpoint, { params: { id }, signal }); + const data = unwrapResponse(resp); + return data; +}; diff --git a/src/apis/request/base/index.ts b/src/apis/request/base/index.ts new file mode 100644 index 0000000..a174b11 --- /dev/null +++ b/src/apis/request/base/index.ts @@ -0,0 +1 @@ +export * from './base-employee'; diff --git a/src/apis/request/biz/other/index.ts b/src/apis/request/biz/other/index.ts index 0d4f721..4f231a8 100644 --- a/src/apis/request/biz/other/index.ts +++ b/src/apis/request/biz/other/index.ts @@ -1,3 +1,4 @@ +export * from './ndm-permission'; export * from './ndm-security-box'; export * from './ndm-service-available'; export * from './ndm-switch'; diff --git a/src/apis/request/biz/other/ndm-permission.ts b/src/apis/request/biz/other/ndm-permission.ts new file mode 100644 index 0000000..bc2bd82 --- /dev/null +++ b/src/apis/request/biz/other/ndm-permission.ts @@ -0,0 +1,83 @@ +import { + ndmClient, + userClient, + type NdmPermissionPageQuery, + type NdmPermissionResultVO, + type NdmPermissionSaveVO, + type NdmPermissionUpdateVO, + type PageParams, + type PageResult, + type Station, +} from '@/apis'; +import type { PermissionTypeEnum } from '@/enums'; +import { unwrapResponse } from '@/utils'; + +export const permissionTypesApi = async (options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { + const { stationCode, signal } = options ?? {}; + const client = stationCode ? ndmClient : userClient; + const prefix = stationCode ? `/${stationCode}` : ''; + const endpoint = `${prefix}/api/ndm/ndmPermission/types`; + const resp = await client.get(endpoint, { signal }); + const data = unwrapResponse(resp); + return data; +}; + +export const pagePermissionApi = async (pageQuery: PageParams, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { + const { stationCode, signal } = options ?? {}; + const client = stationCode ? ndmClient : userClient; + const prefix = stationCode ? `/${stationCode}` : ''; + const endpoint = `${prefix}/api/ndm/ndmPermission/page`; + const resp = await client.post>(endpoint, pageQuery, { signal }); + const data = unwrapResponse(resp); + return data; +}; + +export const detailPermissionApi = async (id: string, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { + const { stationCode, signal } = options ?? {}; + const client = stationCode ? ndmClient : userClient; + const prefix = stationCode ? `/${stationCode}` : ''; + const endpoint = `${prefix}/api/ndm/ndmPermission/detail`; + const resp = await client.get(endpoint, { params: { id }, signal }); + const data = unwrapResponse(resp); + return data; +}; + +export const savePermissionApi = async (saveVO: NdmPermissionSaveVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { + const { stationCode, signal } = options ?? {}; + const client = stationCode ? ndmClient : userClient; + const prefix = stationCode ? `/${stationCode}` : ''; + const endpoint = `${prefix}/api/ndm/ndmPermission`; + const resp = await client.post(endpoint, saveVO, { signal }); + const result = unwrapResponse(resp); + return result; +}; + +export const updatePermissionApi = async (updateVO: NdmPermissionUpdateVO, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { + const { stationCode, signal } = options ?? {}; + const client = stationCode ? ndmClient : userClient; + const prefix = stationCode ? `/${stationCode}` : ''; + const endpoint = `${prefix}/api/ndm/ndmPermission`; + const resp = await client.put(endpoint, updateVO, { signal }); + const result = unwrapResponse(resp); + return result; +}; + +export const deletePermissionApi = async (ids: string[], options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { + const { stationCode, signal } = options ?? {}; + const client = stationCode ? ndmClient : userClient; + const prefix = stationCode ? `/${stationCode}` : ''; + const endpoint = `${prefix}/api/ndm/ndmPermission`; + const resp = await client.delete(endpoint, ids, { signal }); + const result = unwrapResponse(resp); + return result; +}; + +export const modifyPermissionApi = async (params: { employeeId: string; saveList: NdmPermissionSaveVO[]; removeList: string[] }, options?: { stationCode?: Station['code']; signal?: AbortSignal }) => { + const { stationCode, signal } = options ?? {}; + const client = stationCode ? ndmClient : userClient; + const prefix = stationCode ? `/${stationCode}` : ''; + const endpoint = `${prefix}/api/ndm/ndmPermission/modify`; + const resp = await client.post(endpoint, params, { signal }); + const result = unwrapResponse(resp); + return result; +}; diff --git a/src/apis/request/index.ts b/src/apis/request/index.ts index ced1b3c..10cbc67 100644 --- a/src/apis/request/index.ts +++ b/src/apis/request/index.ts @@ -1,2 +1,3 @@ +export * from './base'; export * from './biz'; export * from './system'; diff --git a/src/components/device/device-card/ndm-alarm-host/alarm-host-card.vue b/src/components/device/device-card/ndm-alarm-host/alarm-host-card.vue index 1b37911..771a9d1 100644 --- a/src/components/device/device-card/ndm-alarm-host/alarm-host-card.vue +++ b/src/components/device/device-card/ndm-alarm-host/alarm-host-card.vue @@ -1,6 +1,8 @@ + + + + diff --git a/src/components/station/station-card/station-card.vue b/src/components/station/station-card/station-card.vue index a70f7c3..551e290 100644 --- a/src/components/station/station-card/station-card.vue +++ b/src/components/station/station-card/station-card.vue @@ -1,6 +1,7 @@ + + + + diff --git a/src/pages/station/station-page.vue b/src/pages/station/station-page.vue index d2c7983..a17406d 100644 --- a/src/pages/station/station-page.vue +++ b/src/pages/station/station-page.vue @@ -2,9 +2,9 @@ import { initStationAlarms, initStationDevices, syncCameraApi, syncNvrChannelsApi, type Station } from '@/apis'; import { AlarmDetailModal, DeviceDetailModal, DeviceParamConfigModal, IcmpExportModal, RecordCheckExportModal, StationCard, type StationCardProps } from '@/components'; import { useBatchActions, useLineDevicesQuery } from '@/composables'; -import { useAlarmStore, useDeviceStore, useSettingStore, useStationStore } from '@/stores'; +import { useAlarmStore, useDeviceStore, usePermissionStore, useSettingStore } from '@/stores'; import { useMutation } from '@tanstack/vue-query'; -import { objectEntries, useElementSize } from '@vueuse/core'; +import { useElementSize } from '@vueuse/core'; import { isCancel } from 'axios'; import { NButton, NButtonGroup, NCheckbox, NFlex, NGrid, NGridItem, NScrollbar } from 'naive-ui'; import { storeToRefs } from 'pinia'; @@ -13,8 +13,8 @@ import { computed, ref, useTemplateRef } from 'vue'; const settingStore = useSettingStore(); const { stationGridCols } = storeToRefs(settingStore); -const stationStore = useStationStore(); -const { stations } = storeToRefs(stationStore); +const permissionStore = usePermissionStore(); +const stations = computed(() => permissionStore.stations.VIEW ?? []); const deviceStore = useDeviceStore(); const { lineDevices } = storeToRefs(deviceStore); @@ -42,7 +42,10 @@ const showRecordCheckExportModal = ref(false); const abortController = ref(new AbortController()); -const { batchActions, selectedAction, selectableStations, stationSelection, toggleSelectAction, toggleSelectAllStations, confirmAction, cancelAction } = useBatchActions(stations, abortController); +const { batchActions, selectedAction, selectableStations, stationSelection, selectionProps, toggleSelectAction, toggleSelectAllStations, confirmAction, cancelAction } = useBatchActions( + stations, + abortController, +); const { refetch: refetchLineDevicesQuery } = useLineDevicesQuery(); @@ -177,12 +180,7 @@ const onClickDetail: StationCardProps['onClickDetail'] = (type, station) => { diff --git a/src/router/index.ts b/src/router/index.ts index e71a517..8e5af07 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -47,6 +47,15 @@ const router = createRouter({ }, ], }, + { + path: 'permission', + component: () => import('@/pages/permission/permission-page.vue'), + beforeEnter: () => { + const userStore = useUserStore(); + if (userStore.isLamp) return true; + return { path: '/404' }; + }, + }, { path: '/:pathMatch(.*)*', component: () => import('@/pages/error/not-found-page.vue'), diff --git a/src/stores/index.ts b/src/stores/index.ts index 78e3b61..e79f692 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -1,5 +1,6 @@ export * from './alarm'; export * from './device'; +export * from './permission'; export * from './setting'; export * from './station'; export * from './unread'; diff --git a/src/stores/permission.ts b/src/stores/permission.ts new file mode 100644 index 0000000..336fbbe --- /dev/null +++ b/src/stores/permission.ts @@ -0,0 +1,77 @@ +import type { NdmPermissionResultVO, Station } from '@/apis'; +import { NDM_PERMISSION_STORE_ID } from '@/constants'; +import { PERMISSION_TYPE_NAMES, type PermissionType } from '@/enums'; +import { useStationStore } from '@/stores'; +import { defineStore } from 'pinia'; +import { computed, ref } from 'vue'; +import { objectEntries } from '@vueuse/core'; + +type Permissions = Record; + +export const usePermissionStore = defineStore( + NDM_PERMISSION_STORE_ID, + () => { + const stationStore = useStationStore(); + + const permissionRecords = ref(null); + + const permissions = computed(() => { + const result: Permissions = {}; + + const records = permissionRecords.value; + + // 如果权限记录不存在,则不做权限配置 + if (!records) return result; + + // 如果该用户没有任何权限记录,则开放所有权限,否则根据记录配置权限 + if (records.length === 0) { + stationStore.stations.forEach((station) => { + result[station.code] = [...objectEntries(PERMISSION_TYPE_NAMES).map(([permType]) => permType)]; + }); + } else { + stationStore.stations.forEach((station) => { + result[station.code] = []; + const stationPermRecords = records.filter((record) => record.stationCode === station.code); + if (stationPermRecords.length === 0) return; + stationPermRecords.forEach(({ type: permType }) => { + if (!permType) return; + result[station.code]?.push(permType); + }); + }); + } + + return result; + }); + + // 按权限对车站进行分类 + const stations = computed(() => { + const result: Partial> = {}; + // 按原始的车站顺序进行遍历,保持显示顺序不变 + stationStore.stations.forEach((station) => { + const permissionTypes = permissions.value[station.code]; + if (!permissionTypes) return; + permissionTypes.forEach((permissionType) => { + if (!result[permissionType]) result[permissionType] = []; + result[permissionType].push(station); + }); + }); + return result; + }); + + const setPermRecords = (records: NdmPermissionResultVO[]) => { + permissionRecords.value = records; + }; + + return { + permissionRecords, + + permissions, + stations, + + setPermRecords, + }; + }, + { + persist: true, + }, +);