Commit 7f3e4715fe11fada6207f8d40ae4a7aa193d9a64

Authored by ww
1 parent fd5c0bb0

feat: implement camera manage streaming config

... ... @@ -12,9 +12,10 @@ enum CameraManagerApi {
12 12 CAMERA_GET_URL = '/video',
13 13 CAMERA_DELETE_URL = '/video',
14 14 CAMERA_GET_DETAIL_URL = '/video',
15   - STERAMING_GET_URL = '/video/platform',
16   - STERAMING_POST_URL = '/video/platform',
17   - STERAMING_DELETE_URL = '/video/platform',
  15 + STREAMING_GET_URL = '/video/platform',
  16 + STREAMING_POST_URL = '/video/platform',
  17 + STREAMING_DELETE_URL = '/video/platform',
  18 + STREAMING_PLAY_GET_URL = '/video/url',
18 19 }
19 20
20 21 export const cameraPage = (params: CameraQueryParam) => {
... ... @@ -59,7 +60,7 @@ export const getCameraManageDetail = (id: string) => {
59 60 */
60 61 export const getStreamingMediaList = (params: StreamingQueryParam) => {
61 62 return defHttp.get({
62   - url: CameraManagerApi.STERAMING_GET_URL,
  63 + url: CameraManagerApi.STREAMING_GET_URL,
63 64 params,
64 65 });
65 66 };
... ... @@ -71,7 +72,7 @@ export const getStreamingMediaList = (params: StreamingQueryParam) => {
71 72 */
72 73 export const createOrUpdateStreamingMediaRecord = (params: StreamingSubmitParam) => {
73 74 return defHttp.post({
74   - url: CameraManagerApi.STERAMING_POST_URL,
  75 + url: CameraManagerApi.STREAMING_POST_URL,
75 76 params,
76 77 });
77 78 };
... ... @@ -83,7 +84,18 @@ export const createOrUpdateStreamingMediaRecord = (params: StreamingSubmitParam)
83 84 */
84 85 export const deleteStreamingMediaRecord = (params: StreamingMediaDeleteParam) => {
85 86 return defHttp.delete({
86   - url: CameraManagerApi.STERAMING_POST_URL,
  87 + url: CameraManagerApi.STREAMING_POST_URL,
87 88 params,
88 89 });
89 90 };
  91 +
  92 +/**
  93 + * @description 获取流媒体播放地址
  94 + * @param entityId
  95 + * @returns
  96 + */
  97 +export const getStreamingPlayUrl = (entityId: string) => {
  98 + return defHttp.get({
  99 + url: `${CameraManagerApi.STREAMING_PLAY_GET_URL}/${entityId}`,
  100 + });
  101 +};
... ...
... ... @@ -10,6 +10,7 @@ export type CameraParam = {
10 10 };
11 11
12 12 export interface CameraModel {
  13 + accessMode: number;
13 14 avatar?: string;
14 15 brand: string;
15 16 createTime?: '2022-04-19T11:33:13.113Z';
... ... @@ -36,6 +37,21 @@ export interface CameraModel {
36 37 videoUrl: string;
37 38 }
38 39
  40 +export interface StreamingManageRecord {
  41 + id: string;
  42 + creator: string;
  43 + createTime: string;
  44 + name: string;
  45 + enabled: boolean;
  46 + tenantId: string;
  47 + sn: string;
  48 + organizationId: string;
  49 + organizationName: string;
  50 + status: boolean;
  51 + accessMode: number;
  52 + playProtocol: number;
  53 +}
  54 +
39 55 export interface StreamingMediaModel {
40 56 id: string;
41 57 creator: string;
... ...
... ... @@ -29,9 +29,9 @@
29 29 </BasicDrawer>
30 30 </template>
31 31 <script lang="ts">
32   - import { defineComponent, ref, computed, unref } from 'vue';
  32 + import { defineComponent, ref, computed, unref, nextTick } from 'vue';
33 33 import { BasicForm, useForm } from '/@/components/Form';
34   - import { formSchema } from './config.data';
  34 + import { formSchema, manuallyEnter, streamingMediaAcquire } from './config.data';
35 35 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
36 36 import { createOrEditCameraManage } from '/@/api/camera/cameraManager';
37 37 import { message, Upload } from 'ant-design-vue';
... ... @@ -49,7 +49,10 @@
49 49
50 50 const isUpdate = ref(true);
51 51 const editId = ref('');
52   - const [registerForm, { validate, setFieldsValue, resetFields }] = useForm({
  52 + const [
  53 + registerForm,
  54 + { validate, setFieldsValue, resetFields, removeSchemaByFiled, appendSchemaByField },
  55 + ] = useForm({
53 56 labelWidth: 120,
54 57 schemas: formSchema,
55 58 showActionButtonGroup: false,
... ... @@ -60,6 +63,20 @@
60 63 setDrawerProps({ confirmLoading: false });
61 64 isUpdate.value = !!data?.isUpdate;
62 65 if (unref(isUpdate)) {
  66 + await nextTick();
  67 + removeSchemaByFiled([
  68 + 'videoPlatformId',
  69 + 'streamType',
  70 + 'playProtocol',
  71 + 'sn',
  72 + 'brand',
  73 + 'videoUrl',
  74 + ]);
  75 + if (data.record.accessMode === 0) {
  76 + manuallyEnter.forEach((schema) => appendSchemaByField(schema, undefined));
  77 + } else {
  78 + streamingMediaAcquire.forEach((schema) => appendSchemaByField(schema, undefined));
  79 + }
63 80 editId.value = data.record.id;
64 81 tenantLogo.value = data.record?.avatar;
65 82 await setFieldsValue(data.record);
... ... @@ -104,12 +121,6 @@
104 121 try {
105 122 const { createMessage } = useMessage();
106 123 const values = await validate();
107   - if (values.name == undefined || values.name == '')
108   - return createMessage.error('请填写视频名字');
109   - if (values.sn == undefined || values.sn == '')
110   - return createMessage.error('请填写摄像头编号');
111   - if (values.videoUrl == undefined || values.videoUrl == '')
112   - return createMessage.error('请填写视频流');
113 124 if (!values) return;
114 125 if (tenantLogo.value !== '') {
115 126 values.avatar = tenantLogo.value;
... ...
... ... @@ -23,10 +23,13 @@
23 23 </div>
24 24 </template>
25 25 <script setup lang="ts">
26   - import { ref, nextTick, reactive } from 'vue';
  26 + import { ref, nextTick, reactive, unref } from 'vue';
27 27 import { BasicModal, useModalInner } from '/@/components/Modal';
  28 + import type { StreamingManageRecord, CameraModel } from '/@/api/camera/model/cameraModel';
28 29 import { videoPlay } from 'vue3-video-play'; // 引入组件
29 30 import 'vue3-video-play/dist/style.css'; // 引入css
  31 + import { AccessMode } from './config.data';
  32 + import { getStreamingPlayUrl } from '/@/api/camera/cameraManager';
30 33
31 34 const heightNum = ref(800);
32 35 const showVideo = ref(false);
... ... @@ -63,16 +66,26 @@
63 66 console.log(video.value);
64 67 });
65 68
66   - const [register] = useModalInner((data) => {
67   - if (data) {
68   - if (data.record.videoUrl) {
69   - showVideo.value = true;
70   - options.src = data.record.videoUrl;
71   - options.autoPlay = true;
  69 + const [register] = useModalInner(
  70 + async (data: { record: CameraModel | StreamingManageRecord }) => {
  71 + const { record } = data;
  72 + if (record.accessMode === AccessMode.ManuallyEnter) {
  73 + if ((record as CameraModel).videoUrl) {
  74 + showVideo.value = true;
  75 + options.src = (record as CameraModel).videoUrl;
  76 + options.autoPlay = true;
  77 + }
  78 + } else {
  79 + try {
  80 + const { data: { url } = { url: '' } } = await getStreamingPlayUrl(record.id!);
  81 + showVideo.value = true;
  82 + options.src = url;
  83 + } catch (error) {}
72 84 }
73 85 }
74   - });
  86 + );
75 87 const handleCancel = () => {
  88 + console.log(unref(video));
76 89 //关闭暂停播放视频
77 90 video.value.pause();
78 91 };
... ...
... ... @@ -4,6 +4,23 @@ import { copyTransFun } from '/@/utils/fnUtils';
4 4 import type { FormSchema as QFormSchema } from '/@/components/Form/index';
5 5
6 6 import { CameraVideoUrl, CameraMaxLength } from '/@/utils/rules';
  7 +import { getStreamingMediaList } from '/@/api/camera/cameraManager';
  8 +
  9 +export enum AccessMode {
  10 + ManuallyEnter = 0,
  11 + Streaming = 1,
  12 +}
  13 +
  14 +export enum PlayProtocol {
  15 + HTTP = 0,
  16 + HTTPS = 1,
  17 +}
  18 +
  19 +export enum StreamType {
  20 + MASTER = 0,
  21 + CHILD = 1,
  22 + THIRD = 2,
  23 +}
7 24
8 25 // 表格列数据
9 26 export const columns: BasicColumn[] = [
... ... @@ -59,6 +76,97 @@ export const searchFormSchema: FormSchema[] = [
59 76 },
60 77 ];
61 78
  79 +/**
  80 + * @description 手动输入
  81 + */
  82 +export const manuallyEnter: FormSchema[] = [
  83 + {
  84 + field: 'brand',
  85 + label: '视频厂家',
  86 + component: 'Input',
  87 + componentProps: {
  88 + placeholder: '请输入视频厂家',
  89 + },
  90 + },
  91 + {
  92 + field: 'sn',
  93 + label: '摄像头编号',
  94 + required: true,
  95 + component: 'Input',
  96 + rules: [...CameraVideoUrl, { required: true, message: '摄像头编号是必填项' }],
  97 + componentProps: {
  98 + placeholder: '请输入摄像头编号',
  99 + },
  100 + },
  101 + {
  102 + field: 'videoUrl',
  103 + label: '视频流',
  104 + required: true,
  105 + component: 'Input',
  106 + componentProps: {
  107 + placeholder: '请输入视频流',
  108 + maxLength: 255,
  109 + },
  110 + rules: [...CameraVideoUrl, { required: true, message: '视频流是必填项' }],
  111 + },
  112 +];
  113 +
  114 +/**
  115 + * @description 流媒体获取
  116 + */
  117 +export const streamingMediaAcquire: FormSchema[] = [
  118 + {
  119 + field: 'videoPlatformId',
  120 + label: '流媒体配置',
  121 + component: 'ApiSelect',
  122 + componentProps: {
  123 + placeholder: '请选择流媒体配置',
  124 + api: getStreamingMediaList,
  125 + labelField: 'host',
  126 + valueField: 'id',
  127 + },
  128 + },
  129 + {
  130 + field: 'streamType',
  131 + label: '码流',
  132 + component: 'RadioGroup',
  133 + defaultValue: StreamType.MASTER,
  134 + componentProps: {
  135 + placeholder: '请选择码流',
  136 + defaultValue: StreamType.MASTER,
  137 + options: [
  138 + { label: '主码流', value: StreamType.MASTER },
  139 + { label: '子码流', value: StreamType.CHILD },
  140 + { label: '第三码流', value: StreamType.THIRD },
  141 + ],
  142 + },
  143 + },
  144 + {
  145 + field: 'playProtocol',
  146 + label: '播放协议',
  147 + component: 'RadioGroup',
  148 + defaultValue: PlayProtocol.HTTP,
  149 + componentProps: {
  150 + placeholder: '请选择播放协议',
  151 + defaultValue: PlayProtocol.HTTP,
  152 + options: [
  153 + { label: 'http', value: PlayProtocol.HTTP },
  154 + { label: 'https', value: PlayProtocol.HTTPS },
  155 + ],
  156 + },
  157 + },
  158 + {
  159 + field: 'sn',
  160 + label: '监控点编号',
  161 + component: 'Input',
  162 + rules: [...CameraVideoUrl, { required: true, message: '摄像头编号是必填项' }],
  163 +
  164 + componentProps: {
  165 + placeholder: '请输入监控点编号',
  166 + },
  167 + },
  168 +];
  169 +
62 170 // 弹框配置项
63 171 export const formSchema: QFormSchema[] = [
64 172 {
... ... @@ -76,7 +184,7 @@ export const formSchema: QFormSchema[] = [
76 184 placeholder: '请输入视频名字',
77 185 maxLength: 30,
78 186 },
79   - rules: CameraMaxLength,
  187 + rules: [...CameraMaxLength, { required: true, message: '视频名是必填项' }],
80 188 },
81 189 {
82 190 field: 'organizationId',
... ... @@ -92,32 +200,48 @@ export const formSchema: QFormSchema[] = [
92 200 },
93 201 },
94 202 {
95   - field: 'brand',
96   - label: '视频厂家',
97   - component: 'Input',
98   - componentProps: {
99   - placeholder: '请输入视频厂家',
100   - },
101   - },
102   - {
103   - field: 'sn',
104   - label: '摄像头编号',
105   - required: true,
106   - component: 'Input',
107   - rules: CameraVideoUrl,
108   - componentProps: {
109   - placeholder: '请输入摄像头编号',
110   - },
111   - },
112   - {
113   - field: 'videoUrl',
114   - label: '视频流',
115   - required: true,
116   - component: 'Input',
117   - componentProps: {
118   - placeholder: '请输入视频流',
119   - maxLength: 255,
  203 + label: '视频流获取方式',
  204 + field: 'accessMode',
  205 + component: 'RadioGroup',
  206 + rules: [{ required: true, message: '视频流获取方式为必选项', type: 'number' }],
  207 + defaultValue: AccessMode.ManuallyEnter,
  208 + componentProps({ formActionType }) {
  209 + return {
  210 + defaultValue: AccessMode.ManuallyEnter,
  211 + placeholder: '请选择视频流获取方式',
  212 + options: [
  213 + { label: '手动输入', value: AccessMode.ManuallyEnter },
  214 + { label: '流媒体获取', value: AccessMode.Streaming },
  215 + ],
  216 + onChange(event: { target: { value: number } }) {
  217 + formActionType.removeSchemaByFiled([
  218 + 'videoPlatformId',
  219 + 'streamType',
  220 + 'playProtocol',
  221 + 'sn',
  222 + 'brand',
  223 + 'videoUrl',
  224 + ]);
  225 + const {
  226 + target: { value },
  227 + } = event;
  228 + if (value === AccessMode.ManuallyEnter) {
  229 + manuallyEnter.forEach((schema) =>
  230 + formActionType.appendSchemaByField(schema, undefined)
  231 + );
  232 + } else {
  233 + streamingMediaAcquire.forEach((schema) =>
  234 + formActionType.appendSchemaByField(schema, undefined)
  235 + );
  236 +
  237 + formActionType.setFieldsValue({
  238 + streamType: StreamType.MASTER,
  239 + playProtocol: PlayProtocol.HTTP,
  240 + });
  241 + }
  242 + },
  243 + };
120 244 },
121   - rules: CameraVideoUrl,
122 245 },
  246 + ...manuallyEnter,
123 247 ];
... ...
  1 +import { PlayProtocol } from '../manage/config.data';
1 2 import type { StreamingMediaModel } from '/@/api/camera/model/cameraModel';
2 3 import { BasicColumn, FormSchema } from '/@/components/Table';
3 4
... ... @@ -72,8 +73,8 @@ export const formDetailSchema: FormSchema[] = [
72 73 rules: [{ required: true, message: '流媒体部署环境为必填项', type: 'number' }],
73 74 componentProps: {
74 75 options: [
75   - { label: 'http', value: 0 },
76   - { label: 'https', value: 1 },
  76 + { label: 'http', value: PlayProtocol.HTTP },
  77 + { label: 'https', value: PlayProtocol.HTTPS },
77 78 ],
78 79 },
79 80 },
... ...