Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 67dccc5011 | |||
| a0048411a4 | |||
| d177956edd | |||
| d1b973be15 | |||
| 65603d469d | |||
| a92e47bc18 |
@@ -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 type { AxiosError, AxiosRequestConfig, CreateAxiosDefaults } from 'axios';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import type { VimpResponse, VimpResult } from '../../types';
|
||||||
|
|
||||||
interface VimpResult<T = unknown> {
|
export const createVimpClient = (config?: CreateAxiosDefaults) => {
|
||||||
code: number;
|
|
||||||
data: T;
|
|
||||||
msg: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
type VimpResponse<T> = [err: AxiosError | null, data: T | null, resp: VimpResult<T> | null];
|
|
||||||
|
|
||||||
const createVimpClient = (config?: CreateAxiosDefaults) => {
|
|
||||||
const instance = axios.create(config);
|
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>> => {
|
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;
|
const [err, data, result] = resp;
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
if (result) {
|
if (result) {
|
||||||
@@ -51,21 +43,3 @@ const unwrapVimpResponse = <T>(resp: VimpResponse<T>) => {
|
|||||||
export const vimpClient = createVimpClient({
|
export const vimpClient = createVimpClient({
|
||||||
baseURL: `/vimp/api/client`,
|
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 './model';
|
||||||
export * from './query';
|
export * from './query';
|
||||||
export * from './request';
|
export * from './request';
|
||||||
@@ -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 {
|
export interface VimpChannel {
|
||||||
address: string;
|
address: string;
|
||||||
block: 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 { useQuery } from '@tanstack/vue-query';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
import { catalogChannelApi, catalogAllDeviceApi } from './request';
|
import { catalogChannelApi, catalogAllDeviceApi } from '../request';
|
||||||
import type { AxiosRequestConfig } from 'axios';
|
import type { AxiosRequestConfig } from 'axios';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import type { CodeArea, CodeLines, CodeSites } from '../types';
|
import type { CodeArea, CodeLines, CodeSites } from '../../types';
|
||||||
import type { VimpChannel } from '.';
|
import { useCameraStore, useAlarmStore } from '../../stores';
|
||||||
import { useCameraStore, useAlarmStore } from '../stores';
|
import type { VimpChannel } from '../model';
|
||||||
|
|
||||||
export const useVimpDeviceQuery = () => {
|
export const useDeviceCenterQuery = () => {
|
||||||
const cameraStore = useCameraStore();
|
const cameraStore = useCameraStore();
|
||||||
const alarmStore = useAlarmStore();
|
const alarmStore = useAlarmStore();
|
||||||
|
|
||||||
@@ -68,12 +68,8 @@ export const useVimpDeviceQuery = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (cameras.length > 0) {
|
siteCamerasMap[site.code] = cameras;
|
||||||
siteCamerasMap[site.code] = cameras;
|
siteAlarmsMap[site.code] = alarms;
|
||||||
}
|
|
||||||
if (alarms.length > 0) {
|
|
||||||
siteAlarmsMap[site.code] = alarms;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
};
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export * from './catalog.channel';
|
||||||
|
export * from './catalog.all-device';
|
||||||
@@ -1,19 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type TreeProps } from 'naive-ui';
|
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 { h, type CSSProperties } from 'vue';
|
||||||
import { hasOwn } from '@vueuse/core';
|
|
||||||
import { useAlarmStore } from '../stores';
|
import { useAlarmStore } from '../stores';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useDeviceCenterQuery } from '../apis';
|
||||||
|
import { isAlarmNode, isAlarmSiteNode, isAlarmAreaNode } from '../types';
|
||||||
|
|
||||||
const { isLoading } = useVimpDeviceQuery();
|
const { isLoading } = useDeviceCenterQuery();
|
||||||
|
|
||||||
const alarmStore = useAlarmStore();
|
const alarmStore = useAlarmStore();
|
||||||
const { lineTabPanes } = storeToRefs(alarmStore);
|
const { lineTabPanes } = storeToRefs(alarmStore);
|
||||||
|
|
||||||
const selectedDeviceGbCode = defineModel<[string]>('selectedDeviceGbCode', { default: () => [''] });
|
|
||||||
|
|
||||||
const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) => {
|
const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) => {
|
||||||
const hasChildren = (option.children?.length ?? 0) > 0;
|
const hasChildren = (option.children?.length ?? 0) > 0;
|
||||||
if (hasChildren) {
|
if (hasChildren) {
|
||||||
@@ -25,8 +22,8 @@ const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) =>
|
|||||||
|
|
||||||
const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
||||||
// 是车站节点
|
// 是车站节点
|
||||||
if (hasOwn(option, 'online')) {
|
if (isAlarmSiteNode(option)) {
|
||||||
const siteOnline = option['online'] as boolean;
|
const siteOnline = option.online;
|
||||||
const siteNodeStyle: CSSProperties = {
|
const siteNodeStyle: CSSProperties = {
|
||||||
opacity: siteOnline ? 1 : 0.5,
|
opacity: siteOnline ? 1 : 0.5,
|
||||||
};
|
};
|
||||||
@@ -34,8 +31,8 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 是中间节点(一级/二级区域)
|
// 是中间节点(一级/二级区域)
|
||||||
if (!hasOwn(option, 'device') && hasOwn(option, 'site')) {
|
if (isAlarmAreaNode(option)) {
|
||||||
const site = option['site'] as VimpStation;
|
const site = option.site;
|
||||||
const nodeStyle: CSSProperties = {
|
const nodeStyle: CSSProperties = {
|
||||||
opacity: site.online ? 1 : 0.5,
|
opacity: site.online ? 1 : 0.5,
|
||||||
};
|
};
|
||||||
@@ -43,9 +40,9 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 是警报器节点
|
// 是警报器节点
|
||||||
if (hasOwn(option, 'alarm') && hasOwn(option, 'site')) {
|
if (isAlarmNode(option)) {
|
||||||
const alarm = option['alarm'] as VimpChannel;
|
const alarm = option.alarm;
|
||||||
const site = option['site'] as VimpStation;
|
const site = option.site;
|
||||||
|
|
||||||
const alarmOnline = () => {
|
const alarmOnline = () => {
|
||||||
return alarm.status === 1 && site.online;
|
return alarm.status === 1 && site.online;
|
||||||
@@ -59,14 +56,13 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
'div',
|
'div',
|
||||||
{
|
{
|
||||||
style: alarmNodeStyle,
|
style: alarmNodeStyle,
|
||||||
draggable: alarm.status === 1,
|
draggable: alarmOnline(),
|
||||||
onDblclick() {
|
onDblclick() {
|
||||||
if (alarm.status === 0) return;
|
if (!alarmOnline()) return;
|
||||||
selectedDeviceGbCode.value = [alarm.code];
|
|
||||||
window.$message.info(`查看警报器:${JSON.stringify({ code: alarm.code, name: alarm.name })}`);
|
window.$message.info(`查看警报器:${JSON.stringify({ code: alarm.code, name: alarm.name })}`);
|
||||||
},
|
},
|
||||||
onDragstart(event) {
|
onDragstart(event) {
|
||||||
if (alarm.status === 0) return;
|
if (!alarmOnline()) return;
|
||||||
console.log(event);
|
console.log(event);
|
||||||
event.dataTransfer?.setData('type', 'alarm');
|
event.dataTransfer?.setData('type', 'alarm');
|
||||||
event.dataTransfer?.setData('code', alarm.code);
|
event.dataTransfer?.setData('code', alarm.code);
|
||||||
@@ -93,7 +89,6 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
show-line
|
show-line
|
||||||
virtual-scroll
|
virtual-scroll
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
v-model:selected-keys="selectedDeviceGbCode"
|
|
||||||
:data="lineTabPanes.at(0)?.alarmTree"
|
:data="lineTabPanes.at(0)?.alarmTree"
|
||||||
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
||||||
:render-label="renderNodeLabel"
|
:render-label="renderNodeLabel"
|
||||||
@@ -108,7 +103,6 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
show-line
|
show-line
|
||||||
virtual-scroll
|
virtual-scroll
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
v-model:selected-keys="selectedDeviceGbCode"
|
|
||||||
:data="alarmTree"
|
:data="alarmTree"
|
||||||
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
||||||
:render-label="renderNodeLabel"
|
:render-label="renderNodeLabel"
|
||||||
|
|||||||
@@ -1,19 +1,16 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NTabPane, NTabs, NTree, type TreeOverrideNodeClickBehavior, type TreeProps } from 'naive-ui';
|
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 { h, type CSSProperties } from 'vue';
|
||||||
import { hasOwn } from '@vueuse/core';
|
|
||||||
import { useCameraStore } from '../stores';
|
import { useCameraStore } from '../stores';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
|
import { useDeviceCenterQuery } from '../apis';
|
||||||
|
import { isCameraNode, isCameraSiteNode, isCameraAreaNode } from '../types';
|
||||||
|
|
||||||
const { isLoading } = useVimpDeviceQuery();
|
const { isLoading } = useDeviceCenterQuery();
|
||||||
|
|
||||||
const cameraStore = useCameraStore();
|
const cameraStore = useCameraStore();
|
||||||
const { lineTabPanes } = storeToRefs(cameraStore);
|
const { lineTabPanes } = storeToRefs(cameraStore);
|
||||||
|
|
||||||
const selectedDeviceGbCode = defineModel<[string]>('selectedDeviceGbCode', { default: () => [''] });
|
|
||||||
|
|
||||||
const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) => {
|
const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) => {
|
||||||
const hasChildren = (option.children?.length ?? 0) > 0;
|
const hasChildren = (option.children?.length ?? 0) > 0;
|
||||||
if (hasChildren) {
|
if (hasChildren) {
|
||||||
@@ -25,8 +22,8 @@ const overrideNodeClickBehavior: TreeOverrideNodeClickBehavior = ({ option }) =>
|
|||||||
|
|
||||||
const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
||||||
// 是车站节点
|
// 是车站节点
|
||||||
if (hasOwn(option, 'online')) {
|
if (isCameraSiteNode(option)) {
|
||||||
const siteOnline = option['online'] as boolean;
|
const siteOnline = option.online;
|
||||||
const siteNodeStyle: CSSProperties = {
|
const siteNodeStyle: CSSProperties = {
|
||||||
opacity: siteOnline ? 1 : 0.5,
|
opacity: siteOnline ? 1 : 0.5,
|
||||||
};
|
};
|
||||||
@@ -34,8 +31,8 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 是中间节点(一级/二级区域)
|
// 是中间节点(一级/二级区域)
|
||||||
if (!hasOwn(option, 'device') && hasOwn(option, 'site')) {
|
if (isCameraAreaNode(option)) {
|
||||||
const site = option['site'] as VimpStation;
|
const site = option.site;
|
||||||
const nodeStyle: CSSProperties = {
|
const nodeStyle: CSSProperties = {
|
||||||
opacity: site.online ? 1 : 0.5,
|
opacity: site.online ? 1 : 0.5,
|
||||||
};
|
};
|
||||||
@@ -43,9 +40,9 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 是摄像机节点
|
// 是摄像机节点
|
||||||
if (hasOwn(option, 'camera') && hasOwn(option, 'site')) {
|
if (isCameraNode(option)) {
|
||||||
const camera = option['camera'] as VimpChannel;
|
const camera = option.camera;
|
||||||
const site = option['site'] as VimpStation;
|
const site = option.site;
|
||||||
|
|
||||||
const cameraOnline = () => {
|
const cameraOnline = () => {
|
||||||
return camera.status === 1 && site.online;
|
return camera.status === 1 && site.online;
|
||||||
@@ -59,14 +56,13 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
'div',
|
'div',
|
||||||
{
|
{
|
||||||
style: cameraNodeStyle,
|
style: cameraNodeStyle,
|
||||||
draggable: camera.status === 1,
|
draggable: cameraOnline(),
|
||||||
onDblclick() {
|
onDblclick() {
|
||||||
if (camera.status === 0) return;
|
if (!cameraOnline()) return;
|
||||||
selectedDeviceGbCode.value = [camera.code];
|
|
||||||
window.$message.info(`播放:${JSON.stringify({ code: camera.code, name: camera.name })}`);
|
window.$message.info(`播放:${JSON.stringify({ code: camera.code, name: camera.name })}`);
|
||||||
},
|
},
|
||||||
onDragstart(event) {
|
onDragstart(event) {
|
||||||
if (camera.status === 0) return;
|
if (!cameraOnline()) return;
|
||||||
console.log(event);
|
console.log(event);
|
||||||
event.dataTransfer?.setData('type', 'camera');
|
event.dataTransfer?.setData('type', 'camera');
|
||||||
event.dataTransfer?.setData('code', camera.code);
|
event.dataTransfer?.setData('code', camera.code);
|
||||||
@@ -93,7 +89,6 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
show-line
|
show-line
|
||||||
virtual-scroll
|
virtual-scroll
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
v-model:selected-keys="selectedDeviceGbCode"
|
|
||||||
:data="lineTabPanes.at(0)?.cameraTree"
|
:data="lineTabPanes.at(0)?.cameraTree"
|
||||||
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
||||||
:render-label="renderNodeLabel"
|
:render-label="renderNodeLabel"
|
||||||
@@ -108,7 +103,6 @@ const renderNodeLabel: TreeProps['renderLabel'] = ({ option }) => {
|
|||||||
show-line
|
show-line
|
||||||
virtual-scroll
|
virtual-scroll
|
||||||
style="height: 100%"
|
style="height: 100%"
|
||||||
v-model:selected-keys="selectedDeviceGbCode"
|
|
||||||
:data="cameraTree"
|
:data="cameraTree"
|
||||||
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
:override-default-node-click-behavior="overrideNodeClickBehavior"
|
||||||
:render-label="renderNodeLabel"
|
:render-label="renderNodeLabel"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import type { VimpChannel, VimpStation } from '../api';
|
import type { VimpChannel, VimpStation } from '../apis';
|
||||||
import { h, ref } from 'vue';
|
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 {
|
interface BuildLineTabPanesParams {
|
||||||
sites: VimpStation[] | null;
|
sites: VimpStation[] | null;
|
||||||
@@ -79,22 +79,22 @@ export const useAlarmStore = defineStore('vimp-alarm', () => {
|
|||||||
}
|
}
|
||||||
if (!siteArea) continue; // 如果还是未找到区域,则跳过该警报器
|
if (!siteArea) continue; // 如果还是未找到区域,则跳过该警报器
|
||||||
|
|
||||||
// 构造区域节点
|
// 构造1级区域节点
|
||||||
if (!siteNode.children?.find((areaNode) => areaNode.key === `${alarmSiteCode}${alarmMainAreaCode}`)) {
|
if (!siteNode.children?.find((areaNode) => areaNode.key === `${alarmSiteCode}${alarmMainAreaCode}`)) {
|
||||||
const areaNode: AlarmAreaNodeOption = {
|
const mainAreaNode: AlarmMainAreaNodeOption = {
|
||||||
key: `${alarmSiteCode}${alarmMainAreaCode}`,
|
key: `${alarmSiteCode}${alarmMainAreaCode}`,
|
||||||
label: siteArea.name,
|
label: siteArea.name,
|
||||||
children: [],
|
children: [],
|
||||||
stats: { online: 0, offline: 0, total: 0 },
|
stats: { online: 0, offline: 0, total: 0 },
|
||||||
site: site,
|
site: site,
|
||||||
};
|
};
|
||||||
siteNode.children?.push(areaNode);
|
siteNode.children?.push(mainAreaNode);
|
||||||
}
|
}
|
||||||
const areaNode = siteNode.children?.find((areaNode) => areaNode.key === `${alarmSiteCode}${alarmMainAreaCode}`);
|
const targetMainAreaNode = siteNode.children?.find((areaNode) => areaNode.key === `${alarmSiteCode}${alarmMainAreaCode}`);
|
||||||
if (!areaNode) continue; // 如果区域节点不存在,则跳过该警报器
|
if (!targetMainAreaNode) continue; // 如果1级区域节点不存在,则跳过该警报器
|
||||||
|
|
||||||
// 构造子区域节点
|
// 构造2级区域节点
|
||||||
if (!areaNode.children?.find((subAreaNode) => subAreaNode.key === `${alarmSiteCode}${alarmAreaCode}`)) {
|
if (!targetMainAreaNode.children?.find((subAreaNode) => subAreaNode.key === `${alarmSiteCode}${alarmAreaCode}`)) {
|
||||||
let subArea: CodeArea['subs'][number] | undefined = undefined;
|
let subArea: CodeArea['subs'][number] | undefined = undefined;
|
||||||
if (alarmSiteType === 'station') {
|
if (alarmSiteType === 'station') {
|
||||||
subArea = codeStationAreas.find((area) => area.code === alarmMainAreaCode)?.subs.find((subArea) => subArea.code === alarmAreaCode);
|
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 },
|
stats: { online: 0, offline: 0, total: 0 },
|
||||||
site: site,
|
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; // 如果子区域节点不存在,则跳过该警报器
|
if (!subAreaNode) continue; // 如果子区域节点不存在,则跳过该警报器
|
||||||
|
|
||||||
// 构造警报器节点
|
// 构造警报器节点
|
||||||
@@ -141,16 +141,16 @@ export const useAlarmStore = defineStore('vimp-alarm', () => {
|
|||||||
|
|
||||||
// 统计站点、区域、子区域的在线/离线/总警报器数量
|
// 统计站点、区域、子区域的在线/离线/总警报器数量
|
||||||
siteNode.stats.total++;
|
siteNode.stats.total++;
|
||||||
areaNode.stats.total++;
|
targetMainAreaNode.stats.total++;
|
||||||
subAreaNode.stats.total++;
|
subAreaNode.stats.total++;
|
||||||
if (alarm.status === 1) {
|
if (alarm.status === 1) {
|
||||||
siteNode.stats.online++;
|
siteNode.stats.online++;
|
||||||
areaNode.stats.online++;
|
targetMainAreaNode.stats.online++;
|
||||||
subAreaNode.stats.online++;
|
subAreaNode.stats.online++;
|
||||||
}
|
}
|
||||||
if (alarm.status === 0) {
|
if (alarm.status === 0) {
|
||||||
siteNode.stats.offline++;
|
siteNode.stats.offline++;
|
||||||
areaNode.stats.offline++;
|
targetMainAreaNode.stats.offline++;
|
||||||
subAreaNode.stats.offline++;
|
subAreaNode.stats.offline++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import type { VimpChannel, VimpStation } from '../api';
|
import type { VimpChannel, VimpStation } from '../apis';
|
||||||
import { h, ref } from 'vue';
|
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 {
|
interface BuildLineTabPanesParams {
|
||||||
sites: VimpStation[] | null;
|
sites: VimpStation[] | null;
|
||||||
@@ -79,22 +79,22 @@ export const useCameraStore = defineStore('vimp-camera', () => {
|
|||||||
}
|
}
|
||||||
if (!siteArea) continue; // 如果还是未找到区域,则跳过该摄像机
|
if (!siteArea) continue; // 如果还是未找到区域,则跳过该摄像机
|
||||||
|
|
||||||
// 构造区域节点
|
// 构造1级区域节点
|
||||||
if (!siteNode.children?.find((areaNode) => areaNode.key === `${cameraSiteCode}${cameraMainAreaCode}`)) {
|
if (!siteNode.children?.find((areaNode) => areaNode.key === `${cameraSiteCode}${cameraMainAreaCode}`)) {
|
||||||
const areaNode: CameraAreaNodeOption = {
|
const mainAreaNode: CameraMainAreaNodeOption = {
|
||||||
key: `${cameraSiteCode}${cameraMainAreaCode}`,
|
key: `${cameraSiteCode}${cameraMainAreaCode}`,
|
||||||
label: siteArea.name,
|
label: siteArea.name,
|
||||||
children: [],
|
children: [],
|
||||||
stats: { online: 0, offline: 0, total: 0 },
|
stats: { online: 0, offline: 0, total: 0 },
|
||||||
site: site,
|
site: site,
|
||||||
};
|
};
|
||||||
siteNode.children?.push(areaNode);
|
siteNode.children?.push(mainAreaNode);
|
||||||
}
|
}
|
||||||
const areaNode = siteNode.children?.find((areaNode) => areaNode.key === `${cameraSiteCode}${cameraMainAreaCode}`);
|
const targetMainAreaNode = siteNode.children?.find((areaNode) => areaNode.key === `${cameraSiteCode}${cameraMainAreaCode}`);
|
||||||
if (!areaNode) continue; // 如果区域节点不存在,则跳过该摄像机
|
if (!targetMainAreaNode) continue; // 如果1级区域节点不存在,则跳过该摄像机
|
||||||
|
|
||||||
// 构造子区域节点
|
// 构造2级区域节点
|
||||||
if (!areaNode.children?.find((subAreaNode) => subAreaNode.key === `${cameraSiteCode}${cameraAreaCode}`)) {
|
if (!targetMainAreaNode.children?.find((subAreaNode) => subAreaNode.key === `${cameraSiteCode}${cameraAreaCode}`)) {
|
||||||
let subArea: CodeArea['subs'][number] | undefined = undefined;
|
let subArea: CodeArea['subs'][number] | undefined = undefined;
|
||||||
if (cameraSiteType === 'station') {
|
if (cameraSiteType === 'station') {
|
||||||
subArea = codeStationAreas.find((area) => area.code === cameraMainAreaCode)?.subs.find((subArea) => subArea.code === cameraAreaCode);
|
subArea = codeStationAreas.find((area) => area.code === cameraMainAreaCode)?.subs.find((subArea) => subArea.code === cameraAreaCode);
|
||||||
@@ -107,7 +107,7 @@ export const useCameraStore = defineStore('vimp-camera', () => {
|
|||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!subArea) continue; // 如果还是未找到子区域,则跳过该摄像机
|
if (!subArea) continue; // 如果还是未找到2级区域,则跳过该摄像机
|
||||||
|
|
||||||
const subAreaNode: CameraSubAreaNodeOption = {
|
const subAreaNode: CameraSubAreaNodeOption = {
|
||||||
key: `${cameraSiteCode}${cameraAreaCode}`,
|
key: `${cameraSiteCode}${cameraAreaCode}`,
|
||||||
@@ -116,9 +116,9 @@ export const useCameraStore = defineStore('vimp-camera', () => {
|
|||||||
stats: { online: 0, offline: 0, total: 0 },
|
stats: { online: 0, offline: 0, total: 0 },
|
||||||
site: site,
|
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; // 如果子区域节点不存在,则跳过该摄像机
|
if (!subAreaNode) continue; // 如果子区域节点不存在,则跳过该摄像机
|
||||||
|
|
||||||
// 构造摄像机节点
|
// 构造摄像机节点
|
||||||
@@ -143,16 +143,16 @@ export const useCameraStore = defineStore('vimp-camera', () => {
|
|||||||
|
|
||||||
// 统计站点、区域、子区域的在线/离线/总摄像机数量
|
// 统计站点、区域、子区域的在线/离线/总摄像机数量
|
||||||
siteNode.stats.total++;
|
siteNode.stats.total++;
|
||||||
areaNode.stats.total++;
|
targetMainAreaNode.stats.total++;
|
||||||
subAreaNode.stats.total++;
|
subAreaNode.stats.total++;
|
||||||
if (camera.status === 1) {
|
if (camera.status === 1) {
|
||||||
siteNode.stats.online++;
|
siteNode.stats.online++;
|
||||||
areaNode.stats.online++;
|
targetMainAreaNode.stats.online++;
|
||||||
subAreaNode.stats.online++;
|
subAreaNode.stats.online++;
|
||||||
}
|
}
|
||||||
if (camera.status === 0) {
|
if (camera.status === 0) {
|
||||||
siteNode.stats.offline++;
|
siteNode.stats.offline++;
|
||||||
areaNode.stats.offline++;
|
targetMainAreaNode.stats.offline++;
|
||||||
subAreaNode.stats.offline++;
|
subAreaNode.stats.offline++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
export * from './camera';
|
export * from './camera-store';
|
||||||
export * from './alarm';
|
export * from './alarm-store';
|
||||||
|
|||||||
@@ -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 { 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 SiteType = 'station' | 'parking' | 'occ' | 'train';
|
||||||
export type CodeLines = Record<string, { name: string; color: string }>;
|
export type CodeLines = Record<string, { name: string; color: string }>;
|
||||||
@@ -27,18 +27,30 @@ export interface CameraSubAreaNodeOption extends TreeOption {
|
|||||||
site: VimpStation;
|
site: VimpStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CameraAreaNodeOption extends TreeOption {
|
export interface CameraMainAreaNodeOption extends TreeOption {
|
||||||
children?: CameraSubAreaNodeOption[];
|
children?: CameraSubAreaNodeOption[];
|
||||||
stats: CountStats;
|
stats: CountStats;
|
||||||
site: VimpStation;
|
site: VimpStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CameraSiteNodeOption extends TreeOption {
|
export interface CameraSiteNodeOption extends TreeOption {
|
||||||
children?: CameraAreaNodeOption[];
|
children?: CameraMainAreaNodeOption[];
|
||||||
stats: CountStats;
|
stats: CountStats;
|
||||||
online: boolean;
|
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 {
|
export interface CameraLineTabPane extends TabPaneProps {
|
||||||
lineCode: string;
|
lineCode: string;
|
||||||
lineName: string;
|
lineName: string;
|
||||||
@@ -60,18 +72,30 @@ export interface AlarmSubAreaNodeOption extends TreeOption {
|
|||||||
site: VimpStation;
|
site: VimpStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AlarmAreaNodeOption extends TreeOption {
|
export interface AlarmMainAreaNodeOption extends TreeOption {
|
||||||
children?: AlarmSubAreaNodeOption[];
|
children?: AlarmSubAreaNodeOption[];
|
||||||
stats: CountStats;
|
stats: CountStats;
|
||||||
site: VimpStation;
|
site: VimpStation;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AlarmSiteNodeOption extends TreeOption {
|
export interface AlarmSiteNodeOption extends TreeOption {
|
||||||
children?: AlarmAreaNodeOption[];
|
children?: AlarmMainAreaNodeOption[];
|
||||||
stats: CountStats;
|
stats: CountStats;
|
||||||
online: boolean;
|
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 {
|
export interface AlarmLineTabPane extends TabPaneProps {
|
||||||
lineCode: string;
|
lineCode: string;
|
||||||
lineName: string;
|
lineName: string;
|
||||||
@@ -1 +1,2 @@
|
|||||||
export * from './tree';
|
export * from './axios';
|
||||||
|
export * from './device-tree';
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ const resourceTabPanes: ResourceTabPane[] = [
|
|||||||
{ name: 'alarm', tab: '警报器', component: AlarmTree },
|
{ name: 'alarm', tab: '警报器', component: AlarmTree },
|
||||||
];
|
];
|
||||||
|
|
||||||
const selectedDeviceGbCode = ref<[string]>(['']);
|
|
||||||
|
|
||||||
const onDragover = (event: DragEvent) => {
|
const onDragover = (event: DragEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
if (event.dataTransfer) {
|
if (event.dataTransfer) {
|
||||||
@@ -32,13 +30,11 @@ const onDrop = (event: DragEvent) => {
|
|||||||
const code = event.dataTransfer?.getData('code');
|
const code = event.dataTransfer?.getData('code');
|
||||||
if (!code) return;
|
if (!code) return;
|
||||||
const name = event.dataTransfer?.getData('name');
|
const name = event.dataTransfer?.getData('name');
|
||||||
selectedDeviceGbCode.value = [code];
|
|
||||||
window.$message.info(`播放:${JSON.stringify({ code, name })}`);
|
window.$message.info(`播放:${JSON.stringify({ code, name })}`);
|
||||||
} else if (type === 'alarm') {
|
} else if (type === 'alarm') {
|
||||||
const code = event.dataTransfer?.getData('code');
|
const code = event.dataTransfer?.getData('code');
|
||||||
if (!code) return;
|
if (!code) return;
|
||||||
const name = event.dataTransfer?.getData('name');
|
const name = event.dataTransfer?.getData('name');
|
||||||
selectedDeviceGbCode.value = [code];
|
|
||||||
window.$message.info(`查看警报器:${JSON.stringify({ code, name })}`);
|
window.$message.info(`查看警报器:${JSON.stringify({ code, name })}`);
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
@@ -51,7 +47,7 @@ const onDrop = (event: DragEvent) => {
|
|||||||
<NTabs :type="'line'" :placement="'left'" style="height: 100%">
|
<NTabs :type="'line'" :placement="'left'" style="height: 100%">
|
||||||
<NTabPane v-for="{ name: resourceName, tab: resourceTab, component } in resourceTabPanes" :key="resourceName" :tab="resourceTab" :name="resourceName">
|
<NTabPane v-for="{ name: resourceName, tab: resourceTab, component } in resourceTabPanes" :key="resourceName" :tab="resourceTab" :name="resourceName">
|
||||||
<template v-if="!!component">
|
<template v-if="!!component">
|
||||||
<component :is="component" v-model:selected-device-gb-code="selectedDeviceGbCode" />
|
<component :is="component" />
|
||||||
</template>
|
</template>
|
||||||
</NTabPane>
|
</NTabPane>
|
||||||
</NTabs>
|
</NTabs>
|
||||||
@@ -59,7 +55,6 @@ const onDrop = (event: DragEvent) => {
|
|||||||
<div style="flex: 1">
|
<div style="flex: 1">
|
||||||
<div style="height: 480px; background-color: #666; display: grid; place-items: center" @dragover="onDragover" @drop="onDrop">
|
<div style="height: 480px; background-color: #666; display: grid; place-items: center" @dragover="onDragover" @drop="onDrop">
|
||||||
<div>这里是播放器</div>
|
<div>这里是播放器</div>
|
||||||
<div>{{ selectedDeviceGbCode }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user