Commit 9fc75900599f365104e654f6334d23f63b94db00

Authored by xp.Huang
2 parents 59683e06 520ac95c

Merge branch 'feat/transport-type-GBT28181' into 'main_dev'

feat: gbt28181(支持点播、云台控制)

See merge request yunteng/thingskit-front!1208
... ... @@ -19,6 +19,7 @@ enum CameraManagerApi {
19 19 STREAMING_POST_URL = '/video/platform',
20 20 STREAMING_DELETE_URL = '/video/platform',
21 21 STREAMING_PLAY_GET_URL = '/video/url',
  22 + VIDEO_CONTROL_STOP = '/video/control/stop/',
22 23 }
23 24
24 25 export const cameraPage = (params: CameraQueryParam) => {
... ... @@ -127,3 +128,10 @@ export const controlling = (params: any) => {
127 128 params,
128 129 });
129 130 };
  131 +
  132 +//云台控制 停止点播
  133 +export const stopOnDemandVideoApiGet = (deviceId: string, channelId: string) => {
  134 + return defHttp.get({
  135 + url: `${CameraManagerApi.VIDEO_CONTROL_STOP}${deviceId}/${channelId}`,
  136 + });
  137 +};
... ...
  1 +export interface VideoChannelQueryParamsType {
  2 + page: number;
  3 + pageSize: number;
  4 + tbDeviceId?: string;
  5 + name?: string;
  6 + cameraCode?: string;
  7 +}
  8 +
  9 +export interface VideoChannelItemType {
  10 + id: string;
  11 + createTime: string;
  12 + updateTime: string;
  13 + name: string;
  14 + enabled: boolean;
  15 + tenantId: string;
  16 + channelId: string;
  17 + cameraCode: string;
  18 + deviceId: string;
  19 + manufacturer: string;
  20 + model: string;
  21 + owner: string;
  22 + civilCode: string;
  23 + address: string;
  24 + parental: number;
  25 + safetyWay: number;
  26 + registerWay: number;
  27 + certifiable: number;
  28 + errorCode: number;
  29 + secrecy: number;
  30 + status: string;
  31 + longitude: number;
  32 + latitude: number;
  33 + longitudeGcj02: number;
  34 + latitudeGcj02: number;
  35 + longitudeWgs84: number;
  36 + latitudeWgs84: number;
  37 + subCount: number;
  38 + hasAudio: boolean;
  39 + channelType: number;
  40 + ptztype: number;
  41 + ifShowGBT?: boolean;
  42 +}
  43 +
  44 +export interface VideoChannelPlayAddressType {
  45 + code: number;
  46 + message: string;
  47 + data: Data;
  48 +}
  49 +
  50 +export interface Data {
  51 + app: string;
  52 + stream: string;
  53 + ip: any;
  54 + flv: string;
  55 + https_flv: string;
  56 + ws_flv: string;
  57 + wss_flv: string;
  58 + fmp4: string;
  59 + https_fmp4: string;
  60 + ws_fmp4: string;
  61 + wss_fmp4: string;
  62 + hls: string;
  63 + https_hls: string;
  64 + ws_hls: string;
  65 + wss_hls: string;
  66 + ts: string;
  67 + https_ts: string;
  68 + ws_ts: string;
  69 + wss_ts: any;
  70 + rtmp: string;
  71 + rtmps: string;
  72 + rtsp: string;
  73 + rtsps: string;
  74 + rtc: string;
  75 + rtcs: string;
  76 + mediaServerId: string;
  77 + tracks: Track[];
  78 + startTime: any;
  79 + endTime: any;
  80 + progress: number;
  81 +}
  82 +
  83 +export interface Track {
  84 + channels: number;
  85 + codecId: number;
  86 + codecIdName: any;
  87 + codecType: number;
  88 + ready: boolean;
  89 + sampleBit: number;
  90 + sampleRate: number;
  91 + fps: number;
  92 + height: number;
  93 + width: number;
  94 +}
  95 +
  96 +export interface VideoChanneControlType {
  97 + command?: string | number | object;
  98 + horizonSpeed?: string | number | object;
  99 + verticalSpeed?: string | number | object;
  100 + zoomSpeed?: string | number | object;
  101 + tbDeviceId?: string | number | object;
  102 + channelId?: string | number | object;
  103 +}
