Commit 70490d49f4e36d2bea1ff85dc9b5f407401c6555

Authored by xp.Huang
2 parents 765a7235 5fafe334

Merge branch 'ft' into 'main_dev'

fix: 修改消息配置表格里的查看配置权限标识和详情一样

See merge request yunteng/thingskit-front!928
... ... @@ -8,24 +8,6 @@
8 8 @ok="handleSubmit"
9 9 >
10 10 <BasicForm @register="registerForm">
11   - <template #iconSelect>
12   - <Upload
13   - name="avatar"
14   - accept=".png,.jpg,.jpeg,.gif"
15   - list-type="picture-card"
16   - class="avatar-uploader"
17   - :show-upload-list="false"
18   - :customRequest="customUpload"
19   - :before-upload="beforeUpload"
20   - >
21   - <img v-if="tenantLogo" :src="tenantLogo" alt="avatar" />
22   - <div v-else>
23   - <LoadingOutlined v-if="loading" />
24   - <plus-outlined v-else />
25   - <div class="ant-upload-text">上传</div>
26   - </div>
27   - </Upload>
28   - </template>
29 11 <template #videoPlatformIdSlot="{ model, field }">
30 12 <a-select
31 13 placeholder="请选择流媒体配置"
... ... @@ -52,23 +34,20 @@
52 34 import { formSchema } from './config.data';
53 35 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
54 36 import { createOrEditCameraManage } from '/@/api/camera/cameraManager';
55   - import { message, Upload } from 'ant-design-vue';
56 37 import { useMessage } from '/@/hooks/web/useMessage';
57   - import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';
58   - import { upload } from '/@/api/oss/ossFileUploader';
59   - import { FileItem } from '/@/components/Upload/src/typing';
  38 + import { PlusOutlined } from '@ant-design/icons-vue';
60 39 import { getStreamingMediaList } from '/@/api/camera/cameraManager';
61 40 import SteramingDrawer from '../streaming/SteramingDrawer.vue';
62 41 import { useDrawer } from '/@/components/Drawer';
  42 + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
  43 + import { buildUUID } from '/@/utils/uuid';
