feat:以通道的方式展示摄像头
This commit is contained in:
1 parent
31c08dce72
commit
569ea04236
5 files changed
+390
-124
No files matched your search
@@ -22,6 +22,19 @@ export const getChannelPage = (query:any) => {
|
||||
})
|
||||
}
|
||||
|
||||
// 编码设备通道分页查询
|
||||
export const cameraChannelPage = (query: any) => {
|
||||
return request({
|
||||
url: '/admin/deviceChannel/cameraPage',
|
||||
method: 'post',
|
||||
data: query,
|
||||
params: {
|
||||
current: query.current,
|
||||
size: query.size,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getReplayList(data: any) {
|
||||
return request({
|
||||
url: '/admin/deviceChannel/getReplayList',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<camera-list />
|
||||
<camera-list show-channel-tab />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="baseDeviceCamera">
|
||||
|
||||
@@ -6,125 +6,249 @@
|
||||
:defaultTreeWidth="15" :nodeClickable="false" :resizable="!props.embedded"
|
||||
:filter-control="props.embedded ? 'segmented' : 'switch'">
|
||||
<template #default>
|
||||
<el-row shadow="hover" v-show="showSearch" class="ml10">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item style="width: 250px;" label="设备名" prop="deviceName">
|
||||
<el-input v-model="state.queryForm.deviceName" placeholder="请输入设备名" />
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 250px;" label="设备类型" prop="deviceCategory">
|
||||
<dict-select v-model="state.queryForm.deviceCategory" :options="device_category" />
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 250px;" label="状态" prop="isOnline">
|
||||
<dict-select v-model="state.queryForm.isOnline" :options="is_nline" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!hasFixedQuery('isSync')" style="width: 250px;" label="同步状态"
|
||||
prop="isSync">
|
||||
<dict-select v-model="state.queryForm.isSync" :options="is_sync" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
<!-- 设备/通道视图切换(仅作分段控制器,内容由下方 v-show 控制渲染) -->
|
||||
<el-tabs v-if="props.showChannelTab" v-model="activeTab" class="camera-list-tabs ml10">
|
||||
<el-tab-pane :label="deviceTabLabel" name="device" />
|
||||
<el-tab-pane :label="channelTabLabel" name="channel" />
|
||||
</el-tabs>
|
||||
|
||||
<!-- 设备视图 -->
|
||||
<div v-show="isDevicePaneVisible">
|
||||
<el-row shadow="hover" v-show="showSearch" class="ml10">
|
||||
<el-form :model="state.queryForm" ref="queryRef" :inline="true" @keyup.enter="getDataList">
|
||||
<el-form-item style="width: 250px;" label="设备名" prop="deviceName">
|
||||
<el-input v-model="state.queryForm.deviceName" placeholder="请输入设备名" />
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 250px;" label="设备类型" prop="deviceCategory">
|
||||
<dict-select v-model="state.queryForm.deviceCategory" :options="device_category" />
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 250px;" label="状态" prop="isOnline">
|
||||
<dict-select v-model="state.queryForm.isOnline" :options="is_nline" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!hasFixedQuery('isSync')" style="width: 250px;" label="同步状态"
|
||||
prop="isSync">
|
||||
<dict-select v-model="state.queryForm.isSync" :options="is_sync" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn')
|
||||
}}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button v-if="props.enableCrud" icon="folder-add" type="primary" class="ml10"
|
||||
@click="formDialogRef.openDialog()" v-auth="'admin_deviceManage_add'">
|
||||
新 增
|
||||
</el-button>
|
||||
<el-button icon="Refresh" @click="resetQuery">{{ $t('common.resetBtn') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button v-if="props.enableCrud" icon="folder-add" type="primary" class="ml10"
|
||||
@click="formDialogRef.openDialog()" v-auth="'admin_deviceManage_add'">
|
||||
新 增
|
||||
</el-button>
|
||||
<el-button v-if="props.enableCrud && hasAction('delete')" plain :disabled="multiple"
|
||||
icon="Delete" type="primary" v-auth="'admin_deviceManage_del'"
|
||||
@click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<el-button v-if="props.enableCrud" plain icon="upload-filled" class="ml10"
|
||||
@click="uploadExcelRef.show()">
|
||||
导 入
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch"
|
||||
:export="props.enableCrud || props.enableExport ? 'admin_deviceManage_export' : false"
|
||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
||||
@queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" border :cell-style="tableStyle.cellStyle"
|
||||
:header-cell-style="tableStyle.headerCellStyle" @selection-change="selectionChangHandle"
|
||||
@sort-change="sortChangeHandle">
|
||||
<el-table-column v-if="props.enableCrud && hasAction('delete')" type="selection" width="40"
|
||||
align="center" />
|
||||
<el-table-column type="index" label="#" width="80" />
|
||||
<el-table-column prop="deviceCode" align="left" min-width="100" label="设备编码" />
|
||||
<el-table-column prop="deviceName" align="left" min-width="150" label="设备名称" />
|
||||
<el-table-column prop="deviceIp" align="left" min-width="150" label="ip" />
|
||||
<el-table-column prop="devicePort" align="left" min-width="100" label="端口" />
|
||||
<el-table-column prop="deviceCategory" align="left" min-width="150" label="设备大类">
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="device_category" :value="row.deviceCategory" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceManufacturer" align="left" min-width="100" label="厂商类型">
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="dh_device_manufacturer" :value="row.deviceManufacturer" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="orgName" align="left" min-width="150" label="设备所属组织" />
|
||||
<el-table-column prop="isOnline" align="left" min-width="120" label="状态">
|
||||
<template #default="{ row }">
|
||||
<tag-online :isOnline="row.isOnline == 1" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isSync" align="left" min-width="120" label="同步状态">
|
||||
<template #default="{ row }">
|
||||
<tag-sync :isSync="row.isSync == 1" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="offlineReason" align="left" min-width="120" label="离线原因">
|
||||
<template #default="{ row }">
|
||||
{{ row.offlineReason }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="hasRowActions" label="操作" fixed="right" :width="actionColumnWidth">
|
||||
<template #default="{ row }">
|
||||
<div class="grid grid-cols-3 gap-2 w-full">
|
||||
<el-button v-if="hasAction('detail')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="InfoFilled" text type="primary" @click="toDetail(row)">
|
||||
详情
|
||||
<el-button v-if="props.enableCrud && hasAction('delete')" plain :disabled="multiple"
|
||||
icon="Delete" type="primary" v-auth="'admin_deviceManage_del'"
|
||||
@click="handleDelete(selectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<el-button v-if="props.enableCrud" plain icon="upload-filled" class="ml10"
|
||||
@click="uploadExcelRef.show()">
|
||||
导 入
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch"
|
||||
:export="props.enableCrud || props.enableExport ? 'admin_deviceManage_export' : false"
|
||||
@exportExcel="exportExcel" class="ml10 mr20" style="float: right;"
|
||||
@queryTable="getDataList"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="state.dataList" v-loading="state.loading" border
|
||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="selectionChangHandle" @sort-change="sortChangeHandle">
|
||||
<el-table-column v-if="props.enableCrud && hasAction('delete')" type="selection" width="40"
|
||||
align="center" />
|
||||
<el-table-column type="index" label="#" width="80" />
|
||||
<el-table-column prop="deviceCode" align="left" min-width="100" label="设备编码" />
|
||||
<el-table-column prop="deviceName" align="left" min-width="150" label="设备名称" />
|
||||
<el-table-column prop="deviceIp" align="left" min-width="150" label="ip" />
|
||||
<el-table-column prop="devicePort" align="left" min-width="100" label="端口" />
|
||||
<el-table-column prop="deviceCategory" align="left" min-width="150" label="设备大类">
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="device_category" :value="row.deviceCategory" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="deviceManufacturer" align="left" min-width="100" label="厂商类型">
|
||||
<template #default="{ row }">
|
||||
<dict-tag :options="dh_device_manufacturer" :value="row.deviceManufacturer" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="orgName" align="left" min-width="150" label="设备所属组织" />
|
||||
<el-table-column prop="isOnline" align="left" min-width="120" label="状态">
|
||||
<template #default="{ row }">
|
||||
<tag-online :isOnline="row.isOnline == 1" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isSync" align="left" min-width="120" label="同步状态">
|
||||
<template #default="{ row }">
|
||||
<tag-sync :isSync="row.isSync == 1" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="offlineReason" align="left" min-width="120" label="离线原因">
|
||||
<template #default="{ row }">
|
||||
{{ row.offlineReason }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="hasRowActions" label="操作" fixed="right" :width="actionColumnWidth">
|
||||
<template #default="{ row }">
|
||||
<div class="grid grid-cols-3 gap-2 w-full">
|
||||
<el-button v-if="hasAction('detail')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="InfoFilled" text type="primary" @click="toDetail(row)">
|
||||
详情
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('preview')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="VideoPlay" text type="primary"
|
||||
@click="previewVideoRef.openDialog('device', row.id)">
|
||||
预览
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('replay')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="VideoCamera" text type="primary"
|
||||
@click="replayVideoDialogRef.openDialog('device', row.deviceCode)">
|
||||
回放
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('edit')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="edit-pen" text type="primary" v-auth="'admin_deviceManage_edit'"
|
||||
@click="formDialogRef.openDialog(row.id)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('delete')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="delete" text type="primary" v-auth="'admin_deviceManage_del'"
|
||||
@click="handleDelete([row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle"
|
||||
v-bind="state.pagination" />
|
||||
</div>
|
||||
|
||||
<!-- 通道视图(首次切换时才渲染并加载) -->
|
||||
<div v-if="channelInited" v-show="isChannelPaneVisible">
|
||||
<el-row shadow="hover" v-show="showSearch" class="ml10">
|
||||
<el-form :model="channelState.queryForm" ref="channelQueryRef" :inline="true"
|
||||
@keyup.enter="getChannelDataList">
|
||||
<el-form-item style="width: 250px;" label="通道名称" prop="channelName">
|
||||
<el-input v-model="channelState.queryForm.channelName" placeholder="请输入通道名称" />
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 250px;" label="所属设备" prop="deviceName">
|
||||
<el-input v-model="channelState.queryForm.deviceName" placeholder="请输入设备名" />
|
||||
</el-form-item>
|
||||
<el-form-item style="width: 250px;" label="状态" prop="isOnline">
|
||||
<dict-select v-model="channelState.queryForm.isOnline" :options="is_nline" />
|
||||
</el-form-item>
|
||||
<el-form-item v-if="!hasFixedQuery('isSync')" style="width: 250px;" label="同步状态"
|
||||
prop="isSync">
|
||||
<dict-select v-model="channelState.queryForm.isSync" :options="is_sync" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button icon="search" type="primary" @click="getChannelDataList">
|
||||
{{ $t('common.queryBtn') }}
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('preview')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="VideoPlay" text type="primary"
|
||||
@click="previewVideoRef.openDialog(row.id)">
|
||||
预览
|
||||
<el-button icon="Refresh" @click="resetChannelQuery">{{ $t('common.resetBtn') }}
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('replay')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="VideoCamera" text type="primary"
|
||||
@click="replayVideoDialogRef.openDialog('device', row.deviceCode)">
|
||||
回放
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('edit')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="edit-pen" text type="primary" v-auth="'admin_deviceManage_edit'"
|
||||
@click="formDialogRef.openDialog(row.id)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('delete')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="delete" text type="primary" v-auth="'admin_deviceManage_del'"
|
||||
@click="handleDelete([row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle"
|
||||
v-bind="state.pagination" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-row>
|
||||
<el-row>
|
||||
<div class="mb8" style="width: 100%">
|
||||
<el-button v-if="props.enableCrud && hasAction('delete')" plain
|
||||
:disabled="channelMultiple" icon="Delete" type="primary" class="ml10"
|
||||
v-auth="'admin_deviceChannel_del'" @click="handleChannelDelete(channelSelectObjs)">
|
||||
删除
|
||||
</el-button>
|
||||
<right-toolbar v-model:showSearch="showSearch" @queryTable="getChannelDataList"
|
||||
class="ml10 mr20" style="float: right;"></right-toolbar>
|
||||
</div>
|
||||
</el-row>
|
||||
<el-table :data="channelState.dataList" v-loading="channelState.loading" border
|
||||
:cell-style="tableStyle.cellStyle" :header-cell-style="tableStyle.headerCellStyle"
|
||||
@selection-change="channelSelectionChangHandle">
|
||||
<el-table-column v-if="props.enableCrud && hasAction('delete')" type="selection" width="40"
|
||||
align="center" />
|
||||
<el-table-column type="index" label="#" width="80" />
|
||||
<el-table-column prop="channelCode" align="left" min-width="180" label="通道编码" />
|
||||
<el-table-column prop="channelName" align="left" min-width="180" label="通道名称" />
|
||||
<el-table-column prop="deviceName" align="left" min-width="150" label="所属设备" />
|
||||
<el-table-column prop="cameraType" align="left" min-width="120" label="摄像头类型">
|
||||
<template #default="{ row }">
|
||||
<dict-tag v-if="row.cameraType" :options="camera_type" :value="row.cameraType" />
|
||||
<el-tag type="danger" v-else>未知</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="capability" align="left" min-width="200" label="通道能力">
|
||||
<template #default="{ row }">
|
||||
<div class="channel-capability-tags">
|
||||
<el-tag v-for="(v, i) in parseDeviceCapability(row.capability)" :key="i">
|
||||
{{ v }}
|
||||
</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="installLocation" align="left" min-width="180" label="当前所在位置">
|
||||
<template #default="{ row }">
|
||||
<div class="color-success" v-if="row.installLocation">{{ row.installLocation }}
|
||||
</div>
|
||||
<div class="color-danger" v-else>未安装</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isOnline" align="left" min-width="120" label="状态">
|
||||
<template #default="{ row }">
|
||||
<tag-online :isOnline="row.isOnline == 1" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="isSync" align="left" min-width="120" label="同步状态">
|
||||
<template #default="{ row }">
|
||||
<tag-sync :isSync="row.isSync == 1" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-if="hasChannelRowActions" label="操作" fixed="right"
|
||||
:width="channelActionColumnWidth">
|
||||
<template #default="{ row }">
|
||||
<div class="grid grid-cols-3 gap-2 w-full">
|
||||
<el-button v-if="hasAction('preview')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="VideoPlay" text type="primary"
|
||||
@click="previewVideoRef.openDialog('channel', row.channelCode)">
|
||||
预览
|
||||
</el-button>
|
||||
<el-button v-if="hasAction('replay')" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="VideoCamera" text type="primary"
|
||||
@click="replayVideoDialogRef.openDialog('channel', row.channelCode)">
|
||||
回放
|
||||
</el-button>
|
||||
<el-button v-if="props.enableCrud" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="edit-pen" text type="primary" v-auth="'admin_deviceChannel_edit'"
|
||||
@click="channelFormDialogRef.openDialog(row.id, row.deviceCode)">
|
||||
编辑
|
||||
</el-button>
|
||||
<el-button v-if="props.enableCrud" style="margin: 0;" class="!ml-0 w-full"
|
||||
icon="delete" text type="primary" v-auth="'admin_deviceChannel_del'"
|
||||
@click="handleChannelDelete([row.id])">
|
||||
删除
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<pagination @size-change="channelSizeChangeHandle" @current-change="channelCurrentChangeHandle"
|
||||
v-bind="channelState.pagination" />
|
||||
</div>
|
||||
</template>
|
||||
</draggable-org-Tree>
|
||||
|
||||
</div>
|
||||
<!-- 编辑、新增 -->
|
||||
<form-dialog v-if="props.enableCrud || hasAction('edit')" ref="formDialogRef" @refresh="getDataList(false)" />
|
||||
<!-- 通道编辑 -->
|
||||
<device-channer-form v-if="props.showChannelTab && props.enableCrud" ref="channelFormDialogRef"
|
||||
@refresh="getChannelDataList(false)" />
|
||||
<preview-video-dialog v-if="hasAction('preview')" ref="previewVideoRef" />
|
||||
<replay-video-dialog v-if="hasAction('replay')" ref="replayVideoDialogRef" />
|
||||
<upload-excel v-if="props.enableCrud" ref="uploadExcelRef" title="设备导入" url="/admin/deviceManage/read-excel"
|
||||
@@ -136,8 +260,10 @@
|
||||
import { useRouter } from "vue-router"
|
||||
import { BasicTableProps, useTable } from "/@/hooks/table";
|
||||
import * as DeviceManageApi from "/@/api/device/deviceManage";
|
||||
import * as DeviceChannelApi from "/@/api/device/deviceChannel";
|
||||
import { useMessage, useMessageBox } from "/@/hooks/message";
|
||||
import { useDict } from '/@/hooks/dict';
|
||||
import { parseDeviceCapability } from "/@/utils/dispose";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
type CameraAction = 'detail' | 'preview' | 'replay' | 'edit' | 'delete';
|
||||
@@ -148,39 +274,51 @@ const props = withDefaults(defineProps<{
|
||||
enableExport?: boolean;
|
||||
fixedQuery?: Record<string, any>;
|
||||
embedded?: boolean;
|
||||
showChannelTab?: boolean;
|
||||
}>(), {
|
||||
actions: () => ['detail', 'preview', 'replay', 'edit', 'delete'],
|
||||
enableCrud: true,
|
||||
enableExport: false,
|
||||
fixedQuery: () => ({}),
|
||||
embedded: false,
|
||||
showChannelTab: true,
|
||||
});
|
||||
|
||||
const hasAction = (action: CameraAction) => props.actions.includes(action);
|
||||
const hasFixedQuery = (key: string) => Object.prototype.hasOwnProperty.call(props.fixedQuery, key);
|
||||
const hasRowActions = computed(() => props.actions.length > 0);
|
||||
const actionColumnWidth = computed(() => props.actions.length > 3 ? 240 : 200);
|
||||
const hasChannelRowActions = computed(() => hasAction('preview') || hasAction('replay') || props.enableCrud);
|
||||
const channelActionColumnWidth = computed(() => {
|
||||
const count = [hasAction('preview'), hasAction('replay'), props.enableCrud, props.enableCrud].filter(Boolean).length;
|
||||
return count > 3 ? 240 : 200;
|
||||
});
|
||||
|
||||
// 引入组件
|
||||
const FormDialog = defineAsyncComponent(() => import("./deviceForm.vue"));
|
||||
const DeviceChannerForm = defineAsyncComponent(() => import("../detail/components/device-channer-form.vue"));
|
||||
const PreviewVideoDialog = defineAsyncComponent(() => import("./preview-video/preview-video-dialog.vue"));
|
||||
const ReplayVideoDialog = defineAsyncComponent(() => import("./replay-video/replay-video-dialog.vue"));
|
||||
|
||||
const { push } = useRouter()
|
||||
|
||||
// 定义查询字典
|
||||
const { device_category, is_sync, is_nline, dh_device_manufacturer } = useDict("device_category", "is_sync", "is_nline", "dh_device_manufacturer")
|
||||
const { device_category, is_sync, is_nline, dh_device_manufacturer, camera_type } = useDict("device_category", "is_sync", "is_nline", "dh_device_manufacturer", "camera_type")
|
||||
// 定义变量内容
|
||||
const formDialogRef = ref()
|
||||
const channelFormDialogRef = ref()
|
||||
const previewVideoRef = ref()
|
||||
const replayVideoDialogRef = ref()
|
||||
// 搜索变量
|
||||
const uploadExcelRef = ref()
|
||||
const queryRef = ref()
|
||||
const channelQueryRef = ref()
|
||||
const showSearch = ref(true)
|
||||
// 多选变量
|
||||
const selectObjs = ref([]) as any
|
||||
const multiple = ref(true)
|
||||
const channelSelectObjs = ref([]) as any
|
||||
const channelMultiple = ref(true)
|
||||
const draggableDepTreeRef = ref()
|
||||
|
||||
const state: BasicTableProps = reactive<BasicTableProps>({
|
||||
@@ -199,6 +337,38 @@ const {
|
||||
tableStyle
|
||||
} = useTable(state)
|
||||
|
||||
/* ------------------------- 通道视图 ------------------------- */
|
||||
const activeTab = ref('device')
|
||||
// 首次切换到通道 Tab 后才渲染内容,dirty 标记组织树等全局条件变化后待刷新
|
||||
const channelInited = ref(false)
|
||||
const channelDirty = ref(true)
|
||||
|
||||
const channelState: BasicTableProps = reactive<BasicTableProps>({
|
||||
createdIsNeed: false,
|
||||
queryForm: { ...props.fixedQuery, installLocation: true },
|
||||
pageList: (params: any) => DeviceChannelApi.cameraChannelPage({ ...params, ...props.fixedQuery, installLocation: true })
|
||||
})
|
||||
|
||||
const {
|
||||
getDataList: getChannelDataList,
|
||||
currentChangeHandle: channelCurrentChangeHandle,
|
||||
sizeChangeHandle: channelSizeChangeHandle,
|
||||
} = useTable(channelState)
|
||||
|
||||
const isDevicePaneVisible = computed(() => !props.showChannelTab || activeTab.value === 'device')
|
||||
const isChannelPaneVisible = computed(() => props.showChannelTab && activeTab.value === 'channel')
|
||||
const deviceTabLabel = computed(() => `设备 (${state.pagination?.total ?? 0})`)
|
||||
const channelTabLabel = computed(() => channelInited.value ? `通道 (${channelState.pagination?.total ?? 0})` : '通道')
|
||||
|
||||
watch(activeTab, (tab) => {
|
||||
if (tab !== 'channel') return
|
||||
channelInited.value = true
|
||||
if (channelDirty.value) {
|
||||
channelDirty.value = false
|
||||
getChannelDataList()
|
||||
}
|
||||
})
|
||||
|
||||
// 清空搜索条件
|
||||
const resetQuery = () => {
|
||||
// 清空搜索条件
|
||||
@@ -209,6 +379,15 @@ const resetQuery = () => {
|
||||
getDataList()
|
||||
}
|
||||
|
||||
// 清空通道搜索条件
|
||||
const resetChannelQuery = () => {
|
||||
channelQueryRef.value?.resetFields()
|
||||
channelSelectObjs.value = []
|
||||
channelMultiple.value = true
|
||||
draggableDepTreeRef.value.resetData()
|
||||
getChannelDataList()
|
||||
}
|
||||
|
||||
// 导出excel
|
||||
const exportExcel = () => {
|
||||
const timeSuffix = dayjs().format('YYYY-MM-DD_HH-mm-ss')
|
||||
@@ -225,6 +404,11 @@ const selectionChangHandle = (objs: { id: string }[]) => {
|
||||
multiple.value = !objs.length;
|
||||
};
|
||||
|
||||
const channelSelectionChangHandle = (objs: { id: string }[]) => {
|
||||
channelSelectObjs.value = objs.map(({ id }) => id);
|
||||
channelMultiple.value = !objs.length;
|
||||
};
|
||||
|
||||
const toDetail = (row: any) => {
|
||||
push({
|
||||
path: "/device/detail/index",
|
||||
@@ -234,12 +418,23 @@ const toDetail = (row: any) => {
|
||||
})
|
||||
}
|
||||
|
||||
// 树节点选择时
|
||||
// 树节点选择时:组织条件同步写入两个视图,刷新当前视图,另一视图置脏
|
||||
const handleGetSelectNode = (curClickedNode: any, checkedTreeNodes: any, isDeepTree: boolean) => {
|
||||
state.queryForm.ownerCode = curClickedNode.id
|
||||
state.queryForm.orgCodes = checkedTreeNodes.map((item: any) => item.id)
|
||||
state.queryForm.isInclude = !isDeepTree
|
||||
const orgQuery = {
|
||||
ownerCode: curClickedNode.id,
|
||||
orgCodes: checkedTreeNodes.map((item: any) => item.id),
|
||||
isInclude: !isDeepTree,
|
||||
}
|
||||
Object.assign(state.queryForm, orgQuery)
|
||||
Object.assign(channelState.queryForm, orgQuery)
|
||||
getDataList()
|
||||
if (props.showChannelTab) {
|
||||
if (isChannelPaneVisible.value) {
|
||||
getChannelDataList()
|
||||
} else if (channelInited.value) {
|
||||
channelDirty.value = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除操作
|
||||
@@ -258,6 +453,29 @@ const handleDelete = async (ids: string[]) => {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
|
||||
// 通道删除操作
|
||||
const handleChannelDelete = async (ids: string[]) => {
|
||||
if (!ids.length) {
|
||||
useMessage().warning('请先选择要删除的通道');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await useMessageBox().confirm('此操作将永久删除');
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await DeviceChannelApi.delObjs(ids);
|
||||
channelSelectObjs.value = []
|
||||
channelMultiple.value = true
|
||||
getChannelDataList();
|
||||
useMessage().success('删除成功');
|
||||
} catch (err: any) {
|
||||
useMessage().error(err.msg);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -273,4 +491,20 @@ const handleDelete = async (ids: string[]) => {
|
||||
padding: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.camera-list-tabs :deep(.el-tabs__header) {
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
|
||||
.camera-list-tabs :deep(.el-tabs__nav-wrap::after) {
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
.channel-capability-tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
@@ -35,8 +35,11 @@ import * as DeviceChannelApi from "/@/api/device/deviceChannel"
|
||||
|
||||
const previewVideoRef = ref()
|
||||
|
||||
const state = reactive({
|
||||
const state = reactive<any>({
|
||||
dialogVisible: false,
|
||||
// device-设备维度 code=设备id;channel-通道维度 code=通道编码
|
||||
type: "device",
|
||||
code: null,
|
||||
channelList: [],
|
||||
loading: false,
|
||||
treeLoading: false,
|
||||
@@ -57,12 +60,21 @@ const handleClose = () => {
|
||||
}
|
||||
|
||||
// 打开弹窗
|
||||
const openDialog = async (id: string) => {
|
||||
const openDialog = async (type: string, code: string) => {
|
||||
if (!type || !code) return
|
||||
state.type = type
|
||||
state.code = code
|
||||
state.dialogVisible = true
|
||||
// 获取deviceManage信息
|
||||
if (!id) return
|
||||
await getdeviceManageData(id)
|
||||
await getDeviceChannelList()
|
||||
if (state.type === "device") {
|
||||
// 获取deviceManage信息
|
||||
await getdeviceManageData(code)
|
||||
await getDeviceChannelList()
|
||||
return
|
||||
}
|
||||
if (state.type === "channel") {
|
||||
await getDeviceChannelList()
|
||||
return
|
||||
}
|
||||
};
|
||||
|
||||
const videoChangePage = async ({ current, size }: any) => {
|
||||
@@ -149,7 +161,14 @@ const getdeviceManageData = async (id: string) => {
|
||||
const getDeviceChannelList = async () => {
|
||||
state.treeLoading = true
|
||||
try {
|
||||
const { data, code } = await DeviceChannelApi.list({ deviceCode: detail.deviceCode })
|
||||
const _data: any = {}
|
||||
if (state.type == "device") {
|
||||
_data.deviceCode = detail.deviceCode
|
||||
}
|
||||
if (state.type == "channel") {
|
||||
_data.channelCode = state.code
|
||||
}
|
||||
const { data, code } = await DeviceChannelApi.list(_data)
|
||||
if (code != 0) throw new Error()
|
||||
channel.treeList = data
|
||||
channel.list = data
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<camera-list />
|
||||
<camera-list show-channel-tab />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" name="systemDeviceManage">
|
||||
|
||||
Reference in new issue
Block a user