... ...
  1 +import {
  2 + VideoChannelItemType,
  3 + VideoChannelPlayAddressType,
  4 + VideoChannelQueryParamsType,
  5 + VideoChanneControlType,
  6 +} from './model/videoChannelModel';
  7 +import { PaginationResult } from '/#/axios';
  8 +import { defHttp } from '/@/utils/http/axios';
  9 +
  10 +enum Api {
  11 + GET_VIDEO_CHANNEL_LIST = '/video/channel',
  12 + GET_VIDEO_CONTROL_START = '/video/control/start',
  13 + GET_VIDEO_CONTROL_STOP = '/video/control/stop',
  14 + SET_VIDEO_CONTROL_CONTROL = '/video/control/control',
  15 +}
  16 +
  17 +export const getVideoChannelList = (params: VideoChannelQueryParamsType) => {
  18 + return defHttp.get<PaginationResult<VideoChannelItemType>>({
  19 + url: Api.GET_VIDEO_CHANNEL_LIST,
  20 + params,
  21 + });
  22 +};
  23 +
  24 +export const getVideoControlStart = ({
  25 + deviceId,
  26 + channelId,
  27 +}: Record<'deviceId' | 'channelId', string>) => {
  28 + return defHttp.get<VideoChannelPlayAddressType>(
  29 + {
  30 + url: `${Api.GET_VIDEO_CONTROL_START}/${deviceId}/${channelId}`,
  31 + timeout: 30 * 1000,
  32 + },
  33 + {}
  34 + );
  35 +};
  36 +
  37 +export const setVideoControl = (tbDeviceId, channelId, params: VideoChanneControlType) => {
  38 + return defHttp.get<VideoChannelPlayAddressType>({
  39 + url: `${Api.SET_VIDEO_CONTROL_CONTROL}/${tbDeviceId}/${channelId}`,
  40 + // timeout: 30 * 1000,
  41 + params,
  42 + });
  43 +};
... ...
... ... @@ -16,10 +16,10 @@
16 16 @open-gateway-device="handleOpenGatewayDevice"
17 17 />
18 18 </Tabs.TabPane>
19   - <Tabs.TabPane key="modelOfMatter" tab="物模型数据">
  19 + <Tabs.TabPane v-if="!isGBTTransportType" key="modelOfMatter" tab="物模型数据">
20 20 <ModelOfMatter :deviceDetail="deviceDetail" />
21 21 </Tabs.TabPane>
22   - <Tabs.TabPane key="3">
  22 + <Tabs.TabPane v-if="!isGBTTransportType" key="3">
23 23 <template #tab>
24 24 <Badge :offset="[2, -5]" style="color: inherit">
25 25 <span>告警</span>
... ... @@ -35,29 +35,32 @@
35 35 </template>
36 36 <AlarmLog :device-id="deviceDetail.id" class="bg-gray-100" />
37 37 </Tabs.TabPane>
38   - <Tabs.TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === 'GATEWAY'">
  38 + <Tabs.TabPane key="4" tab="子设备" v-if="deviceDetail?.deviceType === DeviceTypeEnum.GATEWAY">
39 39 <ChildDevice
40 40 :fromId="deviceDetail?.tbDeviceId"
41 41 @openTbDeviceDetail="handleOpenTbDeviceDetail"
42 42 />
43 43 </Tabs.TabPane>
44   - <Tabs.TabPane key="7" tab="命令下发记录">
  44 + <Tabs.TabPane v-if="!isGBTTransportType" key="7" tab="命令下发记录">
45 45 <CommandRecord :deviceDetail="deviceDetail" :fromId="deviceDetail?.tbDeviceId" />
46 46 </Tabs.TabPane>
47 47 <!-- 网关设备并且场家是TBox -->
48 48 <Tabs.TabPane
49 49 key="6"
50 50 tab="TBox"
51   - v-if="deviceDetail?.deviceType === 'GATEWAY' && deviceDetail?.brand == 'TBox'"
  51 + v-if="deviceDetail?.deviceType === DeviceTypeEnum.GATEWAY && deviceDetail?.brand == 'TBox'"
52 52 >
53 53 <TBoxDetail :deviceDetail="deviceDetail" />
54 54 </Tabs.TabPane>
55   - <Tabs.TabPane key="eventManage" tab="事件管理">
  55 + <Tabs.TabPane v-if="!isGBTTransportType" key="eventManage" tab="事件管理">
56 56 <EventManage :tbDeviceId="deviceDetail.tbDeviceId" />
57 57 </Tabs.TabPane>
58   - <Tabs.TabPane key="task" tab="任务">
  58 + <Tabs.TabPane v-if="!isGBTTransportType" key="task" tab="任务">
59 59 <Task :tbDeviceId="deviceDetail.tbDeviceId" />
60 60 </Tabs.TabPane>
  61 + <Tabs.TabPane v-if="isGBTTransportType" key="videoChanel" tab="视频通道">
  62 + <VideoChannel :deviceDetail="deviceDetail" />
  63 + </Tabs.TabPane>
61 64 </Tabs>
62 65 </BasicDrawer>
63 66 </template>
... ... @@ -72,10 +75,12 @@
72 75 import { getDeviceDetail } from '/@/api/device/deviceManager';
73 76 import ModelOfMatter from '../tabs/ModelOfMatter.vue';
74 77 import EventManage from '../tabs/EventManage/index.vue';
75   - import { DeviceRecord } from '/@/api/device/model/deviceModel';
  78 + import { DeviceRecord, DeviceTypeEnum } from '/@/api/device/model/deviceModel';
