|
|
@@ -1,569 +1,569 @@
|
|
|
-<template>
|
|
|
-<a-card>
|
|
|
- <template #title >
|
|
|
- <a-row>
|
|
|
- <a-col style="font-size: 20px;margin-right: 10px;" >设备管理</a-col>
|
|
|
- <a-col >
|
|
|
- <a-select
|
|
|
- :value="deviceState.spaceId"
|
|
|
- style="width: 170px;"
|
|
|
- @change="onChangeSpace"
|
|
|
- placeholder="请选择空间"
|
|
|
- allowClear
|
|
|
- >
|
|
|
- <a-select-option
|
|
|
- :key="index"
|
|
|
- :value="item.spaceId"
|
|
|
- v-for="(item, index) in state.spaceList"
|
|
|
- >
|
|
|
- {{item.spaceName}}
|
|
|
- </a-select-option>
|
|
|
- </a-select>
|
|
|
- </a-col>
|
|
|
- </a-row>
|
|
|
- </template>
|
|
|
- <table-pro
|
|
|
- ref="tableProDom"
|
|
|
- :service="SpaceController.devicePage"
|
|
|
- :serviceParams="{deviceName, spaceId: deviceState.spaceId}"
|
|
|
- :columns="columns"
|
|
|
- @add="openModal"
|
|
|
- >
|
|
|
- <template #search >
|
|
|
- <a-space><InputTsx placeholder="请输入设备名称进行搜索" v-model:value="deviceName" /> <a-button type="primary" @click="search">搜索</a-button> </a-space>
|
|
|
- </template>
|
|
|
-
|
|
|
- <template #render="{column, record}" >
|
|
|
-
|
|
|
- <template v-if="column.key === 'status'" >
|
|
|
- <div style="display: flex;align-items: center;" >
|
|
|
- <div :style="{width: '8px',height: '8px',borderRadius: '50%', backgroundColor:SpaceController.statusMap.get(record.status)?.color, marginRight: '5px' }" ></div>
|
|
|
- <div>{{SpaceController.deviceStatusMap.get(record.status)?.label}}</div>
|
|
|
- </div>
|
|
|
- </template>
|
|
|
-
|
|
|
- <template v-if="column.key === 'deviceId'">
|
|
|
- <a @click="baseInfo(record)">{{record.deviceId}}</a>
|
|
|
- </template>
|
|
|
-
|
|
|
- <template v-if="column.key === 'type'">
|
|
|
- <a-tag>{{SpaceController.type.find((item)=>{
|
|
|
- return item.key == record.type
|
|
|
- })?.label}}</a-tag>
|
|
|
- </template>
|
|
|
-
|
|
|
- <template v-if="column.key === 'action'" >
|
|
|
- <a-space>
|
|
|
- <a @click="baseInfo(record)">基本信息</a>
|
|
|
- <a @click="recordParty(record)">录像回放</a>
|
|
|
- <a @click="thumbParty(record)">截图查看</a>
|
|
|
- <a @click="arAnalysis(record)">AI分析</a>
|
|
|
- </a-space>
|
|
|
- </template>
|
|
|
- </template>
|
|
|
-
|
|
|
- </table-pro>
|
|
|
-</a-card>
|
|
|
-
|
|
|
-<RealView
|
|
|
- :open="state.activeVisible"
|
|
|
- @cancel="closeRealView"
|
|
|
- :tab-key="activeTabKey"
|
|
|
- :tabs-list="deviceTabs"
|
|
|
- @tab-chang="key => onTabChange(key)"
|
|
|
->
|
|
|
- <!-- 个人基础信息 -->
|
|
|
- <div v-if="activeTabKey === 'base'" >
|
|
|
- <a-card title="基本信息" >
|
|
|
- <template #extra >
|
|
|
- <a-button type="primary" @click="ok" >提交修改</a-button>
|
|
|
- </template>
|
|
|
- <a-form style="width: 100%;" :labelCol="{span: 3}" :wrapperCol="{span: 14}" >
|
|
|
- <a-form-item label="设备名称" v-bind="validateInfos.deviceName" >
|
|
|
- <InputTsx allowClear placeholder="请输入设备名称" v-model:value="deviceState.deviceName" />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="app" v-bind="validateInfos.app" >
|
|
|
- <InputTsx allowClear placeholder="请输入英文、数字组成的app" v-model:value="deviceState.app" />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="stream" v-bind="validateInfos.stream" >
|
|
|
- <InputTsx allowClear placeholder="请输入英文、数字组成的stream" v-model:value="deviceState.stream" />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="空间名称" v-bind="validateInfos.stream" >
|
|
|
- <a-select
|
|
|
- :value="spaceId"
|
|
|
- style="width: 170px;"
|
|
|
- @change="onChangeSpace"
|
|
|
- placeholder="请选择空间"
|
|
|
- >
|
|
|
- <a-select-option
|
|
|
- :key="index"
|
|
|
- :value="item.spaceId"
|
|
|
- v-for="(item, index) in state.spaceList"
|
|
|
- >
|
|
|
- {{item.spaceName}}
|
|
|
- </a-select-option>
|
|
|
- </a-select>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="设备类型" >
|
|
|
- <a-radio-group v-model:value="deviceState.type" button-style="solid">
|
|
|
- <a-radio-button
|
|
|
- v-for="item in SpaceController.type"
|
|
|
- :key="item.key"
|
|
|
- :value="item.value"
|
|
|
- >
|
|
|
- {{item.label}}
|
|
|
- </a-radio-button>
|
|
|
- </a-radio-group>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="设备地址" >
|
|
|
- <InputTsx allowClear placeholder="请输入设备地址" v-model:value="deviceState.gisName" />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="拉流地址" v-if="['PULL_RTMP', 'PULL_RTSP'].includes(deviceState.type)" >
|
|
|
- <InputTsx v-model:value="deviceState.pullPath" placeholder="请输入拉流地址" />
|
|
|
- </a-form-item>
|
|
|
- <span v-if="deviceState.type === 'GB28181'">
|
|
|
- <a-form-item label="国标Id" >
|
|
|
- <InputTsx v-model:value="deviceState.gbConfig.gbId" placeholder="请输入拉流地址" />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="用户名" >
|
|
|
- <InputTsx v-model:value="deviceState.gbConfig.username" placeholder="请输入用户名"/>
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="用户密码" >
|
|
|
- <InputTsx v-model:value="deviceState.gbConfig.password" placeholder="请输入用户密码" />
|
|
|
- </a-form-item>
|
|
|
- <a-form-item label="国标平台" >
|
|
|
- <a-radio-group v-model:value="deviceState.gbConfig.platform" button-style="solid">
|
|
|
- <a-radio-button value="IPC">IPC</a-radio-button>
|
|
|
- <a-radio-button value="NVR">NVR</a-radio-button>
|
|
|
- </a-radio-group>
|
|
|
- </a-form-item>
|
|
|
- </span>
|
|
|
- <a-form-item label="设备描述" >
|
|
|
- <a-textarea v-model:value="deviceState.description" placeholder="请输入设备描述" :rows="4" />
|
|
|
- </a-form-item>
|
|
|
- </a-form>
|
|
|
- </a-card>
|
|
|
- <a-card v-if="operator === 'preview'" title="推播流地址" style="margin-top: 20px;" >
|
|
|
- <!-- 非国标设备 -->
|
|
|
- <a-row :gutter="[8, 18]" >
|
|
|
- <a-col :span="24">
|
|
|
- <a-row>
|
|
|
- <a-col :span="4">
|
|
|
- 请选择转码模版:
|
|
|
- </a-col>
|
|
|
- <a-col>
|
|
|
- <a-space>
|
|
|
- <a-select style="width: 170px;" >
|
|
|
- <a-select-option key="2" >原始流</a-select-option>
|
|
|
- </a-select>
|
|
|
- <a-button>获取最新地址</a-button>
|
|
|
- </a-space>
|
|
|
- </a-col>
|
|
|
- </a-row>
|
|
|
- </a-col>
|
|
|
- <!-- 推流地址 -->
|
|
|
- <a-col :span="24">
|
|
|
- <a-row>
|
|
|
- <a-col :span="2" >推流地址</a-col>
|
|
|
- <a-col>
|
|
|
- <div v-for="item in gbState.pushList" :key="item" >{{item}}</div>
|
|
|
- </a-col>
|
|
|
- </a-row>
|
|
|
- </a-col>
|
|
|
- <!-- 播放地址 -->
|
|
|
- <a-col :span="24">
|
|
|
- <a-row>
|
|
|
- <a-col :span="2" >播放地址</a-col>
|
|
|
- <a-col >
|
|
|
- <div v-for="item in gbState.pullList" :key="item" >{{item}}</div>
|
|
|
- </a-col>
|
|
|
- </a-row>
|
|
|
- </a-col>
|
|
|
- </a-row>
|
|
|
- </a-card>
|
|
|
- </div>
|
|
|
- <a-card style="background-color: #fff;width: 100%;" v-if="activeTabKey !== 'base'" >
|
|
|
- <a-space >
|
|
|
- <a-range-picker v-model:value="deviceActionParams.times" />
|
|
|
- <a-select style="width: 170px;" v-if="activeTabKey === 'record'" v-model:value="deviceActionParams.recordFormat" >
|
|
|
- <a-select-option v-for="item in SpaceController.recordFormat" :key="item" :value="item" >
|
|
|
- {{item}}
|
|
|
- </a-select-option>
|
|
|
- </a-select>
|
|
|
- <a-select style="width: 170px;" v-if="activeTabKey === 'ai'" v-model:value="deviceActionParams.aiId" >
|
|
|
- <a-select-option v-for="item in state.aiList" :key="item.aiId" :value="item.aiId" >
|
|
|
- {{item.aiName}}
|
|
|
- </a-select-option>
|
|
|
- </a-select>
|
|
|
- <a-button type="primary" @click="searchDevice">搜索</a-button>
|
|
|
- </a-space>
|
|
|
- </a-card>
|
|
|
-
|
|
|
- <!-- 视频 图片区域 -->
|
|
|
- <a-spin :spinning="state.loading" v-if="activeTabKey !== 'base'">
|
|
|
- <a-row :gutter="[8, 8]" style="margin-top: 20px;background-color: #fff;padding: 18px;padding-bottom: 38px;" >
|
|
|
- <a-col :span="4" v-for="item in state.deviceMediaList" :key="item" >
|
|
|
- <div class="media-card">
|
|
|
- <video
|
|
|
- v-if="activeTabKey === 'record'"
|
|
|
- controls
|
|
|
- :src="item.defaultUrl"
|
|
|
- ></video>
|
|
|
- <div v-else-if="activeTabKey === 'thumb'" >
|
|
|
- <a-image
|
|
|
- width="100%"
|
|
|
- height="150px"
|
|
|
- style="object-fit: cover;display: block;"
|
|
|
- :src="item.defaultUrl"
|
|
|
- />
|
|
|
- </div>
|
|
|
- <div v-else-if="activeTabKey === 'ai'" style="height: 150px;" >
|
|
|
- <a-image width="100%" height="150px" style="object-fit: cover;display: block;" :src="item.defaultUrl"></a-image>
|
|
|
- </div>
|
|
|
- <div class="craete-time">{{dayjs(item.ts).format('YYYY/MM/DD HH:mm:ss')}}</div>
|
|
|
- </div>
|
|
|
- </a-col>
|
|
|
- </a-row>
|
|
|
- </a-spin>
|
|
|
-
|
|
|
-</RealView>
|
|
|
-
|
|
|
-</template>
|
|
|
-<script lang='ts' setup >
|
|
|
-import { InputTsx } from '@/components/MicroComponents/index'
|
|
|
-import { reactive, onMounted, nextTick, ref, watch } from 'vue'
|
|
|
-import { Form } from 'ant-design-vue'
|
|
|
-import { OperatorController, SpaceController } from '@/controller'
|
|
|
-import { useRoute } from 'vue-router'
|
|
|
-import dayjs from 'dayjs'
|
|
|
-import { RealView } from '@/components/RealView/index'
|
|
|
-
|
|
|
-const columns = [
|
|
|
- {
|
|
|
- title: '设备ID',
|
|
|
- dataIndex: 'deviceId',
|
|
|
- key: 'deviceId'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '设备名称',
|
|
|
- dataIndex: 'deviceName',
|
|
|
- key: 'deviceName'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '空间类型',
|
|
|
- dataIndex: 'type',
|
|
|
- key: 'type'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '描述',
|
|
|
- dataIndex: 'description',
|
|
|
- key: 'description'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '状态',
|
|
|
- dataIndex: 'status',
|
|
|
- key: 'status'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '操作',
|
|
|
- dataIndex: 'action',
|
|
|
- key: 'action'
|
|
|
- }
|
|
|
-]
|
|
|
-
|
|
|
-const _spaceId = useRoute().query.spaceId
|
|
|
-
|
|
|
-const useForm = Form.useForm
|
|
|
-
|
|
|
-const spaceId = ref(null)
|
|
|
-
|
|
|
-const deviceName = ref(null)
|
|
|
-
|
|
|
-const tableProDom = ref()
|
|
|
-
|
|
|
-const activeTabKey = ref<'base' | 'record' | 'thumb' | 'ai'>('base')
|
|
|
-
|
|
|
-const operator = ref<'add' | 'preview'>('add')
|
|
|
-
|
|
|
-const deviceTabs = [
|
|
|
- { key: 'base', tab: '基础信息' },
|
|
|
- { key: 'record', tab: '录像回放' },
|
|
|
- { key: 'thumb', tab: '截图查看' },
|
|
|
- { key: 'ai', tab: 'AI分析' }
|
|
|
-]
|
|
|
-
|
|
|
-const recordColumn = [
|
|
|
- {
|
|
|
- title: '录制格式',
|
|
|
- dataIndex: 'extra',
|
|
|
- key: 'extra'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '录制时间',
|
|
|
- dataIndex: 'ts',
|
|
|
- key: 'ts'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '可播放地址',
|
|
|
- dataIndex: 'defaultUrl',
|
|
|
- key: 'defaultUrl'
|
|
|
- }
|
|
|
-]
|
|
|
-
|
|
|
-const thumbColumn = [
|
|
|
- {
|
|
|
- title: '截图地址',
|
|
|
- dataIndex: 'defaultUrl',
|
|
|
- key: 'defaultUrl'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '截图时间',
|
|
|
- dataIndex: 'ts',
|
|
|
- key: 'ts'
|
|
|
- }
|
|
|
-]
|
|
|
-
|
|
|
-const aiColumn = [
|
|
|
- {
|
|
|
- title: '算子模型id',
|
|
|
- dataIndex: 'extra',
|
|
|
- key: 'extra'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '结果地址',
|
|
|
- dataIndex: 'defaultUrl',
|
|
|
- key: 'defaultUrl'
|
|
|
- },
|
|
|
- {
|
|
|
- title: '时间',
|
|
|
- dataIndex: 'ts',
|
|
|
- key: 'ts'
|
|
|
- }
|
|
|
-]
|
|
|
-
|
|
|
-const deviceActionMap = new Map([
|
|
|
- ['record', { get: SpaceController.deviceRecordById, column: recordColumn }],
|
|
|
- ['thumb', { get: SpaceController.deviceThumbById, column: thumbColumn }],
|
|
|
- ['ai', { get: SpaceController.deviceAiRetById, column: aiColumn }]
|
|
|
-])
|
|
|
-
|
|
|
-const state = reactive<{
|
|
|
- visible: boolean,
|
|
|
- activeVisible: boolean,
|
|
|
- spaceList: CVS.space[]
|
|
|
- deviceMediaList: any[],
|
|
|
- aiList: CVS.Operator[]
|
|
|
- loading: boolean
|
|
|
-}>({
|
|
|
- visible: false,
|
|
|
- activeVisible: false,
|
|
|
- spaceList: [],
|
|
|
- deviceMediaList: [],
|
|
|
- aiList: [],
|
|
|
- loading: false
|
|
|
-})
|
|
|
-
|
|
|
-const gbState = reactive<{
|
|
|
- channelList: string[]
|
|
|
- pullList: string[],
|
|
|
- gbPullList: string[]
|
|
|
- pushList: string[]
|
|
|
-}>({
|
|
|
- channelList: [],
|
|
|
- pullList: [],
|
|
|
- gbPullList: [],
|
|
|
- pushList: []
|
|
|
-})
|
|
|
-
|
|
|
-const deviceActionParams = reactive({
|
|
|
- times: [],
|
|
|
- startTs: '',
|
|
|
- endTs: '',
|
|
|
- recordFormat: '',
|
|
|
- deviceId: '',
|
|
|
- page: 1,
|
|
|
- pageSize: 10,
|
|
|
- aiId: null
|
|
|
-})
|
|
|
-
|
|
|
-const deviceState = reactive({
|
|
|
- deviceId: '',
|
|
|
- spaceId: null,
|
|
|
- deviceName: '',
|
|
|
- app: '',
|
|
|
- stream: '',
|
|
|
- description: '',
|
|
|
- deviceStreamId: '',
|
|
|
- gisLongitude: '',
|
|
|
- gisLatitude: '',
|
|
|
- gisName: '',
|
|
|
- type: 'RTMP',
|
|
|
- pullPath: '',
|
|
|
- gbConfig: {
|
|
|
- gbId: '',
|
|
|
- username: '',
|
|
|
- password: '',
|
|
|
- platform: 'IPC'
|
|
|
- }
|
|
|
-})
|
|
|
-
|
|
|
-watch(
|
|
|
- () => activeTabKey.value,
|
|
|
- () => {
|
|
|
- activeTabKey.value !== 'base' && getMedia()
|
|
|
- }
|
|
|
-)
|
|
|
-
|
|
|
-watch(
|
|
|
- () => deviceActionParams.times,
|
|
|
- () => {
|
|
|
- deviceActionParams.startTs = dayjs(deviceActionParams.times[0]).unix() as unknown as string
|
|
|
- deviceActionParams.endTs = dayjs(deviceActionParams.times[0]).unix() as unknown as string
|
|
|
- }
|
|
|
-)
|
|
|
-
|
|
|
-watch(
|
|
|
- () => deviceState.deviceId,
|
|
|
- () => {
|
|
|
- if (deviceState.gbConfig && deviceState.gbConfig.gbId) {
|
|
|
- getDeviceChannel()
|
|
|
- getGbPull()
|
|
|
- } else {
|
|
|
- getNotGbPush()
|
|
|
- getNotGbPull()
|
|
|
- }
|
|
|
- }
|
|
|
-)
|
|
|
-
|
|
|
-const { resetFields, validate, validateInfos } = useForm(deviceState, {
|
|
|
- deviceName: [{ required: true, message: '请填写设备名称' }],
|
|
|
- app: [{ required: true, message: '请填写app名称' }],
|
|
|
- stream: [{ required: true, message: '请填写stream名称' }]
|
|
|
-})
|
|
|
-
|
|
|
-const searchDevice = () => getMedia()
|
|
|
-
|
|
|
-const onTabChange = (key: 'record' | 'thumb' | 'ai') => activeTabKey.value = key
|
|
|
-
|
|
|
-const getMedia = async () => {
|
|
|
- state.loading = true
|
|
|
- const { data, sum } = await deviceActionMap.get(activeTabKey.value)?.get({ ...deviceActionParams, deviceId: deviceState.deviceId } as any)
|
|
|
- state.loading = false
|
|
|
- state.deviceMediaList = data
|
|
|
- console.log(state.deviceMediaList)
|
|
|
-}
|
|
|
-
|
|
|
-const ok = () => {
|
|
|
- validate().then(async () => {
|
|
|
- deviceState.deviceStreamId = deviceState.app + '/' + deviceState.stream
|
|
|
- await SpaceController.addDevice(deviceState as unknown as CVS.device)
|
|
|
- closeModal()
|
|
|
- tableProDom.value.reload()
|
|
|
- }).catch(() => {})
|
|
|
-}
|
|
|
-
|
|
|
-// 获取设备通道
|
|
|
-const getDeviceChannel = async () => {
|
|
|
- gbState.channelList = (await SpaceController.deviceChannel(deviceState.deviceId))!
|
|
|
-}
|
|
|
-
|
|
|
-const getGbPull = async () => {
|
|
|
- gbState.gbPullList = (await SpaceController.gbPull(deviceState.deviceId))!
|
|
|
-}
|
|
|
-
|
|
|
-const getNotGbPush = async () => {
|
|
|
- gbState.pushList = (await SpaceController.notGBPush(deviceState.deviceId))!
|
|
|
-}
|
|
|
-
|
|
|
-const getNotGbPull = async () => {
|
|
|
- gbState.pullList = await SpaceController.notGbPull(deviceState.deviceId)
|
|
|
-}
|
|
|
-
|
|
|
-const baseInfo = (record: CVS.device) => {
|
|
|
- activeTabKey.value = 'base'
|
|
|
- nextTick(() => {
|
|
|
- state.activeVisible = true
|
|
|
- console.log(record)
|
|
|
- resetFields({ ...record })
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-const recordParty = async (record: CVS.device) => {
|
|
|
- state.activeVisible = true
|
|
|
- resetFields({ ...record })
|
|
|
- deviceActionParams.deviceId = record.deviceId as unknown as string
|
|
|
- activeTabKey.value = 'record'
|
|
|
- getMedia()
|
|
|
-}
|
|
|
-
|
|
|
-const thumbParty = (record: CVS.device) => {
|
|
|
- state.activeVisible = true
|
|
|
- resetFields({ ...record })
|
|
|
- deviceActionParams.deviceId = record.deviceId as unknown as string
|
|
|
- activeTabKey.value = 'thumb'
|
|
|
- getMedia()
|
|
|
-}
|
|
|
-
|
|
|
-const arAnalysis = (record: CVS.device) => {
|
|
|
- state.activeVisible = true
|
|
|
- resetFields({ ...record })
|
|
|
- deviceActionParams.deviceId = record.deviceId as unknown as string
|
|
|
- activeTabKey.value = 'ai'
|
|
|
- getMedia()
|
|
|
-}
|
|
|
-
|
|
|
-const onChangeSpace = (spaceId: string) => {
|
|
|
- deviceState.spaceId = spaceId as any
|
|
|
- deviceState.type = spaceId ? state.spaceList.find(item => item.spaceId === spaceId)!.type : 'RTSP'
|
|
|
- nextTick(() => {
|
|
|
- tableProDom.value.reload({ page: 1 })
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-const closeModal = () => state.visible = false
|
|
|
-
|
|
|
-const openModal = () => {
|
|
|
- resetFields({})
|
|
|
- operator.value = 'add'
|
|
|
- state.activeVisible = true
|
|
|
-}
|
|
|
-
|
|
|
-const closeRealView = () => {
|
|
|
- state.activeVisible = false
|
|
|
- operator.value = 'preview'
|
|
|
-}
|
|
|
-
|
|
|
-const getSpaceList = async () => {
|
|
|
- state.spaceList = await SpaceController.list()
|
|
|
- deviceState.spaceId = _spaceId as any
|
|
|
-}
|
|
|
-
|
|
|
-const getAiList = async () => {
|
|
|
- state.aiList = await OperatorController.list()
|
|
|
-}
|
|
|
-
|
|
|
-const search = () => tableProDom.value.reload()
|
|
|
-
|
|
|
-onMounted(async () => {
|
|
|
- getAiList()
|
|
|
- await getSpaceList()
|
|
|
- if (_spaceId) deviceState.spaceId = Number(_spaceId)
|
|
|
-})
|
|
|
-</script>
|
|
|
-<style lang='less' scoped >
|
|
|
-
|
|
|
-.media-card {
|
|
|
- width: 100%;
|
|
|
- height: 150px !important;
|
|
|
- background-color: #000;
|
|
|
- video {
|
|
|
- width: 100%;
|
|
|
- height: 150px !important;
|
|
|
- }
|
|
|
- .craete-time {
|
|
|
- margin-top: 5px;
|
|
|
- }
|
|
|
-}
|
|
|
-</style>
|
|
|
-
|
|
|
- getAiList()
|
|
|
+<template>
|
|
|
+<a-card>
|
|
|
+ <template #title >
|
|
|
+ <a-row>
|
|
|
+ <a-col style="font-size: 20px;margin-right: 10px;" >设备管理</a-col>
|
|
|
+ <a-col >
|
|
|
+ <a-select
|
|
|
+ :value="deviceState.spaceId"
|
|
|
+ style="width: 170px;"
|
|
|
+ @change="onChangeSpace"
|
|
|
+ placeholder="请选择空间"
|
|
|
+ allowClear
|
|
|
+ >
|
|
|
+ <a-select-option
|
|
|
+ :key="index"
|
|
|
+ :value="item.spaceId"
|
|
|
+ v-for="(item, index) in state.spaceList"
|
|
|
+ >
|
|
|
+ {{item.spaceName}}
|
|
|
+ </a-select-option>
|
|
|
+ </a-select>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </template>
|
|
|
+ <table-pro
|
|
|
+ ref="tableProDom"
|
|
|
+ :service="SpaceController.devicePage"
|
|
|
+ :serviceParams="{deviceName, spaceId: deviceState.spaceId}"
|
|
|
+ :columns="columns"
|
|
|
+ @add="openModal"
|
|
|
+ >
|
|
|
+ <template #search >
|
|
|
+ <a-space><InputTsx placeholder="请输入设备名称进行搜索" v-model:value="deviceName" /> <a-button type="primary" @click="search">搜索</a-button> </a-space>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template #render="{column, record}" >
|
|
|
+
|
|
|
+ <template v-if="column.key === 'status'" >
|
|
|
+ <div style="display: flex;align-items: center;" >
|
|
|
+ <div :style="{width: '8px',height: '8px',borderRadius: '50%', backgroundColor:SpaceController.statusMap.get(record.status)?.color, marginRight: '5px' }" ></div>
|
|
|
+ <div>{{SpaceController.deviceStatusMap.get(record.status)?.label}}</div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="column.key === 'deviceId'">
|
|
|
+ <a @click="baseInfo(record)">{{record.deviceId}}</a>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="column.key === 'type'">
|
|
|
+ <a-tag>{{SpaceController.type.find((item)=>{
|
|
|
+ return item.key == record.type
|
|
|
+ })?.label}}</a-tag>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="column.key === 'action'" >
|
|
|
+ <a-space>
|
|
|
+ <a @click="baseInfo(record)">基本信息</a>
|
|
|
+ <a @click="recordParty(record)">录像回放</a>
|
|
|
+ <a @click="thumbParty(record)">截图查看</a>
|
|
|
+ <a @click="arAnalysis(record)">AI分析</a>
|
|
|
+ </a-space>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ </table-pro>
|
|
|
+</a-card>
|
|
|
+
|
|
|
+<RealView
|
|
|
+ :open="state.activeVisible"
|
|
|
+ @cancel="closeRealView"
|
|
|
+ :tab-key="activeTabKey"
|
|
|
+ :tabs-list="deviceTabs"
|
|
|
+ @tab-chang="key => onTabChange(key)"
|
|
|
+>
|
|
|
+ <!-- 个人基础信息 -->
|
|
|
+ <div v-if="activeTabKey === 'base'" >
|
|
|
+ <a-card title="基本信息" >
|
|
|
+ <template #extra >
|
|
|
+ <a-button type="primary" @click="ok" >提交修改</a-button>
|
|
|
+ </template>
|
|
|
+ <a-form style="width: 100%;" :labelCol="{span: 3}" :wrapperCol="{span: 14}" >
|
|
|
+ <a-form-item label="设备名称" v-bind="validateInfos.deviceName" >
|
|
|
+ <InputTsx allowClear placeholder="请输入设备名称" v-model:value="deviceState.deviceName" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="app" v-bind="validateInfos.app" >
|
|
|
+ <InputTsx allowClear placeholder="请输入英文、数字组成的app" v-model:value="deviceState.app" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="stream" v-bind="validateInfos.stream" >
|
|
|
+ <InputTsx allowClear placeholder="请输入英文、数字组成的stream" v-model:value="deviceState.stream" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="空间名称" v-bind="validateInfos.stream" >
|
|
|
+ <a-select
|
|
|
+ :value="spaceId"
|
|
|
+ style="width: 170px;"
|
|
|
+ @change="onChangeSpace"
|
|
|
+ placeholder="请选择空间"
|
|
|
+ >
|
|
|
+ <a-select-option
|
|
|
+ :key="index"
|
|
|
+ :value="item.spaceId"
|
|
|
+ v-for="(item, index) in state.spaceList"
|
|
|
+ >
|
|
|
+ {{item.spaceName}}
|
|
|
+ </a-select-option>
|
|
|
+ </a-select>
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="设备类型" >
|
|
|
+ <a-radio-group v-model:value="deviceState.type" button-style="solid">
|
|
|
+ <a-radio-button
|
|
|
+ v-for="item in SpaceController.type"
|
|
|
+ :key="item.key"
|
|
|
+ :value="item.value"
|
|
|
+ >
|
|
|
+ {{item.label}}
|
|
|
+ </a-radio-button>
|
|
|
+ </a-radio-group>
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="设备地址" >
|
|
|
+ <InputTsx allowClear placeholder="请输入设备地址" v-model:value="deviceState.gisName" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="拉流地址" v-if="['PULL_RTMP', 'PULL_RTSP'].includes(deviceState.type)" >
|
|
|
+ <InputTsx v-model:value="deviceState.pullPath" placeholder="请输入拉流地址" />
|
|
|
+ </a-form-item>
|
|
|
+ <span v-if="deviceState.type === 'GB28181'">
|
|
|
+ <a-form-item label="国标Id" >
|
|
|
+ <InputTsx v-model:value="deviceState.gbConfig.gbId" placeholder="请输入拉流地址" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="用户名" >
|
|
|
+ <InputTsx v-model:value="deviceState.gbConfig.username" placeholder="请输入用户名"/>
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="用户密码" >
|
|
|
+ <InputTsx v-model:value="deviceState.gbConfig.password" placeholder="请输入用户密码" />
|
|
|
+ </a-form-item>
|
|
|
+ <a-form-item label="国标平台" >
|
|
|
+ <a-radio-group v-model:value="deviceState.gbConfig.platform" button-style="solid">
|
|
|
+ <a-radio-button value="IPC">IPC</a-radio-button>
|
|
|
+ <a-radio-button value="NVR">NVR</a-radio-button>
|
|
|
+ </a-radio-group>
|
|
|
+ </a-form-item>
|
|
|
+ </span>
|
|
|
+ <a-form-item label="设备描述" >
|
|
|
+ <a-textarea v-model:value="deviceState.description" placeholder="请输入设备描述" :rows="4" />
|
|
|
+ </a-form-item>
|
|
|
+ </a-form>
|
|
|
+ </a-card>
|
|
|
+ <a-card v-if="operator === 'preview'" title="推播流地址" style="margin-top: 20px;" >
|
|
|
+ <!-- 非国标设备 -->
|
|
|
+ <a-row :gutter="[8, 18]" >
|
|
|
+ <a-col :span="24">
|
|
|
+ <a-row>
|
|
|
+ <a-col :span="4">
|
|
|
+ 请选择转码模版:
|
|
|
+ </a-col>
|
|
|
+ <a-col>
|
|
|
+ <a-space>
|
|
|
+ <a-select style="width: 170px;" >
|
|
|
+ <a-select-option key="2" >原始流</a-select-option>
|
|
|
+ </a-select>
|
|
|
+ <a-button>获取最新地址</a-button>
|
|
|
+ </a-space>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-col>
|
|
|
+ <!-- 推流地址 -->
|
|
|
+ <a-col :span="24">
|
|
|
+ <a-row>
|
|
|
+ <a-col :span="2" >推流地址</a-col>
|
|
|
+ <a-col>
|
|
|
+ <div v-for="item in gbState.pushList" :key="item" >{{item}}</div>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-col>
|
|
|
+ <!-- 播放地址 -->
|
|
|
+ <a-col :span="24">
|
|
|
+ <a-row>
|
|
|
+ <a-col :span="2" >播放地址</a-col>
|
|
|
+ <a-col >
|
|
|
+ <div v-for="item in gbState.pullList" :key="item" >{{item}}</div>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-card>
|
|
|
+ </div>
|
|
|
+ <a-card style="background-color: #fff;width: 100%;" v-if="activeTabKey !== 'base'" >
|
|
|
+ <a-space >
|
|
|
+ <a-range-picker v-model:value="deviceActionParams.times" />
|
|
|
+ <a-select style="width: 170px;" v-if="activeTabKey === 'record'" v-model:value="deviceActionParams.recordFormat" >
|
|
|
+ <a-select-option v-for="item in SpaceController.recordFormat" :key="item" :value="item" >
|
|
|
+ {{item}}
|
|
|
+ </a-select-option>
|
|
|
+ </a-select>
|
|
|
+ <a-select style="width: 170px;" v-if="activeTabKey === 'ai'" v-model:value="deviceActionParams.aiId" >
|
|
|
+ <a-select-option v-for="item in state.aiList" :key="item.aiId" :value="item.aiId" >
|
|
|
+ {{item.aiName}}
|
|
|
+ </a-select-option>
|
|
|
+ </a-select>
|
|
|
+ <a-button type="primary" @click="searchDevice">搜索</a-button>
|
|
|
+ </a-space>
|
|
|
+ </a-card>
|
|
|
+
|
|
|
+ <!-- 视频 图片区域 -->
|
|
|
+ <a-spin :spinning="state.loading" v-if="activeTabKey !== 'base'">
|
|
|
+ <a-row :gutter="[8, 8]" style="margin-top: 20px;background-color: #fff;padding: 18px;padding-bottom: 38px;" >
|
|
|
+ <a-col :span="4" v-for="item in state.deviceMediaList" :key="item" >
|
|
|
+ <div class="media-card">
|
|
|
+ <video
|
|
|
+ v-if="activeTabKey === 'record'"
|
|
|
+ controls
|
|
|
+ :src="item.defaultUrl"
|
|
|
+ ></video>
|
|
|
+ <div v-else-if="activeTabKey === 'thumb'" >
|
|
|
+ <a-image
|
|
|
+ width="100%"
|
|
|
+ height="150px"
|
|
|
+ style="object-fit: cover;display: block;"
|
|
|
+ :src="item.defaultUrl"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div v-else-if="activeTabKey === 'ai'" style="height: 150px;" >
|
|
|
+ <a-image width="100%" height="150px" style="object-fit: cover;display: block;" :src="item.defaultUrl"></a-image>
|
|
|
+ </div>
|
|
|
+ <div class="craete-time">{{dayjs(item.ts).format('YYYY/MM/DD HH:mm:ss')}}</div>
|
|
|
+ </div>
|
|
|
+ </a-col>
|
|
|
+ </a-row>
|
|
|
+ </a-spin>
|
|
|
+
|
|
|
+</RealView>
|
|
|
+
|
|
|
+</template>
|
|
|
+<script lang='ts' setup >
|
|
|
+import { InputTsx } from '@/components/MicroComponents/index'
|
|
|
+import { reactive, onMounted, nextTick, ref, watch } from 'vue'
|
|
|
+import { Form } from 'ant-design-vue'
|
|
|
+import { OperatorController, SpaceController } from '@/controller'
|
|
|
+import { useRoute } from 'vue-router'
|
|
|
+import dayjs from 'dayjs'
|
|
|
+import { RealView } from '@/components/RealView/index'
|
|
|
+
|
|
|
+const columns = [
|
|
|
+ {
|
|
|
+ title: '设备ID',
|
|
|
+ dataIndex: 'deviceId',
|
|
|
+ key: 'deviceId'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '设备名称',
|
|
|
+ dataIndex: 'deviceName',
|
|
|
+ key: 'deviceName'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '空间类型',
|
|
|
+ dataIndex: 'type',
|
|
|
+ key: 'type'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '描述',
|
|
|
+ dataIndex: 'description',
|
|
|
+ key: 'description'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '状态',
|
|
|
+ dataIndex: 'status',
|
|
|
+ key: 'status'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ dataIndex: 'action',
|
|
|
+ key: 'action'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const _spaceId = useRoute().query.spaceId
|
|
|
+
|
|
|
+const useForm = Form.useForm
|
|
|
+
|
|
|
+const spaceId = ref(null)
|
|
|
+
|
|
|
+const deviceName = ref(null)
|
|
|
+
|
|
|
+const tableProDom = ref()
|
|
|
+
|
|
|
+const activeTabKey = ref<'base' | 'record' | 'thumb' | 'ai'>('base')
|
|
|
+
|
|
|
+const operator = ref<'add' | 'preview'>('add')
|
|
|
+
|
|
|
+const deviceTabs = [
|
|
|
+ { key: 'base', tab: '基础信息' },
|
|
|
+ { key: 'record', tab: '录像回放' },
|
|
|
+ { key: 'thumb', tab: '截图查看' },
|
|
|
+ { key: 'ai', tab: 'AI分析' }
|
|
|
+]
|
|
|
+
|
|
|
+const recordColumn = [
|
|
|
+ {
|
|
|
+ title: '录制格式',
|
|
|
+ dataIndex: 'extra',
|
|
|
+ key: 'extra'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '录制时间',
|
|
|
+ dataIndex: 'ts',
|
|
|
+ key: 'ts'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '可播放地址',
|
|
|
+ dataIndex: 'defaultUrl',
|
|
|
+ key: 'defaultUrl'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const thumbColumn = [
|
|
|
+ {
|
|
|
+ title: '截图地址',
|
|
|
+ dataIndex: 'defaultUrl',
|
|
|
+ key: 'defaultUrl'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '截图时间',
|
|
|
+ dataIndex: 'ts',
|
|
|
+ key: 'ts'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const aiColumn = [
|
|
|
+ {
|
|
|
+ title: '算子模型id',
|
|
|
+ dataIndex: 'extra',
|
|
|
+ key: 'extra'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '结果地址',
|
|
|
+ dataIndex: 'defaultUrl',
|
|
|
+ key: 'defaultUrl'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '时间',
|
|
|
+ dataIndex: 'ts',
|
|
|
+ key: 'ts'
|
|
|
+ }
|
|
|
+]
|
|
|
+
|
|
|
+const deviceActionMap = new Map([
|
|
|
+ ['record', { get: SpaceController.deviceRecordById, column: recordColumn }],
|
|
|
+ ['thumb', { get: SpaceController.deviceThumbById, column: thumbColumn }],
|
|
|
+ ['ai', { get: SpaceController.deviceAiRetById, column: aiColumn }]
|
|
|
+])
|
|
|
+
|
|
|
+const state = reactive<{
|
|
|
+ visible: boolean,
|
|
|
+ activeVisible: boolean,
|
|
|
+ spaceList: CVS.space[]
|
|
|
+ deviceMediaList: any[],
|
|
|
+ aiList: CVS.Operator[]
|
|
|
+ loading: boolean
|
|
|
+}>({
|
|
|
+ visible: false,
|
|
|
+ activeVisible: false,
|
|
|
+ spaceList: [],
|
|
|
+ deviceMediaList: [],
|
|
|
+ aiList: [],
|
|
|
+ loading: false
|
|
|
+})
|
|
|
+
|
|
|
+const gbState = reactive<{
|
|
|
+ channelList: string[]
|
|
|
+ pullList: string[],
|
|
|
+ gbPullList: string[]
|
|
|
+ pushList: string[]
|
|
|
+}>({
|
|
|
+ channelList: [],
|
|
|
+ pullList: [],
|
|
|
+ gbPullList: [],
|
|
|
+ pushList: []
|
|
|
+})
|
|
|
+
|
|
|
+const deviceActionParams = reactive({
|
|
|
+ times: [],
|
|
|
+ startTs: '',
|
|
|
+ endTs: '',
|
|
|
+ recordFormat: '',
|
|
|
+ deviceId: '',
|
|
|
+ page: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ aiId: null
|
|
|
+})
|
|
|
+
|
|
|
+const deviceState = reactive({
|
|
|
+ deviceId: '',
|
|
|
+ spaceId: null,
|
|
|
+ deviceName: '',
|
|
|
+ app: '',
|
|
|
+ stream: '',
|
|
|
+ description: '',
|
|
|
+ deviceStreamId: '',
|
|
|
+ gisLongitude: '',
|
|
|
+ gisLatitude: '',
|
|
|
+ gisName: '',
|
|
|
+ type: 'RTMP',
|
|
|
+ pullPath: '',
|
|
|
+ gbConfig: {
|
|
|
+ gbId: '',
|
|
|
+ username: '',
|
|
|
+ password: '',
|
|
|
+ platform: 'IPC'
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => activeTabKey.value,
|
|
|
+ () => {
|
|
|
+ activeTabKey.value !== 'base' && getMedia()
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => deviceActionParams.times,
|
|
|
+ () => {
|
|
|
+ deviceActionParams.startTs = dayjs(deviceActionParams.times[0]).unix() as unknown as string
|
|
|
+ deviceActionParams.endTs = dayjs(deviceActionParams.times[0]).unix() as unknown as string
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => deviceState.deviceId,
|
|
|
+ () => {
|
|
|
+ if (deviceState.gbConfig && deviceState.gbConfig.gbId) {
|
|
|
+ getDeviceChannel()
|
|
|
+ getGbPull()
|
|
|
+ } else {
|
|
|
+ getNotGbPush()
|
|
|
+ getNotGbPull()
|
|
|
+ }
|
|
|
+ }
|
|
|
+)
|
|
|
+
|
|
|
+const { resetFields, validate, validateInfos } = useForm(deviceState, {
|
|
|
+ deviceName: [{ required: true, message: '请填写设备名称' }],
|
|
|
+ app: [{ required: true, message: '请填写app名称' }],
|
|
|
+ stream: [{ required: true, message: '请填写stream名称' }]
|
|
|
+})
|
|
|
+
|
|
|
+const searchDevice = () => getMedia()
|
|
|
+
|
|
|
+const onTabChange = (key: 'record' | 'thumb' | 'ai') => activeTabKey.value = key
|
|
|
+
|
|
|
+const getMedia = async () => {
|
|
|
+ state.loading = true
|
|
|
+ const { data, sum } = await deviceActionMap.get(activeTabKey.value)?.get({ ...deviceActionParams, deviceId: deviceState.deviceId } as any)
|
|
|
+ state.loading = false
|
|
|
+ state.deviceMediaList = data
|
|
|
+ console.log(state.deviceMediaList)
|
|
|
+}
|
|
|
+
|
|
|
+const ok = () => {
|
|
|
+ validate().then(async () => {
|
|
|
+ deviceState.deviceStreamId = deviceState.app + '/' + deviceState.stream
|
|
|
+ await SpaceController.addDevice(deviceState as unknown as CVS.device)
|
|
|
+ closeModal()
|
|
|
+ tableProDom.value.reload()
|
|
|
+ }).catch(() => {})
|
|
|
+}
|
|
|
+
|
|
|
+// 获取设备通道
|
|
|
+const getDeviceChannel = async () => {
|
|
|
+ gbState.channelList = (await SpaceController.deviceChannel(deviceState.deviceId))!
|
|
|
+}
|
|
|
+
|
|
|
+const getGbPull = async () => {
|
|
|
+ gbState.gbPullList = (await SpaceController.gbPull(deviceState.deviceId))!
|
|
|
+}
|
|
|
+
|
|
|
+const getNotGbPush = async () => {
|
|
|
+ gbState.pushList = (await SpaceController.notGBPush(deviceState.deviceId))!
|
|
|
+}
|
|
|
+
|
|
|
+const getNotGbPull = async () => {
|
|
|
+ gbState.pullList = await SpaceController.notGbPull(deviceState.deviceId)
|
|
|
+}
|
|
|
+
|
|
|
+const baseInfo = (record: CVS.device) => {
|
|
|
+ activeTabKey.value = 'base'
|
|
|
+ nextTick(() => {
|
|
|
+ state.activeVisible = true
|
|
|
+ console.log(record)
|
|
|
+ resetFields({ ...record })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const recordParty = async (record: CVS.device) => {
|
|
|
+ state.activeVisible = true
|
|
|
+ resetFields({ ...record })
|
|
|
+ deviceActionParams.deviceId = record.deviceId as unknown as string
|
|
|
+ activeTabKey.value = 'record'
|
|
|
+ getMedia()
|
|
|
+}
|
|
|
+
|
|
|
+const thumbParty = (record: CVS.device) => {
|
|
|
+ state.activeVisible = true
|
|
|
+ resetFields({ ...record })
|
|
|
+ deviceActionParams.deviceId = record.deviceId as unknown as string
|
|
|
+ activeTabKey.value = 'thumb'
|
|
|
+ getMedia()
|
|
|
+}
|
|
|
+
|
|
|
+const arAnalysis = (record: CVS.device) => {
|
|
|
+ state.activeVisible = true
|
|
|
+ resetFields({ ...record })
|
|
|
+ deviceActionParams.deviceId = record.deviceId as unknown as string
|
|
|
+ activeTabKey.value = 'ai'
|
|
|
+ getMedia()
|
|
|
+}
|
|
|
+
|
|
|
+const onChangeSpace = (spaceId: string) => {
|
|
|
+ deviceState.spaceId = spaceId as any
|
|
|
+ deviceState.type = spaceId ? state.spaceList.find(item => item.spaceId === spaceId)!.type : 'RTSP'
|
|
|
+ nextTick(() => {
|
|
|
+ tableProDom.value.reload({ page: 1 })
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+const closeModal = () => state.visible = false
|
|
|
+
|
|
|
+const openModal = () => {
|
|
|
+ resetFields({})
|
|
|
+ operator.value = 'add'
|
|
|
+ state.activeVisible = true
|
|
|
+}
|
|
|
+
|
|
|
+const closeRealView = () => {
|
|
|
+ state.activeVisible = false
|
|
|
+ operator.value = 'preview'
|
|
|
+}
|
|
|
+
|
|
|
+const getSpaceList = async () => {
|
|
|
+ state.spaceList = await SpaceController.list()
|
|
|
+ deviceState.spaceId = _spaceId as any
|
|
|
+}
|
|
|
+
|
|
|
+const getAiList = async () => {
|
|
|
+ state.aiList = await OperatorController.list()
|
|
|
+}
|
|
|
+
|
|
|
+const search = () => tableProDom.value.reload()
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ getAiList()
|
|
|
+ await getSpaceList()
|
|
|
+ if (_spaceId) deviceState.spaceId = Number(_spaceId)
|
|
|
+})
|
|
|
+</script>
|
|
|
+<style lang='less' scoped >
|
|
|
+
|
|
|
+.media-card {
|
|
|
+ width: 100%;
|
|
|
+ height: 150px !important;
|
|
|
+ background-color: #000;
|
|
|
+ video {
|
|
|
+ width: 100%;
|
|
|
+ height: 150px !important;
|
|
|
+ }
|
|
|
+ .craete-time {
|
|
|
+ margin-top: 5px;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+
|
|
|
+ getAiList()
|