Commit a2b21f85eae544d52ec3203c13247f618423a1be
1 parent
c79a9d7e
feat: add streaming media config page
Showing
5 changed files
with
380 additions
and
1 deletions
1 | 1 | import { defHttp } from '/@/utils/http/axios'; |
2 | -import { CameraModel, CameraQueryParam } from './model/cameraModel'; | |
2 | +import { | |
3 | + CameraModel, | |
4 | + CameraQueryParam, | |
5 | + StreamingMediaDeleteParam, | |
6 | + StreamingQueryParam, | |
7 | + StreamingSubmitParam, | |
8 | +} from './model/cameraModel'; | |
3 | 9 | |
4 | 10 | enum CameraManagerApi { |
5 | 11 | CAMERA_POST_URL = '/video', |
6 | 12 | CAMERA_GET_URL = '/video', |
7 | 13 | CAMERA_DELETE_URL = '/video', |
8 | 14 | CAMERA_GET_DETAIL_URL = '/video', |
15 | + STERAMING_GET_URL = '/video/platform', | |
16 | + STERAMING_POST_URL = '/video/platform', | |
17 | + STERAMING_DELETE_URL = '/video/platform', | |
9 | 18 | } |
10 | 19 | |
11 | 20 | export const cameraPage = (params: CameraQueryParam) => { |
... | ... | @@ -42,3 +51,39 @@ export const getCameraManageDetail = (id: string) => { |
42 | 51 | url: CameraManagerApi.CAMERA_GET_DETAIL_URL + `/${id}`, |
43 | 52 | }); |
44 | 53 | }; |
54 | + | |
55 | +/** | |
56 | + * @description 获取流媒体列表 | |
57 | + * @param params | |
58 | + * @returns | |
59 | + */ | |
60 | +export const getStreamingMediaList = (params: StreamingQueryParam) => { | |
61 | + return defHttp.get({ | |
62 | + url: CameraManagerApi.STERAMING_GET_URL, | |
63 | + params, | |
64 | + }); | |
65 | +}; | |
66 | + | |
67 | +/** | |
68 | + * @description 更新/新增流媒体记录 | |
69 | + * @param params | |
70 | + * @returns | |
71 | + */ | |
72 | +export const createOrUpdateStreamingMediaRecord = (params: StreamingSubmitParam) => { | |
73 | + return defHttp.post({ | |
74 | + url: CameraManagerApi.STERAMING_POST_URL, | |
75 | + params, | |
76 | + }); | |
77 | +}; | |
78 | + | |
79 | +/** | |
80 | + * @description 删除流媒体记录 | |
81 | + * @param params | |
82 | + * @returns | |
83 | + */ | |
84 | +export const deleteStreamingMediaRecord = (params: StreamingMediaDeleteParam) => { | |
85 | + return defHttp.delete({ | |
86 | + url: CameraManagerApi.STERAMING_POST_URL, | |
87 | + params, | |
88 | + }); | |
89 | +}; | ... | ... |
... | ... | @@ -35,3 +35,34 @@ export interface CameraModel { |
35 | 35 | updater?: string; |
36 | 36 | videoUrl: string; |
37 | 37 | } |
38 | + | |
39 | +export interface StreamingMediaModel { | |
40 | + id: string; | |
41 | + creator: string; | |
42 | + createTime: string; | |
43 | + enabled: boolean; | |
44 | + tenantId: string; | |
45 | + type: number; | |
46 | + host: string; | |
47 | + appKey: string; | |
48 | + appSecret: string; | |
49 | + ssl: number; | |
50 | +} | |
51 | + | |
52 | +export interface StreamingQueryParam { | |
53 | + host?: string; | |
54 | +} | |
55 | + | |
56 | +export interface StreamingSubmitParam { | |
57 | + type: number; | |
58 | + ssl: number; | |
59 | + host: string; | |
60 | + appKey: string; | |
61 | + appSecret: string; | |
62 | + id?: string; | |
63 | +} | |
64 | + | |
65 | +export interface StreamingMediaDeleteParam { | |
66 | + tenantId?: string; | |
67 | + ids: string[]; | |
68 | +} | ... | ... |
1 | +<script lang="ts" setup> | |
2 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | |
3 | + import { BasicForm, useForm } from '/@/components/Form'; | |
4 | + import { formDetailSchema } from './config.data'; | |
5 | + import type { DrawerParams } from './config.data'; | |
6 | + import { ref, computed, unref } from 'vue'; | |
7 | + import { createOrUpdateStreamingMediaRecord } from '/@/api/camera/cameraManager'; | |
8 | + import { StreamingMediaModel } from '/@/api/camera/model/cameraModel'; | |
9 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
10 | + | |
11 | + const emit = defineEmits({ | |
12 | + success: null, | |
13 | + }); | |
14 | + | |
15 | + const createFlag = ref(false); | |
16 | + | |
17 | + const getDrawerTitle = computed(() => `${unref(createFlag) ? '新增' : '编辑'}流媒体配置`); | |
18 | + | |
19 | + let id: Nullable<string> = null; | |
20 | + | |
21 | + const [register, { getFieldsValue, setFieldsValue, resetFields, validate }] = useForm({ | |
22 | + schemas: formDetailSchema, | |
23 | + labelWidth: 90, | |
24 | + showActionButtonGroup: false, | |
25 | + }); | |
26 | + | |
27 | + const [registerDrawer, { setDrawerProps }] = useDrawerInner((data: DrawerParams) => { | |
28 | + createFlag.value = data.createFlag; | |
29 | + if (!unref(createFlag)) { | |
30 | + id = data.record!.id; | |
31 | + setFieldsValue(data.record); | |
32 | + } else { | |
33 | + resetFields(); | |
34 | + } | |
35 | + }); | |
36 | + | |
37 | + const handleSubmit = async () => { | |
38 | + await validate(); | |
39 | + let value = getFieldsValue() as StreamingMediaModel; | |
40 | + let message = '修改成功'; | |
41 | + if (unref(createFlag)) message = '添加成功'; | |
42 | + else value = { ...value, id: id! }; | |
43 | + try { | |
44 | + setDrawerProps({ | |
45 | + confirmLoading: true, | |
46 | + }); | |
47 | + await createOrUpdateStreamingMediaRecord(value); | |
48 | + const { createMessage } = useMessage(); | |
49 | + createMessage.success(message); | |
50 | + emit('success'); | |
51 | + } catch (e) { | |
52 | + } finally { | |
53 | + setDrawerProps({ | |
54 | + confirmLoading: false, | |
55 | + }); | |
56 | + } | |
57 | + }; | |
58 | +</script> | |
59 | + | |
60 | +<template> | |
61 | + <BasicDrawer | |
62 | + @register="registerDrawer" | |
63 | + v-bind="$attrs" | |
64 | + showFooter | |
65 | + :title="getDrawerTitle" | |
66 | + width="30%" | |
67 | + @ok="handleSubmit" | |
68 | + > | |
69 | + <BasicForm @register="register" /> | |
70 | + </BasicDrawer> | |
71 | +</template> | ... | ... |
src/views/camera/streaming/config.data.ts
0 → 100644
1 | +import type { StreamingMediaModel } from '/@/api/camera/model/cameraModel'; | |
2 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | |
3 | + | |
4 | +export interface DrawerParams { | |
5 | + createFlag: boolean; | |
6 | + record?: StreamingMediaModel; | |
7 | +} | |
8 | + | |
9 | +export const streamingMediaTypeMapping = { | |
10 | + 0: '海康ISC平台', | |
11 | +}; | |
12 | + | |
13 | +export const streamingMediaSSLMapping = { | |
14 | + 0: 'http', | |
15 | + 1: 'https', | |
16 | +}; | |
17 | + | |
18 | +export const columnSchema: BasicColumn[] = [ | |
19 | + { | |
20 | + title: '平台类型', | |
21 | + dataIndex: 'type', | |
22 | + width: 80, | |
23 | + slots: { customRender: 'type' }, | |
24 | + }, | |
25 | + { | |
26 | + title: '部署环境', | |
27 | + dataIndex: 'ssl', | |
28 | + width: 80, | |
29 | + slots: { customRender: 'ssl' }, | |
30 | + }, | |
31 | + { | |
32 | + title: '平台地址', | |
33 | + dataIndex: 'host', | |
34 | + width: 80, | |
35 | + }, | |
36 | + { | |
37 | + title: '用户Key', | |
38 | + dataIndex: 'appKey', | |
39 | + width: 80, | |
40 | + }, | |
41 | + { | |
42 | + title: '用户密钥', | |
43 | + dataIndex: 'appSecret', | |
44 | + width: 80, | |
45 | + }, | |
46 | +]; | |
47 | + | |
48 | +export const formSchema: FormSchema[] = [ | |
49 | + { | |
50 | + field: 'host', | |
51 | + label: '平台地址', | |
52 | + component: 'Input', | |
53 | + colProps: { span: 8 }, | |
54 | + }, | |
55 | +]; | |
56 | + | |
57 | +export const formDetailSchema: FormSchema[] = [ | |
58 | + { | |
59 | + label: '平台类型', | |
60 | + field: 'type', | |
61 | + component: 'Select', | |
62 | + rules: [{ required: true, message: '平台类型为必填项', type: 'number' }], | |
63 | + componentProps: { | |
64 | + options: [{ label: '海康ISC平台', value: 0 }], | |
65 | + }, | |
66 | + }, | |
67 | + { | |
68 | + label: '部署环境', | |
69 | + field: 'ssl', | |
70 | + component: 'RadioGroup', | |
71 | + rules: [{ required: true, message: '流媒体部署环境为必填项', type: 'number' }], | |
72 | + componentProps: { | |
73 | + options: [ | |
74 | + { label: 'http', value: 0 }, | |
75 | + { label: 'https', value: 1 }, | |
76 | + ], | |
77 | + }, | |
78 | + }, | |
79 | + { | |
80 | + label: '平台地址', | |
81 | + field: 'host', | |
82 | + component: 'Input', | |
83 | + helpMessage: ['平台IP + 端口'], | |
84 | + rules: [{ required: true, message: '平台地址为必填项' }], | |
85 | + }, | |
86 | + { | |
87 | + label: '用户Key', | |
88 | + field: 'appKey', | |
89 | + component: 'Input', | |
90 | + rules: [{ required: true, message: '用户Key为必填项' }], | |
91 | + }, | |
92 | + { | |
93 | + label: '用户密钥', | |
94 | + field: 'appSecret', | |
95 | + component: 'Input', | |
96 | + rules: [{ required: true, message: '用户密钥为必填项' }], | |
97 | + }, | |
98 | +]; | ... | ... |
src/views/camera/streaming/index.vue
0 → 100644
1 | +<script lang="ts" setup> | |
2 | + import { PageWrapper } from '/@/components/Page'; | |
3 | + import { useDrawer } from '/@/components/Drawer'; | |
4 | + import type { DrawerParams } from './config.data'; | |
5 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | |
6 | + import { | |
7 | + columnSchema, | |
8 | + formSchema, | |
9 | + streamingMediaTypeMapping, | |
10 | + streamingMediaSSLMapping, | |
11 | + } from './config.data'; | |
12 | + import SteramingDrawer from './SteramingDrawer.vue'; | |
13 | + import { getStreamingMediaList, deleteStreamingMediaRecord } from '/@/api/camera/cameraManager'; | |
14 | + import { StreamingMediaModel } from '/@/api/camera/model/cameraModel'; | |
15 | + import { ref } from 'vue'; | |
16 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
17 | + | |
18 | + const enabledBatchDelete = ref(true); | |
19 | + const [register, { reload, getSelectRowKeys }] = useTable({ | |
20 | + title: '流媒体列表', | |
21 | + api: getStreamingMediaList, | |
22 | + columns: columnSchema, | |
23 | + showIndexColumn: false, | |
24 | + clickToRowSelect: false, | |
25 | + formConfig: { | |
26 | + labelWidth: 120, | |
27 | + schemas: formSchema, | |
28 | + }, | |
29 | + useSearchForm: true, | |
30 | + showTableSetting: true, | |
31 | + bordered: true, | |
32 | + rowKey: 'id', | |
33 | + actionColumn: { | |
34 | + width: 100, | |
35 | + title: '操作', | |
36 | + dataIndex: 'action', | |
37 | + slots: { customRender: 'action' }, | |
38 | + fixed: 'right', | |
39 | + }, | |
40 | + | |
41 | + rowSelection: { | |
42 | + type: 'checkbox', | |
43 | + onChange(rowKeys: string[]) { | |
44 | + enabledBatchDelete.value = rowKeys.length <= 0; | |
45 | + }, | |
46 | + }, | |
47 | + }); | |
48 | + | |
49 | + const [registerDrawer, { openDrawer }] = useDrawer(); | |
50 | + | |
51 | + const handleCreateStreamingMedia = () => { | |
52 | + openDrawer<DrawerParams>(true, { | |
53 | + createFlag: true, | |
54 | + }); | |
55 | + }; | |
56 | + | |
57 | + const handleUpdateStreamingMedia = (record: StreamingMediaModel) => { | |
58 | + openDrawer<DrawerParams>(true, { | |
59 | + createFlag: false, | |
60 | + record, | |
61 | + }); | |
62 | + }; | |
63 | + | |
64 | + const handleDeleteRecord = async (record?: StreamingMediaModel) => { | |
65 | + let ids = record ? [record.id] : getSelectRowKeys(); | |
66 | + try { | |
67 | + await deleteStreamingMediaRecord({ ids }); | |
68 | + enabledBatchDelete.value = true; | |
69 | + const { createMessage } = useMessage(); | |
70 | + createMessage.success('删除成功'); | |
71 | + } catch (e) { | |
72 | + } finally { | |
73 | + reload(); | |
74 | + } | |
75 | + }; | |
76 | + | |
77 | + const handleDrawerSubmitSuccess = () => { | |
78 | + openDrawer(false); | |
79 | + reload(); | |
80 | + }; | |
81 | +</script> | |
82 | + | |
83 | +<template> | |
84 | + <PageWrapper dense contentFullHeight> | |
85 | + <BasicTable @register="register"> | |
86 | + <template #type="{ record }"> | |
87 | + <span>{{ streamingMediaTypeMapping[record.type] }}</span> | |
88 | + </template> | |
89 | + <template #ssl="{ record }"> | |
90 | + <span>{{ streamingMediaSSLMapping[record.ssl] }}</span> | |
91 | + </template> | |
92 | + <template #action="{ record }"> | |
93 | + <TableAction | |
94 | + :actions="[ | |
95 | + { | |
96 | + label: '编辑', | |
97 | + auth: 'api:yt:streaming:update', | |
98 | + icon: 'clarity:note-edit-line', | |
99 | + onClick: handleUpdateStreamingMedia.bind(null, record), | |
100 | + }, | |
101 | + { | |
102 | + label: '删除', | |
103 | + auth: 'api:yt:streaming:delete', | |
104 | + icon: 'ant-design:delete-outlined', | |
105 | + color: 'error', | |
106 | + popConfirm: { | |
107 | + title: '是否确认删除', | |
108 | + confirm: handleDeleteRecord.bind(null, record), | |
109 | + }, | |
110 | + }, | |
111 | + ]" | |
112 | + /> | |
113 | + </template> | |
114 | + <template #toolbar> | |
115 | + <Authority value="api:yt:streaming:post"> | |
116 | + <a-button type="primary" @click="handleCreateStreamingMedia">新增流媒体</a-button> | |
117 | + </Authority> | |
118 | + <Authority value="api:yt:streaming:delete"> | |
119 | + <a-button | |
120 | + color="error" | |
121 | + type="primary" | |
122 | + :disabled="enabledBatchDelete" | |
123 | + @click="handleDeleteRecord()" | |
124 | + > | |
125 | + 批量删除 | |
126 | + </a-button> | |
127 | + </Authority> | |
128 | + </template> | |
129 | + </BasicTable> | |
130 | + <SteramingDrawer @register="registerDrawer" @success="handleDrawerSubmitSuccess" /> | |
131 | + </PageWrapper> | |
132 | +</template> | |
133 | + | |
134 | +<style></style> | ... | ... |