76 79 import Task from '../tabs/Task.vue';
77 80 import AlarmLog from '/@/views/alarm/log/index.vue';
78 81 import { Icon } from '/@/components/Icon';
  82 + import VideoChannel from '../tabs/VideoChannel/index.vue';
  83 + import { TransportTypeEnum } from '../../../profiles/components/TransportDescript/const';
79 84
80 85 const emit = defineEmits(['reload', 'register', 'openTbDeviceDetail', 'openGatewayDeviceDetail']);
81 86
... ... @@ -84,12 +89,14 @@
84 89 const deviceDetailRef = ref();
85 90 const deviceDetail = ref<DeviceRecord>({} as unknown as DeviceRecord);
86 91
87   - const isTransportType = ref<Boolean>(false); //获取产品是不是GB/T 28181
  92 + const isGBTTransportType = ref<boolean>(false); //获取产品是不是GB/T 28181
88 93 // 详情回显
89 94 const [register] = useDrawerInner(async (data) => {
90 95 const { id, transportType, deviceType } = data || {};
91   - isTransportType.value =
92   - transportType == 'GB/T28181' && deviceType == 'DIRECT_CONNECTION' ? true : false;
  96 + isGBTTransportType.value = !!(
  97 + transportType == TransportTypeEnum.GBT28181 && deviceType == DeviceTypeEnum.DIRECT_CONNECTION
  98 + );
  99 +
93 100 // 设备详情
94 101 const res = await getDeviceDetail(id);
95 102 deviceDetail.value = res;
... ...
... ... @@ -2,43 +2,46 @@ import { h } from 'vue';
2 2 import { BasicColumn, FormSchema } from '/@/components/Table';
3 3 import { Tag } from 'ant-design-vue';
4 4 import { withInstall } from '/@/utils/index';
5   -import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
6 5
7 6 import VideoPlay from './video.vue';
8 7 export const Video = withInstall(VideoPlay);
9 8
  9 +enum ChannelStatusEnum {
  10 + ONLINE = 'ONLINE',
  11 +}
  12 +
10 13 export const configColumns: BasicColumn[] = [
11 14 {
12 15 title: '通道编号',
13   - dataIndex: 'channellNumber',
14   - },
15   - {
16   - title: '设备名称',
17   - dataIndex: 'deviceName',
  16 + dataIndex: 'cameraCode',
18 17 },
19 18 {
20 19 title: '通道名称',
21   - dataIndex: 'channelName',
  20 + dataIndex: 'name',
22 21 },
23 22 {
24   - title: '厂家',
25   - dataIndex: 'manufacturer',
  23 + title: '型号',
  24 + dataIndex: 'model',
26 25 },
27 26 {
28   - title: '开启音频',
29   - dataIndex: 'turnOnAudio',
30   - slots: { customRender: 'turnOnAudio' },
  27 + title: '厂商',
  28 + dataIndex: 'manufacturer',
31 29 },
  30 + // {
  31 + // title: '开启音频',
  32 + // dataIndex: 'hasAudio',
  33 + // slots: { customRender: 'hasAudio' },
  34 + // },
32 35 {
33 36 title: '状态',
34   - dataIndex: 'state',
35   - format: (text) => {
  37 + dataIndex: 'status',
  38 + customRender: ({ text }: { text: ChannelStatusEnum }) => {
36 39 return h(
37 40 Tag,
38 41 {
39   - color: Number(text) === 1 ? 'green' : 'blue',
  42 + color: text === ChannelStatusEnum.ONLINE ? 'green' : 'blue',
40 43 },
41   - () => (Number(text) === 1 ? '在线' : '离线')
  44 + () => (text === ChannelStatusEnum.ONLINE ? '在线' : '离线')
42 45 );
43 46 },
44 47 },
... ... @@ -52,46 +55,21 @@ export const configColumns: BasicColumn[] = [
52 55 export const searchFormSchema: FormSchema[] | any = [
53 56 {
54 57 field: 'name',
55   - label: '设备名称',
  58 + label: '通道名称',
56 59 component: 'Input',
57 60 colProps: { span: 6 },
58 61 componentProps: {
59 62 maxLength: 255,
60   - placeholder: '请输入设备名称',
  63 + placeholder: '请输入通道名称',
61 64 },
62 65 },
63 66 {
64   - field: 'deviceType',
65   - label: '设备类型',
66   - component: 'Select',
67   - colProps: { span: 6 },
68   - componentProps: {
69   - options: [
70   - { label: '网关设备', value: DeviceTypeEnum.GATEWAY },
71   - { label: '直连设备', value: DeviceTypeEnum.DIRECT_CONNECTION },
72   - { label: '网关子设备', value: DeviceTypeEnum.SENSOR },
73   - ],
74   - placeholder: '请选择设备类型',
75   - },
76   - },
77   - // {
78   - // field: 'channelName',
79   - // label: '通道名称',
80   - // component: 'Input',
81   - // colProps: { span: 6 },
82   - // componentProps: {
83   - // maxLength: 255,
84   - // placeholder: '请输入通道名称',
85   - // },
86   - // },
87   - {
88   - field: 'manufacturer',
89   - label: '厂家',
90   - component: 'Select',
  67 + field: 'cameraCode',
  68 + label: '国标编号',
  69 + component: 'Input',
91 70 colProps: { span: 6 },
92 71 componentProps: {
93   - options: [{}],
94   - placeholder: '请选择厂家',
  72 + placeholder: '请输入国标编号',
95 73 },
96 74 },
97 75 ];
... ...
... ... @@ -3,13 +3,13 @@
3 3 class="bg-neutral-100 dark:text-gray-300 dark:bg-dark-700 p-4"
4 4 @register="registerTable"
5 5 >
6   - <template #turnOnAudio="{ record }">
  6 + <template #hasAudio="{ record }">
7 7 <Switch
8 8 :checked="record.status === 1"
9 9 :loading="record.pendingStatus"
10 10 checkedChildren="开启"
11 11 unCheckedChildren="关闭"
12   - @change="(checked:boolean)=>handleTurnVideo(checked,record)"
  12 + @change="(checked: boolean) => handleTurnVideo(checked, record)"
13 13 />
14 14 </template>
15 15 <template #action="{ record }">
... ... @@ -22,7 +22,8 @@
22 22 onClick: handlePlay.bind(null, record),
23 23 },
24 24 ]"
25   - /></template>
  25 + />
  26 + </template>
26 27 </BasicTable>
27 28 <VideoModal @register="registerModal" />
28 29 </template>
... ... @@ -34,28 +35,22 @@
34 35 import { DeviceRecord } from '/@/api/device/model/deviceModel';
35 36 import VideoModal from './videoModal.vue';
36 37 import { useModal } from '/@/components/Modal';
37   - import { onMounted } from 'vue';
38 38 import { useMessage } from '/@/hooks/web/useMessage';
  39 + import { getVideoChannelList } from '/@/api/device/videoChannel';
39 40
40   - defineProps({
41   - fromId: {
42   - type: String,
43   - default: '',
44   - },
45   - deviceDetail: {
46   - type: Object as PropType<DeviceRecord>,
47   - required: true,
48   - },
49   - });
  41 + const props = defineProps<{ deviceDetail: DeviceRecord }>();
50 42
51 43 const [registerModal, { openModal }] = useModal();
52 44
53   - const [registerTable, { setTableData, setProps, setSelectedRowKeys, reload }] = useTable({
54   - // api: deviceCommandRecordGetQuery,
  45 + const [registerTable, { setProps, setSelectedRowKeys, reload }] = useTable({
  46 + api: getVideoChannelList,
55 47 columns: configColumns,
56 48 showTableSetting: true,
57 49 bordered: true,
58 50 showIndexColumn: false,
  51 + beforeFetch: (params: Recordable) => {
  52 + return { ...params, tbDeviceId: props.deviceDetail.tbDeviceId };
  53 + },
59 54 formConfig: {
60 55 labelWidth: 120,
61 56 schemas: searchFormSchema,
... ... @@ -81,196 +76,10 @@
81 76 }
82 77 };
83 78
84   - const tableList = [
85   - {
86   - id: '8b66f4fa-88e0-42b2-be33-60652cd2bda1',
87   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
88   - createTime: '2023-03-10 17:16:54',
89   - updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
90   - updateTime: '2023-04-11 10:25:49',
91   - name: 'dasd',
92   - enabled: false,
93   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
94   - videoUrl: 'ws://192.168.10.134:28080/rtp/62020000492000000002_34020000001320000001.live.flv',
95   - sn: 's',
96   - organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
97   - organizationName: '车车组织',
98   - status: false,
99   - accessMode: 0,
100   - playProtocol: 0,
101   - channellNumber: 1,
102   - },
103   - {
104   - id: '9ff408ab-980f-470c-a55c-e4e284ddd34d',
105   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
106   - createTime: '2023-02-22 14:50:13',
107   - updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
108   - updateTime: '2023-04-11 10:36:25',
109   - name: '2',
110   - enabled: false,
111   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
112   - videoUrl:
113   - 'https://vcsplay.scjtonline.cn:8099/live/HD_d80a740b-2672-4ad1-90e4-52eb71d8c2ef.m3u8?auth_key=1681180571-0-0-dfdb334e5f83838ade5f01f61f910107',
114   - sn: '212',
115   - organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
116   - organizationName: '车车组织',
117   - status: false,
118   - accessMode: 0,
119   - playProtocol: 0,
120   - channellNumber: 1,
121   - },
122   - {
123   - id: 'a6edd8fb-a91a-4a1b-8124-65959206dac4',
124   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
125   - createTime: '2023-02-21 16:39:51',
126   - updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
127   - updateTime: '2023-04-11 10:33:27',
128   - name: 'dasda',
129   - enabled: false,
130   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
131   - videoUrl:
132   - 'https://vcsplay.scjtonline.cn:8200/live/HD_1b361aa9-5230-48ba-b8be-d1e2c4e9b178.m3u8?auth_key=1681180365-0-0-e77f40e88550091053139f5562d8afa2',
133   - brand: 'dasdad',
134   - sn: 'adsad',
135   - organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
136   - organizationName: '车车组织',
137   - status: false,
138   - accessMode: 0,
139   - playProtocol: 0,
140   - channellNumber: 1,
141   - },
142   - {
143   - id: '51b4c0bc-8050-4b37-bdb3-9fe08b14cf86',
144   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
145   - createTime: '2023-02-21 16:37:44',
146   - updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
147   - updateTime: '2023-04-11 10:56:59',
148   - name: '视频',
149   - enabled: false,
150   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
151   - videoUrl:
152   - 'https://vcsplay.scjtonline.cn:8093/live/HD_c54034ca-4a6d-11eb-8edc-3cd2e55e088c.m3u8?auth_key=1681181808-0-0-d756d9b0426b71482e45b9377958e4dc',
153   - brand: '视频厂家',
154   - sn: 'DART2143SAD12RE',
155   - organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
156   - organizationName: '车车组织',
157   - status: false,
158   - accessMode: 0,
159   - playProtocol: 0,
160   - channellNumber: 1,
161   - },
162   - {
163   - id: '8c0e6ed0-3176-4e76-bd8e-92f722f61e79',
164   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
165   - createTime: '2022-12-01 15:55:54',
166   - updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
167   - updateTime: '2023-04-11 10:59:22',
168   - name: '视频',
169   - enabled: false,
170   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
171   - avatar: 'https://demo.thingskit.com:9000/yunteng/itbbqOBXIUzWvjq.jpeg',
172   - videoUrl: 'http://113.204.115.250:83/openUrl/iFzoWME/live.m3u8',
173   - brand: '厂家',
174   - sn: 'JDKSA11321',
175   - organizationId: '9196fd9a-624a-4891-a8b3-ce588baedf9f',
176   - organizationName: '丰田',
177   - status: false,
178   - channellNumber: 1,
179   - accessMode: 0,
180   - playProtocol: 0,
181   - },
182   - {
183   - id: 'c30422a7-9498-49a5-96d5-e77f3a2823e3',
184   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
185   - createTime: '2022-12-01 14:42:52',
186   - updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
187   - updateTime: '2023-03-02 17:12:53',
188   - name: '湖南卫视',
189   - enabled: false,
190   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
191   - videoUrl:
192   - 'http://219.151.31.38/liveplay-kk.rtxapp.com/live/program/live/hnwshd/4000000/mnf.m3u8',
193   - brand: 'BUZHIDAO',
194   - sn: 'QKDK123456',
195   - organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
196   - organizationName: '车车组织',
197   - status: false,
198   - channellNumber: 1,
199   - accessMode: 0,
200   - playProtocol: 0,
201   - },
202   - {
203   - id: 'e3253015-b8df-4e8f-ad0c-f634d3fd927e',
204   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
205   - createTime: '2022-11-29 11:19:00',
206   - name: '玩具视频播放',
207   - enabled: false,
208   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
209   - avatar: 'http://nc.tianzow.com:29000/yunteng/tgygMQmYaaPDPdG.jpg',
210   - videoUrl: 'https://ask.dcloud.net.cn/topic.m3u8',
211   - brand: '成都厂家',
212   - sn: 'TCL1528GOP',
213   - organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
214   - organizationName: '车车组织',
215   - status: false,
216   - accessMode: 0,
217   - channellNumber: 1,
218   - playProtocol: 0,
219   - },
220   - {
221   - id: '9edc9f73-3a9a-4e4b-9b4c-b955329b99b3',
222   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
223   - createTime: '2022-11-29 11:13:44',
224   - updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
225   - updateTime: '2023-01-11 10:03:18',
226   - name: '视频',
227   - enabled: false,
228   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
229   - sn: '7aeb4061f3cf4ba384ed8e1a3027d2a8',
230   - organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
231   - organizationName: '车车组织',
232   - status: false,
233   - accessMode: 1,
234   - videoPlatformId: '8cc7c20e-693b-48ea-9124-994e0908c83e',
235   - streamType: 0,
236   - playProtocol: 0,
237   - channellNumber: 1,
238   - videoPlatformDTO: {
239   - enabled: false,
240   - host: '113.204.115.250:7120',
241   - appKey: '28238690',
242   - appSecret: 'F3e3Ffvo9Wyg9jkl8BUS',
243   - ssl: 1,
244   - },
245   - },
246   - {
247   - id: '9d6675ad-07ed-45ae-bb4a-457000e164f8',
248   - creator: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
249   - createTime: '2022-11-21 11:49:59',
250   - updater: '694a8f7f-f7ed-4a9c-af89-a3d18fc3663e',
251   - updateTime: '2023-04-11 10:53:27',
252   - name: '新视频',
253   - enabled: false,
254   - tenantId: '0277ca80-693d-11ed-9e12-e5edad4f7148',
255   - videoUrl: 'http://www.w3school.com.cn/example/html5/mov_bbb.mp4',
256   - brand: '1111',
257   - sn: 'XYZ',
258   - organizationId: '27ef2a83-6f1f-4e33-824b-80afac684699',
259   - organizationName: '车车组织',
260   - status: false,
261   - accessMode: 0,
262   - channellNumber: 1,
263   - playProtocol: 0,
264   - },
265   - ];
266   -
267   - onMounted(() => {
268   - setTableData(tableList);
269   - });
270   -
271 79 const handlePlay = (record: Recordable) => {
272 80 openModal(true, {
273 81 record,
  82 + ifShowGBT: true,
274 83 });
275 84 };
276 85 </script>
... ...
... ... @@ -20,13 +20,20 @@
20 20 } from '@ant-design/icons-vue';
21 21 import { Button } from 'ant-design-vue';
22 22 import { nextTick } from 'vue';
23   - import { controlling } from '/@/api/camera/cameraManager';
  23 + import { controlling, stopOnDemandVideoApiGet } from '/@/api/camera/cameraManager';
  24 + import { setVideoControl } from '/@/api/device/videoChannel';
24 25
25 26 const { prefixCls } = useDesign('basic-video-play');
  27 + interface IGbtOption {
  28 + tbDeviceId: string;
  29 + channelId: string;
  30 + }
26 31
27 32 const props = defineProps<{
28 33 options?: VideoJsPlayerOptions;
29 34 withToken?: boolean;
  35 + isGBT?: boolean;
  36 + GBTOption: IGbtOption;
30 37 }>();
31 38
32 39 const emit = defineEmits<{
... ... @@ -38,6 +45,11 @@
38 45
39 46 const videoPlayInstance = ref<Nullable<VideoJsPlayer>>();
40 47
  48 + const getGBT = computed(() => {
  49 + const { isGBT } = props;
  50 + return isGBT;
  51 + });
  52 +
41 53 const getOptions = computed(() => {
42 54 const { options, withToken } = props;
43 55
... ... @@ -85,8 +97,9 @@
85 97
86 98 //播放/暂停
87 99 const handleClick = () => {
88   - unref(isPlay) && unref(videoPlayInstance)?.pause();
89   - !unref(isPlay) && unref(videoPlayInstance)?.play();
  100 + // unref(isPlay) ((true,停止),(false,开启))
  101 + if (unref(isPlay)) unref(videoPlayInstance)?.pause();
  102 + else unref(videoPlayInstance)?.play();
90 103 };
91 104
92 105 const getId = () => {
... ... @@ -100,6 +113,17 @@
100 113 controlling({ cameraIndexCode: organizationId, action, command: direction });
101 114 };
102 115
  116 + // 国标控制
  117 + const handleGBTControl = (command: string, action?: number | string) => {
  118 + const { tbDeviceId, channelId } = props.GBTOption;
  119 + setVideoControl(tbDeviceId, channelId, {
  120 + command,
  121 + horizonSpeed: action,
  122 + verticalSpeed: action,
  123 + zoomSpeed: action,
  124 + });
  125 + };
  126 +
103 127 const isPlay = ref<Boolean | null | undefined>(false);
104 128
105 129 onMounted(async () => {
... ... @@ -126,10 +150,19 @@
126 150
127 151 //长按开始
128 152 const moveStart = (action) => {
  153 + if (unref(getGBT)) {
  154 + handleGBTControl(action, '30');
  155 + return;
  156 + }
129 157 handleControl(0, action);
130 158 };
  159 +
131 160 // 长按结束
132 161 const moveStop = (action) => {
  162 + if (unref(getGBT)) {
  163 + handleGBTControl('STOP', '30');
  164 + return;
  165 + }
133 166 handleControl(1, action);
134 167 };
135 168
... ... @@ -137,8 +170,15 @@
137 170 unref(videoPlayInstance)?.dispose();
138 171 videoPlayInstance.value = null;
139 172 emit('onUnmounted');
  173 + stopOnDemandVideo();
140 174 });
141 175
  176 + // 停止点播视频
  177 + const stopOnDemandVideo = async () => {
  178 + const { tbDeviceId, channelId } = props.GBTOption;
  179 + await stopOnDemandVideoApiGet(tbDeviceId, channelId);
  180 + };
  181 +
142 182 defineExpose({
143 183 reloadPlayer: init,
144 184 getInstance: () => unref(videoPlayInstance),
... ... @@ -178,8 +218,8 @@
178 218 <div>
179 219 <Button
180 220 class="left-top in-block"
181   - @mousedown="moveStart('up')"
182   - @mouseup="moveStop('up')"
  221 + @mousedown="moveStart('UP')"
  222 + @mouseup="moveStop('UP')"
183 223 >
184 224 <CaretUpOutlined class="icon-rotate child-icon" />
185 225 </Button>
... ...
... ... @@ -10,90 +10,73 @@
10 10 :showOkBtn="false"
11 11 @cancel="handleCancel"
12 12 >
13   - <div class="flex items-center justify-center w-full h-full min-h-96 video-container">
14   - <Video
  13 + <div
  14 + class="flex items-center justify-center w-full h-full min-h-96 video-container bg-dark-50"
  15 + >
  16 + <VideoPlayer
  17 + ref="videoInstance"
15 18 v-if="showVideo"
16   - :options="(options as any)"
  19 + :options="(options as VideoJsPlayerOptions)"
17 20 :withToken="withToken"
18   - @on-unmounted="handleCloseFlvPlayUrl"
  21 + :isGBT="isGBT"
  22 + :GBTOption="GBTOption"
19 23 />
20 24 </div>
21 25 </BasicModal>
22 26 </div>
23 27 </template>
24 28 <script setup lang="ts">
25   - import { ref, reactive, unref } from 'vue';
  29 + import { ref, reactive } from 'vue';
26 30 import { BasicModal, useModalInner } from '/@/components/Modal';
27   - import type { StreamingManageRecord, CameraModel } from '/@/api/camera/model/cameraModel';
28   - import { getVideoTypeByUrl } from '/@/components/Video';
29   - import { closeFlvPlay, getFlvPlayUrl, getStreamingPlayUrl } from '/@/api/camera/cameraManager';
30   - import { isRtspProtocol } from '/@/components/Video/src/utils';
31 31 import { VideoJsPlayerOptions } from 'video.js';
32   - import { useFingerprint } from '/@/utils/useFingerprint';
33   - import { GetResult } from '@fingerprintjs/fingerprintjs';
34   - import { AccessMode } from '/@/views/camera/manage/config.data';
35   - import { Video } from './config';
  32 + import VideoPlayer from './video.vue';
  33 + import { getVideoControlStart } from '/@/api/device/videoChannel';
  34 + import { VideoChannelItemType } from '/@/api/device/model/videoChannelModel';
  35 + import { getVideoTypeByUrl } from '/@/components/Video';
36 36
37 37 const heightNum = ref(800);
38 38 const showVideo = ref(false);
39 39
40   - const playUrl = ref('');
  40 + const videoInstance = ref<InstanceType<typeof VideoPlayer>>();
41 41
42 42 const videoId = ref<string>();
43 43
44 44 const withToken = ref(false);
45 45
46   - const fingerprintResult = ref<Nullable<GetResult>>(null);
47   -
48 46 const options = reactive<VideoJsPlayerOptions>({
49 47 width: '100%' as unknown as number,
50 48 height: 384 as unknown as number,
51 49 autoplay: true,
52 50 });
  51 + const GBTOption = ref({
  52 + tbDeviceId: '',
  53 + channelId: '',
  54 + });
  55 + const isGBT = ref<boolean>(false);
53 56
54   - const setSources = (url: string, fingerprintResult: GetResult, id) => {
55   - const flag = isRtspProtocol(url);
56   - options.sources = [
57   - {
58   - src: flag ? getFlvPlayUrl(url, fingerprintResult.visitorId) : url,
59   - type: getVideoTypeByUrl(url),
60   - id,
61   - },
62   - ];
63   - };
64   -
65   - const { getResult } = useFingerprint();
66   - const [register] = useModalInner(
67   - async (data: { record: CameraModel | StreamingManageRecord }) => {
68   - const { record } = data;
  57 + const [register, { setModalProps }] = useModalInner(
  58 + async (data: { record: VideoChannelItemType }) => {
  59 + const { record, ifShowGBT = false } = data;
69 60 videoId.value = record.id || '';
70   - const result = await getResult();
71   - fingerprintResult.value = result;
72   - if (record.accessMode === AccessMode.ManuallyEnter) {
73   - if ((record as CameraModel).videoUrl) {
74   - if (isRtspProtocol((record as CameraModel).videoUrl)) {
75   - playUrl.value = (record as CameraModel).videoUrl;
76   - closeFlvPlay(unref(playUrl), result.visitorId);
77   - withToken.value = true;
78   - }
79   - setSources((record as CameraModel).videoUrl, result, record.id);
80   - }
81   - } else {
82   - try {
83   - const { data: { url } = { url: '' } } = await getStreamingPlayUrl(record.id!);
84   - setSources(url, result, record.id);
85   - } catch (error) {}
  61 + isGBT.value = ifShowGBT;
  62 + GBTOption.value.tbDeviceId = record.deviceId;
  63 + GBTOption.value.channelId = record.channelId;
  64 + try {
  65 + setModalProps({ loading: true, loadingTip: '视频加载中...' });
  66 +
  67 + const result = await getVideoControlStart({
  68 + deviceId: record.deviceId,
  69 + channelId: record.channelId,
  70 + });
  71 + options.sources = [{ src: result.data.flv, type: getVideoTypeByUrl(result.data.flv) }];
  72 + showVideo.value = true;
  73 + } catch (error) {
  74 + } finally {
  75 + setModalProps({ loading: false });
86 76 }
87   - showVideo.value = true;
88 77 }
89 78 );
90 79
91   - const handleCloseFlvPlayUrl = () => {
92   - if (isRtspProtocol(unref(playUrl))) {
93   - closeFlvPlay(unref(playUrl)!, unref(fingerprintResult)!.visitorId!);
94   - }
95   - };
96   -
97 80 const handleCancel = () => {
98 81 showVideo.value = false;
99 82 withToken.value = false;
... ...
... ... @@ -148,12 +148,12 @@
148 148 }
149 149 };
150 150 const handleStepNext = (e, data) => {
151   - // const { deviceType } = unref(DevConStRef)?.getFieldsValue() || {};
  151 + const { deviceType } = unref(DevConStRef)?.getFieldsValue() || {};
152 152 if (e) {
153 153 current.value++;
154 154 unref(isUpdate)
155   - ? unref(TransConStRef)?.editOrAddTransportTypeStatus(true)
156   - : unref(TransConStRef)?.editOrAddTransportTypeStatus(false);
  155 + ? unref(TransConStRef)?.editOrAddTransportTypeStatus(true, deviceType)
  156 + : unref(TransConStRef)?.editOrAddTransportTypeStatus(false, deviceType);
157 157 } else {
158 158 setTransConfEditFormData(data);
159 159 }
... ...
  1 +export enum TransportTypeEnum {
  2 + DEFAULT = 'DEFAULT',
  3 + MQTT = 'MQTT',
  4 + COAP = 'COAP',
  5 + LWM2M = 'LWM2M',
  6 + SNMP = 'SNMP',
  7 + TCP = 'TCP',
  8 + GBT28181 = 'GBT28181',
  9 +}
  10 +
1 11 export enum TransportPayloadTypeEnum {
2 12 PROTOBUF = 'PROTOBUF',
3 13 JSON = 'JSON',
... ...
... ... @@ -2,7 +2,7 @@
2 2 <div
3 3 class="step2-style"
4 4 :style="[
5   - isMqttType == 'DEFAULT' || isMqttType == 'GB/T28181'
  5 + isMqttType == 'DEFAULT' || isMqttType == 'GBT28181'
6 6 ? { minHeight: 0 + 'px' }
7 7 : { minHeight: 800 + 'px' },
8 8 ]"
... ... @@ -58,6 +58,7 @@
58 58 import Lwm2mCpns from './cpns/lwm2m/index.vue';
59 59 import SnmpCpns from './cpns/snmp/index.vue';
60 60 import TcpCpns from './cpns/tcp/index.vue';
  61 + import { DeviceTypeEnum } from '/@/api/device/model/deviceModel';
61 62
62 63 const emits = defineEmits(['prev']);
63 64 const props = defineProps({
... ... @@ -150,10 +151,14 @@
150 151 ...getTcpVal,
151 152 ...val,
152 153 };
  154 +
  155 + if (val?.transportType === 'GBT28181') {
  156 + step2Data.transportConfiguration = { type: val?.transportType };
  157 + }
153 158 return step2Data;
154 159 };
155 160
156   - const editOrAddTransportTypeStatus = (status: boolean) => {
  161 + const editOrAddTransportTypeStatus = (status: boolean, deviceType: DeviceTypeEnum) => {
157 162 const options = [
158 163 { label: '默认', value: 'DEFAULT' },
159 164 { label: 'MQTT', value: 'MQTT' },
... ... @@ -162,12 +167,12 @@
162 167 // { label: 'SNMP', value: 'SNMP' },
163 168 { label: 'TCP/UDP', value: 'TCP' },
164 169 ];
165   - // if (deviceType == 'DIRECT_CONNECTION') {
166   - // options.push({ label: 'GB/T 28181', value: 'GB/T28181' });//暂时隐藏 GBT 28181写完放出来
167   - // }
168   - // if (deviceType != 'DIRECT_CONNECTION' && isMqttType.value == 'GB/T28181') {
169   - // setFieldsValue({ transportType: null });
170   - // }
  170 + if (deviceType == DeviceTypeEnum.DIRECT_CONNECTION) {
  171 + options.push({ label: 'GBT28181', value: 'GBT28181' }); //暂时隐藏 GBT 28181写完放出来
  172 + }
  173 + if (deviceType != 'DIRECT_CONNECTION' && isMqttType.value == 'GBT28181') {
  174 + setFieldsValue({ transportType: null });
  175 + }
171 176 updateSchema({
172 177 field: 'transportType',
173 178 componentProps: {
... ...