Commit 67d1de3831df2c6d6446ccfdcb6e177bf6b4a6c6
Committed by
xp.Huang
1 parent
b1aeeabc
fix: 看板组件图标能使用自定义图标
Showing
18 changed files
with
788 additions
and
102 deletions
... | ... | @@ -71,9 +71,12 @@ |
71 | 71 | return false; |
72 | 72 | } |
73 | 73 | } |
74 | - | |
75 | 74 | if (file.size > props.maxSize) { |
76 | - createMessage.warning(`文件大小超过${Math.floor(props.maxSize / 1024 / 1024)}mb`); | |
75 | + createMessage.warning( | |
76 | + `文件大小超过${Math.floor( | |
77 | + props.maxSize > 1024 * 1024 ? props.maxSize / 1024 / 1024 : props.maxSize / 1024 | |
78 | + )}${props.maxSize > 1024 * 1024 * 1 ? 'mb' : 'kb'}` | |
79 | + ); | |
77 | 80 | return false; |
78 | 81 | } |
79 | 82 | handleUpload(file); | ... | ... |
... | ... | @@ -30,7 +30,7 @@ |
30 | 30 | auth: 'api:yt:sceneLinkage:update', |
31 | 31 | icon: 'clarity:note-edit-line', |
32 | 32 | onClick: handleEdit.bind(null, record), |
33 | - ifShow: record.status !== 1 && record.isEdge !== 1, | |
33 | + ifShow: record.status !== 1, | |
34 | 34 | }, |
35 | 35 | ]" |
36 | 36 | :drop-down-actions="[ |
... | ... | @@ -39,7 +39,7 @@ |
39 | 39 | auth: 'api:yt:sceneLinkage:delete', |
40 | 40 | icon: 'ant-design:delete-outlined', |
41 | 41 | color: 'error', |
42 | - ifShow: record.status !== 1 && record.isEdge !== 1, | |
42 | + ifShow: record.status !== 1, | |
43 | 43 | popConfirm: { |
44 | 44 | title: '是否确认删除', |
45 | 45 | confirm: handleDeleteOrBatchDelete.bind(null, record), |
... | ... | @@ -56,7 +56,6 @@ |
56 | 56 | :loading="record.pendingStatus" |
57 | 57 | checkedChildren="启用" |
58 | 58 | unCheckedChildren="禁用" |
59 | - :disabled="record.isEdge === 1" | |
60 | 59 | @change="(checked:boolean)=>statusChange(checked,record)" |
61 | 60 | /> |
62 | 61 | </Authority> | ... | ... |
... | ... | @@ -56,7 +56,7 @@ |
56 | 56 | </script> |
57 | 57 | |
58 | 58 | <template> |
59 | - <BasicModal @register="register" title="组件设置" @ok="handleOk"> | |
59 | + <BasicModal @register="register" title="组件设置" @ok="handleOk" :width="700"> | |
60 | 60 | <!-- --> |
61 | 61 | <component ref="settingFormEl" :is="getSettingComponent" /> |
62 | 62 | </BasicModal> | ... | ... |
... | ... | @@ -29,6 +29,8 @@ |
29 | 29 | import { MessageAlert } from './components/MessageAlert'; |
30 | 30 | import { createSelectWidgetKeysContext, createSelectWidgetModeContext } from './useContext'; |
31 | 31 | import { useGetCategoryByComponentKey } from '../packages/hook/useGetCategoryByComponentKey'; |
32 | + import { deleteFilePath } from '/@/api/oss/ossFileUploader'; | |
33 | + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; | |
32 | 34 | |
33 | 35 | const props = defineProps<{ |
34 | 36 | layout: Layout[]; |
... | ... | @@ -227,6 +229,20 @@ |
227 | 229 | return `${category} / ${componentConfig.title}`; |
228 | 230 | }); |
229 | 231 | |
232 | + const countElementOccurrences = (arr) => { | |
233 | + const countMap = {}; | |
234 | + | |
235 | + arr.forEach((element) => { | |
236 | + if (countMap[element]) { | |
237 | + countMap[element]++; | |
238 | + } else { | |
239 | + countMap[element] = 1; | |
240 | + } | |
241 | + }); | |
242 | + | |
243 | + return countMap; | |
244 | + }; | |
245 | + | |
230 | 246 | const handleSubmit = async () => { |
231 | 247 | const validateResult = await validate(); |
232 | 248 | if (validateResult && !validateResult.flag) { |
... | ... | @@ -241,6 +257,59 @@ |
241 | 257 | } |
242 | 258 | } |
243 | 259 | const value = getFormValues(); |
260 | + const { record } = value || {}; | |
261 | + try { | |
262 | + const currentRecordIconUrl = ref<any>([]); | |
263 | + // 判断当前自定义组件表单以前的自定义图片呢url | |
264 | + currentRecord.value?.dataSource.forEach((item) => { | |
265 | + if (item.componentInfo?.customIcon) { | |
266 | + item.componentInfo?.customIcon.forEach((icon: FileItem) => { | |
267 | + currentRecordIconUrl.value.push(icon.url); | |
268 | + }); | |
269 | + } | |
270 | + }); | |
271 | + // 取当前修改过后的自定义图片url | |
272 | + const dataSourceUrl = record.dataSource?.map( | |
273 | + (item) => item.componentInfo.customIcon?.[0].url | |
274 | + ); | |
275 | + | |
276 | + // 当前自定义组件取出要进行删除的图标url | |
277 | + const dataSourceDeleteUrl = unref(currentRecordIconUrl).filter( | |
278 | + (item) => !dataSourceUrl?.includes(item) | |
279 | + ); | |
280 | + | |
281 | + //查询外部所有组件的自定义图标的url | |
282 | + const oldDataSource = props.layout; | |
283 | + const customIconUrls = ref<any>([]); | |
284 | + oldDataSource?.forEach((item: any) => { | |
285 | + item.dataSource?.forEach((dataSource) => { | |
286 | + if (dataSource.componentInfo?.customIcon) { | |
287 | + dataSource.componentInfo?.customIcon.forEach((icon: FileItem) => { | |
288 | + customIconUrls.value.push(icon.url); | |
289 | + }); | |
290 | + } | |
291 | + }); | |
292 | + }); | |
293 | + // const dataSourceDeleteUrl = record.dataSource?.map((item) => item.componentInfo.deleteUrl); | |
294 | + | |
295 | + if (unref(customIconUrls) && unref(customIconUrls).length && dataSourceDeleteUrl?.length) { | |
296 | + // 判断外部所有组件是否有dataSourceDeleteUrl使用中的url | |
297 | + const deletePromise = unref(customIconUrls)?.filter((item) => | |
298 | + dataSourceDeleteUrl?.includes(item) | |
299 | + ); | |
300 | + const deleteUrlInfo = countElementOccurrences(deletePromise); | |
301 | + const deleteUrl = deletePromise?.filter((item) => deleteUrlInfo?.[item] == 1); | |
302 | + Promise.all( | |
303 | + deleteUrl.map((item) => { | |
304 | + deleteFilePath(item); | |
305 | + }) | |
306 | + ); | |
307 | + } | |
308 | + } catch (err) { | |
309 | + // eslint-disable-next-line no-console | |
310 | + console.log(err); | |
311 | + } | |
312 | + | |
244 | 313 | try { |
245 | 314 | loading.value = true; |
246 | 315 | unref(currentMode) === DataActionModeEnum.UPDATE | ... | ... |
... | ... | @@ -3,15 +3,68 @@ |
3 | 3 | import { useForm, BasicForm } from '/@/components/Form'; |
4 | 4 | import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type'; |
5 | 5 | import { option } from './config'; |
6 | + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; | |
7 | + import { createImgPreview } from '/@/components/Preview'; | |
8 | + import { upload } from '/@/api/oss/ossFileUploader'; | |
6 | 9 | |
7 | 10 | const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({ |
8 | 11 | schemas: [ |
9 | 12 | { |
13 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
14 | + label: '文本字体大小', | |
15 | + component: 'InputNumber', | |
16 | + defaultValue: 14, | |
17 | + componentProps: { | |
18 | + min: 0, | |
19 | + max: 100, | |
20 | + formatter: (e) => { | |
21 | + const value = e?.toString().replace(/^0/g, ''); | |
22 | + if (value) { | |
23 | + return value.replace(/^0/g, ''); | |
24 | + } else { | |
25 | + return 0; | |
26 | + } | |
27 | + }, | |
28 | + }, | |
29 | + }, | |
30 | + { | |
31 | + field: ComponentConfigFieldEnum.PASS_WORD, | |
32 | + label: '操作密码', | |
33 | + component: 'InputPassword', | |
34 | + defaultValue: '', | |
35 | + }, | |
36 | + { | |
37 | + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
38 | + label: '显示设备名称', | |
39 | + component: 'Checkbox', | |
40 | + defaultValue: option.showDeviceName, | |
41 | + }, | |
42 | + { | |
43 | + field: ComponentConfigFieldEnum.DEFAULT_CUSTOM, | |
44 | + label: '图标类型', | |
45 | + component: 'RadioGroup', | |
46 | + defaultValue: 'default', | |
47 | + componentProps: ({ formModel }) => { | |
48 | + return { | |
49 | + options: [ | |
50 | + { label: '系统默认', value: 'default' }, | |
51 | + { label: '自定义', value: 'custom' }, | |
52 | + ], | |
53 | + onChange() { | |
54 | + formModel[ComponentConfigFieldEnum.CUSTOM_ICON] = []; | |
55 | + }, | |
56 | + }; | |
57 | + }, | |
58 | + }, | |
59 | + { | |
10 | 60 | field: ComponentConfigFieldEnum.ICON_COLOR, |
11 | 61 | label: '图标颜色', |
12 | 62 | component: 'ColorPicker', |
13 | 63 | changeEvent: 'update:value', |
14 | 64 | defaultValue: option.iconColor, |
65 | + ifShow: ({ model }) => { | |
66 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
67 | + }, | |
15 | 68 | }, |
16 | 69 | { |
17 | 70 | field: ComponentConfigFieldEnum.ICON, |
... | ... | @@ -19,6 +72,9 @@ |
19 | 72 | component: 'IconDrawer', |
20 | 73 | changeEvent: 'update:value', |
21 | 74 | defaultValue: option.icon, |
75 | + ifShow: ({ model }) => { | |
76 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
77 | + }, | |
22 | 78 | componentProps({ formModel }) { |
23 | 79 | const color = formModel[ComponentConfigFieldEnum.ICON_COLOR]; |
24 | 80 | return { |
... | ... | @@ -27,34 +83,51 @@ |
27 | 83 | }, |
28 | 84 | }, |
29 | 85 | { |
30 | - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
31 | - label: '显示设备名称', | |
32 | - component: 'Checkbox', | |
33 | - defaultValue: option.showDeviceName, | |
34 | - }, | |
35 | - { | |
36 | - field: ComponentConfigFieldEnum.FONT_SIZE, | |
37 | - label: '文本字体大小', | |
38 | - component: 'InputNumber', | |
39 | - defaultValue: 14, | |
40 | - componentProps: { | |
41 | - min: 0, | |
42 | - max: 100, | |
43 | - formatter: (e) => { | |
44 | - const value = e?.toString().replace(/^0/g, ''); | |
45 | - if (value) { | |
46 | - return value.replace(/^0/g, ''); | |
47 | - } else { | |
48 | - return 0; | |
49 | - } | |
50 | - }, | |
86 | + field: ComponentConfigFieldEnum.CUSTOM_ICON, | |
87 | + label: '图标', | |
88 | + component: 'ApiUpload', | |
89 | + ifShow: ({ model }) => model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] === 'custom', | |
90 | + changeEvent: 'update:fileList', | |
91 | + valueField: 'fileList', | |
92 | + helpMessage: ['支持.svg格式,建议尺寸为32*32px,大小不超过50kb '], | |
93 | + componentProps: ({ formModel }) => { | |
94 | + return { | |
95 | + listType: 'picture-card', | |
96 | + maxFileLimit: 1, | |
97 | + maxSize: 50 * 1024, | |
98 | + accept: '.svg', | |
99 | + api: async (file: File) => { | |
100 | + try { | |
101 | + const formData = new FormData(); | |
102 | + const { name } = file; | |
103 | + formData.set('file', file); | |
104 | + const { fileStaticUri, fileName } = await upload(formData); | |
105 | + return { | |
106 | + uid: fileStaticUri, | |
107 | + name: name || fileName, | |
108 | + url: fileStaticUri, | |
109 | + } as FileItem; | |
110 | + } catch (error) { | |
111 | + return {}; | |
112 | + } | |
113 | + }, | |
114 | + // showUploadList: true, | |
115 | + onDownload() {}, | |
116 | + onPreview: (fileList: FileItem) => { | |
117 | + createImgPreview({ imageList: [fileList.url!] }); | |
118 | + }, | |
119 | + | |
120 | + onDelete(url: string) { | |
121 | + formModel.deleteUrl = url!; | |
122 | + }, | |
123 | + }; | |
51 | 124 | }, |
52 | 125 | }, |
53 | 126 | { |
54 | - field: ComponentConfigFieldEnum.PASS_WORD, | |
55 | - label: '操作密码', | |
56 | - component: 'InputPassword', | |
57 | - defaultValue: '', | |
127 | + field: 'deleteUrl', | |
128 | + label: '', | |
129 | + component: 'Input', | |
130 | + show: false, | |
58 | 131 | }, |
59 | 132 | ], |
60 | 133 | showActionButtonGroup: false, | ... | ... |
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 | fontSize: persetFontSize, |
32 | 32 | password: persetPassword, |
33 | 33 | } = persetOption || {}; |
34 | - const { icon, iconColor, fontSize, password } = componentInfo || {}; | |
34 | + const { icon, iconColor, fontSize, password, customIcon, defaultCustom } = componentInfo || {}; | |
35 | 35 | |
36 | 36 | const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute); |
37 | 37 | return { |
... | ... | @@ -41,6 +41,8 @@ |
41 | 41 | fontSize: fontSize || persetFontSize || 14, |
42 | 42 | password: password || persetPassword, |
43 | 43 | commandType, |
44 | + defaultCustom: defaultCustom || 'default', | |
45 | + customIcon: customIcon || [], | |
44 | 46 | }; |
45 | 47 | }); |
46 | 48 | |
... | ... | @@ -81,10 +83,17 @@ |
81 | 83 | <main class="w-full h-full flex justify-around items-center" :style="getScale"> |
82 | 84 | <div class="flex flex-col justify-center items-center"> |
83 | 85 | <SvgIcon |
84 | - :name="getDesign.icon" | |
86 | + v-if="getDesign.defaultCustom !== 'custom'" | |
87 | + :name="getDesign.icon!" | |
85 | 88 | prefix="iconfont" |
86 | - :style="{ color: getDesign.iconColor }" | |
87 | 89 | :size="getRatio ? getRatio * 60 : 60" |
90 | + :style="{ color: getDesign.iconColor }" | |
91 | + /> | |
92 | + <img | |
93 | + v-else | |
94 | + :src="getDesign.customIcon[0]?.url" | |
95 | + :style="{ width: getRatio ? getRatio * 60 + 'px' : '60px' }" | |
96 | + :alt="getDesign.customIcon[0]?.name" | |
88 | 97 | /> |
89 | 98 | <span |
90 | 99 | class="mt-3 truncate text-gray-500 text-center" | ... | ... |
... | ... | @@ -3,30 +3,13 @@ |
3 | 3 | import { useForm, BasicForm } from '/@/components/Form'; |
4 | 4 | import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type'; |
5 | 5 | import { option } from './config'; |
6 | + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; | |
7 | + import { createImgPreview } from '/@/components/Preview'; | |
8 | + import { upload } from '/@/api/oss/ossFileUploader'; | |
6 | 9 | |
7 | 10 | const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({ |
8 | 11 | schemas: [ |
9 | 12 | { |
10 | - field: ComponentConfigFieldEnum.ICON_COLOR, | |
11 | - label: '图标颜色', | |
12 | - component: 'ColorPicker', | |
13 | - changeEvent: 'update:value', | |
14 | - defaultValue: option.iconColor, | |
15 | - }, | |
16 | - { | |
17 | - field: ComponentConfigFieldEnum.ICON, | |
18 | - label: '图标', | |
19 | - component: 'IconDrawer', | |
20 | - changeEvent: 'update:value', | |
21 | - defaultValue: option.icon, | |
22 | - componentProps({ formModel }) { | |
23 | - const color = formModel[ComponentConfigFieldEnum.ICON_COLOR]; | |
24 | - return { | |
25 | - color, | |
26 | - }; | |
27 | - }, | |
28 | - }, | |
29 | - { | |
30 | 13 | field: ComponentConfigFieldEnum.FONT_SIZE, |
31 | 14 | label: '文本字体大小', |
32 | 15 | component: 'InputNumber', |
... | ... | @@ -45,16 +28,106 @@ |
45 | 28 | }, |
46 | 29 | }, |
47 | 30 | { |
31 | + field: ComponentConfigFieldEnum.PASS_WORD, | |
32 | + label: '操作密码', | |
33 | + component: 'InputPassword', | |
34 | + defaultValue: '', | |
35 | + }, | |
36 | + { | |
48 | 37 | field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, |
49 | 38 | label: '显示设备名称', |
50 | 39 | component: 'Checkbox', |
51 | 40 | defaultValue: option.showDeviceName, |
52 | 41 | }, |
53 | 42 | { |
54 | - field: ComponentConfigFieldEnum.PASS_WORD, | |
55 | - label: '操作密码', | |
56 | - component: 'InputPassword', | |
57 | - defaultValue: '', | |
43 | + field: ComponentConfigFieldEnum.DEFAULT_CUSTOM, | |
44 | + label: '图标类型', | |
45 | + component: 'RadioGroup', | |
46 | + defaultValue: 'default', | |
47 | + componentProps: ({ formModel }) => { | |
48 | + return { | |
49 | + options: [ | |
50 | + { label: '系统默认', value: 'default' }, | |
51 | + { label: '自定义', value: 'custom' }, | |
52 | + ], | |
53 | + onChange() { | |
54 | + formModel[ComponentConfigFieldEnum.CUSTOM_ICON] = []; | |
55 | + }, | |
56 | + }; | |
57 | + }, | |
58 | + }, | |
59 | + { | |
60 | + field: ComponentConfigFieldEnum.ICON_COLOR, | |
61 | + label: '图标颜色', | |
62 | + component: 'ColorPicker', | |
63 | + changeEvent: 'update:value', | |
64 | + defaultValue: option.iconColor, | |
65 | + ifShow: ({ model }) => { | |
66 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
67 | + }, | |
68 | + }, | |
69 | + { | |
70 | + field: ComponentConfigFieldEnum.ICON, | |
71 | + label: '图标', | |
72 | + component: 'IconDrawer', | |
73 | + changeEvent: 'update:value', | |
74 | + defaultValue: option.icon, | |
75 | + ifShow: ({ model }) => { | |
76 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
77 | + }, | |
78 | + componentProps({ formModel }) { | |
79 | + const color = formModel[ComponentConfigFieldEnum.ICON_COLOR]; | |
80 | + return { | |
81 | + color, | |
82 | + }; | |
83 | + }, | |
84 | + }, | |
85 | + { | |
86 | + field: ComponentConfigFieldEnum.CUSTOM_ICON, | |
87 | + label: '图标', | |
88 | + component: 'ApiUpload', | |
89 | + ifShow: ({ model }) => model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] === 'custom', | |
90 | + changeEvent: 'update:fileList', | |
91 | + valueField: 'fileList', | |
92 | + helpMessage: ['支持.svg格式,建议尺寸为32*32px,大小不超过50kb '], | |
93 | + componentProps: ({ formModel }) => { | |
94 | + return { | |
95 | + listType: 'picture-card', | |
96 | + maxSize: 50 * 1024, | |
97 | + maxFileLimit: 1, | |
98 | + accept: '.svg', | |
99 | + api: async (file: File) => { | |
100 | + try { | |
101 | + const formData = new FormData(); | |
102 | + const { name } = file; | |
103 | + formData.set('file', file); | |
104 | + const { fileStaticUri, fileName } = await upload(formData); | |
105 | + return { | |
106 | + uid: fileStaticUri, | |
107 | + name: name || fileName, | |
108 | + url: fileStaticUri, | |
109 | + } as FileItem; | |
110 | + } catch (error) { | |
111 | + return {}; | |
112 | + } | |
113 | + }, | |
114 | + // showUploadList: true, | |
115 | + onDownload() {}, | |
116 | + onPreview: (fileList: FileItem) => { | |
117 | + createImgPreview({ imageList: [fileList.url!] }); | |
118 | + }, | |
119 | + | |
120 | + onDelete(url: string) { | |
121 | + formModel.deleteUrl = url!; | |
122 | + }, | |
123 | + }; | |
124 | + }, | |
125 | + }, | |
126 | + { | |
127 | + field: 'deleteUrl', | |
128 | + label: '', | |
129 | + component: 'Input', | |
130 | + show: false, | |
58 | 131 | }, |
59 | 132 | ], |
60 | 133 | showActionButtonGroup: false, | ... | ... |
... | ... | @@ -38,8 +38,17 @@ |
38 | 38 | } = persetOption || {}; |
39 | 39 | return { |
40 | 40 | dataSource: dataSource.map((item) => { |
41 | - const { fontColor, icon, iconColor, unit, showDeviceName, password, fontSize } = | |
42 | - item.componentInfo; | |
41 | + const { | |
42 | + fontColor, | |
43 | + icon, | |
44 | + iconColor, | |
45 | + unit, | |
46 | + showDeviceName, | |
47 | + password, | |
48 | + fontSize, | |
49 | + customIcon, | |
50 | + defaultCustom, | |
51 | + } = item.componentInfo; | |
43 | 52 | const { |
44 | 53 | attribute, |
45 | 54 | attributeRename, |
... | ... | @@ -76,6 +85,8 @@ |
76 | 85 | closeCommand, |
77 | 86 | openService, |
78 | 87 | closeService, |
88 | + defaultCustom: defaultCustom || 'default', | |
89 | + customIcon: customIcon || [], | |
79 | 90 | } as SwitchItemType; |
80 | 91 | }), |
81 | 92 | }; |
... | ... | @@ -128,11 +139,24 @@ |
128 | 139 | :key="item.id" |
129 | 140 | class="flex justify-between items-center w-full px-4" |
130 | 141 | > |
131 | - <SvgIcon | |
142 | + <!-- <SvgIcon | |
132 | 143 | :name="item.icon!" |
133 | 144 | prefix="iconfont" |
134 | 145 | :size="getRatio ? 30 * getRatio : 30" |
135 | 146 | :style="{ color: item.iconColor }" |
147 | + /> --> | |
148 | + <SvgIcon | |
149 | + v-if="item.defaultCustom !== 'custom'" | |
150 | + :name="item.icon!" | |
151 | + prefix="iconfont" | |
152 | + :size="getRatio ? getRatio * 30 : 30" | |
153 | + :style="{ color: item.iconColor }" | |
154 | + /> | |
155 | + <img | |
156 | + v-else | |
157 | + :src="item.customIcon[0]?.url" | |
158 | + :style="{ width: getRatio ? getRatio * 30 + 'px' : '30px' }" | |
159 | + :alt="item.customIcon[0]?.name" | |
136 | 160 | /> |
137 | 161 | <div |
138 | 162 | class="text-gray-500 truncate mx-2" | ... | ... |
... | ... | @@ -3,15 +3,68 @@ |
3 | 3 | import { useForm, BasicForm } from '/@/components/Form'; |
4 | 4 | import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type'; |
5 | 5 | import { option } from './config'; |
6 | + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; | |
7 | + import { createImgPreview } from '/@/components/Preview'; | |
8 | + import { upload } from '/@/api/oss/ossFileUploader'; | |
6 | 9 | |
7 | 10 | const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({ |
8 | 11 | schemas: [ |
9 | 12 | { |
13 | + field: ComponentConfigFieldEnum.FONT_SIZE, | |
14 | + label: '文本字体大小', | |
15 | + component: 'InputNumber', | |
16 | + defaultValue: 14, | |
17 | + componentProps: { | |
18 | + min: 0, | |
19 | + max: 100, | |
20 | + formatter: (e) => { | |
21 | + const value = e?.toString().replace(/^0/g, ''); | |
22 | + if (value) { | |
23 | + return value.replace(/^0/g, ''); | |
24 | + } else { | |
25 | + return 0; | |
26 | + } | |
27 | + }, | |
28 | + }, | |
29 | + }, | |
30 | + { | |
31 | + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
32 | + label: '显示设备名称', | |
33 | + component: 'Checkbox', | |
34 | + defaultValue: option.showDeviceName, | |
35 | + }, | |
36 | + { | |
37 | + field: ComponentConfigFieldEnum.SHOW_TIME, | |
38 | + label: '显示时间', | |
39 | + component: 'Checkbox', | |
40 | + defaultValue: option.showTime, | |
41 | + }, | |
42 | + { | |
43 | + field: ComponentConfigFieldEnum.DEFAULT_CUSTOM, | |
44 | + label: '图标类型', | |
45 | + component: 'RadioGroup', | |
46 | + defaultValue: 'default', | |
47 | + componentProps: ({ formModel }) => { | |
48 | + return { | |
49 | + options: [ | |
50 | + { label: '系统默认', value: 'default' }, | |
51 | + { label: '自定义', value: 'custom' }, | |
52 | + ], | |
53 | + onChange() { | |
54 | + formModel[ComponentConfigFieldEnum.CUSTOM_ICON] = []; | |
55 | + }, | |
56 | + }; | |
57 | + }, | |
58 | + }, | |
59 | + { | |
10 | 60 | field: ComponentConfigFieldEnum.ICON, |
11 | 61 | label: '开启状态图标', |
12 | 62 | component: 'IconDrawer', |
13 | 63 | changeEvent: 'update:value', |
14 | 64 | defaultValue: option.icon, |
65 | + ifShow: ({ model }) => { | |
66 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
67 | + }, | |
15 | 68 | componentProps({ formModel }) { |
16 | 69 | const color = formModel[ComponentConfigFieldEnum.ICON_COLOR]; |
17 | 70 | return { |
... | ... | @@ -24,6 +77,9 @@ |
24 | 77 | label: '开启图标颜色', |
25 | 78 | component: 'ColorPicker', |
26 | 79 | changeEvent: 'update:value', |
80 | + ifShow: ({ model }) => { | |
81 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
82 | + }, | |
27 | 83 | defaultValue: option.iconColor, |
28 | 84 | }, |
29 | 85 | { |
... | ... | @@ -32,6 +88,9 @@ |
32 | 88 | component: 'IconDrawer', |
33 | 89 | changeEvent: 'update:value', |
34 | 90 | defaultValue: option.iconClose, |
91 | + ifShow: ({ model }) => { | |
92 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
93 | + }, | |
35 | 94 | componentProps({ formModel }) { |
36 | 95 | const color = formModel[ComponentConfigFieldEnum.ICON_COLOR_CLOSE]; |
37 | 96 | return { |
... | ... | @@ -44,37 +103,84 @@ |
44 | 103 | label: '关闭图标颜色', |
45 | 104 | component: 'ColorPicker', |
46 | 105 | changeEvent: 'update:value', |
106 | + ifShow: ({ model }) => { | |
107 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
108 | + }, | |
47 | 109 | defaultValue: option.iconColorClose, |
48 | 110 | }, |
49 | 111 | { |
50 | - field: ComponentConfigFieldEnum.FONT_SIZE, | |
51 | - label: '文本字体大小', | |
52 | - component: 'InputNumber', | |
53 | - defaultValue: 14, | |
54 | - componentProps: { | |
55 | - min: 0, | |
56 | - max: 100, | |
57 | - formatter: (e) => { | |
58 | - const value = e?.toString().replace(/^0/g, ''); | |
59 | - if (value) { | |
60 | - return value.replace(/^0/g, ''); | |
61 | - } else { | |
62 | - return 0; | |
63 | - } | |
64 | - }, | |
112 | + field: ComponentConfigFieldEnum.CUSTOM_ICON, | |
113 | + label: '开启状态图标', | |
114 | + component: 'ApiUpload', | |
115 | + ifShow: ({ model }) => model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] === 'custom', | |
116 | + changeEvent: 'update:fileList', | |
117 | + valueField: 'fileList', | |
118 | + helpMessage: ['支持.svg格式,建议尺寸为32*32px,大小不超过50kb '], | |
119 | + componentProps: ({}) => { | |
120 | + return { | |
121 | + listType: 'picture-card', | |
122 | + maxSize: 50 * 1024, | |
123 | + maxFileLimit: 1, | |
124 | + accept: '.svg', | |
125 | + api: async (file: File) => { | |
126 | + try { | |
127 | + const formData = new FormData(); | |
128 | + const { name } = file; | |
129 | + formData.set('file', file); | |
130 | + const { fileStaticUri, fileName } = await upload(formData); | |
131 | + return { | |
132 | + uid: fileStaticUri, | |
133 | + name: name || fileName, | |
134 | + url: fileStaticUri, | |
135 | + } as FileItem; | |
136 | + } catch (error) { | |
137 | + return {}; | |
138 | + } | |
139 | + }, | |
140 | + // showUploadList: true, | |
141 | + onDownload() {}, | |
142 | + onPreview: (fileList: FileItem) => { | |
143 | + createImgPreview({ imageList: [fileList.url!] }); | |
144 | + }, | |
145 | + }; | |
65 | 146 | }, |
66 | 147 | }, |
67 | 148 | { |
68 | - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
69 | - label: '显示设备名称', | |
70 | - component: 'Checkbox', | |
71 | - defaultValue: option.showDeviceName, | |
72 | - }, | |
73 | - { | |
74 | - field: ComponentConfigFieldEnum.SHOW_TIME, | |
75 | - label: '显示时间', | |
76 | - component: 'Checkbox', | |
77 | - defaultValue: option.showTime, | |
149 | + field: ComponentConfigFieldEnum.CUSTOM_ICON_CLOSE, | |
150 | + label: '关闭状态图标', | |
151 | + component: 'ApiUpload', | |
152 | + helpMessage: ['支持.svg格式,建议尺寸为32*32px,大小不超过50kb '], | |
153 | + ifShow: ({ model }) => model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] === 'custom', | |
154 | + changeEvent: 'update:fileList', | |
155 | + valueField: 'fileList', | |
156 | + componentProps: ({}) => { | |
157 | + return { | |
158 | + listType: 'picture-card', | |
159 | + maxSize: 0 * 1024, | |
160 | + maxFileLimit: 1, | |
161 | + accept: '.svg', | |
162 | + api: async (file: File) => { | |
163 | + try { | |
164 | + const formData = new FormData(); | |
165 | + const { name } = file; | |
166 | + formData.set('file', file); | |
167 | + const { fileStaticUri, fileName } = await upload(formData); | |
168 | + return { | |
169 | + uid: fileStaticUri, | |
170 | + name: name || fileName, | |
171 | + url: fileStaticUri, | |
172 | + } as FileItem; | |
173 | + } catch (error) { | |
174 | + return {}; | |
175 | + } | |
176 | + }, | |
177 | + // showUploadList: true, | |
178 | + onDownload() {}, | |
179 | + onPreview: (fileList: FileItem) => { | |
180 | + createImgPreview({ imageList: [fileList.url!] }); | |
181 | + }, | |
182 | + }; | |
183 | + }, | |
78 | 184 | }, |
79 | 185 | ], |
80 | 186 | showActionButtonGroup: false, | ... | ... |
... | ... | @@ -32,8 +32,19 @@ |
32 | 32 | |
33 | 33 | const { componentInfo, attributeName, attributeRename } = option; |
34 | 34 | |
35 | - const { icon, iconColor, fontColor, unit, iconClose, iconColorClose, showTime, fontSize } = | |
36 | - componentInfo || {}; | |
35 | + const { | |
36 | + icon, | |
37 | + iconColor, | |
38 | + fontColor, | |
39 | + unit, | |
40 | + iconClose, | |
41 | + iconColorClose, | |
42 | + showTime, | |
43 | + fontSize, | |
44 | + customIcon, | |
45 | + customIconClose, | |
46 | + defaultCustom, | |
47 | + } = componentInfo || {}; | |
37 | 48 | return { |
38 | 49 | iconColor: iconColor || persetIconColor, |
39 | 50 | unit: unit ?? perseUnit, |
... | ... | @@ -44,6 +55,9 @@ |
44 | 55 | iconColorClose: iconColorClose || persetIconColorClose, |
45 | 56 | showTime: showTime ?? persetShowTime, |
46 | 57 | fontSize: fontSize || persetFontSize || 14, |
58 | + defaultCustom: defaultCustom || 'default', | |
59 | + customIcon: customIcon || [], | |
60 | + customIconClose: customIconClose || [], | |
47 | 61 | }; |
48 | 62 | }); |
49 | 63 | |
... | ... | @@ -68,10 +82,17 @@ |
68 | 82 | <DeviceName :config="config" /> |
69 | 83 | <div class="flex flex-1 flex-col justify-center items-center"> |
70 | 84 | <SvgIcon |
85 | + v-if="getDesign.defaultCustom !== 'custom'" | |
71 | 86 | :name="isOpenClose ? getDesign.icon : getDesign.iconClose" |
72 | 87 | prefix="iconfont" |
73 | 88 | :size="getRatio ? getRatio * 70 : 70" |
74 | - :style="{ color: isOpenClose ? getDesign.iconColor : getDesign.iconColorClose }" | |
89 | + :style="{ color: getDesign.iconColor }" | |
90 | + /> | |
91 | + <img | |
92 | + v-else | |
93 | + :src="isOpenClose ? getDesign.customIcon[0]?.url : getDesign.customIconClose[0]?.url" | |
94 | + :style="{ width: getRatio ? getRatio * 70 + 'px' : '70px' }" | |
95 | + :alt="getDesign.customIcon[0]?.name" | |
75 | 96 | /> |
76 | 97 | <div |
77 | 98 | class="text-gray-500 truncate m-2" | ... | ... |
... | ... | @@ -3,6 +3,9 @@ |
3 | 3 | import { useForm, BasicForm } from '/@/components/Form'; |
4 | 4 | import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type'; |
5 | 5 | import { option } from './config'; |
6 | + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; | |
7 | + import { createImgPreview } from '/@/components/Preview'; | |
8 | + import { upload } from '/@/api/oss/ossFileUploader'; | |
6 | 9 | |
7 | 10 | const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({ |
8 | 11 | schemas: [ |
... | ... | @@ -61,11 +64,37 @@ |
61 | 64 | }, |
62 | 65 | }, |
63 | 66 | { |
67 | + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
68 | + label: '显示设备名称', | |
69 | + component: 'Checkbox', | |
70 | + defaultValue: option.showDeviceName, | |
71 | + }, | |
72 | + { | |
73 | + field: ComponentConfigFieldEnum.DEFAULT_CUSTOM, | |
74 | + label: '图标类型', | |
75 | + component: 'RadioGroup', | |
76 | + defaultValue: 'default', | |
77 | + componentProps: ({ formModel }) => { | |
78 | + return { | |
79 | + options: [ | |
80 | + { label: '系统默认', value: 'default' }, | |
81 | + { label: '自定义', value: 'custom' }, | |
82 | + ], | |
83 | + onChange() { | |
84 | + formModel[ComponentConfigFieldEnum.CUSTOM_ICON] = []; | |
85 | + }, | |
86 | + }; | |
87 | + }, | |
88 | + }, | |
89 | + { | |
64 | 90 | field: ComponentConfigFieldEnum.ICON_COLOR, |
65 | 91 | label: '图标颜色', |
66 | 92 | component: 'ColorPicker', |
67 | 93 | changeEvent: 'update:value', |
68 | 94 | defaultValue: option.iconColor, |
95 | + ifShow: ({ model }) => { | |
96 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
97 | + }, | |
69 | 98 | }, |
70 | 99 | { |
71 | 100 | field: ComponentConfigFieldEnum.ICON, |
... | ... | @@ -73,6 +102,9 @@ |
73 | 102 | component: 'IconDrawer', |
74 | 103 | changeEvent: 'update:value', |
75 | 104 | defaultValue: option.icon, |
105 | + ifShow: ({ model }) => { | |
106 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
107 | + }, | |
76 | 108 | componentProps({ formModel }) { |
77 | 109 | const color = formModel[ComponentConfigFieldEnum.ICON_COLOR]; |
78 | 110 | return { |
... | ... | @@ -81,10 +113,50 @@ |
81 | 113 | }, |
82 | 114 | }, |
83 | 115 | { |
84 | - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
85 | - label: '显示设备名称', | |
86 | - component: 'Checkbox', | |
87 | - defaultValue: option.showDeviceName, | |
116 | + field: ComponentConfigFieldEnum.CUSTOM_ICON, | |
117 | + label: '图标', | |
118 | + component: 'ApiUpload', | |
119 | + ifShow: ({ model }) => model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] === 'custom', | |
120 | + changeEvent: 'update:fileList', | |
121 | + valueField: 'fileList', | |
122 | + helpMessage: ['支持.svg格式,建议尺寸为32*32px,大小不超过50kb '], | |
123 | + componentProps: ({ formModel }) => { | |
124 | + return { | |
125 | + maxSize: 50 * 1024, | |
126 | + listType: 'picture-card', | |
127 | + maxFileLimit: 1, | |
128 | + accept: '.svg', | |
129 | + api: async (file: File) => { | |
130 | + try { | |
131 | + const formData = new FormData(); | |
132 | + const { name } = file; | |
133 | + formData.set('file', file); | |
134 | + const { fileStaticUri, fileName } = await upload(formData); | |
135 | + return { | |
136 | + uid: fileStaticUri, | |
137 | + name: name || fileName, | |
138 | + url: fileStaticUri, | |
139 | + } as FileItem; | |
140 | + } catch (error) { | |
141 | + return {}; | |
142 | + } | |
143 | + }, | |
144 | + // showUploadList: true, | |
145 | + onDownload() {}, | |
146 | + onPreview: (fileList: FileItem) => { | |
147 | + createImgPreview({ imageList: [fileList.url!] }); | |
148 | + }, | |
149 | + onDelete(url: string) { | |
150 | + formModel.deleteUrl = url!; | |
151 | + }, | |
152 | + }; | |
153 | + }, | |
154 | + }, | |
155 | + { | |
156 | + field: 'deleteUrl', | |
157 | + label: '', | |
158 | + component: 'Input', | |
159 | + show: false, | |
88 | 160 | }, |
89 | 161 | ], |
90 | 162 | showActionButtonGroup: false, | ... | ... |
... | ... | @@ -31,7 +31,6 @@ |
31 | 31 | |
32 | 32 | const getDesign = computed(() => { |
33 | 33 | const { persetOption = {}, option } = props.config; |
34 | - | |
35 | 34 | const { |
36 | 35 | iconColor: persetIconColor, |
37 | 36 | unit: perseUnit, |
... | ... | @@ -44,7 +43,8 @@ |
44 | 43 | const { componentInfo, attributeRename } = option; |
45 | 44 | const { functionName } = unref(getThingModelTsl) || {}; |
46 | 45 | |
47 | - const { icon, iconColor, fontColor, unit, valueSize, fontSize } = componentInfo || {}; | |
46 | + const { icon, iconColor, fontColor, unit, valueSize, fontSize, customIcon, defaultCustom } = | |
47 | + componentInfo || {}; | |
48 | 48 | return { |
49 | 49 | iconColor: iconColor || persetIconColor, |
50 | 50 | unit: unit ?? perseUnit, |
... | ... | @@ -53,6 +53,8 @@ |
53 | 53 | attribute: attributeRename || functionName, |
54 | 54 | valueSize: valueSize || persetValueSize || 20, |
55 | 55 | fontSize: fontSize || persetFontSize || 14, |
56 | + defaultCustom: defaultCustom || 'default', | |
57 | + customIcon: customIcon || [], | |
56 | 58 | }; |
57 | 59 | }); |
58 | 60 | |
... | ... | @@ -78,11 +80,18 @@ |
78 | 80 | <DeviceName :config="config" /> |
79 | 81 | <div class="flex-1 flex justify-center items-center flex-col w-full"> |
80 | 82 | <SvgIcon |
83 | + v-if="getDesign.defaultCustom !== 'custom'" | |
81 | 84 | :name="getDesign.icon!" |
82 | 85 | prefix="iconfont" |
83 | 86 | :size="getRatio ? getRatio * 70 : 70" |
84 | 87 | :style="{ color: getDesign.iconColor }" |
85 | 88 | /> |
89 | + <img | |
90 | + v-else | |
91 | + :src="getDesign.customIcon[0]?.url" | |
92 | + :style="{ width: getRatio ? getRatio * 70 + 'px' : '70px' }" | |
93 | + :alt="getDesign.customIcon[0]?.name" | |
94 | + /> | |
86 | 95 | <h1 |
87 | 96 | class="font-bold m-2 truncate w-full text-center" |
88 | 97 | :style="{ | ... | ... |
... | ... | @@ -3,6 +3,9 @@ |
3 | 3 | import { useForm, BasicForm } from '/@/components/Form'; |
4 | 4 | import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type'; |
5 | 5 | import { option } from './config'; |
6 | + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; | |
7 | + import { createImgPreview } from '/@/components/Preview'; | |
8 | + import { upload } from '/@/api/oss/ossFileUploader'; | |
6 | 9 | |
7 | 10 | const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({ |
8 | 11 | schemas: [ |
... | ... | @@ -60,11 +63,37 @@ |
60 | 63 | }, |
61 | 64 | }, |
62 | 65 | { |
66 | + field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
67 | + label: '显示设备名称', | |
68 | + component: 'Checkbox', | |
69 | + defaultValue: option.showDeviceName, | |
70 | + }, | |
71 | + { | |
72 | + field: ComponentConfigFieldEnum.DEFAULT_CUSTOM, | |
73 | + label: '图标类型', | |
74 | + component: 'RadioGroup', | |
75 | + defaultValue: 'default', | |
76 | + componentProps: ({ formModel }) => { | |
77 | + return { | |
78 | + options: [ | |
79 | + { label: '系统默认', value: 'default' }, | |
80 | + { label: '自定义', value: 'custom' }, | |
81 | + ], | |
82 | + onChange() { | |
83 | + formModel[ComponentConfigFieldEnum.CUSTOM_ICON] = []; | |
84 | + }, | |
85 | + }; | |
86 | + }, | |
87 | + }, | |
88 | + { | |
63 | 89 | field: ComponentConfigFieldEnum.ICON_COLOR, |
64 | 90 | label: '图标颜色', |
65 | 91 | component: 'ColorPicker', |
66 | 92 | changeEvent: 'update:value', |
67 | 93 | defaultValue: option.iconColor, |
94 | + ifShow: ({ model }) => { | |
95 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
96 | + }, | |
68 | 97 | }, |
69 | 98 | { |
70 | 99 | field: ComponentConfigFieldEnum.ICON, |
... | ... | @@ -72,6 +101,9 @@ |
72 | 101 | component: 'IconDrawer', |
73 | 102 | changeEvent: 'update:value', |
74 | 103 | defaultValue: option.icon, |
104 | + ifShow: ({ model }) => { | |
105 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
106 | + }, | |
75 | 107 | componentProps({ formModel }) { |
76 | 108 | const color = formModel[ComponentConfigFieldEnum.ICON_COLOR]; |
77 | 109 | return { |
... | ... | @@ -80,10 +112,50 @@ |
80 | 112 | }, |
81 | 113 | }, |
82 | 114 | { |
83 | - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
84 | - label: '显示设备名称', | |
85 | - component: 'Checkbox', | |
86 | - defaultValue: option.showDeviceName, | |
115 | + field: ComponentConfigFieldEnum.CUSTOM_ICON, | |
116 | + label: '图标', | |
117 | + component: 'ApiUpload', | |
118 | + ifShow: ({ model }) => model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] === 'custom', | |
119 | + changeEvent: 'update:fileList', | |
120 | + valueField: 'fileList', | |
121 | + helpMessage: ['支持.svg格式,建议尺寸为32*32px,大小不超过50kb '], | |
122 | + componentProps: ({ formModel }) => { | |
123 | + return { | |
124 | + listType: 'picture-card', | |
125 | + maxSize: 50 * 1024, | |
126 | + maxFileLimit: 1, | |
127 | + accept: '.svg', | |
128 | + api: async (file: File) => { | |
129 | + try { | |
130 | + const formData = new FormData(); | |
131 | + const { name } = file; | |
132 | + formData.set('file', file); | |
133 | + const { fileStaticUri, fileName } = await upload(formData); | |
134 | + return { | |
135 | + uid: fileStaticUri, | |
136 | + name: name || fileName, | |
137 | + url: fileStaticUri, | |
138 | + } as FileItem; | |
139 | + } catch (error) { | |
140 | + return {}; | |
141 | + } | |
142 | + }, | |
143 | + // showUploadList: true, | |
144 | + onDownload() {}, | |
145 | + onPreview: (fileList: FileItem) => { | |
146 | + createImgPreview({ imageList: [fileList.url!] }); | |
147 | + }, | |
148 | + onDelete(url: string) { | |
149 | + formModel.deleteUrl = url!; | |
150 | + }, | |
151 | + }; | |
152 | + }, | |
153 | + }, | |
154 | + { | |
155 | + field: 'deleteUrl', | |
156 | + label: '', | |
157 | + component: 'Input', | |
158 | + show: false, | |
87 | 159 | }, |
88 | 160 | ], |
89 | 161 | showActionButtonGroup: false, | ... | ... |
... | ... | @@ -40,7 +40,8 @@ |
40 | 40 | |
41 | 41 | const { componentInfo, attribute, attributeRename } = option; |
42 | 42 | |
43 | - const { icon, iconColor, fontColor, unit, valueSize, fontSize } = componentInfo || {}; | |
43 | + const { icon, iconColor, fontColor, unit, valueSize, fontSize, customIcon, defaultCustom } = | |
44 | + componentInfo || {}; | |
44 | 45 | return { |
45 | 46 | iconColor: iconColor || persetIconColor, |
46 | 47 | unit: unit ?? perseUnit, |
... | ... | @@ -49,6 +50,8 @@ |
49 | 50 | attribute: attributeRename || unref(getThingModelTsl)?.functionName || attribute, |
50 | 51 | valueSize: valueSize || persetValueSize || 20, |
51 | 52 | fontSize: fontSize || persetFontSize || 14, |
53 | + defaultCustom: defaultCustom || 'default', | |
54 | + customIcon: customIcon || [], | |
52 | 55 | }; |
53 | 56 | }); |
54 | 57 | |
... | ... | @@ -73,11 +76,18 @@ |
73 | 76 | <DeviceName :config="config" /> |
74 | 77 | <div :style="getScale" class="flex-1 flex justify-center items-center flex-col w-full"> |
75 | 78 | <SvgIcon |
79 | + v-if="getDesign.defaultCustom !== 'custom'" | |
76 | 80 | :name="getDesign.icon!" |
77 | 81 | prefix="iconfont" |
78 | 82 | :size="getRatio ? getRatio * 70 : 70" |
79 | 83 | :style="{ color: getDesign.iconColor }" |
80 | 84 | /> |
85 | + <img | |
86 | + v-else | |
87 | + :src="getDesign.customIcon[0]?.url" | |
88 | + :style="{ width: getRatio ? getRatio * 70 + 'px' : '70px' }" | |
89 | + :alt="getDesign.customIcon[0]?.name" | |
90 | + /> | |
81 | 91 | <h1 |
82 | 92 | class="my-4 font-bold !my-2 truncate w-full text-center" |
83 | 93 | :style="{ | ... | ... |
... | ... | @@ -4,6 +4,10 @@ |
4 | 4 | import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type'; |
5 | 5 | import { option } from './config'; |
6 | 6 | |
7 | + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; | |
8 | + import { createImgPreview } from '/@/components/Preview'; | |
9 | + import { upload } from '/@/api/oss/ossFileUploader'; | |
10 | + | |
7 | 11 | const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({ |
8 | 12 | schemas: [ |
9 | 13 | { |
... | ... | @@ -60,11 +64,31 @@ |
60 | 64 | }, |
61 | 65 | }, |
62 | 66 | { |
67 | + field: ComponentConfigFieldEnum.DEFAULT_CUSTOM, | |
68 | + label: '图标类型', | |
69 | + component: 'RadioGroup', | |
70 | + defaultValue: 'default', | |
71 | + componentProps: ({ formModel }) => { | |
72 | + return { | |
73 | + options: [ | |
74 | + { label: '系统默认', value: 'default' }, | |
75 | + { label: '自定义', value: 'custom' }, | |
76 | + ], | |
77 | + onChange() { | |
78 | + formModel[ComponentConfigFieldEnum.CUSTOM_ICON] = []; | |
79 | + }, | |
80 | + }; | |
81 | + }, | |
82 | + }, | |
83 | + { | |
63 | 84 | field: ComponentConfigFieldEnum.ICON_COLOR, |
64 | 85 | label: '图标颜色', |
65 | 86 | component: 'ColorPicker', |
66 | 87 | changeEvent: 'update:value', |
67 | 88 | defaultValue: option.iconColor, |
89 | + ifShow: ({ model }) => { | |
90 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
91 | + }, | |
68 | 92 | }, |
69 | 93 | { |
70 | 94 | field: ComponentConfigFieldEnum.ICON, |
... | ... | @@ -73,6 +97,9 @@ |
73 | 97 | changeEvent: 'update:value', |
74 | 98 | valueField: 'value', |
75 | 99 | defaultValue: option.icon, |
100 | + ifShow: ({ model }) => { | |
101 | + return model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] !== 'custom'; | |
102 | + }, | |
76 | 103 | componentProps({ formModel }) { |
77 | 104 | const color = formModel[ComponentConfigFieldEnum.ICON_COLOR]; |
78 | 105 | return { |
... | ... | @@ -80,6 +107,51 @@ |
80 | 107 | }; |
81 | 108 | }, |
82 | 109 | }, |
110 | + { | |
111 | + field: ComponentConfigFieldEnum.CUSTOM_ICON, | |
112 | + label: '图标', | |
113 | + component: 'ApiUpload', | |
114 | + ifShow: ({ model }) => model[ComponentConfigFieldEnum.DEFAULT_CUSTOM] === 'custom', | |
115 | + changeEvent: 'update:fileList', | |
116 | + valueField: 'fileList', | |
117 | + helpMessage: ['支持.svg格式,建议尺寸为32*32px,大小不超过50kb '], | |
118 | + componentProps: ({ formModel }) => { | |
119 | + return { | |
120 | + listType: 'picture-card', | |
121 | + maxSize: 50 * 1024, | |
122 | + maxFileLimit: 1, | |
123 | + accept: '.svg', | |
124 | + api: async (file: File) => { | |
125 | + try { | |
126 | + const formData = new FormData(); | |
127 | + const { name } = file; | |
128 | + formData.set('file', file); | |
129 | + const { fileStaticUri, fileName } = await upload(formData); | |
130 | + return { | |
131 | + uid: fileStaticUri, | |
132 | + name: name || fileName, | |
133 | + url: fileStaticUri, | |
134 | + } as FileItem; | |
135 | + } catch (error) { | |
136 | + return {}; | |
137 | + } | |
138 | + }, | |
139 | + onDownload() {}, | |
140 | + onPreview: (fileList: FileItem) => { | |
141 | + createImgPreview({ imageList: [fileList.url!] }); | |
142 | + }, | |
143 | + onDelete(url: string) { | |
144 | + formModel.deleteUrl = url!; | |
145 | + }, | |
146 | + }; | |
147 | + }, | |
148 | + }, | |
149 | + { | |
150 | + field: 'deleteUrl', | |
151 | + label: '', | |
152 | + component: 'Input', | |
153 | + show: false, | |
154 | + }, | |
83 | 155 | ], |
84 | 156 | showActionButtonGroup: false, |
85 | 157 | labelWidth: 120, | ... | ... |
... | ... | @@ -35,7 +35,8 @@ |
35 | 35 | |
36 | 36 | return { |
37 | 37 | dataSource: dataSource.map((item) => { |
38 | - const { fontColor, icon, iconColor, unit, valueSize, fontSize } = item.componentInfo; | |
38 | + const { fontColor, icon, iconColor, unit, valueSize, fontSize, customIcon, defaultCustom } = | |
39 | + item.componentInfo; | |
39 | 40 | const { attribute, attributeRename, deviceName, deviceRename, deviceId, deviceProfileId } = |
40 | 41 | item; |
41 | 42 | const tsl = getDeviceProfileTslByIdWithIdentifier?.(deviceProfileId, attribute); |
... | ... | @@ -50,6 +51,8 @@ |
50 | 51 | id: deviceId, |
51 | 52 | valueSize: valueSize || persetValueSize || 20, |
52 | 53 | fontSize: fontSize || persetFontSize || 14, |
54 | + defaultCustom: defaultCustom || 'default', | |
55 | + customIcon: customIcon || [], | |
53 | 56 | }; |
54 | 57 | }), |
55 | 58 | }; |
... | ... | @@ -67,6 +70,8 @@ |
67 | 70 | fontColor: '#357CFB', |
68 | 71 | fontSize: 16, |
69 | 72 | valueSize: 16, |
73 | + defaultCustom: 'default', | |
74 | + customIcon: [], | |
70 | 75 | }, |
71 | 76 | { |
72 | 77 | id: buildUUID(), |
... | ... | @@ -79,6 +84,8 @@ |
79 | 84 | fontColor: '#FFA000', |
80 | 85 | fontSize: 16, |
81 | 86 | valueSize: 16, |
87 | + defaultCustom: 'default', | |
88 | + customIcon: [], | |
82 | 89 | }, |
83 | 90 | ]); |
84 | 91 | |
... | ... | @@ -114,11 +121,24 @@ |
114 | 121 | class="flex justify-between items-center mt-2" |
115 | 122 | > |
116 | 123 | <div class="flex items-center"> |
117 | - <SvgIcon | |
124 | + <!-- <SvgIcon | |
118 | 125 | :name="item.icon!" |
119 | 126 | prefix="iconfont" |
120 | 127 | :size="getRatio ? 30 * getRatio : 30" |
121 | 128 | :style="{ color: item.iconColor }" |
129 | + /> --> | |
130 | + <SvgIcon | |
131 | + v-if="item.defaultCustom !== 'custom'" | |
132 | + :name="item.icon!" | |
133 | + prefix="iconfont" | |
134 | + :size="getRatio ? getRatio * 30 : 30" | |
135 | + :style="{ color: item.iconColor }" | |
136 | + /> | |
137 | + <img | |
138 | + v-else | |
139 | + :src="item.customIcon[0]?.url" | |
140 | + :style="{ width: getRatio ? getRatio * 30 + 'px' : '30px' }" | |
141 | + :alt="item.customIcon[0]?.name" | |
122 | 142 | /> |
123 | 143 | <div |
124 | 144 | class="text-gray-500 ml-6" | ... | ... |
... | ... | @@ -36,4 +36,8 @@ export enum ComponentConfigFieldEnum { |
36 | 36 | MIN_NUMBER = 'minNumber', |
37 | 37 | MAX_NUMBER = 'maxNumber', |
38 | 38 | PASS_WORD = 'password', //操作密码 |
39 | + DEFAULT_CUSTOM = 'defaultCustom', | |
40 | + DEFAULT_CUSTOM_CLOSE = 'defaultCustomClose', | |
41 | + CUSTOM_ICON = 'customIcon', | |
42 | + CUSTOM_ICON_CLOSE = 'customIconClose', | |
39 | 43 | } | ... | ... |
... | ... | @@ -20,6 +20,8 @@ |
20 | 20 | import { useGetComponentConfig } from '../../../packages/hook/useGetComponetConfig'; |
21 | 21 | import { isBoolean } from '/@/utils/is'; |
22 | 22 | import { useApp } from '../../hooks/useApp'; |
23 | + import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; | |
24 | + import { deleteFilePath } from '/@/api/oss/ossFileUploader'; | |
23 | 25 | |
24 | 26 | const props = defineProps<{ |
25 | 27 | sourceInfo: WidgetDataType; |
... | ... | @@ -74,8 +76,56 @@ |
74 | 76 | emit('update', toRaw(props.sourceInfo)); |
75 | 77 | } |
76 | 78 | |
79 | + const countElementOccurrences = (arr) => { | |
80 | + const countMap = {}; | |
81 | + | |
82 | + arr.forEach((element) => { | |
83 | + if (countMap[element]) { | |
84 | + countMap[element]++; | |
85 | + } else { | |
86 | + countMap[element] = 1; | |
87 | + } | |
88 | + }); | |
89 | + | |
90 | + return countMap; | |
91 | + }; | |
92 | + | |
77 | 93 | async function handleDelete() { |
78 | 94 | try { |
95 | + const { componentData: oldDataSource } = props.rawDataSource; | |
96 | + const customIconUrls = ref<any>([]); | |
97 | + oldDataSource?.forEach((item: any) => { | |
98 | + item.dataSource?.forEach((dataSource) => { | |
99 | + if (dataSource.componentInfo?.customIcon) { | |
100 | + dataSource.componentInfo?.customIcon.forEach((icon: FileItem) => { | |
101 | + customIconUrls.value.push(icon.url); | |
102 | + }); | |
103 | + } | |
104 | + }); | |
105 | + }); | |
106 | + | |
107 | + const { dataSource: deleteDataSource } = props.sourceInfo; | |
108 | + const dataSourceDeleteUrl = deleteDataSource.map( | |
109 | + (item) => item.componentInfo.customIcon?.[0].url | |
110 | + ); | |
111 | + | |
112 | + if (dataSourceDeleteUrl?.length) { | |
113 | + // 判断外部所有组件是否有dataSourceDeleteUrl使用中的url | |
114 | + const deletePromise = unref(customIconUrls)?.filter((item) => | |
115 | + dataSourceDeleteUrl?.includes(item) | |
116 | + ); | |
117 | + | |
118 | + const deleteUrlInfo = countElementOccurrences(deletePromise); | |
119 | + const deleteUrl = deletePromise?.filter((item) => deleteUrlInfo?.[item] == 1); | |
120 | + Promise.all( | |
121 | + deleteUrl.map((item) => { | |
122 | + deleteFilePath(item); | |
123 | + }) | |
124 | + ); | |
125 | + } | |
126 | + } catch (err) {} | |
127 | + | |
128 | + try { | |
79 | 129 | await deleteDataComponent({ dataBoardId: unref(boardId), ids: [props.sourceInfo.id] }); |
80 | 130 | createMessage.success('删除成功'); |
81 | 131 | emit('ok'); | ... | ... |