Showing
10 changed files
with
257 additions
and
40 deletions
... | ... | @@ -4,7 +4,9 @@ import { FormSchema as QFormSchema, useComponentRegister } from '/@/components/F |
4 | 4 | import { CameraVideoUrl, CameraMaxLength } from '/@/utils/rules'; |
5 | 5 | import { h } from 'vue'; |
6 | 6 | import SnHelpMessage from './SnHelpMessage.vue'; |
7 | +import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; | |
7 | 8 | import { OrgTreeSelect } from '../../common/OrgTreeSelect'; |
9 | +import { findDictItemByCode } from '/@/api/system/dict'; | |
8 | 10 | |
9 | 11 | useComponentRegister('OrgTreeSelect', OrgTreeSelect); |
10 | 12 | |
... | ... | @@ -42,6 +44,16 @@ export enum MediaType { |
42 | 44 | M3U8 = 'm3u8', |
43 | 45 | } |
44 | 46 | |
47 | +const streamingTypeList = [ | |
48 | + { label: 'GBT-28181', value: 'GBT-28181' }, | |
49 | + { label: '其他', value: 'other' }, | |
50 | +]; | |
51 | + | |
52 | +export enum streamingType { | |
53 | + GBT = 'GBT-28181', | |
54 | + OTHER = 'other', | |
55 | +} | |
56 | + | |
45 | 57 | // 表格列数据 |
46 | 58 | export const columns: BasicColumn[] = [ |
47 | 59 | { |
... | ... | @@ -148,6 +160,44 @@ export const formSchema: QFormSchema[] = [ |
148 | 160 | }, |
149 | 161 | }, |
150 | 162 | { |
163 | + field: 'streamingType', | |
164 | + label: '流媒体类型', | |
165 | + component: 'Select', | |
166 | + ifShow({ values }) { | |
167 | + return values.accessMode == AccessMode.Streaming; | |
168 | + }, | |
169 | + componentProps() { | |
170 | + return { | |
171 | + placeholder: '请选择流媒体类型', | |
172 | + defaultValue: streamingType.OTHER, | |
173 | + options: streamingTypeList, | |
174 | + }; | |
175 | + }, | |
176 | + }, | |
177 | + { | |
178 | + field: 'device', | |
179 | + label: '设备选择', | |
180 | + ifShow({ values }) { | |
181 | + return values.streamingType == streamingType.GBT; | |
182 | + }, | |
183 | + component: 'ApiSelect', | |
184 | + componentProps() { | |
185 | + return { | |
186 | + api: findDictItemByCode, | |
187 | + params: { | |
188 | + dictCode: 'device_type', | |
189 | + }, | |
190 | + valueField: 'itemValue', | |
191 | + labelField: 'itemText', | |
192 | + placeholder: '请选择设备类型', | |
193 | + onChange: (value: DeviceTypeEnum) => { | |
194 | + console.log(value, 'value'); | |
195 | + }, | |
196 | + getPopupContainer: () => document.body, | |
197 | + }; | |
198 | + }, | |
199 | + }, | |
200 | + { | |
151 | 201 | field: 'brand', |
152 | 202 | label: '视频厂家', |
153 | 203 | component: 'Input', |
... | ... | @@ -193,7 +243,9 @@ export const formSchema: QFormSchema[] = [ |
193 | 243 | label: '流媒体配置', |
194 | 244 | component: 'Select', |
195 | 245 | ifShow({ values }) { |
196 | - return values.accessMode === AccessMode.Streaming; | |
246 | + return ( | |
247 | + values.accessMode === AccessMode.Streaming && values.streamingType != streamingType.GBT | |
248 | + ); | |
197 | 249 | }, |
198 | 250 | slot: 'videoPlatformIdSlot', |
199 | 251 | componentProps: { |
... | ... | @@ -206,7 +258,9 @@ export const formSchema: QFormSchema[] = [ |
206 | 258 | component: 'RadioGroup', |
207 | 259 | defaultValue: StreamType.MASTER, |
208 | 260 | ifShow({ values }) { |
209 | - return values.accessMode === AccessMode.Streaming; | |
261 | + return ( | |
262 | + values.accessMode === AccessMode.Streaming && values.streamingType != streamingType.GBT | |
263 | + ); | |
210 | 264 | }, |
211 | 265 | componentProps: { |
212 | 266 | placeholder: '请选择码流', |
... | ... | @@ -224,7 +278,9 @@ export const formSchema: QFormSchema[] = [ |
224 | 278 | component: 'RadioGroup', |
225 | 279 | defaultValue: PlayProtocol.HTTP, |
226 | 280 | ifShow({ values }) { |
227 | - return values.accessMode === AccessMode.Streaming; | |
281 | + return ( | |
282 | + values.accessMode === AccessMode.Streaming && values.streamingType != streamingType.GBT | |
283 | + ); | |
228 | 284 | }, |
229 | 285 | helpMessage: ['平台使用https的hls协议,需联系海康开放平台专家支持。'], |
230 | 286 | componentProps: { |
... | ... | @@ -242,7 +298,9 @@ export const formSchema: QFormSchema[] = [ |
242 | 298 | component: 'Input', |
243 | 299 | rules: [...CameraVideoUrl, { required: true, message: '摄像头编号是必填项' }], |
244 | 300 | ifShow({ values }) { |
245 | - return values.accessMode === AccessMode.Streaming; | |
301 | + return ( | |
302 | + values.accessMode === AccessMode.Streaming && values.streamingType != streamingType.GBT | |
303 | + ); | |
246 | 304 | }, |
247 | 305 | componentProps: { |
248 | 306 | placeholder: '请输入监控点编号', | ... | ... |
... | ... | @@ -16,7 +16,7 @@ |
16 | 16 | @open-gateway-device="handleOpenGatewayDevice" |
17 | 17 | /> |
18 | 18 | </TabPane> |
19 | - <TabPane key="modelOfMatter" tab="物模型数据"> | |
19 | + <TabPane v-if="!isTransportType" key="modelOfMatter" tab="物模型数据"> | |
20 | 20 | <ModelOfMatter :deviceDetail="deviceDetail" /> |
21 | 21 | </TabPane> |
22 | 22 | <!-- <TabPane key="2" tab="实时数据" v-if="deviceDetail?.deviceType !== 'GATEWAY'"> |
... | ... | @@ -28,32 +28,43 @@ |
28 | 28 | <!-- <TabPane key="5" tab="命令下发" v-if="deviceDetail?.deviceType !== 'SENSOR'"> |
29 | 29 | <CommandIssuance :deviceDetail="deviceDetail" /> |
30 | 30 | </TabPane> --> |
31 | - <TabPane key="3" tab="告警"><Alarm :id="deviceDetail.id" /></TabPane> | |
32 | - <TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === 'GATEWAY'"> | |
31 | + <TabPane v-if="!isTransportType" key="3" tab="告警"><Alarm :id="deviceDetail.id" /></TabPane> | |
32 | + <TabPane | |
33 | + key="4" | |
34 | + tab="子设备" | |
35 | + v-if="deviceDetail?.deviceType === 'GATEWAY' && !isTransportType" | |
36 | + > | |
33 | 37 | <ChildDevice |
34 | 38 | :fromId="deviceDetail?.tbDeviceId" |
35 | 39 | @openTbDeviceDetail="handleOpenTbDeviceDetail" |
36 | 40 | /> |
37 | 41 | </TabPane> |
38 | - <TabPane key="7" tab="命令下发记录"> | |
42 | + <TabPane v-if="!isTransportType" key="7" tab="命令下发记录"> | |
39 | 43 | <CommandRecord :deviceDetail="deviceDetail" :fromId="deviceDetail?.tbDeviceId" /> |
40 | 44 | </TabPane> |
41 | 45 | <!-- 网关设备并且场家是TBox --> |
42 | 46 | <TabPane |
43 | 47 | key="6" |
44 | 48 | tab="TBox" |
45 | - v-if="deviceDetail?.deviceType === 'GATEWAY' && deviceDetail?.brand == 'TBox'" | |
49 | + v-if=" | |
50 | + deviceDetail?.deviceType === 'GATEWAY' && | |
51 | + deviceDetail?.brand == 'TBox' && | |
52 | + !isTransportType | |
53 | + " | |
46 | 54 | > |
47 | 55 | <TBoxDetail :deviceDetail="deviceDetail" /> |
48 | 56 | </TabPane> |
49 | 57 | <!-- 网关设备并且是TBox --> |
50 | 58 | |
51 | - <TabPane key="eventManage" tab="事件管理"> | |
59 | + <TabPane v-if="!isTransportType" key="eventManage" tab="事件管理"> | |
52 | 60 | <EventManage :tbDeviceId="deviceDetail.tbDeviceId" /> |
53 | 61 | </TabPane> |
54 | - <TabPane key="task" tab="任务"> | |
62 | + <TabPane v-if="!isTransportType" key="task" tab="任务"> | |
55 | 63 | <Task :tbDeviceId="deviceDetail.tbDeviceId" /> |
56 | 64 | </TabPane> |
65 | + <TabPane key="videoChannel" tab="视频通道"> | |
66 | + <VideoChannel :deviceDetail="deviceDetail" :fromId="deviceDetail?.tbDeviceId" /> | |
67 | + </TabPane> | |
57 | 68 | </Tabs> |
58 | 69 | </BasicDrawer> |
59 | 70 | </template> |
... | ... | @@ -74,6 +85,7 @@ |
74 | 85 | import EventManage from '../tabs/EventManage/index.vue'; |
75 | 86 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; |
76 | 87 | import Task from '../tabs/Task.vue'; |
88 | + import { VideoChannel } from '../tabs/VideoChannel/index'; | |
77 | 89 | |
78 | 90 | export default defineComponent({ |
79 | 91 | name: 'DeviceModal', |
... | ... | @@ -91,6 +103,7 @@ |
91 | 103 | CommandRecord, |
92 | 104 | EventManage, |
93 | 105 | Task, |
106 | + VideoChannel, | |
94 | 107 | }, |
95 | 108 | emits: ['reload', 'register', 'openTbDeviceDetail', 'openGatewayDeviceDetail'], |
96 | 109 | setup(_props, { emit }) { |
... | ... | @@ -99,9 +112,12 @@ |
99 | 112 | const deviceDetailRef = ref(); |
100 | 113 | const deviceDetail = ref<DeviceRecord>({} as unknown as DeviceRecord); |
101 | 114 | const tbDeviceId = ref(''); |
115 | + | |
116 | + const isTransportType = ref<Boolean>(false); //获取产品是不是GB/T 28181 | |
102 | 117 | // 详情回显 |
103 | 118 | const [register] = useDrawerInner(async (data) => { |
104 | - const { id } = data; | |
119 | + const { id, transportType } = data; | |
120 | + isTransportType.value = transportType == 'GB/T28181' ? true : false; | |
105 | 121 | // 设备详情 |
106 | 122 | const res = await getDeviceDetail(id); |
107 | 123 | deviceDetail.value = res; |
... | ... | @@ -132,6 +148,7 @@ |
132 | 148 | tbDeviceId, |
133 | 149 | handleOpenTbDeviceDetail, |
134 | 150 | handleOpenGatewayDevice, |
151 | + isTransportType, | |
135 | 152 | }; |
136 | 153 | }, |
137 | 154 | }); | ... | ... |
1 | +import { h } from 'vue'; | |
2 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | |
3 | +import { Tag } from 'ant-design-vue'; | |
4 | + | |
5 | +export const configColumns: BasicColumn[] = [ | |
6 | + { | |
7 | + title: '通道编号', | |
8 | + dataIndex: 'channellNumber', | |
9 | + }, | |
10 | + { | |
11 | + title: '设备名称', | |
12 | + dataIndex: 'deviceName', | |
13 | + }, | |
14 | + { | |
15 | + title: '通道名称', | |
16 | + dataIndex: 'channelName', | |
17 | + }, | |
18 | + { | |
19 | + title: '厂家', | |
20 | + dataIndex: 'manufacturer', | |
21 | + }, | |
22 | + { | |
23 | + title: '开启音频', | |
24 | + dataIndex: 'turnOnAudio', | |
25 | + slots: { customRender: 'turnOnAudio' }, | |
26 | + }, | |
27 | + { | |
28 | + title: '状态', | |
29 | + dataIndex: 'state', | |
30 | + format: (text) => { | |
31 | + return h( | |
32 | + Tag, | |
33 | + { | |
34 | + color: Number(text) === 1 ? 'green' : 'blue', | |
35 | + }, | |
36 | + () => (Number(text) === 1 ? '在线' : '离线') | |
37 | + ); | |
38 | + }, | |
39 | + }, | |
40 | + { | |
41 | + title: '操作', | |
42 | + dataIndex: 'action', | |
43 | + }, | |
44 | +]; | |
45 | + | |
46 | +export const searchFormSchema: FormSchema[] | any = [{}]; | ... | ... |
1 | +<template> | |
2 | + <BasicTable | |
3 | + class="bg-neutral-100 dark:text-gray-300 dark:bg-dark-700 p-4" | |
4 | + @register="registerTable" | |
5 | + > | |
6 | + <template #turnOnAudio="{ record }"> | |
7 | + <Switch | |
8 | + :checked="record.status === 1" | |
9 | + :loading="record.pendingStatus" | |
10 | + checkedChildren="开启" | |
11 | + unCheckedChildren="关闭" | |
12 | + @change="(checked:boolean)=>handleTurnVideo(checked,record)" | |
13 | + /> | |
14 | + </template> | |
15 | + <template #action="{ record }"> | |
16 | + <TableAction | |
17 | + :actions="[ | |
18 | + { | |
19 | + label: '播放', | |
20 | + auth: 'api:yt:sceneLinkage:get', | |
21 | + icon: 'ant-design:playCircle-outlined', | |
22 | + onClick: handlePlay.bind(null, record), | |
23 | + }, | |
24 | + ]" | |
25 | + /></template> | |
26 | + </BasicTable> | |
27 | +</template> | |
28 | + | |
29 | +<script lang="ts" setup> | |
30 | + import { configColumns, searchFormSchema } from './config'; | |
31 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
32 | + import { Switch } from 'ant-design-vue'; | |
33 | + import { DeviceRecord } from '/@/api/device/model/deviceModel'; | |
34 | + import { watch } from 'vue'; | |
35 | + | |
36 | + const props = defineProps({ | |
37 | + fromId: { | |
38 | + type: String, | |
39 | + default: '', | |
40 | + }, | |
41 | + deviceDetail: { | |
42 | + type: Object as PropType<DeviceRecord>, | |
43 | + required: true, | |
44 | + }, | |
45 | + }); | |
46 | + | |
47 | + watch( | |
48 | + () => props, | |
49 | + () => { | |
50 | + console.log(props, 'props'); | |
51 | + } | |
52 | + ); | |
53 | + | |
54 | + const [registerTable] = useTable({ | |
55 | + // api: deviceCommandRecordGetQuery, | |
56 | + columns: configColumns, | |
57 | + showTableSetting: true, | |
58 | + bordered: true, | |
59 | + showIndexColumn: false, | |
60 | + formConfig: { | |
61 | + labelWidth: 120, | |
62 | + schemas: searchFormSchema, | |
63 | + }, | |
64 | + beforeFetch: (params) => { | |
65 | + console.log(params); | |
66 | + }, | |
67 | + useSearchForm: true, | |
68 | + }); | |
69 | + | |
70 | + const handleTurnVideo = (checked: Boolean, record: Recordable) => { | |
71 | + console.log(checked, record, 'record'); | |
72 | + }; | |
73 | + | |
74 | + const handlePlay = (record: Recordable) => { | |
75 | + console.log(record); | |
76 | + }; | |
77 | +</script> | ... | ... |
... | ... | @@ -336,10 +336,12 @@ |
336 | 336 | } |
337 | 337 | |
338 | 338 | function handleDetail(record: Recordable) { |
339 | - const { id, tbDeviceId } = record; | |
339 | + const { id, tbDeviceId, deviceProfile } = record; | |
340 | + const { transportType } = deviceProfile || {}; | |
340 | 341 | openDrawer(true, { |
341 | 342 | id, |
342 | 343 | tbDeviceId, |
344 | + transportType, | |
343 | 345 | }); |
344 | 346 | } |
345 | 347 | ... | ... |
... | ... | @@ -127,11 +127,12 @@ |
127 | 127 | } |
128 | 128 | }; |
129 | 129 | const handleStepNext = (e, data) => { |
130 | + const { deviceType } = unref(DevConStRef)?.getFieldsValue() || {}; | |
130 | 131 | if (e) { |
131 | 132 | current.value++; |
132 | 133 | unref(isUpdate) |
133 | - ? unref(TransConStRef)?.editOrAddTransportTypeStatus(true) | |
134 | - : unref(TransConStRef)?.editOrAddTransportTypeStatus(false); | |
134 | + ? unref(TransConStRef)?.editOrAddTransportTypeStatus(true, deviceType) | |
135 | + : unref(TransConStRef)?.editOrAddTransportTypeStatus(false, deviceType); | |
135 | 136 | } else { |
136 | 137 | setTransConfEditFormData(data); |
137 | 138 | } | ... | ... |
... | ... | @@ -45,19 +45,20 @@ |
45 | 45 | ifShowBtn: { type: Boolean, default: true }, |
46 | 46 | }); |
47 | 47 | |
48 | - const [register, { validate, setFieldsValue, resetFields, updateSchema }] = useForm({ | |
49 | - labelWidth: 100, | |
50 | - schemas: step1Schemas, | |
51 | - actionColOptions: { | |
52 | - span: 14, | |
53 | - }, | |
54 | - showResetButton: false, | |
55 | - showActionButtonGroup: props.ifShowBtn ? true : false, | |
56 | - submitButtonOptions: { | |
57 | - text: '下一步', | |
58 | - }, | |
59 | - submitFunc: customSubmitFunc, | |
60 | - }); | |
48 | + const [register, { validate, setFieldsValue, resetFields, updateSchema, getFieldsValue }] = | |
49 | + useForm({ | |
50 | + labelWidth: 100, | |
51 | + schemas: step1Schemas, | |
52 | + actionColOptions: { | |
53 | + span: 14, | |
54 | + }, | |
55 | + showResetButton: false, | |
56 | + showActionButtonGroup: props.ifShowBtn ? true : false, | |
57 | + submitButtonOptions: { | |
58 | + text: '下一步', | |
59 | + }, | |
60 | + submitFunc: customSubmitFunc, | |
61 | + }); | |
61 | 62 | const editOrAddNameStatus = (nameStatus) => |
62 | 63 | updateSchema({ |
63 | 64 | field: 'name', |
... | ... | @@ -129,6 +130,7 @@ |
129 | 130 | resetFormData, |
130 | 131 | getFormData, |
131 | 132 | editOrAddDeviceTypeStatus, |
133 | + getFieldsValue, | |
132 | 134 | }); |
133 | 135 | </script> |
134 | 136 | <style lang="less" scoped> | ... | ... |
1 | 1 | <template> |
2 | 2 | <div |
3 | 3 | class="step2-style" |
4 | - :style="[isMqttType == 'DEFAULT' ? { minHeight: 0 + 'px' } : { minHeight: 800 + 'px' }]" | |
4 | + :style="[ | |
5 | + isMqttType == 'DEFAULT' || isMqttType == 'GB/T28181' | |
6 | + ? { minHeight: 0 + 'px' } | |
7 | + : { minHeight: 800 + 'px' }, | |
8 | + ]" | |
5 | 9 | > |
6 | 10 | <div |
7 | 11 | :style="[ |
... | ... | @@ -138,6 +142,7 @@ |
138 | 142 | const getSnmpVal = await snmpRef.value?.getFormData(); |
139 | 143 | const getTcpVal = await tcpRef.value?.getFormData(); |
140 | 144 | step2Data.transportConfiguration = { |
145 | + type: isMqttType.value, | |
141 | 146 | ...getMqttVal, |
142 | 147 | ...getCoapVal, |
143 | 148 | ...getLwm2mVal, |
... | ... | @@ -148,19 +153,26 @@ |
148 | 153 | return step2Data; |
149 | 154 | }; |
150 | 155 | |
151 | - const editOrAddTransportTypeStatus = (status: boolean) => { | |
156 | + const editOrAddTransportTypeStatus = (status: boolean, deviceType?: string) => { | |
157 | + const options = [ | |
158 | + { label: '默认', value: 'DEFAULT' }, | |
159 | + { label: 'MQTT', value: 'MQTT' }, | |
160 | + { label: 'CoAP', value: 'COAP' }, | |
161 | + // { label: 'LWM2M', value: 'LWM2M' }, | |
162 | + // { label: 'SNMP', value: 'SNMP' }, | |
163 | + { label: 'TCP/UDP', value: 'TCP' }, | |
164 | + ]; | |
165 | + if (deviceType == 'DIRECT_CONNECTION') { | |
166 | + options.push({ label: 'GB/T 28181', value: 'GB/T28181' }); | |
167 | + } | |
168 | + if (deviceType != 'DIRECT_CONNECTION' && isMqttType.value == 'GB/T28181') { | |
169 | + setFieldsValue({ transportType: null }); | |
170 | + } | |
152 | 171 | updateSchema({ |
153 | 172 | field: 'transportType', |
154 | 173 | componentProps: { |
155 | 174 | disabled: status, |
156 | - options: [ | |
157 | - { label: '默认', value: 'DEFAULT' }, | |
158 | - { label: 'MQTT', value: 'MQTT' }, | |
159 | - { label: 'CoAP', value: 'COAP' }, | |
160 | - // { label: 'LWM2M', value: 'LWM2M' }, | |
161 | - // { label: 'SNMP', value: 'SNMP' }, | |
162 | - { label: 'TCP/UDP', value: 'TCP' }, | |
163 | - ], | |
175 | + options, | |
164 | 176 | onChange(e) { |
165 | 177 | isMqttType.value = e; |
166 | 178 | }, | ... | ... |
... | ... | @@ -78,6 +78,6 @@ export const getSendValues = async (option, getDesign, checked) => { |
78 | 78 | |
79 | 79 | export const CommandTypeEnumLIst = { |
80 | 80 | '0': { CUSTOM: 0, name: '自定义' }, |
81 | - '1': { CUSTOM: 0, name: '服务' }, | |
82 | - '2': { CUSTOM: 0, name: '属性' }, | |
81 | + '1': { CUSTOM: 1, name: '服务' }, | |
82 | + '2': { CUSTOM: 2, name: '属性' }, | |
83 | 83 | }; | ... | ... |