6 Commits

Author SHA1 Message Date
yangsy 67dccc5011 refactor(vimp): 移除冗余的选中设备GB编码相关代码
删除alarm-tree、camera-tree组件中的选中状态定义、节点绑定及双击设置逻辑,同时移除vimp主页面中对应的状态声明、组件传参和状态展示代码
2026-05-27 22:28:57 +08:00
yangsy a0048411a4 重构(alarm-tree): 使用 alarmOnline 函数替代直接状态检查
将多处行内的告警状态检查替换为统一的 alarmOnline 辅助函数,后续若需调整在线状态校验逻辑仅需修改一处,提升代码可读性与可维护性。
2026-05-27 22:25:50 +08:00
yangsy d177956edd fix(device-center-query): 移除设备及告警数据赋值的非空判断
解决空数组无法更新对应站点映射的问题,避免残留旧数据
2026-05-27 21:48:03 +08:00
yangsy d1b973be15 refactor(vimp/types): 重命名树类型模块为设备树并补充类型定义
创建device-tree.ts作为新的设备树类型模块,迁移原tree.ts中的类型定义,新增摄像机、警报器设备树的节点类型、类型守卫函数及标签页属性类型,同时更新类型入口文件的导出路径。
2026-05-27 21:31:16 +08:00
yangsy 65603d469d refactor(vimp): 抽离并重构vimp的摄像机、告警store与树形类型
- 新增camera-store.ts与alarm-store.ts,封装摄像机、告警业务逻辑为独立Pinia store
- 重构tree.ts中的树形节点类型命名与关联判断函数
- 更新stores/index.ts的导出文件路径
- 移除alarm-tree.vue中的冗余类型导入
2026-05-27 21:29:59 +08:00
yangsy a92e47bc18 refactor(vimp): 重构vimp模块的API目录与导入路径
重新梳理vimp模块的API代码结构,拆分为client、model、query、request子模块并添加统一导出入口;修正所有相关文件的导入路径,新增通用响应类型与工具函数,优化树组件的类型判断逻辑,同时新增设备查询相关API与查询hook。
2026-05-27 15:43:53 +08:00
20 changed files with 142 additions and 127 deletions
+1
View File
@@ -0,0 +1 @@
export * from './vimp-client';
@@ -1,16 +1,8 @@
import type { VimpChannel, VimpStation } from './model';
import type { AxiosError, AxiosRequestConfig, CreateAxiosDefaults } from 'axios';
import axios from 'axios';
import type { VimpResponse, VimpResult } from '../../types';
interface VimpResult<T = unknown> {
code: number;
data: T;
msg: string;
}
type VimpResponse<T> = [err: AxiosError | null, data: T | null, resp: VimpResult<T> | null];
const createVimpClient = (config?: CreateAxiosDefaults) => {
export const createVimpClient = (config?: CreateAxiosDefaults) => {
const instance = axios.create(config);
const vimpPost = <T>(url: string, data?: AxiosRequestConfig['data'], options?: Partial<Omit<AxiosRequestConfig, 'data'>> & { retRaw?: boolean; upload?: boolean }): Promise<VimpResponse<T>> => {
@@ -38,7 +30,7 @@ const createVimpClient = (config?: CreateAxiosDefaults) => {
};
};
const unwrapVimpResponse = <T>(resp: VimpResponse<T>) => {
export const unwrapVimpResponse = <T>(resp: VimpResponse<T>) => {
const [err, data, result] = resp;
if (err) throw err;
if (result) {
@@ -51,21 +43,3 @@ const unwrapVimpResponse = <T>(resp: VimpResponse<T>) => {
export const vimpClient = createVimpClient({
baseURL: `/vimp/api/client`,
});
export const catalogAllDeviceApi = async (options?: { signal?: AbortSignal }) => {
const { signal } = options ?? {};
const client = vimpClient;
const endpoint = `/catalog/allDevice`;
const resp = await client.post<VimpStation[]>(endpoint, {}, { signal });
const data = unwrapVimpResponse(resp);
return data;
};
export const catalogChannelApi = async (code: string, options?: { signal?: AbortSignal }) => {
const { signal } = options ?? {};
const client = vimpClient;
const endpoint = `/catalog/channel`;
const resp = await client.post<VimpChannel[]>(endpoint, { code, time: '' }, { signal });
const data = unwrapVimpResponse(resp);
return data;
};
@@ -1,3 +1,4 @@
export * from './client';
export * from './model';
export * from './query';
export * from './request';
+2
View File
@@ -0,0 +1,2 @@
export * from './vimp-channel';
export * from './vimp-station';
@@ -1,9 +1,3 @@
export interface VimpStation {
code: string;
name: string;
online: boolean;
}
export interface VimpChannel {
address: string;
block: string;
@@ -0,0 +1,5 @@
export interface VimpStation {
code: string;
name: string;
online: boolean;
}
@@ -1,13 +1,13 @@
import { useQuery } from '@tanstack/vue-query';
import { computed } from 'vue';
import { catalogChannelApi, catalogAllDeviceApi } from './request';
import { catalogChannelApi, catalogAllDeviceApi } from '../request';
import type { AxiosRequestConfig } from 'axios';
import axios from 'axios';
import type { CodeArea, CodeLines, CodeSites } from '../types';
import type { VimpChannel } from '.';
import { useCameraStore, useAlarmStore } from '../stores';
import type { CodeArea, CodeLines, CodeSites } from '../../types';
import { useCameraStore, useAlarmStore } from '../../stores';
import type { VimpChannel } from '../model';
export const useVimpDeviceQuery = () => {
export const useDeviceCenterQuery = () => {
const cameraStore = useCameraStore();
const alarmStore = useAlarmStore();
@@ -68,14 +68,10 @@ export const useVimpDeviceQuery = () => {
}
});
if (cameras.length > 0) {
siteCamerasMap[site.code] = cameras;
}
if (alarms.length > 0) {
siteAlarmsMap[site.code] = alarms;
}
}
}
cameraStore.buildLineTabPanes({
sites,
+1
View File
@@ -0,0 +1 @@
export * from './device-center-query';
@@ -0,0 +1,11 @@
import { unwrapVimpResponse, vimpClient } from '../client';
import type { VimpStation } from '../model';
export const catalogAllDeviceApi = async (options?: { signal?: AbortSignal }) => {
const { signal } = options ?? {};
const client = vimpClient;
const endpoint = `/catalog/allDevice`;
const resp = await client.post<VimpStation[]>(endpoint, {}, { signal });
const data = unwrapVimpResponse(resp);
return data;
};
@@ -0,0 +1,11 @@
import { unwrapVimpResponse, vimpClient } from '../client';
import type { VimpChannel } from '../model';
export const catalogChannelApi = async (code: string, options?: { signal?: AbortSignal }) => {
const { signal } = options ?? {};
const client = vimpClient;
const endpoint = `/catalog/channel`;
const resp = await client.post<VimpChannel[]>(endpoint, { code, time: '' }, { signal });
const data = unwrapVimpResponse(resp);
return data;
};
+2
View File
@@ -0,0 +1,2 @@
export * from './catalog.channel';
export * from './catalog.all-device';
+13 -19
View File
@@ -1,19 +1,16 @@
<script setup lang="ts">
import { NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type TreeProps } from 'naive-ui';
import { useVimpDeviceQuery } from '../api/query';
import type { VimpChannel, VimpStation } from '../api/model';
import { h, type CSSProperties } from 'vue';
import { hasOwn } from '@vueuse/core';
import { useAlarmStore } from '../stores';
import { storeToRefs } from 'pinia';
import { useDeviceCenterQuery } from '../apis';
import { isAlarmNode, isAlarmSiteNode, isAlarmAreaNode } from '../types';
const { isLoading } = useVimpDeviceQuery();
const { isLoading } = useDeviceCenterQuery();
const alarmStore = useAlarmStore();
const { lineTabPanes } = storeToRefs(alarmStore);
const selectedDeviceGbCode = defineModel<[string]>('selectedDeviceGbCode', { default: () => [''] });
const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) => {
const hasChildren = (option.children?.length ?? 0) > 0;
if (hasChildren) {
@@ -25,8 +22,8 @@ const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) =>
const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
// 是车站节点
if (hasOwn(option, 'online')) {
const siteOnline = option['online'] as boolean;
if (isAlarmSiteNode(option)) {
const siteOnline = option.online;
const siteNodeStyle: CSSProperties = {
opacity: siteOnline ? 1 : 0.5,
};
@@ -34,8 +31,8 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
}
// 是中间节点(一级/二级区域)
if (!hasOwn(option, 'device') && hasOwn(option, 'site')) {
const site = option['site'] as VimpStation;
if (isAlarmAreaNode(option)) {
const site = option.site;
const nodeStyle: CSSProperties = {
opacity: site.online ? 1 : 0.5,
};
@@ -43,9 +40,9 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
}
// 是警报器节点
if (hasOwn(option, 'alarm') && hasOwn(option, 'site')) {
const alarm = option['alarm'] as VimpChannel;
const site = option['site'] as VimpStation;
if (isAlarmNode(option)) {
const alarm = option.alarm;
const site = option.site;
const alarmOnline = () => {
return alarm.status === 1 && site.online;
@@ -59,14 +56,13 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
'div',
{
style: alarmNodeStyle,
draggable: alarm.status === 1,
draggable: alarmOnline(),
onDblclick() {
if (alarm.status === 0) return;
selectedDeviceGbCode.value = [alarm.code];
if (!alarmOnline()) return;
window.$message.info(`查看警报器:${JSON.stringify({ code: alarm.code, name: alarm.name })}`);
},
onDragstart(event) {
if (alarm.status === 0) return;
if (!alarmOnline()) return;
console.log(event);
event.dataTransfer?.setData('type', 'alarm');
event.dataTransfer?.setData('code', alarm.code);
@@ -93,7 +89,6 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
show-line
virtual-scroll
style="height: 100%"
v-model:selected-keys="selectedDeviceGbCode"
:data="lineTabPanes.at(0)?.alarmTree"
:override-default-node-click-behavior="overrideNodeClickBehavior"
:render-label="renderNodeLabel"
@@ -108,7 +103,6 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
show-line
virtual-scroll
style="height: 100%"
v-model:selected-keys="selectedDeviceGbCode"
:data="alarmTree"
:override-default-node-click-behavior="overrideNodeClickBehavior"
:render-label="renderNodeLabel"
+13 -19
View File
@@ -1,19 +1,16 @@
<script setup lang="ts">
import { NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type TreeProps } from 'naive-ui';
import { useVimpDeviceQuery } from '../api/query';
import type { VimpChannel, VimpStation } from '../api/model';
import { h, type CSSProperties } from 'vue';
import { hasOwn } from '@vueuse/core';
import { useCameraStore } from '../stores';
import { storeToRefs } from 'pinia';
import { useDeviceCenterQuery } from '../apis';
import { isCameraNode, isCameraSiteNode, isCameraAreaNode } from '../types';
const { isLoading } = useVimpDeviceQuery();
const { isLoading } = useDeviceCenterQuery();
const cameraStore = useCameraStore();
const { lineTabPanes } = storeToRefs(cameraStore);
const selectedDeviceGbCode = defineModel<[string]>('selectedDeviceGbCode', { default: () => [''] });
const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) => {
const hasChildren = (option.children?.length ?? 0) > 0;
if (hasChildren) {
@@ -25,8 +22,8 @@ const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) =>
const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
// 是车站节点
if (hasOwn(option, 'online')) {
const siteOnline = option['online'] as boolean;
if (isCameraSiteNode(option)) {
const siteOnline = option.online;
const siteNodeStyle: CSSProperties = {
opacity: siteOnline ? 1 : 0.5,
};
@@ -34,8 +31,8 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
}
// 是中间节点(一级/二级区域)
if (!hasOwn(option, 'device') && hasOwn(option, 'site')) {
const site = option['site'] as VimpStation;
if (isCameraAreaNode(option)) {
const site = option.site;
const nodeStyle: CSSProperties = {
opacity: site.online ? 1 : 0.5,
};
@@ -43,9 +40,9 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
}
// 是摄像机节点
if (hasOwn(option, 'camera') && hasOwn(option, 'site')) {
const camera = option['camera'] as VimpChannel;
const site = option['site'] as VimpStation;
if (isCameraNode(option)) {
const camera = option.camera;
const site = option.site;
const cameraOnline = () => {
return camera.status === 1 && site.online;
@@ -59,14 +56,13 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
'div',
{
style: cameraNodeStyle,
draggable: camera.status === 1,
draggable: cameraOnline(),
onDblclick() {
if (camera.status === 0) return;
selectedDeviceGbCode.value = [camera.code];
if (!cameraOnline()) return;
window.$message.info(`播放:${JSON.stringify({ code: camera.code, name: camera.name })}`);
},
onDragstart(event) {
if (camera.status === 0) return;
if (!cameraOnline()) return;
console.log(event);
event.dataTransfer?.setData('type', 'camera');
event.dataTransfer?.setData('code', camera.code);
@@ -93,7 +89,6 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
show-line
virtual-scroll
style="height: 100%"
v-model:selected-keys="selectedDeviceGbCode"
:data="lineTabPanes.at(0)?.cameraTree"
:override-default-node-click-behavior="overrideNodeClickBehavior"
:render-label="renderNodeLabel"
@@ -108,7 +103,6 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
show-line
virtual-scroll
style="height: 100%"
v-model:selected-keys="selectedDeviceGbCode"
:data="cameraTree"
:override-default-node-click-behavior="overrideNodeClickBehavior"
:render-label="renderNodeLabel"
@@ -1,7 +1,7 @@
import { defineStore } from 'pinia';
import type { VimpChannel, VimpStation } from '../api';
import type { VimpChannel, VimpStation } from '../apis';
import { h, ref } from 'vue';
import type { AlarmAreaNodeOption, AlarmNodeOption, CodeArea, CodeLines, CodeSites, AlarmLineTabPane, AlarmSiteNodeOption, AlarmSubAreaNodeOption } from '../types';
import type { AlarmMainAreaNodeOption, AlarmNodeOption, CodeArea, CodeLines, CodeSites, AlarmLineTabPane, AlarmSiteNodeOption, AlarmSubAreaNodeOption } from '../types';
interface BuildLineTabPanesParams {
sites: VimpStation[] | null;
@@ -79,22 +79,22 @@ export const useAlarmStore = defineStore('vimp-alarm', () => {
}
if (!siteArea) continue; // 如果还是未找到区域,则跳过该警报器
// 构造区域节点
// 构造1级区域节点
if (!siteNode.children?.find((areaNode) => areaNode.key === `${alarmSiteCode}${alarmMainAreaCode}`)) {
const areaNode: AlarmAreaNodeOption = {
const mainAreaNode: AlarmMainAreaNodeOption = {
key: `${alarmSiteCode}${alarmMainAreaCode}`,
label: siteArea.name,
children: [],
stats: { online: 0, offline: 0, total: 0 },
site: site,
};
siteNode.children?.push(areaNode);
siteNode.children?.push(mainAreaNode);
}
const areaNode = siteNode.children?.find((areaNode) => areaNode.key === `${alarmSiteCode}${alarmMainAreaCode}`);
if (!areaNode) continue; // 如果区域节点不存在,则跳过该警报器
const targetMainAreaNode = siteNode.children?.find((areaNode) => areaNode.key === `${alarmSiteCode}${alarmMainAreaCode}`);
if (!targetMainAreaNode) continue; // 如果1级区域节点不存在,则跳过该警报器
// 构造区域节点
if (!areaNode.children?.find((subAreaNode) => subAreaNode.key === `${alarmSiteCode}${alarmAreaCode}`)) {
// 构造2级区域节点
if (!targetMainAreaNode.children?.find((subAreaNode) => subAreaNode.key === `${alarmSiteCode}${alarmAreaCode}`)) {
let subArea: CodeArea['subs'][number] | undefined = undefined;
if (alarmSiteType === 'station') {
subArea = codeStationAreas.find((area) => area.code === alarmMainAreaCode)?.subs.find((subArea) => subArea.code === alarmAreaCode);
@@ -116,9 +116,9 @@ export const useAlarmStore = defineStore('vimp-alarm', () => {
stats: { online: 0, offline: 0, total: 0 },
site: site,
};
areaNode.children?.push(subAreaNode);
targetMainAreaNode.children?.push(subAreaNode);
}
const subAreaNode = areaNode.children?.find((subAreaNode) => subAreaNode.key === `${alarmSiteCode}${alarmAreaCode}`);
const subAreaNode = targetMainAreaNode.children?.find((subAreaNode) => subAreaNode.key === `${alarmSiteCode}${alarmAreaCode}`);
if (!subAreaNode) continue; // 如果子区域节点不存在,则跳过该警报器
// 构造警报器节点
@@ -141,16 +141,16 @@ export const useAlarmStore = defineStore('vimp-alarm', () => {
// 统计站点、区域、子区域的在线/离线/总警报器数量
siteNode.stats.total++;
areaNode.stats.total++;
targetMainAreaNode.stats.total++;
subAreaNode.stats.total++;
if (alarm.status === 1) {
siteNode.stats.online++;
areaNode.stats.online++;
targetMainAreaNode.stats.online++;
subAreaNode.stats.online++;
}
if (alarm.status === 0) {
siteNode.stats.offline++;
areaNode.stats.offline++;
targetMainAreaNode.stats.offline++;
subAreaNode.stats.offline++;
}
}
@@ -1,7 +1,7 @@
import { defineStore } from 'pinia';
import type { VimpChannel, VimpStation } from '../api';
import type { VimpChannel, VimpStation } from '../apis';
import { h, ref } from 'vue';
import type { CameraAreaNodeOption, CameraNodeOption, CodeArea, CodeLines, CodeSites, CameraLineTabPane, CameraSiteNodeOption, CameraSubAreaNodeOption } from '../types';
import type { CameraMainAreaNodeOption, CameraNodeOption, CodeArea, CodeLines, CodeSites, CameraLineTabPane, CameraSiteNodeOption, CameraSubAreaNodeOption } from '../types';
interface BuildLineTabPanesParams {
sites: VimpStation[] | null;
@@ -79,22 +79,22 @@ export const useCameraStore = defineStore('vimp-camera', () => {
}
if (!siteArea) continue; // 如果还是未找到区域,则跳过该摄像机
// 构造区域节点
// 构造1级区域节点
if (!siteNode.children?.find((areaNode) => areaNode.key === `${cameraSiteCode}${cameraMainAreaCode}`)) {
const areaNode: CameraAreaNodeOption = {
const mainAreaNode: CameraMainAreaNodeOption = {
key: `${cameraSiteCode}${cameraMainAreaCode}`,
label: siteArea.name,
children: [],
stats: { online: 0, offline: 0, total: 0 },
site: site,
};
siteNode.children?.push(areaNode);
siteNode.children?.push(mainAreaNode);
}
const areaNode = siteNode.children?.find((areaNode) => areaNode.key === `${cameraSiteCode}${cameraMainAreaCode}`);
if (!areaNode) continue; // 如果区域节点不存在,则跳过该摄像机
const targetMainAreaNode = siteNode.children?.find((areaNode) => areaNode.key === `${cameraSiteCode}${cameraMainAreaCode}`);
if (!targetMainAreaNode) continue; // 如果1级区域节点不存在,则跳过该摄像机
// 构造区域节点
if (!areaNode.children?.find((subAreaNode) => subAreaNode.key === `${cameraSiteCode}${cameraAreaCode}`)) {
// 构造2级区域节点
if (!targetMainAreaNode.children?.find((subAreaNode) => subAreaNode.key === `${cameraSiteCode}${cameraAreaCode}`)) {
let subArea: CodeArea['subs'][number] | undefined = undefined;
if (cameraSiteType === 'station') {
subArea = codeStationAreas.find((area) => area.code === cameraMainAreaCode)?.subs.find((subArea) => subArea.code === cameraAreaCode);
@@ -107,7 +107,7 @@ export const useCameraStore = defineStore('vimp-camera', () => {
} else {
continue;
}
if (!subArea) continue; // 如果还是未找到区域,则跳过该摄像机
if (!subArea) continue; // 如果还是未找到2级区域,则跳过该摄像机
const subAreaNode: CameraSubAreaNodeOption = {
key: `${cameraSiteCode}${cameraAreaCode}`,
@@ -116,9 +116,9 @@ export const useCameraStore = defineStore('vimp-camera', () => {
stats: { online: 0, offline: 0, total: 0 },
site: site,
};
areaNode.children?.push(subAreaNode);
targetMainAreaNode.children?.push(subAreaNode);
}
const subAreaNode = areaNode.children?.find((subAreaNode) => subAreaNode.key === `${cameraSiteCode}${cameraAreaCode}`);
const subAreaNode = targetMainAreaNode.children?.find((subAreaNode) => subAreaNode.key === `${cameraSiteCode}${cameraAreaCode}`);
if (!subAreaNode) continue; // 如果子区域节点不存在,则跳过该摄像机
// 构造摄像机节点
@@ -143,16 +143,16 @@ export const useCameraStore = defineStore('vimp-camera', () => {
// 统计站点、区域、子区域的在线/离线/总摄像机数量
siteNode.stats.total++;
areaNode.stats.total++;
targetMainAreaNode.stats.total++;
subAreaNode.stats.total++;
if (camera.status === 1) {
siteNode.stats.online++;
areaNode.stats.online++;
targetMainAreaNode.stats.online++;
subAreaNode.stats.online++;
}
if (camera.status === 0) {
siteNode.stats.offline++;
areaNode.stats.offline++;
targetMainAreaNode.stats.offline++;
subAreaNode.stats.offline++;
}
}
+2 -2
View File
@@ -1,2 +1,2 @@
export * from './camera';
export * from './alarm';
export * from './camera-store';
export * from './alarm-store';
+9
View File
@@ -0,0 +1,9 @@
import type { AxiosError } from 'axios';
export interface VimpResult<T = unknown> {
code: number;
data: T;
msg: string;
}
export type VimpResponse<T> = [err: AxiosError | null, data: T | null, resp: VimpResult<T> | null];
@@ -1,5 +1,5 @@
import type { TabPaneProps, TreeOption } from 'naive-ui';
import type { VimpChannel, VimpStation } from '../api';
import type { VimpChannel, VimpStation } from '../apis/model';
export type SiteType = 'station' | 'parking' | 'occ' | 'train';
export type CodeLines = Record<string, { name: string; color: string }>;
@@ -27,18 +27,30 @@ export interface CameraSubAreaNodeOption extends TreeOption {
site: VimpStation;
}
export interface CameraAreaNodeOption extends TreeOption {
export interface CameraMainAreaNodeOption extends TreeOption {
children?: CameraSubAreaNodeOption[];
stats: CountStats;
site: VimpStation;
}
export interface CameraSiteNodeOption extends TreeOption {
children?: CameraAreaNodeOption[];
children?: CameraMainAreaNodeOption[];
stats: CountStats;
online: boolean;
}
export function isCameraSiteNode(option: TreeOption): option is CameraSiteNodeOption {
return 'online' in option && !('camera' in option);
}
export function isCameraAreaNode(option: TreeOption): option is CameraMainAreaNodeOption | CameraSubAreaNodeOption {
return 'site' in option && !('camera' in option) && !('online' in option);
}
export function isCameraNode(option: TreeOption): option is CameraNodeOption {
return 'camera' in option && 'site' in option;
}
export interface CameraLineTabPane extends TabPaneProps {
lineCode: string;
lineName: string;
@@ -60,18 +72,30 @@ export interface AlarmSubAreaNodeOption extends TreeOption {
site: VimpStation;
}
export interface AlarmAreaNodeOption extends TreeOption {
export interface AlarmMainAreaNodeOption extends TreeOption {
children?: AlarmSubAreaNodeOption[];
stats: CountStats;
site: VimpStation;
}
export interface AlarmSiteNodeOption extends TreeOption {
children?: AlarmAreaNodeOption[];
children?: AlarmMainAreaNodeOption[];
stats: CountStats;
online: boolean;
}
export function isAlarmSiteNode(option: TreeOption): option is AlarmSiteNodeOption {
return 'online' in option && !('alarm' in option);
}
export function isAlarmAreaNode(option: TreeOption): option is AlarmMainAreaNodeOption | AlarmSubAreaNodeOption {
return 'site' in option && !('alarm' in option) && !('online' in option);
}
export function isAlarmNode(option: TreeOption): option is AlarmNodeOption {
return 'alarm' in option && 'site' in option;
}
export interface AlarmLineTabPane extends TabPaneProps {
lineCode: string;
lineName: string;
+2 -1
View File
@@ -1 +1,2 @@
export * from './tree';
export * from './axios';
export * from './device-tree';
+1 -6
View File
@@ -15,8 +15,6 @@ const resourceTabPanes: ResourceTabPane[] = [
{ name: 'alarm', tab: '警报器', component: AlarmTree },
];
const selectedDeviceGbCode = ref<[string]>(['']);
const onDragover = (event: DragEvent) => {
event.preventDefault();
if (event.dataTransfer) {
@@ -32,13 +30,11 @@ const onDrop = (event: DragEvent) => {
const code = event.dataTransfer?.getData('code');
if (!code) return;
const name = event.dataTransfer?.getData('name');
selectedDeviceGbCode.value = [code];
window.$message.info(`播放:${JSON.stringify({ code, name })}`);
} else if (type === 'alarm') {
const code = event.dataTransfer?.getData('code');
if (!code) return;
const name = event.dataTransfer?.getData('name');
selectedDeviceGbCode.value = [code];
window.$message.info(`查看警报器:${JSON.stringify({ code, name })}`);
} else {
}
@@ -51,7 +47,7 @@ const onDrop = (event: DragEvent) => {
<NTabs :type="'line'" :placement="'left'" style="height: 100%">
<NTabPane v-for="{ name: resourceName, tab: resourceTab, component } in resourceTabPanes" :key="resourceName" :tab="resourceTab" :name="resourceName">
<template v-if="!!component">
<component :is="component" v-model:selected-device-gb-code="selectedDeviceGbCode" />
<component :is="component" />
</template>
</NTabPane>
</NTabs>
@@ -59,7 +55,6 @@ const onDrop = (event: DragEvent) => {
<div style="flex: 1">
<div style="height: 480px; background-color: #666; display: grid; place-items: center" @dragover="onDragover" @drop="onDrop">
<div>这里是播放器</div>
<div>{{ selectedDeviceGbCode }}</div>
</div>
</div>
</div>