63 44
64 45 export default defineComponent({
65 46 name: 'ContactDrawer',
66 47 components: {
67 48 BasicDrawer,
68 49 BasicForm,
69   - Upload,
70 50 PlusOutlined,
71   - LoadingOutlined,
72 51 SteramingDrawer,
73 52 VNodes: (_, { attrs }) => {
74 53 return attrs.vnodes;
... ... @@ -118,42 +97,19 @@
118 97 if (unref(isUpdate)) {
119 98 await nextTick();
120 99 editId.value = data.record.id;
121   - tenantLogo.value = data.record?.avatar;
122   - await setFieldsValue(data.record);
  100 + if (data.record.avatar) {
  101 + setFieldsValue({
  102 + avatar: [{ uid: buildUUID(), name: 'name', url: data.record.avatar } as FileItem],
  103 + });
  104 + }
  105 + const { avatar, ...params } = data.record;
  106 + console.log(avatar);
  107 + await setFieldsValue({ ...params });
123 108 } else {
124   - tenantLogo.value = '';
125 109 editId.value = '';
126 110 }
127 111 });
128 112
129   - const tenantLogo = ref('');
130   -
131   - async function customUpload({ file }) {
132   - if (beforeUpload(file)) {
133   - tenantLogo.value = '';
134   - loading.value = true;
135   - const formData = new FormData();
136   - formData.append('file', file);
137   - const response = await upload(formData);
138   - if (response.fileStaticUri) {
139   - tenantLogo.value = response.fileStaticUri;
140   - loading.value = false;
141   - }
142   - }
143   - }
144   -
145   - const beforeUpload = (file: FileItem) => {
146   - const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
147   - if (!isJpgOrPng) {
148   - message.error('只能上传图片文件!');
149   - }
150   - const isLt2M = (file.size as number) / 1024 / 1024 < 5;
151   - if (!isLt2M) {
152   - message.error('图片大小不能超过5MB!');
153   - }
154   - return isJpgOrPng && isLt2M;
155   - };
156   -
157 113 const getTitle = computed(() => (!unref(isUpdate) ? '新增视频配置' : '编辑视频配置'));
158 114
159 115 async function handleSubmit() {
... ... @@ -162,8 +118,9 @@
162 118 const { createMessage } = useMessage();
163 119 const values = await validate();
164 120 if (!values) return;
165   - if (tenantLogo.value !== '') {
166   - values.avatar = tenantLogo.value;
  121 + if (Reflect.has(values, 'avatar')) {
  122 + const file = (values.avatar || []).at(0) || {};
  123 + values.avatar = file.url || null;
167 124 }
168 125 if (editId.value !== '') {
169 126 values.id = editId.value;
... ... @@ -188,9 +145,6 @@
188 145 registerDrawer,
189 146 registerForm,
190 147 handleSubmit,
191   - customUpload,
192   - beforeUpload,
193   - tenantLogo,
194 148 loading,
195 149 streamConfigOptions,
196 150 registerSteramingDrawer,
... ...
... ... @@ -5,6 +5,9 @@ import { CameraVideoUrl, CameraMaxLength } from '/@/utils/rules';
5 5 import { h } from 'vue';
6 6 import SnHelpMessage from './SnHelpMessage.vue';
7 7 import { OrgTreeSelect } from '../../common/OrgTreeSelect';
  8 +import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
  9 +import { createImgPreview } from '/@/components/Preview';
  10 +import { uploadThumbnail } from '/@/api/configuration/center/configurationCenter';
8 11
9 12 useComponentRegister('OrgTreeSelect', OrgTreeSelect);
10 13
... ... @@ -102,8 +105,33 @@ export const formSchema: QFormSchema[] = [
102 105 {
103 106 field: 'avatar',
104 107 label: '视频封面',
105   - slot: 'iconSelect',
106   - component: 'Input',
  108 + component: 'ApiUpload',
  109 + changeEvent: 'update:fileList',
  110 + valueField: 'fileList',
  111 + componentProps: () => {
  112 + return {
  113 + listType: 'picture-card',
  114 + maxFileLimit: 1,
  115 + accept: '.png,.jpg,.jpeg,.gif',
  116 + api: async (file: File) => {
  117 + try {
  118 + const formData = new FormData();
  119 + formData.set('file', file);
  120 + const { fileStaticUri, fileName } = await uploadThumbnail(formData);
  121 + return {
  122 + uid: fileStaticUri,
  123 + name: fileName,
  124 + url: fileStaticUri,
  125 + } as FileItem;
  126 + } catch (error) {
  127 + return {};
  128 + }
  129 + },
  130 + onPreview: (fileList: FileItem) => {
  131 + createImgPreview({ imageList: [fileList.url!] });
  132 + },
  133 + };
  134 + },
107 135 },
108 136 {
109 137 field: 'name',
... ...
... ... @@ -12,6 +12,9 @@ import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/compo
12 12 import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum';
13 13 import { TaskTypeEnum } from '/@/views/task/center/config';
14 14 import { AddressTypeEnum } from '/@/views/task/center/components/PollCommandInput';
  15 +import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
  16 +import { createImgPreview } from '/@/components/Preview';
  17 +import { uploadThumbnail } from '/@/api/configuration/center/configurationCenter';
15 18
16 19 useComponentRegister('JSONEditor', JSONEditor);
17 20 useComponentRegister('ObjectModelValidateForm', ObjectModelValidateForm);
... ... @@ -29,8 +32,33 @@ export const step1Schemas: FormSchema[] = [
29 32 {
30 33 field: 'icon',
31 34 label: '设备图片',
32   - slot: 'iconSelect',
33   - component: 'Input',
  35 + component: 'ApiUpload',
  36 + changeEvent: 'update:fileList',
  37 + valueField: 'fileList',
  38 + componentProps: () => {
  39 + return {
  40 + listType: 'picture-card',
  41 + maxFileLimit: 1,
  42 + accept: '.png,.jpg,.jpeg,.gif',
  43 + api: async (file: File) => {
  44 + try {
  45 + const formData = new FormData();
  46 + formData.set('file', file);
  47 + const { fileStaticUri, fileName } = await uploadThumbnail(formData);
  48 + return {
  49 + uid: fileStaticUri,
  50 + name: fileName,
  51 + url: fileStaticUri,
  52 + } as FileItem;
  53 + } catch (error) {
  54 + return {};
  55 + }
  56 + },
  57 + onPreview: (fileList: FileItem) => {
  58 + createImgPreview({ imageList: [fileList.url!] });
  59 + },
  60 + };
  61 + },
34 62 },
35 63 {
36 64 field: 'alias',
... ...
... ... @@ -32,14 +32,14 @@ export const columns: BasicColumn[] = [
32 32 h(
33 33 'div',
34 34 {
35   - class: 'cursor-pointer',
  35 + class: 'cursor-pointer truncate',
36 36 },
37 37 `${record.alias}`
38 38 ),
39 39 h(
40 40 'div',
41 41 {
42   - class: 'cursor-pointer text-blue-500',
  42 + class: 'cursor-pointer text-blue-500 truncate',
43 43 onClick: () => {
44 44 handeleCopy(`${record.name}`);
45 45 },
... ...
... ... @@ -5,7 +5,7 @@
5 5 @register="register"
6 6 destroyOnClose
7 7 @close="closeDrawer"
8   - :title="deviceDetail.alias || deviceDetail.name"
  8 + :title="drawerTitle"
9 9 width="80%"
10 10 >
11 11 <Tabs v-model:activeKey="activeKey" :size="size">
... ... @@ -58,7 +58,7 @@
58 58 </BasicDrawer>
59 59 </template>
60 60 <script lang="ts">
61   - import { defineComponent, ref } from 'vue';
  61 + import { defineComponent, ref, computed } from 'vue';
62 62 import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
63 63
64 64 import { Tabs } from 'ant-design-vue';
... ... @@ -122,6 +122,13 @@
122 122 emit('openGatewayDeviceDetail', { id: data.gatewayId });
123 123 };
124 124
  125 + const drawerTitle = computed(() => {
  126 + return (
  127 + deviceDetail.value?.alias?.slice(0, 40) + '...' ||
  128 + deviceDetail.value?.name?.slice(0, 40) + '...'
  129 + );
  130 + });
  131 +
125 132 return {
126 133 size,
127 134 activeKey,
... ... @@ -132,6 +139,7 @@
132 139 tbDeviceId,
133 140 handleOpenTbDeviceDetail,
134 141 handleOpenGatewayDevice,
  142 + drawerTitle,
135 143 };
136 144 },
137 145 });
... ...
... ... @@ -157,7 +157,7 @@
157 157 sn: stepRecord.name,
158 158 customerId: currentDeviceData.customerId,
159 159 deviceInfo: {
160   - avatar: DeviceStep1Ref.value?.devicePic,
  160 + avatar: stepRecord?.icon,
161 161 ...DeviceStep1Ref.value?.devicePositionState,
162 162 },
163 163 };
... ... @@ -169,7 +169,7 @@
169 169 ...stepRecord,
170 170 sn: stepRecord.name,
171 171 deviceInfo: {
172   - avatar: DeviceStep1Ref.value?.devicePic,
  172 + avatar: stepRecord?.icon,
173 173 ...DeviceStep1Ref.value?.devicePositionState,
174 174 },
175 175 deviceToken:
... ...
... ... @@ -22,24 +22,6 @@
22 22 </div>
23 23 </div>
24 24 </template>
25   - <template #iconSelect>
26   - <Upload
27   - name="avatar"
28   - accept=".png,.jpg,.jpeg,.gif"
29   - :show-upload-list="false"
30   - list-type="picture-card"
31   - class="avatar-uploader"
32   - :customRequest="customUpload"
33   - :before-upload="beforeUpload"
34   - >
35   - <img v-if="devicePic" :src="devicePic" alt="avatar" />
36   - <div v-else>
37   - <LoadingOutlined v-if="loading" />
38   - <PlusOutlined v-else />
39   - <div class="ant-upload-text">图片上传</div>
40   - </div>
41   - </Upload>
42   - </template>
43 25 <template #snCode="{ model, field }">
44 26 <div class="flex">
45 27 <Input v-model:value="model[field]" placeholder="请输入设备名称" />
... ... @@ -115,10 +97,9 @@
115 97 import { BasicForm, useForm } from '/@/components/Form';
116 98 import { step1Schemas } from '../../config/data';
117 99 import { useScript } from '/@/hooks/web/useScript';
118   - import { Input, Upload, message, Modal, Form, Row, Col, AutoComplete } from 'ant-design-vue';
119   - import { EnvironmentTwoTone, PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';
  100 + import { Input, message, Modal, Form, Row, Col, AutoComplete } from 'ant-design-vue';
  101 + import { EnvironmentTwoTone } from '@ant-design/icons-vue';
120 102 import { upload } from '/@/api/oss/ossFileUploader';
121   - import { FileItem } from '/@/components/Upload/src/typing';
122 103 import { BAI_DU_MAP_URL } from '/@/utils/fnUtils';
123 104 import { generateSNCode } from '/@/api/device/deviceManager';
124 105 import icon from '/@/assets/images/wz.png';
... ... @@ -130,21 +111,20 @@
130 111 import DeptDrawer from '/@/views/system/organization/OrganizationDrawer.vue';
131 112 import { TaskTypeEnum } from '/@/views/task/center/config';
132 113 import { toRaw } from 'vue';
  114 + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
  115 + import { buildUUID } from '/@/utils/uuid';
133 116
134 117 export default defineComponent({
135 118 components: {
136 119 BasicForm,
137 120 Input,
138 121 AutoComplete,
139   - Upload,
140 122 EnvironmentTwoTone,
141   - PlusOutlined,
142 123 Modal,
143 124 Form,
144 125 FormItem: Form.Item,
145 126 Row,
146 127 Col,
147   - LoadingOutlined,
148 128 DeptDrawer,
149 129 },
150 130 props: {
... ... @@ -202,8 +182,11 @@
202 182 async function nextStep() {
203 183 try {
204 184 let values = await validate();
205   - values = { devicePic: devicePic.value, ...positionState, ...values };
206   - delete values.icon;
  185 + if (Reflect.has(values, 'icon')) {
  186 + const file = (unref(values.icon) || []).at(0) || {};
  187 + values.icon = file.url || null;
  188 + }
  189 + values = { ...positionState, ...values };
207 190 delete values.deviceAddress;
208 191 emit('next', values);
209 192 // 获取输入的数据
... ... @@ -405,6 +388,11 @@
405 388 positionState.address = deviceInfo.address;
406 389 devicePositionState.value = { ...toRaw(positionState) };
407 390 devicePic.value = deviceInfo.avatar;
  391 + if (deviceInfo.avatar) {
  392 + setFieldsValue({
  393 + icon: [{ uid: buildUUID(), name: 'name', url: deviceInfo.avatar } as FileItem],
  394 + });
  395 + }
408 396 setFieldsValue({
409 397 ...data,
410 398 code: data?.code,
... ... @@ -414,6 +402,10 @@
414 402 // 父组件调用获取字段值的方法
415 403 function parentGetFieldsValue() {
416 404 const value = getFieldsValue();
  405 + if (Reflect.has(value, 'icon')) {
  406 + const file = (value.icon || []).at(0) || {};
  407 + value.icon = file.url || null;
  408 + }
417 409 return {
418 410 ...value,
419 411 ...(value?.code || value?.addressCode
... ...
... ... @@ -47,7 +47,7 @@
47 47 </div>
48 48 </BasicModal>
49 49 </div>
50   - <Description @register="register" class="mt-4" :data="deviceDetail" />
  50 + <Description @register="register" class="mt-4" :data="deviceDetail" :contentStyle="CS" />
51 51 </div>
52 52 <div class="mt-4" v-if="!isCustomer">
53 53 <a-button type="primary" class="mr-4" @click="copyTbDeviceId">复制设备ID</a-button>
... ... @@ -116,6 +116,15 @@
116 116 column: 2,
117 117 });
118 118
  119 + const CS = {
  120 + 'max-width': '600px',
  121 + 'word-break': 'break-all',
  122 + overflow: 'hidden',
  123 + display: '-webkit-box',
  124 + '-webkit-line-clamp': 2,
  125 + '-webkit-box-orient': 'vertical',
  126 + };
  127 +
119 128 // 地图
120 129 const mapWrapRef = ref<HTMLDivElement>();
121 130
... ... @@ -217,6 +226,7 @@
217 226 remoteConnectiondGateway,
218 227 locationImage,
219 228 isCustomer,
  229 + CS,
220 230 };
221 231 },
222 232 });
... ...
... ... @@ -12,6 +12,9 @@ import { EventType, EventTypeColor, EventTypeName } from '../list/cpns/tabs/Even
12 12
13 13 import { useClipboard } from '@vueuse/core';
14 14 import { useMessage } from '/@/hooks/web/useMessage';
  15 +import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
  16 +import { createImgPreview } from '/@/components/Preview';
  17 +import { uploadThumbnail } from '/@/api/configuration/center/configurationCenter';
15 18
16 19 export enum Mode {
17 20 CARD = 'card',
... ... @@ -162,8 +165,33 @@ export const step1Schemas: FormSchema[] = [
162 165 {
163 166 field: 'image',
164 167 label: '上传图片',
165   - component: 'Input',
166   - slot: 'imageSelect',
  168 + component: 'ApiUpload',
  169 + changeEvent: 'update:fileList',
  170 + valueField: 'fileList',
  171 + componentProps: () => {
  172 + return {
  173 + listType: 'picture-card',
  174 + maxFileLimit: 1,
  175 + accept: '.png,.jpg,.jpeg,.gif',
  176 + api: async (file: File) => {
  177 + try {
  178 + const formData = new FormData();
  179 + formData.set('file', file);
  180 + const { fileStaticUri, fileName } = await uploadThumbnail(formData);
  181 + return {
  182 + uid: fileStaticUri,
  183 + name: fileName,
  184 + url: fileStaticUri,
  185 + } as FileItem;
  186 + } catch (error) {
  187 + return {};
  188 + }
  189 + },
  190 + onPreview: (fileList: FileItem) => {
  191 + createImgPreview({ imageList: [fileList.url!] });
  192 + },
  193 + };
  194 + },
167 195 },
168 196 {
169 197 field: 'deviceType',
... ...
1 1 <template>
2 2 <div class="step1">
3   - <BasicForm @register="register">
4   - <template #imageSelect>
5   - <Upload
6   - style="width: 20vw"
7   - name="avatar"
8   - accept=".png,.jpg,.jpeg,.gif"
9   - list-type="picture-card"
10   - class="avatar-uploader"
11   - :show-upload-list="false"
12   - :customRequest="customUploadqrcodePic"
13   - :before-upload="beforeUploadqrcodePic"
14   - >
15   - <img
16   - v-if="deviceConfigPic"
17   - :src="deviceConfigPic"
18   - alt=""
19   - style="width: 6.25rem; height: 6.25rem"
20   - />
21   - <div v-else>
22   - <LoadingOutlined v-if="loading" />
23   - <PlusOutlined v-else />
24   - <div class="ant-upload-text">图片上传</div>
25   - </div>
26   - </Upload>
27   - </template>
28   - </BasicForm>
  3 + <BasicForm @register="register" />
29 4 </div>
30 5 </template>
31 6 <script lang="ts" setup>
32   - import { ref, nextTick } from 'vue';
  7 + import { nextTick } from 'vue';
33 8 import { BasicForm, useForm } from '/@/components/Form';
34 9 import { step1Schemas } from '../device.profile.data';
35   - import { uploadApi } from '/@/api/personal/index';
36   - import { Upload } from 'ant-design-vue';
37   - import { PlusOutlined, LoadingOutlined } from '@ant-design/icons-vue';
38   - import { useMessage } from '/@/hooks/web/useMessage';
39   - import type { FileItem } from '/@/components/Upload/src/typing';
  10 + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue';
  11 + import { buildUUID } from '/@/utils/uuid';
40 12
41 13 const emits = defineEmits(['next', 'emitDeviceType']);
42   - const loading = ref(false);
43   - const { createMessage } = useMessage();
44   - const deviceConfigPic = ref('');
45 14 const props = defineProps({
46 15 ifShowBtn: { type: Boolean, default: true },
47 16 });
... ... @@ -66,32 +35,6 @@
66 35 disabled: nameStatus,
67 36 },
68 37 });
69   - const customUploadqrcodePic = async ({ file }) => {
70   - if (beforeUploadqrcodePic(file)) {
71   - deviceConfigPic.value = '';
72   - loading.value = true;
73   - const formData = new FormData();
74   - formData.append('file', file);
75   - const response = await uploadApi(formData);
76   - if (response.fileStaticUri) {
77   - deviceConfigPic.value = response.fileStaticUri;
78   - loading.value = false;
79   - }
80   - }
81   - };
82   - const beforeUploadqrcodePic = (file: FileItem) => {
83   - const isJpgOrPng =
84   - file.type === 'image/jpeg' || file.type === 'image/png' || file.type === 'image/jpg';
85   - if (!isJpgOrPng) {
86   - createMessage.error('只能上传图片文件!');
87   - }
88   - const isLt2M = (file.size as number) / 1024 / 1024 < 5;
89   - if (!isLt2M) {
90   - createMessage.error('图片大小不能超过5MB!');
91   - }
92   - return isJpgOrPng && isLt2M;
93   - };
94   -
95 38 const setFieldsdefaultRuleChainId = async (id) => {
96 39 await nextTick();
97 40 setFieldsValue({ defaultRuleChainId: id });
... ... @@ -105,20 +48,28 @@
105 48 }
106 49 //回显数据
107 50 const setFormData = (v) => {
108   - setFieldsValue(v);
109   - deviceConfigPic.value = v.image;
  51 + if (v.image) {
  52 + setFieldsValue({
  53 + image: [{ uid: buildUUID(), name: 'name', url: v.image } as FileItem],
  54 + });
  55 + }
  56 + const { image, ...params } = v;
  57 + console.log(image);
  58 + setFieldsValue({ ...params });
110 59 };
111 60 //获取数据
112 61 async function getFormData() {
113 62 const values = await validate();
114 63 if (!values) return;
115   - Reflect.set(values, 'image', deviceConfigPic.value);
  64 + if (Reflect.has(values, 'image')) {
  65 + const file = (values.image || []).at(0) || {};
  66 + values.image = file.url || null;
  67 + }
116 68 return values;
117 69 }
118 70 //清空数据
119 71 const resetFormData = () => {
120 72 resetFields();
121   - deviceConfigPic.value = '';
122 73 };
123 74
124 75 const editOrAddDeviceTypeStatus = (status: boolean) => {
... ...
... ... @@ -17,7 +17,7 @@
17 17 </Authority>
18 18 </template>
19 19 <template #config="{ record }">
20   - <Authority value="api:yt:message:get:config">
  20 + <Authority value="api:yt:template:get">
21 21 <a-button type="link" class="ml-2" @click="showData(record)"> 查看配置 </a-button>
22 22 </Authority>
23 23 </template>
... ...