Commit aee2e0b87e73089617f3f967125e89cd7c5507d1
Merge branch 'main_dev' into 'main'
fix:设备批量导入产品类型错误 See merge request yunteng/thingskit-front!1117
Showing
89 changed files
with
1116 additions
and
881 deletions
... | ... | @@ -25,7 +25,7 @@ module.exports = defineConfig({ |
25 | 25 | 'plugin:jest/recommended', |
26 | 26 | ], |
27 | 27 | rules: { |
28 | - 'no-console': 'error', | |
28 | + 'no-console': ['error', { allow: ['warn', 'error'] }], | |
29 | 29 | 'vue/script-setup-uses-vars': 'error', |
30 | 30 | '@typescript-eslint/ban-ts-ignore': 'off', |
31 | 31 | '@typescript-eslint/explicit-function-return-type': 'off', | ... | ... |
... | ... | @@ -51,6 +51,11 @@ enum DeviceManagerApi { |
51 | 51 | * @description 通过设备列表获取设备信息 |
52 | 52 | */ |
53 | 53 | QUERY_DEVICES = '/device/get/devices', |
54 | + | |
55 | + /** | |
56 | + * @description 批量变更产品 | |
57 | + */ | |
58 | + BATCH_UPDATE_PRODUCT = '/device/batch/update', | |
54 | 59 | } |
55 | 60 | |
56 | 61 | export const devicePage = (params: DeviceQueryParam) => { |
... | ... | @@ -378,3 +383,13 @@ export const doBatchClearAlarm = (ids: string[]) => { |
378 | 383 | { joinPrefix: false } |
379 | 384 | ); |
380 | 385 | }; |
386 | + | |
387 | +export const doBatchUpdateProduct = (params: { deviceIds: string[]; deviceProfileId: string }) => { | |
388 | + return defHttp.post( | |
389 | + { | |
390 | + url: DeviceManagerApi.BATCH_UPDATE_PRODUCT, | |
391 | + data: params, | |
392 | + }, | |
393 | + { joinPrefix: false } | |
394 | + ); | |
395 | +}; | ... | ... |
... | ... | @@ -65,3 +65,19 @@ export interface ImportModelOfMatterType { |
65 | 65 | tkDeviceProfileId?: string; |
66 | 66 | categoryId?: string; |
67 | 67 | } |
68 | + | |
69 | +export interface ModelOfMatterItemRecordType { | |
70 | + id: string; | |
71 | + creator: string; | |
72 | + createTime: string; | |
73 | + enabled: boolean; | |
74 | + tenantId: string; | |
75 | + functionType: string; | |
76 | + functionName: string; | |
77 | + identifier: string; | |
78 | + extensionDesc: any; | |
79 | + accessMode: string; | |
80 | + functionJson: FunctionJson; | |
81 | + status: number; | |
82 | + deviceProfileId: string; | |
83 | +} | ... | ... |
... | ... | @@ -2,6 +2,7 @@ import { BasicPageParams } from '../model/baseModel'; |
2 | 2 | import { |
3 | 3 | GetModelTslParams, |
4 | 4 | ImportModelOfMatterType, |
5 | + ModelOfMatterItemRecordType, | |
5 | 6 | ModelOfMatterParams, |
6 | 7 | } from './model/modelOfMatterModel'; |
7 | 8 | import { defHttp } from '/@/utils/http/axios'; |
... | ... | @@ -36,7 +37,7 @@ export const getModelList = ( |
36 | 37 | id?: string; |
37 | 38 | } |
38 | 39 | ) => { |
39 | - return defHttp.get({ | |
40 | + return defHttp.get<ModelOfMatterItemRecordType[]>({ | |
40 | 41 | url: `${ModelOfMatter.LIST}`, |
41 | 42 | params, |
42 | 43 | }); | ... | ... |
... | ... | @@ -48,13 +48,21 @@ |
48 | 48 | <template #content> |
49 | 49 | <section class="flex flex-wrap w-36"> |
50 | 50 | <table class="border-collapse" @click="handleSelectConfirm"> |
51 | - <tr v-for="row in MAX_ROW" :key="row" class="border border-gray-300 border-solid"> | |
51 | + <tr | |
52 | + v-for="rowNumber in MAX_ROW" | |
53 | + :key="rowNumber" | |
54 | + class="border border-gray-300 border-solid" | |
55 | + > | |
52 | 56 | <td |
53 | - v-for="col in MAX_COL" | |
54 | - :class="selectedLayout.col >= col && selectedLayout.row >= row ? 'bg-blue-500' : ''" | |
55 | - :key="col" | |
57 | + v-for="colNumber in MAX_COL" | |
58 | + :class=" | |
59 | + selectedLayout.col >= colNumber && selectedLayout.row >= rowNumber | |
60 | + ? 'bg-blue-500' | |
61 | + : '' | |
62 | + " | |
63 | + :key="colNumber" | |
56 | 64 | class="w-4 h-4 border border-gray-300 border-solid cursor-pointer" |
57 | - @mouseover="handleOver(row, col)" | |
65 | + @mouseover="handleOver(rowNumber, colNumber)" | |
58 | 66 | > |
59 | 67 | </td> |
60 | 68 | </tr> | ... | ... |
... | ... | @@ -77,7 +77,6 @@ |
77 | 77 | try { |
78 | 78 | const data = e.target && e.target.result; |
79 | 79 | const workbook = XLSX.read(data, { type: 'array' }); |
80 | - // console.log(workbook); | |
81 | 80 | /* DO SOMETHING WITH workbook HERE */ |
82 | 81 | const excelData = getExcelData(workbook); |
83 | 82 | emit('success', excelData); | ... | ... |
... | ... | @@ -90,7 +90,7 @@ |
90 | 90 | () => { |
91 | 91 | !unref(isFirstLoad) && fetch(); |
92 | 92 | }, |
93 | - { deep: true }, | |
93 | + { deep: true } | |
94 | 94 | ); |
95 | 95 | |
96 | 96 | async function fetch() { |
... | ... | @@ -110,6 +110,7 @@ |
110 | 110 | } |
111 | 111 | emitChange(); |
112 | 112 | } catch (error) { |
113 | + // eslint-disable-next-line no-console | |
113 | 114 | console.warn(error); |
114 | 115 | } finally { |
115 | 116 | loading.value = false; | ... | ... |
1 | +<script setup lang="ts"> | |
2 | + import { InputGroup, Button, Popconfirm } from 'ant-design-vue'; | |
3 | + import { computed, ref, unref, watch } from 'vue'; | |
4 | + import { componentMap } from '../componentMap'; | |
5 | + import { ComponentType } from '../types'; | |
6 | + import Icon from '/@/components/Icon'; | |
7 | + import { PopConfirm } from '/@/components/Table'; | |
8 | + import { upperFirst } from '/@/components/Transition/src/ExpandTransition'; | |
9 | + | |
10 | + const props = withDefaults( | |
11 | + defineProps<{ | |
12 | + value?: number | string | Recordable | Recordable[]; | |
13 | + component?: ComponentType; | |
14 | + componentProps?: Recordable; | |
15 | + disabled?: boolean; | |
16 | + changeEvent?: string; | |
17 | + valueField?: string; | |
18 | + defaultLockStatus?: boolean; | |
19 | + popconfirm?: Omit<PopConfirm, 'confirm' | 'cancel'>; | |
20 | + }>(), | |
21 | + { | |
22 | + changeEvent: 'change', | |
23 | + valueField: 'value', | |
24 | + disabled: false, | |
25 | + component: 'Input', | |
26 | + defaultLockStatus: true, | |
27 | + componentProps: () => ({}), | |
28 | + } | |
29 | + ); | |
30 | + | |
31 | + const slots = defineSlots<{ | |
32 | + popconfirmTitle?: () => any; | |
33 | + }>(); | |
34 | + | |
35 | + const emits = defineEmits(['change']); | |
36 | + | |
37 | + const ControlComponent = computed(() => componentMap.get(props.component)); | |
38 | + | |
39 | + const getControlComponentProps = computed(() => { | |
40 | + const { componentProps, changeEvent, component, valueField, value } = props; | |
41 | + const isCheck = component && ['Switch', 'Checkbox'].includes(component); | |
42 | + const eventKey = `on${upperFirst(changeEvent)}`; | |
43 | + return { | |
44 | + ...componentProps, | |
45 | + [eventKey]: (...args: Nullable<Recordable>[]) => { | |
46 | + const [e] = args; | |
47 | + if (componentProps?.[eventKey]) { | |
48 | + componentProps?.[eventKey](...args); | |
49 | + } | |
50 | + const target = e ? e.target : null; | |
51 | + const value = target ? (isCheck ? target.checked : target.value) : e; | |
52 | + emits('change', value); | |
53 | + }, | |
54 | + [valueField]: value, | |
55 | + }; | |
56 | + }); | |
57 | + | |
58 | + const popconfirmVisible = ref(false); | |
59 | + | |
60 | + const confirm = () => { | |
61 | + controlDisableStatus.value = false; | |
62 | + popconfirmVisible.value = false; | |
63 | + }; | |
64 | + | |
65 | + const cancel = () => { | |
66 | + popconfirmVisible.value = false; | |
67 | + }; | |
68 | + | |
69 | + const getPopConfirmProps = computed(() => { | |
70 | + const { popconfirm } = props; | |
71 | + | |
72 | + return { | |
73 | + ...popconfirm, | |
74 | + onConfirm: confirm, | |
75 | + onCancel: cancel, | |
76 | + onVisibleChange: () => { | |
77 | + if (!unref(controlDisableStatus)) { | |
78 | + popconfirmVisible.value = false; | |
79 | + controlDisableStatus.value = true; | |
80 | + return; | |
81 | + } | |
82 | + }, | |
83 | + title: slots.popconfirmTitle ? slots.popconfirmTitle : popconfirm?.title, | |
84 | + }; | |
85 | + }); | |
86 | + | |
87 | + const controlDisableStatus = ref(props.defaultLockStatus); | |
88 | + | |
89 | + watch( | |
90 | + () => props.defaultLockStatus, | |
91 | + (target) => { | |
92 | + controlDisableStatus.value = !!target; | |
93 | + }, | |
94 | + { immediate: true } | |
95 | + ); | |
96 | +</script> | |
97 | + | |
98 | +<template> | |
99 | + <InputGroup compact class="w-full !flex"> | |
100 | + <ControlComponent | |
101 | + v-bind="getControlComponentProps" | |
102 | + class="flex-auto" | |
103 | + :disabled="controlDisableStatus" | |
104 | + /> | |
105 | + <Popconfirm v-model:visible="popconfirmVisible" v-bind="getPopConfirmProps"> | |
106 | + <Button type="primary" :disabled="disabled"> | |
107 | + <Icon | |
108 | + :icon="controlDisableStatus ? 'ant-design:lock-outlined' : 'ant-design:unlock-outlined'" | |
109 | + /> | |
110 | + </Button> | |
111 | + </Popconfirm> | |
112 | + </InputGroup> | |
113 | +</template> | ... | ... |
... | ... | @@ -113,7 +113,7 @@ |
113 | 113 | const { TabPane } = Tabs; |
114 | 114 | const { prefixCls } = useDesign('easy-cron-inner'); |
115 | 115 | provide('prefixCls', prefixCls); |
116 | - const emit = defineEmits([...cronEmits]); | |
116 | + const emit = defineEmits(cronEmits); | |
117 | 117 | const props = defineProps({ ...cronProps }); |
118 | 118 | const activeKey = ref(props.hideSecond ? 'minute' : 'second'); |
119 | 119 | const second = ref('*'); |
... | ... | @@ -236,7 +236,7 @@ |
236 | 236 | if (/^[0-7]$/.test(week)) { |
237 | 237 | return convert(week); |
238 | 238 | } else if (patten1.test(week)) { |
239 | - return week.replace(patten1, ($0, before, separator, after) => { | |
239 | + return week.replace(patten1, (_$0, before, separator, after) => { | |
240 | 240 | if (separator === '/') { |
241 | 241 | return convert(before) + separator + after; |
242 | 242 | } else { | ... | ... |
... | ... | @@ -23,8 +23,8 @@ |
23 | 23 | |
24 | 24 | export default defineComponent({ |
25 | 25 | name: 'EasyCronModal', |
26 | - inheritAttrs: false, | |
27 | 26 | components: { BasicModal, EasyCron, Button }, |
27 | + inheritAttrs: false, | |
28 | 28 | setup() { |
29 | 29 | const attrs = useAttrs(); |
30 | 30 | const [registerModal, { closeModal }] = useModalInner(); | ... | ... |
... | ... | @@ -45,7 +45,7 @@ export function useTabSetup(props, context, options) { |
45 | 45 | |
46 | 46 | // 根据不同的类型计算出的value |
47 | 47 | const computeValue = computed(() => { |
48 | - let valueArray: any[] = []; | |
48 | + const valueArray: any[] = []; | |
49 | 49 | switch (type.value) { |
50 | 50 | case TypeEnum.unset: |
51 | 51 | valueArray.push('?'); |
... | ... | @@ -79,7 +79,7 @@ export function useTabSetup(props, context, options) { |
79 | 79 | }); |
80 | 80 | // 指定值范围区间,介于最小值和最大值之间 |
81 | 81 | const specifyRange = computed(() => { |
82 | - let range: number[] = []; | |
82 | + const range: number[] = []; | |
83 | 83 | if (maxValue.value != null) { |
84 | 84 | for (let i = minValue.value; i <= maxValue.value; i++) { |
85 | 85 | range.push(i); | ... | ... |
... | ... | @@ -207,7 +207,6 @@ |
207 | 207 | }); |
208 | 208 | |
209 | 209 | function handleSearch(searchValue: string) { |
210 | - console.log('searchValue', searchValue); | |
211 | 210 | if (searchValue !== searchText.value) searchText.value = searchValue; |
212 | 211 | emit('update:searchValue', searchValue); |
213 | 212 | if (!searchValue) { | ... | ... |
... | ... | @@ -16,8 +16,6 @@ |
16 | 16 | import { computed, defineComponent, unref, ref } from 'vue'; |
17 | 17 | import { Layout } from 'ant-design-vue'; |
18 | 18 | |
19 | - import { GithubFilled } from '@ant-design/icons-vue'; | |
20 | - | |
21 | 19 | import { DOC_URL, GITHUB_URL, SITE_URL } from '/@/settings/siteSetting'; |
22 | 20 | import { openWindow } from '/@/utils'; |
23 | 21 | |
... | ... | @@ -29,7 +27,7 @@ |
29 | 27 | |
30 | 28 | export default defineComponent({ |
31 | 29 | name: 'LayoutFooter', |
32 | - components: { Footer: Layout.Footer, GithubFilled }, | |
30 | + components: { Footer: Layout.Footer }, | |
33 | 31 | setup() { |
34 | 32 | const { t } = useI18n(); |
35 | 33 | const { getShowFooter } = useRootSetting(); | ... | ... |
... | ... | @@ -148,7 +148,6 @@ |
148 | 148 | |
149 | 149 | function renderMenu() { |
150 | 150 | const { menus, ...menuProps } = unref(getCommonProps); |
151 | - // console.log(menus); | |
152 | 151 | if (!menus || !menus.length) return null; |
153 | 152 | return !props.isHorizontal ? ( |
154 | 153 | <SimpleMenu {...menuProps} isSplitMenu={unref(getSplit)} items={menus} /> | ... | ... |
... | ... | @@ -100,7 +100,7 @@ export default defineComponent({ |
100 | 100 | <> |
101 | 101 | <TypePicker |
102 | 102 | menuTypeList={menuTypeList} |
103 | - handler={(item: typeof menuTypeList[0]) => { | |
103 | + handler={(item: (typeof menuTypeList)[0]) => { | |
104 | 104 | baseHandler(HandlerEnum.CHANGE_LAYOUT, { |
105 | 105 | mode: item.mode, |
106 | 106 | type: item.type, | ... | ... |
... | ... | @@ -85,9 +85,7 @@ |
85 | 85 | /^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/; |
86 | 86 | if (reg.test(formData.mobile)) { |
87 | 87 | const sendRes = await passwordResetCode(formData.mobile); |
88 | - console.log(sendRes); | |
89 | 88 | if (sendRes === '') { |
90 | - console.log('发送成功了'); | |
91 | 89 | return true; |
92 | 90 | } |
93 | 91 | return false; | ... | ... |
... | ... | @@ -11,8 +11,7 @@ |
11 | 11 | */ |
12 | 12 | export function simpleDebounce(fn, delay = 100) { |
13 | 13 | let timer: any | null = null; |
14 | - return function () { | |
15 | - let args = arguments; | |
14 | + return function (...args) { | |
16 | 15 | if (timer) { |
17 | 16 | clearTimeout(timer); |
18 | 17 | } |
... | ... | @@ -61,4 +60,3 @@ export function dateFormat(date, block) { |
61 | 60 | }); |
62 | 61 | return format; |
63 | 62 | } |
64 | - | ... | ... |
... | ... | @@ -8,7 +8,6 @@ export function listToTree(lists: getMenuListResultModel): getMenuListResultMode |
8 | 8 | lists.forEach((goods) => { |
9 | 9 | goods['menuName'] = t(goods.meta.title); // 为goods添加属性menuName |
10 | 10 | |
11 | - // console.log(goods.children?.length); | |
12 | 11 | if (goods.children?.length) { |
13 | 12 | listToTree(goods.children); |
14 | 13 | // goods.children.forEach((goodChildren) => { | ... | ... |
... | ... | @@ -102,8 +102,7 @@ |
102 | 102 | avatar: [{ uid: buildUUID(), name: 'name', url: data.record.avatar } as FileItem], |
103 | 103 | }); |
104 | 104 | } |
105 | - const { avatar, ...params } = data.record; | |
106 | - console.log(avatar); | |
105 | + const { ...params } = data.record; | |
107 | 106 | await setFieldsValue({ ...params }); |
108 | 107 | } else { |
109 | 108 | editId.value = ''; | ... | ... |
... | ... | @@ -82,11 +82,11 @@ |
82 | 82 | </script> |
83 | 83 | |
84 | 84 | <template> |
85 | - <section class="flex"> | |
86 | - <ApiTreeSelect v-bind="getBindProps" /> | |
87 | - <Button v-if="getShowCreate" type="link" @click="handleOpenCreate" :disabled="disabled" | |
88 | - >新增组织</Button | |
89 | - > | |
85 | + <section class="!flex"> | |
86 | + <ApiTreeSelect v-bind="getBindProps" class="flex-auto" /> | |
87 | + <Button v-if="getShowCreate" type="link" @click="handleOpenCreate" :disabled="disabled"> | |
88 | + 新增组织 | |
89 | + </Button> | |
90 | 90 | <OrganizationDrawer v-if="getShowCreate" @register="registerDrawer" @success="handleReload" /> |
91 | 91 | </section> |
92 | 92 | </template> | ... | ... |
... | ... | @@ -75,9 +75,7 @@ export const formSchema: FormSchema[] = [ |
75 | 75 | } |
76 | 76 | }, |
77 | 77 | // showUploadList: true, |
78 | - onDownload(file) { | |
79 | - console.log(file); | |
80 | - }, | |
78 | + onDownload() {}, | |
81 | 79 | onPreview: (fileList: FileItem) => { |
82 | 80 | createImgPreview({ imageList: [fileList.url!] }); |
83 | 81 | }, | ... | ... |
... | ... | @@ -153,7 +153,7 @@ |
153 | 153 | <template #renderItem="{ item }: BasicCardListRenderItem<BigScreenCenterItemsModel>"> |
154 | 154 | <Card |
155 | 155 | :style="{ |
156 | - '--viewType': item.viewType === ViewType.PUBLIC_VIEW ? '#1890ff' : '#faad14', | |
156 | + '--viewType': item.viewType === ViewType.PUBLIC_VIEW ? '#faad14' : '#1890ff', | |
157 | 157 | }" |
158 | 158 | class="card-container" |
159 | 159 | > | ... | ... |
... | ... | @@ -192,7 +192,6 @@ |
192 | 192 | getRestData.value = resp; |
193 | 193 | commonRest(resp, jsonEditorRef.value?.setJsonValue); |
194 | 194 | } catch (e) { |
195 | - console.log(e); | |
196 | 195 | if (Object.prototype.toString.call(e) === '[object Object]') { |
197 | 196 | jsonEditorRef.value?.setJsonValue(e); |
198 | 197 | } else { | ... | ... |
1 | 1 | import { FormProps, FormSchema, useComponentRegister } from '/@/components/Form'; |
2 | 2 | import { findDictItemByCode } from '/@/api/system/dict'; |
3 | -import { deviceProfile, getGatewayDevice } from '/@/api/device/deviceManager'; | |
3 | +import { getGatewayDevice, queryDeviceProfileBy } from '/@/api/device/deviceManager'; | |
4 | 4 | import { TransportTypeEnum } from '../../profiles/components/TransportDescript/const'; |
5 | 5 | import { JSONEditorValidator } from '/@/components/CodeEditor/src/JSONEditor'; |
6 | 6 | import { JSONEditor } from '/@/components/CodeEditor'; |
7 | 7 | import { DeviceTypeEnum } from '/@/api/device/model/deviceModel'; |
8 | 8 | import { getModelServices } from '/@/api/device/modelOfMatter'; |
9 | 9 | import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; |
10 | -import { nextTick, toRaw, unref } from 'vue'; | |
10 | +import { h, nextTick, toRaw, unref } from 'vue'; | |
11 | 11 | import ObjectModelValidateForm from '/@/components/Form/src/externalCompns/components/ObjectModelValidateForm/ObjectModelValidateForm.vue'; |
12 | 12 | import { CommandDeliveryWayEnum, ServiceCallTypeEnum } from '/@/enums/toolEnum'; |
13 | 13 | import { TaskTypeEnum } from '/@/views/task/center/config'; |
... | ... | @@ -18,9 +18,13 @@ import { uploadThumbnail } from '/@/api/configuration/center/configurationCenter |
18 | 18 | |
19 | 19 | import { getOrganizationList } from '/@/api/system/system'; |
20 | 20 | import { copyTransFun } from '/@/utils/fnUtils'; |
21 | +import LockControlGroup from '/@/components/Form/src/components/LockControlGroup.vue'; | |
22 | +import { OrgTreeSelect } from '/@/views/common/OrgTreeSelect'; | |
21 | 23 | |
22 | 24 | useComponentRegister('JSONEditor', JSONEditor); |
23 | 25 | useComponentRegister('ObjectModelValidateForm', ObjectModelValidateForm); |
26 | +useComponentRegister('LockControlGroup', LockControlGroup); | |
27 | +useComponentRegister('OrgTreeSelect', OrgTreeSelect); | |
24 | 28 | |
25 | 29 | export enum TypeEnum { |
26 | 30 | IS_GATEWAY = 'GATEWAY', |
... | ... | @@ -30,6 +34,17 @@ export enum TypeEnum { |
30 | 34 | export const isGateWay = (type: string) => { |
31 | 35 | return type === TypeEnum.IS_GATEWAY; |
32 | 36 | }; |
37 | + | |
38 | +const updateProductHelpMessage = [ | |
39 | + '注意:', | |
40 | + '修改设备产品时,如果"大屏"、"组态"、"看板"、"场景联动"、"数据流转"等有关联设备,请自行调整并保存。', | |
41 | +]; | |
42 | + | |
43 | +const updateOrgHelpMessage = [ | |
44 | + '注意:', | |
45 | + '1、修改设备组织时,如果"大屏"、"组态"、"看板"、"场景联动"、"数据流转"等有关联设备,请自行调整并保存。', | |
46 | + '2、网关设备在修改组织时,其关联网关子设备组织归属于网关组织及以下不用修改,否则将同步更新网关子设备组织为网关组织。', | |
47 | +]; | |
33 | 48 | // 第一步的表单 |
34 | 49 | export const step1Schemas: FormSchema[] = [ |
35 | 50 | { |
... | ... | @@ -96,43 +111,60 @@ export const step1Schemas: FormSchema[] = [ |
96 | 111 | show: false, |
97 | 112 | }, |
98 | 113 | { |
114 | + field: 'isUpdate', | |
115 | + label: '编辑模式', | |
116 | + component: 'Switch', | |
117 | + show: false, | |
118 | + }, | |
119 | + { | |
99 | 120 | field: 'profileId', |
100 | 121 | label: '所属产品', |
101 | 122 | required: true, |
102 | - component: 'ApiSelect', | |
123 | + component: 'LockControlGroup', | |
124 | + helpMessage: updateProductHelpMessage, | |
125 | + renderComponentContent: () => ({ | |
126 | + popconfirmTitle: () => | |
127 | + updateProductHelpMessage.map((text) => h('div', { style: { maxWidth: '200px' } }, text)), | |
128 | + }), | |
103 | 129 | componentProps: ({ formActionType, formModel }) => { |
104 | 130 | const { setFieldsValue } = formActionType; |
105 | 131 | return { |
106 | - api: async () => { | |
107 | - const options = await deviceProfile(); | |
108 | - const { profileId } = formModel; | |
109 | - if (profileId) { | |
110 | - const selectRecord = options.find((item) => item.tbProfileId === profileId); | |
111 | - selectRecord && setFieldsValue({ transportType: selectRecord!.transportType }); | |
112 | - } | |
113 | - return options; | |
114 | - }, | |
115 | - labelField: 'name', | |
116 | - valueField: 'tbProfileId', | |
117 | - onChange( | |
118 | - _value: string, | |
119 | - option: { deviceType: string; transportType: string; id: string } | |
120 | - ) { | |
121 | - const { deviceType, transportType, id } = option; | |
122 | - setFieldsValue({ | |
123 | - deviceType: deviceType, | |
124 | - transportType, | |
125 | - deviceProfileId: id, | |
126 | - gatewayId: null, | |
127 | - codeType: transportType === TransportTypeEnum.TCP ? TaskTypeEnum.MODBUS_RTU : null, | |
128 | - code: null, | |
129 | - addressCode: null, | |
130 | - }); | |
132 | + component: 'ApiSelect', | |
133 | + defaultLockStatus: !!formModel?.isUpdate, | |
134 | + componentProps: { | |
135 | + api: async () => { | |
136 | + const options = await queryDeviceProfileBy({ | |
137 | + deviceType: formModel?.isUpdate ? formModel?.deviceType : null, | |
138 | + }); | |
139 | + const { profileId } = formModel; | |
140 | + if (profileId) { | |
141 | + const selectRecord = options.find((item) => item.tbProfileId === profileId); | |
142 | + selectRecord && setFieldsValue({ transportType: selectRecord!.transportType }); | |
143 | + } | |
144 | + return options; | |
145 | + }, | |
146 | + labelField: 'name', | |
147 | + valueField: 'tbProfileId', | |
148 | + onChange( | |
149 | + _value: string, | |
150 | + option: { deviceType: string; transportType: string; id: string } | |
151 | + ) { | |
152 | + const { deviceType, transportType, id } = option; | |
153 | + setFieldsValue({ | |
154 | + deviceType: deviceType, | |
155 | + transportType, | |
156 | + deviceProfileId: id, | |
157 | + gatewayId: null, | |
158 | + codeType: transportType === TransportTypeEnum.TCP ? TaskTypeEnum.MODBUS_RTU : null, | |
159 | + code: null, | |
160 | + addressCode: null, | |
161 | + }); | |
162 | + }, | |
163 | + showSearch: true, | |
164 | + placeholder: '请选择产品', | |
165 | + filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => | |
166 | + option.label.includes(inputValue), | |
131 | 167 | }, |
132 | - showSearch: true, | |
133 | - placeholder: '请选择产品', | |
134 | - filterOption: (inputValue: string, option: Record<'label' | 'value', string>) => | |
135 | - option.label.includes(inputValue), | |
136 | 168 | }; |
137 | 169 | }, |
138 | 170 | }, |
... | ... | @@ -311,9 +343,19 @@ export const step1Schemas: FormSchema[] = [ |
311 | 343 | { |
312 | 344 | field: 'organizationId', |
313 | 345 | label: '所属组织', |
314 | - component: 'Select', | |
346 | + component: 'LockControlGroup', | |
315 | 347 | required: true, |
316 | - slot: 'addOrg', | |
348 | + helpMessage: updateOrgHelpMessage, | |
349 | + renderComponentContent: () => ({ | |
350 | + popconfirmTitle: () => | |
351 | + updateOrgHelpMessage.map((text) => h('div', { style: { maxWidth: '240px' } }, text)), | |
352 | + }), | |
353 | + componentProps: ({ formModel }) => { | |
354 | + return { | |
355 | + component: 'OrgTreeSelect', | |
356 | + defaultLockStatus: !!formModel?.isUpdate, | |
357 | + }; | |
358 | + }, | |
317 | 359 | }, |
318 | 360 | { |
319 | 361 | field: 'label', | ... | ... |
... | ... | @@ -7,6 +7,63 @@ import { h } from 'vue'; |
7 | 7 | import { Tag, Tooltip } from 'ant-design-vue'; |
8 | 8 | import { handeleCopy } from '../../profiles/step/topic'; |
9 | 9 | |
10 | +export enum DeviceListAuthEnum { | |
11 | + /** | |
12 | + * @description 新增 | |
13 | + */ | |
14 | + CREATE = 'api:yt:device:post', | |
15 | + | |
16 | + /** | |
17 | + * @description 删除 | |
18 | + */ | |
19 | + DELETE = 'api:yt:device:delete', | |
20 | + | |
21 | + /** | |
22 | + * @description 编辑 | |
23 | + */ | |
24 | + UPDATE = 'api:yt:device:update', | |
25 | + | |
26 | + /** | |
27 | + * @description 详情 | |
28 | + */ | |
29 | + DETAIL = 'api:yt:device:get', | |
30 | + | |
31 | + /** | |
32 | + * @description 导入 | |
33 | + */ | |
34 | + IMPORT = 'api:yt:device:import', | |
35 | + | |
36 | + /** | |
37 | + * @description 公开 | |
38 | + */ | |
39 | + PUBLIC = 'api:yt:device:public', | |
40 | + | |
41 | + /** | |
42 | + * @description 上下线 | |
43 | + */ | |
44 | + ONLINE = 'api:yt:device:online:record', | |
45 | + | |
46 | + /** | |
47 | + * @description 管理设备凭证 | |
48 | + */ | |
49 | + EQUIPMENT = 'api:yt:device:equipment', | |
50 | + | |
51 | + /** | |
52 | + * @description 分配客户 | |
53 | + */ | |
54 | + ASSIGN = 'api:yt:device:assign', | |
55 | + | |
56 | + /** | |
57 | + * @description 命令下发 | |
58 | + */ | |
59 | + RPC = 'api:yt:device:rpc', | |
60 | + | |
61 | + /** | |
62 | + * @description 更新产品 | |
63 | + */ | |
64 | + UPDATE_PRODUCT = 'api:yt:device:update:product', | |
65 | +} | |
66 | + | |
10 | 67 | // 表格列数据 |
11 | 68 | export const columns: BasicColumn[] = [ |
12 | 69 | { | ... | ... |
1 | +import { getDeviceProfile } from '/@/api/alarm/position'; | |
2 | +import { FormSchema } from '/@/components/Form'; | |
3 | + | |
4 | +enum FormFieldsEnum { | |
5 | + DEVICE_TYPE = 'deviceType', | |
6 | + SOURCE_DEVICE_PROFILE_ID = 'sourceDeviceProfileName', | |
7 | + TARGET_DEVICE_PROFILE_ID = 'deviceProfileId', | |
8 | +} | |
9 | + | |
10 | +export type FormGetFiledValueResultType = Record<FormFieldsEnum, string>; | |
11 | + | |
12 | +export const formSchemas: FormSchema[] = [ | |
13 | + { | |
14 | + field: FormFieldsEnum.SOURCE_DEVICE_PROFILE_ID, | |
15 | + component: 'Input', | |
16 | + label: '源产品', | |
17 | + dynamicDisabled: true, | |
18 | + required: true, | |
19 | + }, | |
20 | + { | |
21 | + field: FormFieldsEnum.DEVICE_TYPE, | |
22 | + label: '设备类型', | |
23 | + component: 'Input', | |
24 | + show: false, | |
25 | + }, | |
26 | + { | |
27 | + field: FormFieldsEnum.TARGET_DEVICE_PROFILE_ID, | |
28 | + component: 'ApiSelect', | |
29 | + label: '目标产品', | |
30 | + required: true, | |
31 | + componentProps: ({ formModel }) => { | |
32 | + return { | |
33 | + api: getDeviceProfile, | |
34 | + params: formModel[FormFieldsEnum.DEVICE_TYPE], | |
35 | + labelField: 'name', | |
36 | + valueField: 'tbProfileId', | |
37 | + placeholder: '请选择目标产品', | |
38 | + getPopupContainer: () => document.body, | |
39 | + }; | |
40 | + }, | |
41 | + }, | |
42 | +]; | ... | ... |
1 | +<script setup lang="ts"> | |
2 | + import { ref, unref } from 'vue'; | |
3 | + import { BatchUpdateProductModalParamsType } from '.'; | |
4 | + import { FormGetFiledValueResultType, formSchemas } from './config'; | |
5 | + import { doBatchUpdateProduct } from '/@/api/device/deviceManager'; | |
6 | + import { BasicForm, useForm } from '/@/components/Form'; | |
7 | + import Icon from '/@/components/Icon'; | |
8 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | |
9 | + import { useMessage } from '/@/hooks/web/useMessage'; | |
10 | + | |
11 | + const emits = defineEmits(['register', 'success']); | |
12 | + | |
13 | + const deviceIds = ref<string[]>([]); | |
14 | + const [registerForm, { validate, getFieldsValue, setFieldsValue, resetFields }] = useForm({ | |
15 | + layout: 'vertical', | |
16 | + showActionButtonGroup: false, | |
17 | + schemas: formSchemas, | |
18 | + }); | |
19 | + | |
20 | + const [registerModal, { setModalProps, closeModal }] = useModalInner( | |
21 | + async ({ record }: BatchUpdateProductModalParamsType) => { | |
22 | + resetFields(); | |
23 | + deviceIds.value = record.deviceIds; | |
24 | + setFieldsValue(record); | |
25 | + } | |
26 | + ); | |
27 | + | |
28 | + const { createMessage } = useMessage(); | |
29 | + const handleOk = async () => { | |
30 | + try { | |
31 | + await validate(); | |
32 | + setModalProps({ loading: true, confirmLoading: true }); | |
33 | + | |
34 | + const result = getFieldsValue() as FormGetFiledValueResultType; | |
35 | + | |
36 | + await doBatchUpdateProduct({ | |
37 | + deviceIds: unref(deviceIds), | |
38 | + deviceProfileId: result.deviceProfileId, | |
39 | + }); | |
40 | + | |
41 | + createMessage.success('操作成功'); | |
42 | + | |
43 | + closeModal(); | |
44 | + emits('success'); | |
45 | + } finally { | |
46 | + setModalProps({ loading: false, confirmLoading: false }); | |
47 | + } | |
48 | + }; | |
49 | +</script> | |
50 | + | |
51 | +<template> | |
52 | + <BasicModal @register="registerModal" @ok="handleOk"> | |
53 | + <template #title> | |
54 | + <div>批量更新产品</div> | |
55 | + <div class="mt-4 font-normal text-sm"> | |
56 | + <Icon icon="ant-design:info-circle-outlined" /> | |
57 | + <span> | |
58 | + 注意:修改设备产品时只能修改为同类型产品,如果"大屏"、"组态"、"看板"、"场景联动"、"数据流转"等有关联设备,请自行调整并保存。 | |
59 | + </span> | |
60 | + </div> | |
61 | + </template> | |
62 | + <!-- <template #title> | |
63 | + <span></span> | |
64 | + </template> --> | |
65 | + <BasicForm @register="registerForm" /> | |
66 | + </BasicModal> | |
67 | +</template> | ... | ... |
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | @next="handleStep1Next" |
21 | 21 | ref="DeviceStep1Ref" |
22 | 22 | v-show="current === 0" |
23 | - :isUpdate="!isUpdate" | |
23 | + :isUpdate="isUpdate" | |
24 | 24 | /> |
25 | 25 | <DeviceStep2 |
26 | 26 | ref="DeviceStep2Ref" |
... | ... | @@ -33,7 +33,7 @@ |
33 | 33 | </BasicModal> |
34 | 34 | </template> |
35 | 35 | <script lang="ts"> |
36 | - import { defineComponent, ref, computed, unref } from 'vue'; | |
36 | + import { defineComponent, ref, computed, unref, nextTick } from 'vue'; | |
37 | 37 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
38 | 38 | import { createOrEditDevice } from '/@/api/device/deviceManager'; |
39 | 39 | import DeviceStep1 from '../step/DeviceStep1.vue'; |
... | ... | @@ -60,16 +60,17 @@ |
60 | 60 | const DeviceStep2Ref = ref<InstanceType<typeof DeviceStep2>>(); |
61 | 61 | const { createMessage } = useMessage(); |
62 | 62 | const current = ref(0); |
63 | - const isUpdate = ref<Boolean>(false); | |
63 | + const isUpdate = ref(false); | |
64 | 64 | const deviceInfo = ref({}); |
65 | 65 | let currentDeviceData = {} as Recordable; |
66 | 66 | const getTitle = computed(() => (!unref(isUpdate) ? '新增设备' : '编辑设备')); |
67 | 67 | // 所有参数 |
68 | 68 | let stepState = ref(); |
69 | 69 | // 编辑回显 |
70 | - const [register, { closeModal, setModalProps }] = useModalInner((data) => { | |
70 | + const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { | |
71 | 71 | setModalProps({ confirmLoading: false, loading: true }); |
72 | 72 | isUpdate.value = data?.isUpdate; |
73 | + await nextTick(); | |
73 | 74 | if (unref(isUpdate)) { |
74 | 75 | const { record } = data; |
75 | 76 | currentDeviceData = record; | ... | ... |
... | ... | @@ -2,26 +2,6 @@ |
2 | 2 | <div class="step1"> |
3 | 3 | <div class="step1-form"> |
4 | 4 | <BasicForm @register="register"> |
5 | - <template #addOrg="{ model, field }"> | |
6 | - <div style="display: flex; align-items: center"> | |
7 | - <div style="width: 245px"> | |
8 | - <a-tree-select | |
9 | - @change="handleTreeOrg" | |
10 | - v-model:value="model[field]" | |
11 | - show-search | |
12 | - style="width: 100%" | |
13 | - :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }" | |
14 | - placeholder="请选择组织" | |
15 | - allow-clear | |
16 | - tree-default-expand-all | |
17 | - :tree-data="model?.['organizationList'] || treeData" | |
18 | - /> | |
19 | - </div> | |
20 | - <div> | |
21 | - <a-button type="link" @click="handleOpenOrgDrawer">新增组织</a-button> | |
22 | - </div> | |
23 | - </div> | |
24 | - </template> | |
25 | 5 | <template #snCode="{ model, field }"> |
26 | 6 | <div class="flex"> |
27 | 7 | <Input :maxlength="36" v-model:value="model[field]" placeholder="请输入设备名称" /> |
... | ... | @@ -36,7 +16,7 @@ |
36 | 16 | </Input> |
37 | 17 | </template> |
38 | 18 | </BasicForm> |
39 | - <div class="flex justify-center" v-if="isUpdate"> | |
19 | + <div class="flex justify-center" v-if="!isUpdate"> | |
40 | 20 | <a-button type="primary" @click="nextStep">下一步</a-button> |
41 | 21 | </div> |
42 | 22 | </div> |
... | ... | @@ -91,11 +71,10 @@ |
91 | 71 | </Spin> |
92 | 72 | </div> |
93 | 73 | </Modal> |
94 | - <DeptDrawer @register="registerModal" @success="handleSuccess" /> | |
95 | 74 | </div> |
96 | 75 | </template> |
97 | 76 | <script lang="ts"> |
98 | - import { defineComponent, ref, nextTick, unref, reactive, toRefs, onMounted } from 'vue'; | |
77 | + import { defineComponent, ref, nextTick, unref, reactive } from 'vue'; | |
99 | 78 | import { BasicForm, useForm } from '/@/components/Form'; |
100 | 79 | import { step1Schemas } from '../../config/data'; |
101 | 80 | import { useScript } from '/@/hooks/web/useScript'; |
... | ... | @@ -109,8 +88,6 @@ |
109 | 88 | import { validatorLongitude, validatorLatitude } from '/@/utils/rules'; |
110 | 89 | import { getOrganizationList } from '/@/api/system/system'; |
111 | 90 | import { copyTransFun } from '/@/utils/fnUtils'; |
112 | - import { useDrawer } from '/@/components/Drawer'; | |
113 | - import DeptDrawer from '/@/views/system/organization/OrganizationDrawer.vue'; | |
114 | 91 | import { TaskTypeEnum } from '/@/views/task/center/config'; |
115 | 92 | import { toRaw } from 'vue'; |
116 | 93 | import { FileItem } from '/@/components/Form/src/components/ApiUpload.vue'; |
... | ... | @@ -129,7 +106,6 @@ |
129 | 106 | FormItem: Form.Item, |
130 | 107 | Row, |
131 | 108 | Col, |
132 | - DeptDrawer, | |
133 | 109 | Spin, |
134 | 110 | }, |
135 | 111 | props: { |
... | ... | @@ -152,16 +128,7 @@ |
152 | 128 | copyTransFun(data as any as any[]); |
153 | 129 | orgData.treeData = data; |
154 | 130 | }; |
155 | - onMounted(async () => { | |
156 | - await getOrganizationListFunc(); | |
157 | - }); | |
158 | - const { treeData } = toRefs(orgData); | |
159 | - const [registerModal, { openDrawer }] = useDrawer(); | |
160 | - const handleOpenOrgDrawer = () => { | |
161 | - openDrawer(true, { | |
162 | - isUpdate: false, | |
163 | - }); | |
164 | - }; | |
131 | + | |
165 | 132 | const handleSuccess = async () => { |
166 | 133 | await getOrganizationListFunc(); |
167 | 134 | }; |
... | ... | @@ -178,27 +145,18 @@ |
178 | 145 | const devicePic = ref(''); |
179 | 146 | const loading = ref(false); |
180 | 147 | |
181 | - const [ | |
182 | - register, | |
183 | - { | |
184 | - validate, | |
185 | - resetFields, | |
186 | - setFieldsValue, | |
187 | - getFieldsValue, | |
188 | - updateSchema, | |
189 | - clearValidate, | |
190 | - validateFields, | |
191 | - }, | |
192 | - ] = useForm({ | |
193 | - labelWidth: 140, | |
194 | - schemas: step1Schemas, | |
195 | - actionColOptions: { | |
196 | - span: 14, | |
197 | - }, | |
198 | - labelAlign: 'right', | |
199 | - showResetButton: false, | |
200 | - showSubmitButton: false, | |
201 | - }); | |
148 | + const [register, { validate, resetFields, setFieldsValue, getFieldsValue, updateSchema }] = | |
149 | + useForm({ | |
150 | + labelWidth: 140, | |
151 | + schemas: step1Schemas, | |
152 | + actionColOptions: { | |
153 | + span: 14, | |
154 | + }, | |
155 | + labelAlign: 'right', | |
156 | + showResetButton: false, | |
157 | + showSubmitButton: false, | |
158 | + }); | |
159 | + | |
202 | 160 | async function nextStep() { |
203 | 161 | try { |
204 | 162 | let values = await validate(); |
... | ... | @@ -245,7 +203,7 @@ |
245 | 203 | const selectPosition = async () => { |
246 | 204 | visible.value = true; |
247 | 205 | if ( |
248 | - !unref(isUpdate1) && | |
206 | + unref(isUpdate1) && | |
249 | 207 | unref(devicePositionState).longitude && |
250 | 208 | unref(devicePositionState).latitude |
251 | 209 | ) { |
... | ... | @@ -440,8 +398,10 @@ |
440 | 398 | positionState.address = deviceInfo.address; |
441 | 399 | devicePositionState.value = { ...toRaw(positionState) }; |
442 | 400 | devicePic.value = deviceInfo.avatar; |
401 | + | |
443 | 402 | if (deviceInfo.avatar) { |
444 | 403 | setFieldsValue({ |
404 | + isUpdate: unref(isUpdate1), | |
445 | 405 | icon: [{ uid: buildUUID(), name: 'name', url: deviceInfo.avatar } as FileItem], |
446 | 406 | }); |
447 | 407 | } |
... | ... | @@ -449,6 +409,7 @@ |
449 | 409 | ...data, |
450 | 410 | code: data?.code, |
451 | 411 | addressCode: parseInt(data?.code || '', 16), |
412 | + isUpdate: unref(isUpdate1), | |
452 | 413 | }); |
453 | 414 | } |
454 | 415 | // 父组件调用获取字段值的方法 |
... | ... | @@ -499,13 +460,6 @@ |
499 | 460 | }); |
500 | 461 | } |
501 | 462 | |
502 | - const handleTreeOrg = (option: string) => { | |
503 | - if (option) clearValidate('organizationId'); | |
504 | - else { | |
505 | - validateFields(['organizationId']); | |
506 | - } | |
507 | - }; | |
508 | - | |
509 | 463 | return { |
510 | 464 | resetFields, |
511 | 465 | positionState, |
... | ... | @@ -534,11 +488,7 @@ |
534 | 488 | loading, |
535 | 489 | rules, |
536 | 490 | redirectPosition, |
537 | - treeData, | |
538 | - registerModal, | |
539 | - handleOpenOrgDrawer, | |
540 | 491 | handleSuccess, |
541 | - handleTreeOrg, | |
542 | 492 | devicePositionState, |
543 | 493 | spinning, |
544 | 494 | }; | ... | ... |
... | ... | @@ -100,11 +100,9 @@ |
100 | 100 | const { send, close } = useWebSocket(state.server, { |
101 | 101 | onConnected() { |
102 | 102 | send(state.sendValue); |
103 | - console.log('建立连接了'); | |
104 | 103 | }, |
105 | 104 | onMessage(_, e) { |
106 | 105 | const { data } = JSON.parse(e.data); |
107 | - console.log('来新消息了', '---data---', data); | |
108 | 106 | const newArray: socketDataType[] = []; |
109 | 107 | for (const key in data) { |
110 | 108 | const [time, value] = data[key].flat(1); |
... | ... | @@ -134,7 +132,6 @@ |
134 | 132 | }); |
135 | 133 | }, |
136 | 134 | onDisconnected() { |
137 | - console.log('断开连接了'); | |
138 | 135 | close(); |
139 | 136 | }, |
140 | 137 | onError() { | ... | ... |
... | ... | @@ -32,13 +32,12 @@ |
32 | 32 | import { BasicTable, useTable, TableAction } from '/@/components/Table'; |
33 | 33 | import { Switch } from 'ant-design-vue'; |
34 | 34 | import { DeviceRecord } from '/@/api/device/model/deviceModel'; |
35 | - import { watch } from 'vue'; | |
36 | 35 | import VideoModal from './videoModal.vue'; |
37 | 36 | import { useModal } from '/@/components/Modal'; |
38 | 37 | import { onMounted } from 'vue'; |
39 | 38 | import { useMessage } from '/@/hooks/web/useMessage'; |
40 | 39 | |
41 | - const props = defineProps({ | |
40 | + defineProps({ | |
42 | 41 | fromId: { |
43 | 42 | type: String, |
44 | 43 | default: '', |
... | ... | @@ -49,13 +48,6 @@ |
49 | 48 | }, |
50 | 49 | }); |
51 | 50 | |
52 | - watch( | |
53 | - () => props, | |
54 | - () => { | |
55 | - console.log(props, 'props'); | |
56 | - } | |
57 | - ); | |
58 | - | |
59 | 51 | const [registerModal, { openModal }] = useModal(); |
60 | 52 | |
61 | 53 | const [registerTable, { setTableData, setProps, setSelectedRowKeys, reload }] = useTable({ |
... | ... | @@ -68,14 +60,10 @@ |
68 | 60 | labelWidth: 120, |
69 | 61 | schemas: searchFormSchema, |
70 | 62 | }, |
71 | - beforeFetch: (params) => { | |
72 | - console.log(params); | |
73 | - }, | |
74 | 63 | useSearchForm: true, |
75 | 64 | }); |
76 | 65 | |
77 | - const handleTurnVideo = async (checked: Boolean, record: Recordable) => { | |
78 | - console.log(checked, record, 'record'); | |
66 | + const handleTurnVideo = async (checked: Boolean, _record: Recordable) => { | |
79 | 67 | setProps({ |
80 | 68 | loading: true, |
81 | 69 | }); |
... | ... | @@ -281,7 +269,6 @@ |
281 | 269 | }); |
282 | 270 | |
283 | 271 | const handlePlay = (record: Recordable) => { |
284 | - console.log(record); | |
285 | 272 | openModal(true, { |
286 | 273 | record, |
287 | 274 | }); | ... | ... |
... | ... | @@ -4,41 +4,57 @@ |
4 | 4 | <OrganizationIdTree @select="handleSelect" ref="organizationIdTreeRef" /> |
5 | 5 | <BasicTable style="flex: auto" @register="registerTable" class="w-5/6 xl:w-4/5"> |
6 | 6 | <template #toolbar> |
7 | - <Authority value="api:yt:device:post"> | |
7 | + <Authority :value="DeviceListAuthEnum.CREATE"> | |
8 | 8 | <a-button type="primary" @click="handleCreate" v-if="authBtn(role)"> |
9 | 9 | 新增设备 |
10 | 10 | </a-button> |
11 | 11 | </Authority> |
12 | - <Authority value="api:yt:device:delete"> | |
13 | - <Popconfirm | |
14 | - title="您确定要批量删除数据" | |
15 | - ok-text="确定" | |
16 | - cancel-text="取消" | |
17 | - @confirm="handleDelete()" | |
18 | - > | |
19 | - <a-button color="error" v-if="authBtn(role)" :disabled="!isExistOption"> | |
20 | - 批量删除 | |
21 | - </a-button> | |
22 | - </Popconfirm> | |
23 | - </Authority> | |
24 | - <Authority value="api:yt:device:import"> | |
12 | + | |
13 | + <Authority :value="DeviceListAuthEnum.IMPORT"> | |
25 | 14 | <Button type="primary" @click="handleBatchImport">导入</Button> |
26 | 15 | </Authority> |
27 | - <Authority value="api:yt:device:assign"> | |
28 | - <a-button | |
16 | + | |
17 | + <Authority | |
18 | + :value="[ | |
19 | + DeviceListAuthEnum.DELETE, | |
20 | + DeviceListAuthEnum.ASSIGN, | |
21 | + DeviceListAuthEnum.UPDATE_PRODUCT, | |
22 | + ]" | |
23 | + > | |
24 | + <AuthDropDown | |
29 | 25 | v-if="authBtn(role)" |
30 | - type="primary" | |
31 | - @click="handleBatchAssign" | |
32 | 26 | :disabled="!isExistOption" |
27 | + :dropMenuList="[ | |
28 | + { | |
29 | + text: '删除设备', | |
30 | + auth: DeviceListAuthEnum.DELETE, | |
31 | + icon: 'ant-design:delete-outlined', | |
32 | + event: '', | |
33 | + popconfirm: { | |
34 | + title: '您确定要批量删除数据', | |
35 | + onConfirm: () => handleDelete(), | |
36 | + }, | |
37 | + }, | |
38 | + { | |
39 | + text: '分配客户', | |
40 | + auth: DeviceListAuthEnum.ASSIGN, | |
41 | + icon: 'mdi:account-arrow-left', | |
42 | + event: '', | |
43 | + onClick: handleBatchAssign.bind(null), | |
44 | + }, | |
45 | + { | |
46 | + text: '更新产品', | |
47 | + auth: DeviceListAuthEnum.UPDATE_PRODUCT, | |
48 | + icon: 'clarity:note-edit-line', | |
49 | + event: '', | |
50 | + disabled: batchUpdateProductFlag, | |
51 | + onClick: handelOpenBatchUpdateProductModal, | |
52 | + }, | |
53 | + ]" | |
33 | 54 | > |
34 | - 批量分配 | |
35 | - </a-button> | |
55 | + <Button type="primary" :disabled="!isExistOption">批量操作</Button> | |
56 | + </AuthDropDown> | |
36 | 57 | </Authority> |
37 | - <!-- <Authority> | |
38 | - <a-button type="primary" @click="handelCollect()" :disabled="!isExistOption"> | |
39 | - 批量收藏 | |
40 | - </a-button> | |
41 | - </Authority> --> | |
42 | 58 | </template> |
43 | 59 | <template #img="{ record }"> |
44 | 60 | <TableImg |
... | ... | @@ -121,12 +137,12 @@ |
121 | 137 | { |
122 | 138 | label: '详情', |
123 | 139 | icon: 'ant-design:eye-outlined', |
124 | - auth: 'api:yt:device:get', | |
140 | + auth: DeviceListAuthEnum.DETAIL, | |
125 | 141 | onClick: handleDetail.bind(null, record), |
126 | 142 | }, |
127 | 143 | { |
128 | 144 | label: '编辑', |
129 | - auth: 'api:yt:device:update', | |
145 | + auth: DeviceListAuthEnum.UPDATE, | |
130 | 146 | icon: 'clarity:note-edit-line', |
131 | 147 | ifShow: authBtn(role), |
132 | 148 | onClick: handleEdit.bind(null, record), |
... | ... | @@ -138,7 +154,7 @@ |
138 | 154 | label: '取消分配', |
139 | 155 | icon: 'mdi:account-arrow-left', |
140 | 156 | ifShow: authBtn(role) && !record?.customerAdditionalInfo?.isPublic, |
141 | - auth: 'api:yt:device:assign', | |
157 | + auth: DeviceListAuthEnum.ASSIGN, | |
142 | 158 | popConfirm: { |
143 | 159 | title: '是否取消分配客户', |
144 | 160 | confirm: handleCancelDispatchCustomer.bind(null, record), |
... | ... | @@ -148,12 +164,12 @@ |
148 | 164 | label: '分配客户', |
149 | 165 | icon: 'mdi:account-arrow-right', |
150 | 166 | ifShow: authBtn(role), |
151 | - auth: 'api:yt:device:assign', | |
167 | + auth: DeviceListAuthEnum.ASSIGN, | |
152 | 168 | onClick: handleDispatchCustomer.bind(null, record), |
153 | 169 | }, |
154 | 170 | { |
155 | 171 | label: record?.customerAdditionalInfo?.isPublic ? '私有' : '公开', |
156 | - auth: 'api:yt:device:public', | |
172 | + auth: DeviceListAuthEnum.PUBLIC, | |
157 | 173 | icon: record?.customerAdditionalInfo?.isPublic |
158 | 174 | ? 'ant-design:lock-outlined' |
159 | 175 | : 'ant-design:unlock-outlined', |
... | ... | @@ -161,7 +177,7 @@ |
161 | 177 | }, |
162 | 178 | { |
163 | 179 | label: '上下线记录', |
164 | - auth: 'api:yt:device:online:record', | |
180 | + auth: DeviceListAuthEnum.ONLINE, | |
165 | 181 | icon: 'ant-design:rise-outlined', |
166 | 182 | onClick: handleUpAndDownRecord.bind(null, record), |
167 | 183 | }, |
... | ... | @@ -173,7 +189,6 @@ |
173 | 189 | } |
174 | 190 | : { |
175 | 191 | label: '取消收藏', |
176 | - auth: 'api:yt:device:online:record', | |
177 | 192 | icon: 'ant-design:heart-outlined', |
178 | 193 | popConfirm: { |
179 | 194 | title: '是否取消收藏', |
... | ... | @@ -182,7 +197,7 @@ |
182 | 197 | }, |
183 | 198 | { |
184 | 199 | label: '删除', |
185 | - auth: 'api:yt:device:delete', | |
200 | + auth: DeviceListAuthEnum.DELETE, | |
186 | 201 | icon: 'ant-design:delete-outlined', |
187 | 202 | ifShow: authBtn(role) && record.customerId === undefined, |
188 | 203 | color: 'error', |
... | ... | @@ -208,11 +223,16 @@ |
208 | 223 | <CustomerModal @register="registerCustomerModal" @reload="handleReload" /> |
209 | 224 | |
210 | 225 | <BatchImportModal @register="registerImportModal" @import-finally="handleImportFinally" /> |
226 | + | |
227 | + <BatchUpdateProductModal | |
228 | + @register="registerBatchUpdateProductModal" | |
229 | + @success="handleBatchUpdateProductSuccess" | |
230 | + /> | |
211 | 231 | </PageWrapper> |
212 | 232 | </div> |
213 | 233 | </template> |
214 | -<script lang="ts"> | |
215 | - import { defineComponent, reactive, unref, onMounted } from 'vue'; | |
234 | +<script lang="ts" setup> | |
235 | + import { reactive, onMounted, ref } from 'vue'; | |
216 | 236 | import { |
217 | 237 | DeviceModel, |
218 | 238 | DeviceRecord, |
... | ... | @@ -220,8 +240,8 @@ |
220 | 240 | DeviceTypeEnum, |
221 | 241 | } from '/@/api/device/model/deviceModel'; |
222 | 242 | import { BasicTable, useTable, TableAction, TableImg } from '/@/components/Table'; |
223 | - import { columns, searchFormSchema } from './config/device.data'; | |
224 | - import { Tag, Popover, Popconfirm, Button, Tooltip } from 'ant-design-vue'; | |
243 | + import { columns, DeviceListAuthEnum, searchFormSchema } from './config/device.data'; | |
244 | + import { Tag, Popover, Button, Tooltip } from 'ant-design-vue'; | |
225 | 245 | import { HeartTwoTone } from '@ant-design/icons-vue'; |
226 | 246 | import { |
227 | 247 | deleteDevice, |
... | ... | @@ -246,326 +266,295 @@ |
246 | 266 | import { USER_INFO_KEY } from '/@/enums/cacheEnum'; |
247 | 267 | import { getAuthCache } from '/@/utils/auth'; |
248 | 268 | import { authBtn } from '/@/enums/roleEnum'; |
249 | - import { useClipboard } from '@vueuse/core'; | |
250 | 269 | import { QuestionCircleOutlined } from '@ant-design/icons-vue'; |
251 | 270 | import { Authority } from '/@/components/Authority'; |
252 | 271 | import { useRoute, useRouter } from 'vue-router'; |
253 | 272 | import { useBatchOperation } from '/@/utils/useBatchOperation'; |
254 | 273 | import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm'; |
255 | 274 | import { useAuthDeviceDetail } from './hook/useAuthDeviceDetail'; |
275 | + import { | |
276 | + BatchUpdateProductModal, | |
277 | + BatchUpdateProductModalParamsType, | |
278 | + } from './cpns/modal/BatchUpdateProductModal'; | |
279 | + import { DataActionModeEnum } from '/@/enums/toolEnum'; | |
280 | + import { AuthDropDown } from '/@/components/Widget'; | |
256 | 281 | |
257 | - export default defineComponent({ | |
258 | - name: 'DeviceManagement', | |
259 | - components: { | |
260 | - BasicTable, | |
261 | - PageWrapper, | |
262 | - TableAction, | |
263 | - OrganizationIdTree, | |
264 | - Tag, | |
265 | - DeviceModal, | |
266 | - DeviceDetailDrawer, | |
267 | - CustomerModal, | |
268 | - TableImg, | |
269 | - QuestionCircleOutlined, | |
270 | - Popover, | |
271 | - Authority, | |
272 | - Popconfirm, | |
273 | - BatchImportModal, | |
274 | - Button, | |
275 | - // HeartOutlined, | |
276 | - HeartTwoTone, | |
277 | - Tooltip, | |
278 | - }, | |
279 | - setup(_) { | |
280 | - const { isCustomer } = useAuthDeviceDetail(); | |
281 | - const { createMessage } = useMessage(); | |
282 | - const go = useGo(); | |
283 | - const ROUTER = useRouter(); | |
284 | - const ROUTE = useRoute(); | |
285 | - const searchInfo = reactive<Recordable>({}); | |
286 | - const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); | |
287 | - const [registerModal, { openModal }] = useModal(); | |
288 | - const [registerCustomerModal, { openModal: openCustomerModal }] = useModal(); | |
289 | - const [registerDetailDrawer, { openDrawer }] = useDrawer(); | |
290 | - const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer(); | |
291 | - const [registerGatewayDetailDrawer, { openDrawer: openGatewayDetailDrawer }] = useDrawer(); | |
292 | - const [registerImportModal, { openModal: openImportModal }] = useModal(); | |
282 | + const { isCustomer } = useAuthDeviceDetail(); | |
283 | + const { createMessage } = useMessage(); | |
284 | + const go = useGo(); | |
285 | + const ROUTER = useRouter(); | |
286 | + const ROUTE = useRoute(); | |
287 | + const searchInfo = reactive<Recordable>({}); | |
288 | + const { organizationIdTreeRef, resetFn } = useResetOrganizationTree(searchInfo); | |
289 | + const [registerModal, { openModal }] = useModal(); | |
290 | + const [registerCustomerModal, { openModal: openCustomerModal }] = useModal(); | |
291 | + const [registerDetailDrawer, { openDrawer }] = useDrawer(); | |
292 | + const [registerTbDetailDrawer, { openDrawer: openTbDeviceDrawer }] = useDrawer(); | |
293 | + const [registerGatewayDetailDrawer, { openDrawer: openGatewayDetailDrawer }] = useDrawer(); | |
294 | + const [registerImportModal, { openModal: openImportModal }] = useModal(); | |
295 | + const [registerBatchUpdateProductModal, { openModal: openBatchUpdateProductModal }] = useModal(); | |
293 | 296 | |
294 | - const [ | |
295 | - registerTable, | |
296 | - { | |
297 | - reload, | |
298 | - setLoading, | |
299 | - setSelectedRowKeys, | |
300 | - getForm, | |
301 | - getSelectRowKeys, | |
302 | - getSelectRows, | |
303 | - getRowSelection, | |
304 | - }, | |
305 | - ] = useTable({ | |
306 | - title: '设备列表', | |
307 | - api: devicePage, | |
308 | - columns, | |
309 | - beforeFetch: (params) => { | |
310 | - const { deviceProfileId } = params; | |
311 | - if (!deviceProfileId) return; | |
312 | - const obj = { | |
313 | - ...params, | |
314 | - ...{ | |
315 | - deviceProfileIds: deviceProfileId ? [deviceProfileId] : null, | |
316 | - }, | |
317 | - }; | |
318 | - delete obj.deviceProfileId; | |
319 | - return obj; | |
320 | - }, | |
321 | - formConfig: { | |
322 | - labelWidth: 100, | |
323 | - schemas: searchFormSchema, | |
324 | - resetFunc: resetFn, | |
325 | - }, | |
326 | - useSearchForm: true, | |
327 | - showTableSetting: true, | |
328 | - bordered: true, | |
329 | - showIndexColumn: false, | |
330 | - rowKey: 'id', | |
331 | - searchInfo: searchInfo, | |
332 | - clickToRowSelect: false, | |
333 | - actionColumn: { | |
334 | - width: 200, | |
335 | - title: '操作', | |
336 | - slots: { customRender: 'action' }, | |
337 | - fixed: 'right', | |
338 | - }, | |
339 | - rowSelection: { | |
340 | - type: 'checkbox', | |
341 | - getCheckboxProps: (record: DeviceModel) => { | |
342 | - return { disabled: !!record.customerId }; | |
343 | - }, | |
297 | + const batchUpdateProductFlag = ref(true); | |
298 | + | |
299 | + const [ | |
300 | + registerTable, | |
301 | + { | |
302 | + reload, | |
303 | + setLoading, | |
304 | + setSelectedRowKeys, | |
305 | + getForm, | |
306 | + getSelectRowKeys, | |
307 | + getSelectRows, | |
308 | + getRowSelection, | |
309 | + clearSelectedRowKeys, | |
310 | + }, | |
311 | + ] = useTable({ | |
312 | + title: '设备列表', | |
313 | + api: devicePage, | |
314 | + columns, | |
315 | + beforeFetch: (params) => { | |
316 | + const { deviceProfileId } = params; | |
317 | + if (!deviceProfileId) return; | |
318 | + const obj = { | |
319 | + ...params, | |
320 | + ...{ | |
321 | + deviceProfileIds: deviceProfileId ? [deviceProfileId] : null, | |
344 | 322 | }, |
345 | - }); | |
323 | + }; | |
324 | + delete obj.deviceProfileId; | |
325 | + return obj; | |
326 | + }, | |
327 | + formConfig: { | |
328 | + labelWidth: 100, | |
329 | + schemas: searchFormSchema, | |
330 | + resetFunc: resetFn, | |
331 | + }, | |
332 | + useSearchForm: true, | |
333 | + showTableSetting: true, | |
334 | + bordered: true, | |
335 | + showIndexColumn: false, | |
336 | + rowKey: 'id', | |
337 | + searchInfo: searchInfo, | |
338 | + clickToRowSelect: false, | |
339 | + actionColumn: { | |
340 | + width: 200, | |
341 | + title: '操作', | |
342 | + slots: { customRender: 'action' }, | |
343 | + fixed: 'right', | |
344 | + }, | |
345 | + rowSelection: { | |
346 | + type: 'checkbox', | |
347 | + getCheckboxProps: (record: DeviceModel) => { | |
348 | + return { disabled: !!record.customerId }; | |
349 | + }, | |
350 | + onSelect(_record, _selected, selectedRows) { | |
351 | + const [firstItem] = selectedRows as DeviceRecord[]; | |
352 | + const { deviceType } = firstItem || {}; | |
353 | + batchUpdateProductFlag.value = | |
354 | + !selectedRows.length || | |
355 | + !selectedRows.every((item) => (item as DeviceRecord).deviceType === deviceType); | |
356 | + }, | |
357 | + onSelectAll(_selected, selectedRows) { | |
358 | + const [firstItem] = selectedRows as DeviceRecord[]; | |
359 | + const { deviceType } = firstItem || {}; | |
360 | + batchUpdateProductFlag.value = | |
361 | + !selectedRows.length || | |
362 | + !selectedRows.every((item) => (item as DeviceRecord).deviceType === deviceType); | |
363 | + }, | |
364 | + }, | |
365 | + }); | |
346 | 366 | |
347 | - const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys); | |
367 | + const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys); | |
348 | 368 | |
349 | - const userInfo: any = getAuthCache(USER_INFO_KEY); | |
350 | - const role: string = userInfo.roles[0]; | |
369 | + const userInfo: any = getAuthCache(USER_INFO_KEY); | |
370 | + const role: string = userInfo.roles[0]; | |
351 | 371 | |
352 | - function handleCreate() { | |
353 | - openModal(true, { | |
354 | - isUpdate: false, | |
355 | - }); | |
356 | - } | |
357 | - // 分配客户 | |
358 | - function handleDispatchCustomer(record: Recordable) { | |
359 | - openCustomerModal(true, record); | |
360 | - } | |
361 | - function handleReload() { | |
362 | - setSelectedRowKeys([]); | |
363 | - handleSuccess(); | |
364 | - } | |
365 | - // 取消分配客户 | |
366 | - async function handleCancelDispatchCustomer(record: Recordable) { | |
367 | - try { | |
368 | - // 该设备是否正在被场景联动使用中? | |
369 | - await cancelDispatchCustomer(record); | |
370 | - handleReload(); | |
371 | - } catch {} | |
372 | - } | |
372 | + function handleCreate() { | |
373 | + openModal(true, { | |
374 | + isUpdate: false, | |
375 | + }); | |
376 | + } | |
377 | + // 分配客户 | |
378 | + function handleDispatchCustomer(record: Recordable) { | |
379 | + openCustomerModal(true, record); | |
380 | + } | |
381 | + function handleReload() { | |
382 | + setSelectedRowKeys([]); | |
383 | + handleSuccess(); | |
384 | + } | |
385 | + // 取消分配客户 | |
386 | + async function handleCancelDispatchCustomer(record: Recordable) { | |
387 | + try { | |
388 | + // 该设备是否正在被场景联动使用中? | |
389 | + await cancelDispatchCustomer(record); | |
390 | + handleReload(); | |
391 | + } catch {} | |
392 | + } | |
373 | 393 | |
374 | - function handleDetail(record: Recordable) { | |
375 | - const { id, tbDeviceId, deviceProfile, deviceType } = record; | |
376 | - const { transportType } = deviceProfile || {}; | |
377 | - openDrawer(true, { | |
378 | - id, | |
379 | - tbDeviceId, | |
380 | - transportType, | |
381 | - deviceType, | |
382 | - }); | |
383 | - } | |
394 | + function handleDetail(record: Recordable) { | |
395 | + const { id, tbDeviceId, deviceProfile, deviceType } = record; | |
396 | + const { transportType } = deviceProfile || {}; | |
397 | + openDrawer(true, { | |
398 | + id, | |
399 | + tbDeviceId, | |
400 | + transportType, | |
401 | + deviceType, | |
402 | + }); | |
403 | + } | |
384 | 404 | |
385 | - async function handleEdit(record: Recordable) { | |
386 | - if (record.deviceType === 'SENSOR') { | |
387 | - const res = await getGATEWAY(record.tbDeviceId); | |
388 | - Reflect.set(record, 'gatewayId', res.tbDeviceId); | |
389 | - } | |
390 | - openModal(true, { | |
391 | - isUpdate: true, | |
392 | - record, | |
393 | - }); | |
394 | - } | |
395 | - function handleSuccess() { | |
396 | - reload(); | |
397 | - } | |
398 | - function handleSelect(organization) { | |
399 | - searchInfo.organizationId = organization; | |
400 | - handleSuccess(); | |
401 | - } | |
402 | - function goDeviceProfile(e) { | |
403 | - go(PageEnum.DEVICE_PROFILE + '?name=' + encodeURIComponent(String(e))); | |
404 | - } | |
405 | - const { copied, copy } = useClipboard({ legacy: true }); | |
406 | - const copySN = async (snCode: string) => { | |
407 | - await copy(snCode); | |
408 | - if (unref(copied)) { | |
409 | - createMessage.success('复制成功~'); | |
410 | - } | |
411 | - }; | |
405 | + async function handleEdit(record: Recordable) { | |
406 | + if (record.deviceType === 'SENSOR') { | |
407 | + const res = await getGATEWAY(record.tbDeviceId); | |
408 | + Reflect.set(record, 'gatewayId', res.tbDeviceId); | |
409 | + } | |
410 | + openModal(true, { | |
411 | + isUpdate: true, | |
412 | + record, | |
413 | + }); | |
414 | + } | |
415 | + function handleSuccess() { | |
416 | + reload(); | |
417 | + } | |
418 | + function handleSelect(organization) { | |
419 | + searchInfo.organizationId = organization; | |
420 | + handleSuccess(); | |
421 | + } | |
422 | + function goDeviceProfile(e) { | |
423 | + go(PageEnum.DEVICE_PROFILE + '?name=' + encodeURIComponent(String(e))); | |
424 | + } | |
412 | 425 | |
413 | - const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => { | |
414 | - openTbDeviceDrawer(true, data); | |
415 | - }; | |
426 | + const handleOpenTbDeviceDetail = (data: { id: string; tbDeviceId: string }) => { | |
427 | + openTbDeviceDrawer(true, data); | |
428 | + }; | |
416 | 429 | |
417 | - const handleOpenGatewayDetail = (data: { id: string; tbDeviceId: string }) => { | |
418 | - openGatewayDetailDrawer(true, data); | |
419 | - }; | |
430 | + const handleOpenGatewayDetail = (data: { id: string; tbDeviceId: string }) => { | |
431 | + openGatewayDetailDrawer(true, data); | |
432 | + }; | |
420 | 433 | |
421 | - const handleUpAndDownRecord = (record: Record<'name' | 'alias', string>) => { | |
422 | - ROUTER.push({ | |
423 | - path: '/operation/onlinerecord', | |
424 | - query: { deviceName: record.alias || record.name }, | |
425 | - }); | |
426 | - }; | |
434 | + const handleUpAndDownRecord = (record: Record<'name' | 'alias', string>) => { | |
435 | + ROUTER.push({ | |
436 | + path: '/operation/onlinerecord', | |
437 | + query: { deviceName: record.alias || record.name }, | |
438 | + }); | |
439 | + }; | |
427 | 440 | |
428 | - const handleCheckHasDiffenterOrg = (options: DeviceModel[]) => { | |
429 | - let orgId: string | undefined; | |
430 | - let flag = false; | |
431 | - for (const item of options) { | |
432 | - const _orgId = item.organizationId; | |
433 | - if (!orgId) orgId = _orgId; | |
434 | - if (orgId !== _orgId) { | |
435 | - flag = true; | |
436 | - break; | |
437 | - } | |
438 | - } | |
439 | - return flag; | |
440 | - }; | |
441 | + const handleCheckHasDiffenterOrg = (options: DeviceModel[]) => { | |
442 | + let orgId: string | undefined; | |
443 | + let flag = false; | |
444 | + for (const item of options) { | |
445 | + const _orgId = item.organizationId; | |
446 | + if (!orgId) orgId = _orgId; | |
447 | + if (orgId !== _orgId) { | |
448 | + flag = true; | |
449 | + break; | |
450 | + } | |
451 | + } | |
452 | + return flag; | |
453 | + }; | |
441 | 454 | |
442 | - const handleBatchAssign = () => { | |
443 | - const options = getSelectRows(); | |
444 | - if (handleCheckHasDiffenterOrg(options as DeviceModel[])) { | |
445 | - createMessage.error('当前选中项中存在不同所属组织的设备!'); | |
446 | - return; | |
447 | - } | |
448 | - openCustomerModal(true, options); | |
449 | - }; | |
455 | + const handleBatchAssign = () => { | |
456 | + const options = getSelectRows(); | |
457 | + if (handleCheckHasDiffenterOrg(options as DeviceModel[])) { | |
458 | + createMessage.error('当前选中项中存在不同所属组织的设备!'); | |
459 | + return; | |
460 | + } | |
461 | + openCustomerModal(true, options); | |
462 | + }; | |
450 | 463 | |
451 | - const handleDelete = async (record?: DeviceRecord) => { | |
452 | - let ids: string[] = []; | |
453 | - if (record) { | |
454 | - ids.push(record.id); | |
455 | - } else { | |
456 | - ids = getSelectRowKeys(); | |
457 | - } | |
458 | - try { | |
459 | - setLoading(true); | |
460 | - await deleteDevice(ids); | |
461 | - createMessage.success('删除成功'); | |
462 | - handleReload(); | |
463 | - } catch (error) { | |
464 | - throw error; | |
465 | - } finally { | |
466 | - setLoading(false); | |
467 | - } | |
468 | - }; | |
464 | + const handleDelete = async (record?: DeviceRecord) => { | |
465 | + let ids: string[] = []; | |
466 | + if (record) { | |
467 | + ids.push(record.id); | |
468 | + } else { | |
469 | + ids = getSelectRowKeys(); | |
470 | + } | |
471 | + try { | |
472 | + setLoading(true); | |
473 | + await deleteDevice(ids); | |
474 | + createMessage.success('删除成功'); | |
475 | + handleReload(); | |
476 | + } catch (error) { | |
477 | + throw error; | |
478 | + } finally { | |
479 | + setLoading(false); | |
480 | + } | |
481 | + }; | |
469 | 482 | |
470 | - const handleBatchImport = () => { | |
471 | - openImportModal(true); | |
472 | - }; | |
483 | + const handleBatchImport = () => { | |
484 | + openImportModal(true); | |
485 | + }; | |
473 | 486 | |
474 | - const handleImportFinally = () => { | |
475 | - reload(); | |
476 | - }; | |
487 | + const handleImportFinally = () => { | |
488 | + reload(); | |
489 | + }; | |
477 | 490 | |
478 | - const { createSyncConfirm } = useSyncConfirm(); | |
479 | - const handlePublicDevice = async (record: DeviceRecord) => { | |
480 | - try { | |
481 | - const publicFlag = record?.customerAdditionalInfo?.isPublic; | |
482 | - const type = publicFlag ? '私有' : '公开'; | |
483 | - const flag = await createSyncConfirm({ | |
484 | - iconType: 'warning', | |
485 | - title: `您确定要将设备 '${record.name}' 设为${type}吗?`, | |
486 | - content: `确认后,设备及其所有数据将被设为${type}并${ | |
487 | - publicFlag ? '不' : '' | |
488 | - }可被其他人访问。`, | |
489 | - }); | |
490 | - if (!flag) return; | |
491 | - if (publicFlag) { | |
492 | - await privateDevice(record.tbDeviceId); | |
493 | - } else { | |
494 | - await publicDevice(record.tbDeviceId); | |
495 | - } | |
496 | - reload(); | |
497 | - } catch (error) {} | |
498 | - }; | |
491 | + const { createSyncConfirm } = useSyncConfirm(); | |
492 | + const handlePublicDevice = async (record: DeviceRecord) => { | |
493 | + try { | |
494 | + const publicFlag = record?.customerAdditionalInfo?.isPublic; | |
495 | + const type = publicFlag ? '私有' : '公开'; | |
496 | + const flag = await createSyncConfirm({ | |
497 | + iconType: 'warning', | |
498 | + title: `您确定要将设备 '${record.name}' 设为${type}吗?`, | |
499 | + content: `确认后,设备及其所有数据将被设为${type}并${ | |
500 | + publicFlag ? '不' : '' | |
501 | + }可被其他人访问。`, | |
502 | + }); | |
503 | + if (!flag) return; | |
504 | + if (publicFlag) { | |
505 | + await privateDevice(record.tbDeviceId); | |
506 | + } else { | |
507 | + await publicDevice(record.tbDeviceId); | |
508 | + } | |
509 | + reload(); | |
510 | + } catch (error) {} | |
511 | + }; | |
499 | 512 | |
500 | - // 收藏 && 批量收藏 | |
501 | - const handelCollect = async (record?: Recordable) => { | |
502 | - let ids: string[] = []; | |
503 | - if (record) { | |
504 | - ids.push(record.id); | |
505 | - } else { | |
506 | - ids = await getSelectRowKeys(); | |
507 | - } | |
508 | - try { | |
509 | - setLoading(true); | |
510 | - await deviceCollect(ids); | |
511 | - createMessage.success('操作成功'); | |
512 | - handleReload(); | |
513 | - } catch (error) { | |
514 | - throw error; | |
515 | - } finally { | |
516 | - setLoading(false); | |
517 | - } | |
518 | - }; | |
513 | + // 收藏 && 批量收藏 | |
514 | + const handelCollect = async (record?: Recordable) => { | |
515 | + let ids: string[] = []; | |
516 | + if (record) { | |
517 | + ids.push(record.id); | |
518 | + } else { | |
519 | + ids = await getSelectRowKeys(); | |
520 | + } | |
521 | + try { | |
522 | + setLoading(true); | |
523 | + await deviceCollect(ids); | |
524 | + createMessage.success('操作成功'); | |
525 | + handleReload(); | |
526 | + } catch (error) { | |
527 | + throw error; | |
528 | + } finally { | |
529 | + setLoading(false); | |
530 | + } | |
531 | + }; | |
519 | 532 | |
520 | - onMounted(() => { | |
521 | - const queryParams = ROUTE.query as Record<'deviceProfileId', undefined | string>; | |
522 | - const { setFieldsValue } = getForm(); | |
523 | - setFieldsValue({ deviceProfileId: queryParams.deviceProfileId }); | |
524 | - }); | |
525 | - return { | |
526 | - registerTable, | |
527 | - handleCreate, | |
528 | - handleDetail, | |
529 | - handleEdit, | |
530 | - handleSuccess, | |
531 | - goDeviceProfile, | |
532 | - handleSelect, | |
533 | - registerModal, | |
534 | - registerDetailDrawer, | |
535 | - DeviceTypeEnum, | |
536 | - DeviceState, | |
537 | - searchInfo, | |
538 | - organizationIdTreeRef, | |
539 | - handleDispatchCustomer, | |
540 | - handleCancelDispatchCustomer, | |
541 | - registerCustomerModal, | |
542 | - authBtn, | |
543 | - role, | |
544 | - copySN, | |
545 | - isExistOption, | |
546 | - handleDelete, | |
547 | - handelCollect, | |
548 | - // hasBatchDelete, | |
549 | - // handleDeleteOrBatchDelete, | |
550 | - handleReload, | |
551 | - registerTbDetailDrawer, | |
552 | - handleOpenTbDeviceDetail, | |
553 | - handleOpenGatewayDetail, | |
554 | - registerGatewayDetailDrawer, | |
555 | - handleUpAndDownRecord, | |
556 | - handleBatchAssign, | |
557 | - registerImportModal, | |
558 | - handleBatchImport, | |
559 | - handleImportFinally, | |
560 | - handlePublicDevice, | |
561 | - isCustomer, | |
562 | - }; | |
563 | - }, | |
533 | + onMounted(() => { | |
534 | + const queryParams = ROUTE.query as Record<'deviceProfileId', undefined | string>; | |
535 | + const { setFieldsValue } = getForm(); | |
536 | + setFieldsValue({ deviceProfileId: queryParams.deviceProfileId }); | |
564 | 537 | }); |
538 | + | |
539 | + const handelOpenBatchUpdateProductModal = () => { | |
540 | + const rows: DeviceRecord[] = getSelectRows(); | |
541 | + const [firstItem] = rows; | |
542 | + | |
543 | + openBatchUpdateProductModal(true, { | |
544 | + mode: DataActionModeEnum.UPDATE, | |
545 | + record: { | |
546 | + sourceDeviceProfileName: firstItem.deviceProfile.name, | |
547 | + deviceType: firstItem.deviceType, | |
548 | + deviceIds: rows.map((item) => item.tbDeviceId), | |
549 | + }, | |
550 | + } as BatchUpdateProductModalParamsType); | |
551 | + }; | |
552 | + | |
553 | + const handleBatchUpdateProductSuccess = () => { | |
554 | + reload(); | |
555 | + clearSelectedRowKeys(); | |
556 | + batchUpdateProductFlag.value = true; | |
557 | + }; | |
565 | 558 | </script> |
566 | 559 | |
567 | -<style scoped lang="css"> | |
568 | - /* /deep/.ant-message-notice-content { | |
569 | - max-width: 600px !important; | |
570 | - } */ | |
571 | -</style> | |
560 | +<style scoped lang="css"></style> | ... | ... |
... | ... | @@ -235,7 +235,6 @@ |
235 | 235 | |
236 | 236 | function loadDataSuccess(excelDataList: ExcelData[]) { |
237 | 237 | tableListRef.value = []; |
238 | - console.log(excelDataList); | |
239 | 238 | for (const excelData of excelDataList) { |
240 | 239 | const { |
241 | 240 | header, |
... | ... | @@ -294,9 +293,7 @@ |
294 | 293 | }); |
295 | 294 | }; |
296 | 295 | //导入 |
297 | - function handleImport() { | |
298 | - console.log('record'); | |
299 | - } | |
296 | + function handleImport() {} | |
300 | 297 | function handleSuccess() { |
301 | 298 | reload(); |
302 | 299 | } | ... | ... |
... | ... | @@ -68,21 +68,18 @@ |
68 | 68 | <Button v-if="isShowBtn" class="!bg-gray-200" type="text" @click="handleReturn"> |
69 | 69 | 返回 |
70 | 70 | </Button> |
71 | - <Authority :value="[ModelOfMatterPermission.DELETE, ModelCategoryPermission.DELETE]"> | |
71 | + <Authority | |
72 | + v-if="isShowBtn" | |
73 | + :value="[ModelOfMatterPermission.DELETE, ModelCategoryPermission.DELETE]" | |
74 | + > | |
72 | 75 | <Popconfirm |
73 | 76 | title="您确定要批量删除数据" |
74 | 77 | ok-text="确定" |
75 | 78 | cancel-text="取消" |
76 | - @confirm="handleDeleteOrBatchDelete(null)" | |
79 | + @confirm="handleDeleteOrBatchDelete()" | |
80 | + :disabled="getHasBatchDelete" | |
77 | 81 | > |
78 | - <Button | |
79 | - style="display: none" | |
80 | - type="primary" | |
81 | - color="error" | |
82 | - :disabled="hasBatchDelete" | |
83 | - > | |
84 | - 批量删除 | |
85 | - </Button> | |
82 | + <Button type="primary" danger :disabled="getHasBatchDelete"> 批量删除 </Button> | |
86 | 83 | </Popconfirm> |
87 | 84 | </Authority> |
88 | 85 | </div> |
... | ... | @@ -120,11 +117,7 @@ |
120 | 117 | /> |
121 | 118 | </template> |
122 | 119 | </BasicTable> |
123 | - <PhysicalModelModal | |
124 | - :record="$props.record" | |
125 | - @register="registerModal" | |
126 | - @success="handleSuccess" | |
127 | - /> | |
120 | + <PhysicalModelModal :record="$props.record" @register="registerModal" @success="reload" /> | |
128 | 121 | <PhysicalModelTsl :record="$props.record" @register="registerModalTsl" /> |
129 | 122 | <SelectImport |
130 | 123 | :record="$props.record" |
... | ... | @@ -142,7 +135,6 @@ |
142 | 135 | ModelCategoryPermission, |
143 | 136 | physicalColumn, |
144 | 137 | } from '../device.profile.data'; |
145 | - import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | |
146 | 138 | import { Authority } from '/@/components/Authority'; |
147 | 139 | import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue'; |
148 | 140 | import PhysicalModelTsl from './cpns/physical/PhysicalModelTsl.vue'; |
... | ... | @@ -156,8 +148,11 @@ |
156 | 148 | releaseModel, |
157 | 149 | } from '/@/api/device/modelOfMatter'; |
158 | 150 | import { OpenModelOfMatterModelParams, OpenModelMode } from './cpns/physical/types'; |
159 | - import { ModelOfMatterParams } from '/@/api/device/model/modelOfMatterModel'; | |
160 | - import { ref, unref } from 'vue'; | |
151 | + import { | |
152 | + ModelOfMatterItemRecordType, | |
153 | + ModelOfMatterParams, | |
154 | + } from '/@/api/device/model/modelOfMatterModel'; | |
155 | + import { computed, ref, unref } from 'vue'; | |
161 | 156 | import { isObject } from '/@/utils/is'; |
162 | 157 | import { useRole } from '/@/hooks/business/useRole'; |
163 | 158 | import { ExportModelCategory } from '/@/api/device/modelOfMatter'; |
... | ... | @@ -177,50 +172,45 @@ |
177 | 172 | const [registerModalTsl, { openModal: openModalTsl }] = useModal(); |
178 | 173 | const [registerModalSelect, { openModal: openModalSelect }] = useModal(); |
179 | 174 | |
180 | - const [registerTable, { reload, setProps }] = useTable({ | |
181 | - api: async (params: Record<'page' | 'pageSize', number>) => { | |
182 | - return await getModelList({ | |
183 | - ...params, | |
184 | - id: props.record.id, | |
185 | - selectType: props.record.ifShowClass ? 'category' : undefined, | |
186 | - }); | |
187 | - }, | |
188 | - columns: props.record.ifShowClass | |
189 | - ? physicalColumn.filter((item) => item.dataIndex !== 'status') | |
190 | - : physicalColumn, | |
191 | - showIndexColumn: false, | |
192 | - clickToRowSelect: false, | |
193 | - showTableSetting: true, | |
194 | - bordered: true, | |
195 | - useSearchForm: true, | |
196 | - formConfig: { | |
197 | - schemas: modelOfMatterForm, | |
198 | - labelWidth: 120, | |
199 | - }, | |
200 | - actionColumn: { | |
201 | - width: 200, | |
202 | - title: '操作', | |
203 | - dataIndex: 'action', | |
204 | - slots: { customRender: 'action' }, | |
205 | - fixed: 'right', | |
206 | - }, | |
207 | - }); | |
208 | - | |
209 | - // 刷新 | |
210 | - const handleSuccess = () => { | |
211 | - reload(); | |
212 | - }; | |
213 | - const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | |
214 | - props.record.ifShowClass && (unref(isPlatformAdmin) || unref(isSysadmin)) | |
215 | - ? deleteModelCategory | |
216 | - : deleteModel, | |
217 | - handleSuccess, | |
218 | - setProps | |
219 | - ); | |
175 | + const [registerTable, { reload, getSelectRowKeys, getRowSelection, clearSelectedRowKeys }] = | |
176 | + useTable({ | |
177 | + api: async (params: Record<'page' | 'pageSize', number>) => { | |
178 | + return await getModelList({ | |
179 | + ...params, | |
180 | + id: props.record.id, | |
181 | + selectType: props.record.ifShowClass ? 'category' : undefined, | |
182 | + }); | |
183 | + }, | |
184 | + columns: props.record.ifShowClass | |
185 | + ? physicalColumn.filter((item) => item.dataIndex !== 'status') | |
186 | + : physicalColumn, | |
187 | + showIndexColumn: false, | |
188 | + clickToRowSelect: false, | |
189 | + showTableSetting: true, | |
190 | + bordered: true, | |
191 | + useSearchForm: true, | |
192 | + rowKey: 'id', | |
193 | + formConfig: { | |
194 | + schemas: modelOfMatterForm, | |
195 | + labelWidth: 120, | |
196 | + }, | |
197 | + actionColumn: { | |
198 | + width: 200, | |
199 | + title: '操作', | |
200 | + dataIndex: 'action', | |
201 | + slots: { customRender: 'action' }, | |
202 | + fixed: 'right', | |
203 | + }, | |
204 | + rowSelection: { | |
205 | + getCheckboxProps: (record: ModelOfMatterItemRecordType) => { | |
206 | + return { | |
207 | + disabled: record.status === 1, | |
208 | + }; | |
209 | + }, | |
210 | + }, | |
211 | + }); | |
220 | 212 | |
221 | - selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | |
222 | - return { disabled: record.status === 1 }; | |
223 | - }; | |
213 | + const getHasBatchDelete = computed(() => !getRowSelection().selectedRowKeys?.length); | |
224 | 214 | |
225 | 215 | const handleViewDetail = (record: ModelOfMatterParams) => { |
226 | 216 | if (record) { |
... | ... | @@ -245,6 +235,19 @@ |
245 | 235 | } |
246 | 236 | }; |
247 | 237 | |
238 | + const handleDeleteOrBatchDelete = async (record?: ModelOfMatterItemRecordType) => { | |
239 | + const deleteFn = | |
240 | + props.record.ifShowClass && (unref(isPlatformAdmin) || unref(isSysadmin)) | |
241 | + ? deleteModelCategory | |
242 | + : deleteModel; | |
243 | + | |
244 | + const ids = record ? [record.id] : getSelectRowKeys(); | |
245 | + await deleteFn(ids); | |
246 | + createMessage.success('删除成功'); | |
247 | + clearSelectedRowKeys(); | |
248 | + reload(); | |
249 | + }; | |
250 | + | |
248 | 251 | const handleOpenTsl = () => { |
249 | 252 | openModalTsl(true, { |
250 | 253 | isUpdate: true, | ... | ... |
... | ... | @@ -30,9 +30,7 @@ |
30 | 30 | import { SelectTypes } from 'ant-design-vue/es/select'; |
31 | 31 | |
32 | 32 | const emit = defineEmits(['register', 'emitSelect']); |
33 | - const [register] = useModalInner((data) => { | |
34 | - console.log(data); | |
35 | - }); | |
33 | + const [register] = useModalInner(() => {}); | |
36 | 34 | const heightNum = ref(80); |
37 | 35 | const visible = ref(false); |
38 | 36 | const selectValue = ref('LwM2M'); | ... | ... |
... | ... | @@ -130,14 +130,13 @@ |
130 | 130 | telemetry: [], |
131 | 131 | }); |
132 | 132 | |
133 | - const [registerModel, { resetFields: resetObjectListValue, getFieldsValue: getObjectListValue }] = | |
134 | - useForm({ | |
135 | - labelWidth: 100, | |
136 | - schemas: modelSchemas, | |
137 | - actionColOptions: { | |
138 | - span: 14, | |
139 | - }, | |
140 | - }); | |
133 | + const [registerModel, { resetFields: resetObjectListValue }] = useForm({ | |
134 | + labelWidth: 100, | |
135 | + schemas: modelSchemas, | |
136 | + actionColOptions: { | |
137 | + span: 14, | |
138 | + }, | |
139 | + }); | |
141 | 140 | const [ |
142 | 141 | registerSettings, |
143 | 142 | { |
... | ... | @@ -152,14 +151,13 @@ |
152 | 151 | span: 14, |
153 | 152 | }, |
154 | 153 | }); |
155 | - const [registerDevice, { resetFields: resetDeviceValue, getFieldsValue: getDeviceValue }] = | |
156 | - useForm({ | |
157 | - labelWidth: 100, | |
158 | - schemas: deviceSchemas, | |
159 | - actionColOptions: { | |
160 | - span: 14, | |
161 | - }, | |
162 | - }); | |
154 | + const [registerDevice, { resetFields: resetDeviceValue }] = useForm({ | |
155 | + labelWidth: 100, | |
156 | + schemas: deviceSchemas, | |
157 | + actionColOptions: { | |
158 | + span: 14, | |
159 | + }, | |
160 | + }); | |
163 | 161 | const [registerModal, { openModal }] = useModal(); |
164 | 162 | |
165 | 163 | const handleAdd = () => { |
... | ... | @@ -205,10 +203,6 @@ |
205 | 203 | }; |
206 | 204 | |
207 | 205 | const getFormData = async () => { |
208 | - const objectListVal = getObjectListValue(); | |
209 | - const deviceVal = getDeviceValue(); | |
210 | - console.log('第一个tab', objectListVal); | |
211 | - console.log('第四个tab', deviceVal); | |
212 | 206 | getBootStrapFormValue(); |
213 | 207 | const settingsVal = await settingsValidate(); |
214 | 208 | if (!settingsVal) return; | ... | ... |
... | ... | @@ -172,8 +172,7 @@ export const formSchema: FormSchema[] = [ |
172 | 172 | const record = await findMessageConfig(params); |
173 | 173 | return record.filter((item) => item.status === 1); |
174 | 174 | } catch (error) { |
175 | - // eslint-disable-next-line no-console | |
176 | - console.log(error); | |
175 | + console.error(error); | |
177 | 176 | return []; |
178 | 177 | } |
179 | 178 | }, | ... | ... |
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | border-color: #6b7280; |
7 | 7 | } |
8 | 8 | |
9 | -.vue-flow__handle:hover{ | |
9 | +.vue-flow__handle:hover { | |
10 | 10 | background-color: #000; |
11 | 11 | } |
12 | 12 | |
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 | } |
16 | 16 | |
17 | 17 | .vue-flow__handle-left { |
18 | - left: -12px; | |
18 | + left: -12px; | |
19 | 19 | } |
20 | 20 | |
21 | 21 | .vue-flow__background.vue-flow__container { |
... | ... | @@ -32,7 +32,7 @@ |
32 | 32 | stroke-width: 4; |
33 | 33 | stroke: gray; |
34 | 34 | transition: stroke-width 0.3s; |
35 | -} | |
35 | +} | |
36 | 36 | |
37 | 37 | .connection-focus { |
38 | 38 | stroke-width: 6; |
... | ... | @@ -44,7 +44,7 @@ |
44 | 44 | } |
45 | 45 | |
46 | 46 | /* 连接线移入放大效果 */ |
47 | -.vue-flow__edge:hover > .vue-flow__edge-path { | |
47 | +.vue-flow__edge:hover > .vue-flow__edge-path { | |
48 | 48 | stroke-width: 6 !important; |
49 | 49 | } |
50 | 50 | |
... | ... | @@ -54,18 +54,19 @@ |
54 | 54 | } |
55 | 55 | |
56 | 56 | .vue-flow__edge:hover .vue-flow__edge-textbg { |
57 | - transform: scale(1.1) | |
57 | + transform: scale(1.1); | |
58 | 58 | } |
59 | 59 | |
60 | -.vue-flow__edge:hover .vue-flow__edge-text{ | |
61 | - transform: scale(1.1) | |
60 | +.vue-flow__edge:hover .vue-flow__edge-text { | |
61 | + transform: scale(1.1); | |
62 | 62 | } |
63 | 63 | |
64 | 64 | /* selection 选择框 */ |
65 | -.vue-flow__nodesselection-rect, .vue-flow__selection{ | |
65 | +.vue-flow__nodesselection-rect, | |
66 | +.vue-flow__selection { | |
66 | 67 | border-width: 3px; |
67 | 68 | } |
68 | 69 | |
69 | -.vue-flow__nodesselection-rect { | |
70 | +.vue-flow__nodesselection-rect { | |
70 | 71 | pointer-events: none; |
71 | 72 | } | ... | ... |
... | ... | @@ -85,9 +85,7 @@ |
85 | 85 | /^[1](([3][0-9])|([4][0,1,4-9])|([5][0-3,5-9])|([6][2,5,6,7])|([7][0-8])|([8][0-9])|([9][0-3,5-9]))[0-9]{8}$/; |
86 | 86 | if (reg.test(formData.mobile)) { |
87 | 87 | const sendRes = await passwordResetCode(formData.mobile); |
88 | - console.log(sendRes); | |
89 | 88 | if (sendRes === '') { |
90 | - console.log('发送成功了'); | |
91 | 89 | return true; |
92 | 90 | } |
93 | 91 | return false; | ... | ... |
... | ... | @@ -69,8 +69,8 @@ export function useFormRules(formData?: Recordable) { |
69 | 69 | const mobileFormRule = unref(getMobileFormRule); |
70 | 70 | |
71 | 71 | const mobileRule = { |
72 | - sms: smsFormRule, | |
73 | - mobile: mobileFormRule, | |
72 | + code: smsFormRule, | |
73 | + phoneNumber: mobileFormRule, | |
74 | 74 | }; |
75 | 75 | switch (unref(currentState)) { |
76 | 76 | // register form rules | ... | ... |
... | ... | @@ -34,14 +34,6 @@ |
34 | 34 | const { unit, fontColor, showDeviceName } = item.componentInfo || {}; |
35 | 35 | const { deviceName, deviceRename, attribute, attributeRename, deviceId, attributeName } = |
36 | 36 | item; |
37 | - // return { | |
38 | - // unit: unit ?? persetUnit, | |
39 | - // fontColor: fontColor ?? persetFontColor, | |
40 | - // showDeviceName: showDeviceName ?? persetShowDeviceName, | |
41 | - // attribute, | |
42 | - // deviceName, | |
43 | - // deviceRename, | |
44 | - // }; | |
45 | 37 | return { |
46 | 38 | unit: unit ?? presetUnit, |
47 | 39 | fontColor: fontColor ?? presetFontColor, |
... | ... | @@ -58,7 +50,6 @@ |
58 | 50 | }); |
59 | 51 | |
60 | 52 | const getOffset = (length: number, index: number) => { |
61 | - // try { | |
62 | 53 | const offsetList = ref<any>([]); |
63 | 54 | switch (length) { |
64 | 55 | case 1: |
... | ... | @@ -147,7 +138,6 @@ |
147 | 138 | break; |
148 | 139 | } |
149 | 140 | return unref(offsetList); |
150 | - // } catch {} | |
151 | 141 | }; |
152 | 142 | |
153 | 143 | const series = ref( |
... | ... | @@ -263,7 +253,6 @@ |
263 | 253 | series.value.forEach((item) => { |
264 | 254 | if (item.id === deviceId && item.attribute === attribute && value) { |
265 | 255 | item.value = getNumberValue(value); |
266 | - // time.value = timespan; | |
267 | 256 | } |
268 | 257 | }); |
269 | 258 | }); | ... | ... |
... | ... | @@ -62,7 +62,6 @@ |
62 | 62 | const options = (): EChartsOption => { |
63 | 63 | const { unit, fontColor, pointerColor, maxNumber, valueSize } = unref(getDesign); |
64 | 64 | |
65 | - // getStageColor(gradientInfo); | |
66 | 65 | return { |
67 | 66 | series: [ |
68 | 67 | { |
... | ... | @@ -103,14 +102,6 @@ |
103 | 102 | color: pointerColor, |
104 | 103 | }, |
105 | 104 | }, |
106 | - // anchor: { | |
107 | - // show: true, | |
108 | - // showAbove: true, | |
109 | - // size: 10, | |
110 | - // itemStyle: { | |
111 | - // borderWidth: 4, | |
112 | - // }, | |
113 | - // }, | |
114 | 105 | title: { |
115 | 106 | show: false, |
116 | 107 | }, | ... | ... |
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
4 | 4 | import { formSchema, getHistorySearchParams, SchemaFiled } from './history.config'; |
5 | 5 | import { HistoryModalOkEmitParams } from './type'; |
6 | - import { ref } from 'vue'; | |
6 | + import { ref, unref } from 'vue'; | |
7 | 7 | import { getAllDeviceByOrg } from '/@/api/dataBoard'; |
8 | 8 | import { getDeviceHistoryInfo } from '/@/api/alarm/position'; |
9 | 9 | import { DataSource } from '/@/views/visual/palette/types'; |
... | ... | @@ -19,58 +19,154 @@ |
19 | 19 | ], |
20 | 20 | }); |
21 | 21 | |
22 | - const [registerModal, { closeModal }] = useModalInner(async (dataSource: DataSource[]) => { | |
23 | - try { | |
24 | - dataSource = cloneDeep(dataSource); | |
25 | - if (dataSource.length < 2) return; | |
26 | - dataSource = dataSource.splice(0, 2); | |
27 | - const deviceRecord = dataSource?.at(0) || ({} as DataSource); | |
28 | - if (!deviceRecord.organizationId) return; | |
29 | - const deviceList = await getAllDeviceByOrg( | |
30 | - deviceRecord.organizationId, | |
31 | - deviceRecord.deviceProfileId | |
32 | - ); | |
33 | - const options = deviceList | |
34 | - .filter((item) => item.tbDeviceId === deviceRecord.deviceId) | |
35 | - .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId })); | |
36 | - | |
37 | - const attKey = dataSource.map((item) => ({ | |
38 | - ...item, | |
39 | - label: item.attribute, | |
40 | - value: item.attribute, | |
41 | - })); | |
42 | - updateSchema([ | |
43 | - { | |
44 | - field: SchemaFiled.DEVICE_ID, | |
45 | - componentProps: { | |
46 | - options, | |
47 | - }, | |
22 | + const loading = ref(false); | |
23 | + const getDesign = ref(); | |
24 | + | |
25 | + const getTwoMap = async (dataSource) => { | |
26 | + if (dataSource.length < 2) return; | |
27 | + dataSource = dataSource.splice(0, 2); | |
28 | + const deviceRecord = dataSource?.at(0) || ({} as DataSource); | |
29 | + | |
30 | + if (!deviceRecord.organizationId) return; | |
31 | + const deviceList = await getAllDeviceByOrg( | |
32 | + deviceRecord.organizationId, | |
33 | + deviceRecord.deviceProfileId | |
34 | + ); | |
35 | + const options = deviceList | |
36 | + .filter((item) => item.tbDeviceId === deviceRecord.deviceId) | |
37 | + .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId })); | |
38 | + | |
39 | + const attKey = dataSource.map((item) => ({ | |
40 | + ...item, | |
41 | + label: item.attribute, | |
42 | + value: item.attribute, | |
43 | + })); | |
44 | + | |
45 | + updateSchemaMap(options, attKey, deviceRecord); | |
46 | + }; | |
47 | + | |
48 | + const getOneMap = async (dataSource) => { | |
49 | + const deviceRecord = dataSource?.[0]; | |
50 | + if (!deviceRecord.organizationId) return; | |
51 | + const deviceList = await getAllDeviceByOrg( | |
52 | + deviceRecord.organizationId, | |
53 | + deviceRecord.deviceProfileId | |
54 | + ); | |
55 | + const options = deviceList | |
56 | + .filter((item) => item.tbDeviceId === deviceRecord.deviceId) | |
57 | + .map((item) => ({ ...item, label: item.alias || item.name, value: item.tbDeviceId })); | |
58 | + | |
59 | + const attKey = dataSource?.map((item) => ({ | |
60 | + ...item, | |
61 | + label: item.attributeName, | |
62 | + value: item.attribute, | |
63 | + })); | |
64 | + updateSchemaMap(options, attKey, deviceRecord); | |
65 | + }; | |
66 | + | |
67 | + const updateSchemaMap = (options, attKey, deviceRecord) => { | |
68 | + updateSchema([ | |
69 | + { | |
70 | + field: SchemaFiled.DEVICE_ID, | |
71 | + componentProps: { | |
72 | + options, | |
48 | 73 | }, |
49 | - { | |
50 | - field: SchemaFiled.KEYS, | |
51 | - component: 'Select', | |
52 | - defaultValue: attKey.map((item) => item.value), | |
53 | - componentProps: { | |
54 | - options: attKey, | |
55 | - mode: 'multiple', | |
56 | - disabled: true, | |
57 | - }, | |
74 | + }, | |
75 | + { | |
76 | + field: SchemaFiled.KEYS, | |
77 | + component: 'Select', | |
78 | + defaultValue: attKey.map((item) => item.value), | |
79 | + componentProps: { | |
80 | + options: attKey, | |
81 | + mode: 'multiple', | |
82 | + disabled: true, | |
58 | 83 | }, |
59 | - ]); | |
84 | + }, | |
85 | + ]); | |
60 | 86 | |
61 | - setFieldsValue({ | |
62 | - [SchemaFiled.DEVICE_ID]: deviceRecord.deviceId, | |
63 | - [SchemaFiled.KEYS]: attKey.map((item) => item.value), | |
64 | - }); | |
87 | + setFieldsValue({ | |
88 | + [SchemaFiled.DEVICE_ID]: deviceRecord.deviceId, | |
89 | + [SchemaFiled.KEYS]: attKey.map((item) => item.value), | |
90 | + }); | |
91 | + }; | |
92 | + | |
93 | + const [registerModal, { closeModal }] = useModalInner(async (dataSource: DataSource[]) => { | |
94 | + try { | |
95 | + getDesign.value = dataSource; | |
96 | + dataSource = cloneDeep(dataSource); | |
97 | + //判断选择是不是结构体 | |
98 | + if (dataSource.length == 1 && dataSource?.[0]?.lal) { | |
99 | + getOneMap(dataSource); | |
100 | + return; | |
101 | + } | |
102 | + getTwoMap(dataSource); | |
65 | 103 | } catch (error) { |
66 | 104 | throw error; |
67 | 105 | } |
68 | 106 | }); |
69 | 107 | |
108 | + const getMultipleDataSource = async (res) => { | |
109 | + let timespanList = Object.keys(res).reduce((prev, next) => { | |
110 | + const ts = res[next].map((item) => item.ts); | |
111 | + return [...prev, ...ts]; | |
112 | + }, [] as number[]); | |
113 | + timespanList = [...new Set(timespanList)]; | |
114 | + | |
115 | + const track: Record<'lng' | 'lat', number>[] = []; | |
116 | + const keys = Object.keys(res); | |
117 | + | |
118 | + for (const ts of timespanList) { | |
119 | + const list: { ts: number; value: number }[] = []; | |
120 | + for (const key of keys) { | |
121 | + const record = res[key].find((item) => ts === item.ts); | |
122 | + if (!validEffective(record?.value)) { | |
123 | + continue; | |
124 | + } | |
125 | + list.push(record as any); | |
126 | + } | |
127 | + | |
128 | + if (list.length === 2 && list.every(Boolean)) { | |
129 | + const lng = list.at(0)?.value; | |
130 | + const lat = list.at(1)?.value; | |
131 | + if (lng && lat) track.push({ lng, lat }); | |
132 | + } | |
133 | + } | |
134 | + return track; | |
135 | + }; | |
136 | + | |
137 | + // 单数据源选择结构体 | |
138 | + const getSingleDataSource = async (res) => { | |
139 | + const [keys] = Object.keys(res); | |
140 | + const track: Record<'lng' | 'lat', number>[] = []; | |
141 | + const dataSource = res[keys]?.map((item) => { | |
142 | + return { | |
143 | + value: item.value ? JSON.parse(item.value) : {}, | |
144 | + }; | |
145 | + }); | |
146 | + const list: { value: number }[] = []; | |
147 | + dataSource?.forEach((item) => { | |
148 | + if ( | |
149 | + //判断结构体得值是不是数字 | |
150 | + Object.values(item.value).every((item1) => { | |
151 | + return validEffective(item1 as any); | |
152 | + }) | |
153 | + ) { | |
154 | + list.push(item.value); | |
155 | + } | |
156 | + }); | |
157 | + const { latitude, longitude } = unref(getDesign)?.[0]; //获取选择的经纬度选项 | |
158 | + | |
159 | + list.forEach((item) => { | |
160 | + const lng = item[longitude]; | |
161 | + const lat = item[latitude]; | |
162 | + if (lng && lat) track.push({ lng, lat }); | |
163 | + }); | |
164 | + return track; | |
165 | + }; | |
166 | + | |
70 | 167 | const validEffective = (value = '') => { |
71 | 168 | return !!(value && !isNaN(value as unknown as number)); |
72 | 169 | }; |
73 | - const loading = ref(false); | |
74 | 170 | const handleOk = async () => { |
75 | 171 | try { |
76 | 172 | await validate(); |
... | ... | @@ -84,33 +180,9 @@ |
84 | 180 | ...value, |
85 | 181 | [SchemaFiled.KEYS]: value[SchemaFiled.KEYS].join(','), |
86 | 182 | }); |
183 | + const ifSingle = unref(getDesign)?.length === 1 && unref(getDesign)?.[0]?.lal; | |
87 | 184 | |
88 | - let timespanList = Object.keys(res).reduce((prev, next) => { | |
89 | - const ts = res[next].map((item) => item.ts); | |
90 | - return [...prev, ...ts]; | |
91 | - }, [] as number[]); | |
92 | - timespanList = [...new Set(timespanList)]; | |
93 | - | |
94 | - const track: Record<'lng' | 'lat', number>[] = []; | |
95 | - const keys = Object.keys(res); | |
96 | - | |
97 | - for (const ts of timespanList) { | |
98 | - const list: { ts: number; value: number }[] = []; | |
99 | - for (const key of keys) { | |
100 | - const record = res[key].find((item) => ts === item.ts); | |
101 | - if (!validEffective(record?.value)) { | |
102 | - continue; | |
103 | - } | |
104 | - list.push(record as any); | |
105 | - } | |
106 | - | |
107 | - if (list.length === 2 && list.every(Boolean)) { | |
108 | - const lng = list.at(0)?.value; | |
109 | - const lat = list.at(1)?.value; | |
110 | - if (lng && lat) track.push({ lng, lat }); | |
111 | - } | |
112 | - } | |
113 | - | |
185 | + const track = ifSingle ? await getSingleDataSource(res) : await getMultipleDataSource(res); | |
114 | 186 | emit('ok', { track, value } as HistoryModalOkEmitParams); |
115 | 187 | closeModal(); |
116 | 188 | } catch (error) { | ... | ... |
... | ... | @@ -24,6 +24,14 @@ |
24 | 24 | return props.config.option.dataSource?.at(0)?.deviceId; |
25 | 25 | }); |
26 | 26 | |
27 | + const getDesign = computed(() => { | |
28 | + const { option } = props.config; | |
29 | + const { dataSource } = option || {}; | |
30 | + return { | |
31 | + dataSource: dataSource, | |
32 | + }; | |
33 | + }); | |
34 | + | |
27 | 35 | /** |
28 | 36 | * @description 经度key |
29 | 37 | */ |
... | ... | @@ -42,7 +50,7 @@ |
42 | 50 | return !!(value && !isNaN(value as unknown as number)); |
43 | 51 | }; |
44 | 52 | |
45 | - const updateFn: MultipleDataFetchUpdateFn = (message, deviceId) => { | |
53 | + const getTwoMap = (message, deviceId) => { | |
46 | 54 | if (unref(getDeviceId) !== deviceId) return; |
47 | 55 | |
48 | 56 | const { data = {} } = message; |
... | ... | @@ -51,7 +59,7 @@ |
51 | 59 | |
52 | 60 | const lngData = bindMessage[unref(getLngKey)] || []; |
53 | 61 | const [lngLatest] = lngData; |
54 | - const [, lng] = lngLatest; | |
62 | + const [, lng] = lngLatest || []; | |
55 | 63 | |
56 | 64 | const latData = bindMessage[unref(getLatKey)] || []; |
57 | 65 | const [latLatest] = latData; |
... | ... | @@ -62,6 +70,34 @@ |
62 | 70 | } |
63 | 71 | }; |
64 | 72 | |
73 | + const getOneMap = (message, deviceId) => { | |
74 | + if (unref(getDeviceId) !== deviceId) return; | |
75 | + | |
76 | + const { longitude, latitude, attribute } = unref(getDesign)?.dataSource?.[0] || {}; | |
77 | + const { data } = message || {}; | |
78 | + const bindMessage = data[deviceId]; | |
79 | + const [, values] = attribute && bindMessage?.[attribute][0]; | |
80 | + | |
81 | + const mapValues = values ? JSON.parse(values) : {}; | |
82 | + const lng = longitude && mapValues[longitude]; | |
83 | + const lat = latitude && mapValues[latitude]; | |
84 | + | |
85 | + if (validEffective(lng) && validEffective(lat)) { | |
86 | + drawLine({ lng: Number(lng), lat: Number(lat) }); | |
87 | + } | |
88 | + }; | |
89 | + | |
90 | + const updateFn: MultipleDataFetchUpdateFn = (message, deviceId) => { | |
91 | + const { lal } = unref(getDesign)?.dataSource?.[0] || {}; | |
92 | + // 属性选择结构体类型时 | |
93 | + if (lal && unref(getDesign)?.dataSource?.length == 1) { | |
94 | + getOneMap(message, deviceId); | |
95 | + return; | |
96 | + } | |
97 | + // 选择两个属性时 | |
98 | + getTwoMap(message, deviceId); | |
99 | + }; | |
100 | + | |
65 | 101 | useMultipleDataFetch(props, updateFn); |
66 | 102 | |
67 | 103 | const { drawLine } = useMapTrackPlayBack(mapInstance); |
... | ... | @@ -100,11 +136,3 @@ |
100 | 136 | <div v-show="!loading" ref="wrapRef" :id="wrapId" class="w-full h-full no-drag"> </div> |
101 | 137 | </main> |
102 | 138 | </template> |
103 | - | |
104 | -<style lang="less" scoped> | |
105 | - // .map-spin-wrapper { | |
106 | - // :deep(.ant-spin-container) { | |
107 | - // @apply justify-center items-center p-2 w-full h-full; | |
108 | - // } | |
109 | - // } | |
110 | -</style> | ... | ... |
... | ... | @@ -247,7 +247,6 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
247 | 247 | }); |
248 | 248 | }, |
249 | 249 | placeholder: '请选择设备', |
250 | - getPopupContainer: () => document.body, | |
251 | 250 | ...createPickerSearch(), |
252 | 251 | }; |
253 | 252 | }, |
... | ... | @@ -382,11 +381,18 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
382 | 381 | return []; |
383 | 382 | }, |
384 | 383 | placeholder: '请选择属性', |
385 | - getPopupContainer: () => document.body, | |
386 | 384 | onChange(value: string, option: Record<'label' | 'value' | any, string>) { |
385 | + const { detail }: any = option || {}; | |
387 | 386 | setFieldsValue({ |
388 | 387 | [DataSourceField.ATTRIBUTE_NAME]: value ? option.label : null, |
389 | 388 | [DataSourceField.EXTENSION_DESC]: value ? JSON.stringify(option.extensionDesc) : '', |
389 | + // 地图组件结构体 | |
390 | + lal: | |
391 | + category === 'MAP' && value && detail?.dataType.type === 'STRUCT' | |
392 | + ? JSON.stringify(detail?.dataType.specs) | |
393 | + : null, | |
394 | + latitude: null, | |
395 | + longitude: null, | |
390 | 396 | }); |
391 | 397 | }, |
392 | 398 | ...createPickerSearch(), |
... | ... | @@ -394,6 +400,46 @@ export const commonDataSourceSchemas = (): FormSchema[] => { |
394 | 400 | }, |
395 | 401 | }, |
396 | 402 | { |
403 | + field: 'lal', | |
404 | + label: '经纬度存储的值', | |
405 | + component: 'Input', | |
406 | + show: false, | |
407 | + }, | |
408 | + { | |
409 | + field: 'longitude', | |
410 | + label: '经度', | |
411 | + colProps: { span: 8 }, | |
412 | + component: 'Select', | |
413 | + required: true, | |
414 | + ifShow: ({ model }) => category === 'MAP' && model.lal, | |
415 | + componentProps({ formModel }) { | |
416 | + const { lal } = formModel || {}; | |
417 | + return { | |
418 | + placeholder: '请选择经度', | |
419 | + options: lal | |
420 | + ? JSON.parse(lal)?.map((item) => ({ label: item.functionName, value: item.identifier })) | |
421 | + : [], | |
422 | + }; | |
423 | + }, | |
424 | + }, | |
425 | + { | |
426 | + field: 'latitude', | |
427 | + label: '纬度', | |
428 | + colProps: { span: 8 }, | |
429 | + required: true, | |
430 | + component: 'Select', | |
431 | + ifShow: ({ model }) => category === 'MAP' && model.lal, | |
432 | + componentProps({ formModel }) { | |
433 | + const { lal } = formModel || {}; | |
434 | + return { | |
435 | + placeholder: '请选择纬度', | |
436 | + options: lal | |
437 | + ? JSON.parse(lal)?.map((item) => ({ label: item.functionName, value: item.identifier })) | |
438 | + : [], | |
439 | + }; | |
440 | + }, | |
441 | + }, | |
442 | + { | |
397 | 443 | field: DataSourceField.EXTENSION_DESC, |
398 | 444 | component: 'Input', |
399 | 445 | show: false, | ... | ... |
src/views/visual/packages/template/config.ts
deleted
100644 → 0
1 | -import cloneDeep from 'lodash-es/cloneDeep'; | |
2 | -import { ComponentConfig } from '.'; | |
3 | -import { | |
4 | - ConfigType, | |
5 | - CreateComponentType, | |
6 | - PublicComponentOptions, | |
7 | - PublicPresetOptions, | |
8 | -} from '/@/views/visual/packages/index.type'; | |
9 | -import { PublicConfigClass, componentInitConfig } from '/@/views/visual/packages/publicConfig'; | |
10 | -import { ComponentConfigFieldEnum } from '/@/views/visual/packages/enum'; | |
11 | - | |
12 | -export const option: PublicPresetOptions = { | |
13 | - [ComponentConfigFieldEnum.FONT_COLOR]: '#', | |
14 | - [ComponentConfigFieldEnum.SHOW_DEVICE_NAME]: false, | |
15 | -}; | |
16 | - | |
17 | -export default class Config extends PublicConfigClass implements CreateComponentType { | |
18 | - public key: string = ComponentConfig.key; | |
19 | - | |
20 | - public attr = { ...componentInitConfig }; | |
21 | - | |
22 | - public componentConfig: ConfigType = cloneDeep(ComponentConfig); | |
23 | - | |
24 | - public persetOption = cloneDeep(option); | |
25 | - | |
26 | - public option: PublicComponentOptions; | |
27 | - | |
28 | - constructor(option: PublicComponentOptions) { | |
29 | - super(); | |
30 | - this.option = { ...option }; | |
31 | - } | |
32 | -} |
src/views/visual/packages/template/config.vue
deleted
100644 → 0
1 | -<script lang="ts" setup> | |
2 | - import { ComponentConfigFieldEnum } from '/@/views/visual/packages/enum'; | |
3 | - import { useForm, BasicForm } from '/@/components/Form'; | |
4 | - import { PublicFormInstaceType } from '/@/views/visual/dataSourceBindPanel/index.type'; | |
5 | - | |
6 | - const [register, { getFieldsValue, setFieldsValue, resetFields }] = useForm({ | |
7 | - schemas: [ | |
8 | - { | |
9 | - field: ComponentConfigFieldEnum.FONT_COLOR, | |
10 | - label: '数值字体颜色', | |
11 | - component: 'ColorPicker', | |
12 | - changeEvent: 'update:value', | |
13 | - componentProps: { | |
14 | - defaultValue: '#FD7347', | |
15 | - }, | |
16 | - }, | |
17 | - { | |
18 | - field: ComponentConfigFieldEnum.SHOW_DEVICE_NAME, | |
19 | - label: '显示设备名称', | |
20 | - component: 'Checkbox', | |
21 | - }, | |
22 | - ], | |
23 | - showActionButtonGroup: false, | |
24 | - labelWidth: 120, | |
25 | - baseColProps: { | |
26 | - span: 12, | |
27 | - }, | |
28 | - }); | |
29 | - | |
30 | - const getFormValues = () => { | |
31 | - return getFieldsValue(); | |
32 | - }; | |
33 | - | |
34 | - const setFormValues = (data: Recordable) => { | |
35 | - return setFieldsValue(data); | |
36 | - }; | |
37 | - | |
38 | - defineExpose({ | |
39 | - getFormValues, | |
40 | - setFormValues, | |
41 | - resetFormValues: resetFields, | |
42 | - } as PublicFormInstaceType); | |
43 | -</script> | |
44 | - | |
45 | -<template> | |
46 | - <BasicForm @register="register" /> | |
47 | -</template> |
src/views/visual/packages/template/datasource.vue
deleted
100644 → 0
1 | -<script lang="ts" setup> | |
2 | - import { CreateComponentType } from '/@/views/visual/packages/index.type'; | |
3 | - import { BasicForm, useForm } from '/@/components/Form'; | |
4 | - import { | |
5 | - PublicComponentValueType, | |
6 | - PublicFormInstaceType, | |
7 | - } from '/@/views/visual/dataSourceBindPanel/index.type'; | |
8 | - import { commonDataSourceSchemas } from '../config/common.config'; | |
9 | - | |
10 | - defineProps<{ | |
11 | - values: PublicComponentValueType; | |
12 | - componentConfig: CreateComponentType; | |
13 | - }>(); | |
14 | - | |
15 | - const [register, { getFieldsValue, setFieldsValue, validate, resetFields }] = useForm({ | |
16 | - labelWidth: 0, | |
17 | - showActionButtonGroup: false, | |
18 | - layout: 'horizontal', | |
19 | - labelCol: { span: 0 }, | |
20 | - schemas: commonDataSourceSchemas(), | |
21 | - }); | |
22 | - | |
23 | - const getFormValues = () => { | |
24 | - return getFieldsValue(); | |
25 | - }; | |
26 | - | |
27 | - const setFormValues = (record: Recordable) => { | |
28 | - return setFieldsValue(record); | |
29 | - }; | |
30 | - | |
31 | - defineExpose({ | |
32 | - getFormValues, | |
33 | - setFormValues, | |
34 | - validate, | |
35 | - resetFormValues: resetFields, | |
36 | - } as PublicFormInstaceType); | |
37 | -</script> | |
38 | - | |
39 | -<template> | |
40 | - <BasicForm @register="register" /> | |
41 | -</template> |
src/views/visual/packages/template/index.ts
deleted
100644 → 0
1 | -import { useComponentKeys } from '/@/views/visual/packages/hook/useComponentKeys'; | |
2 | -import { ConfigType, PackagesCategoryEnum } from '/@/views/visual/packages/index.type'; | |
3 | - | |
4 | -const componentKeys = useComponentKeys('componentKeys'); | |
5 | - | |
6 | -export const ComponentConfig: ConfigType = { | |
7 | - ...componentKeys, | |
8 | - title: '组件名', | |
9 | - package: PackagesCategoryEnum.TEXT, | |
10 | -}; |
src/views/visual/packages/template/index.vue
deleted
100644 → 0
1 | -<script lang="ts" setup> | |
2 | - import { ComponentPropsConfigType } from '/@/views/visual/packages/index.type'; | |
3 | - import { option } from './config'; | |
4 | - import { useDataFetch } from '../hook/socket/useSocket'; | |
5 | - import { DataFetchUpdateFn } from '../hook/socket/useSocket.type'; | |
6 | - | |
7 | - const props = defineProps<{ | |
8 | - config: ComponentPropsConfigType<typeof option>; | |
9 | - }>(); | |
10 | - | |
11 | - const updateFn: DataFetchUpdateFn = (_message) => {}; | |
12 | - | |
13 | - useDataFetch(props, updateFn); | |
14 | -</script> | |
15 | - | |
16 | -<template> | |
17 | - <main class="w-full h-full flex flex-col justify-center items-center"> </main> | |
18 | -</template> |
... | ... | @@ -150,7 +150,6 @@ |
150 | 150 | getIsSharePage, |
151 | 151 | (value) => { |
152 | 152 | if (value) { |
153 | - console.log(unref(getDarkMode)); | |
154 | 153 | const root = document.querySelector('#app'); |
155 | 154 | (root as HTMLDivElement).style.backgroundColor = |
156 | 155 | unref(getDarkMode) === ThemeEnum.LIGHT ? '#F5F5F5' : '#1b1b1b'; | ... | ... |
... | ... | @@ -29,6 +29,9 @@ export interface DataSource { |
29 | 29 | customCommand: CustomCommand; |
30 | 30 | videoConfig?: VideoConfigType; |
31 | 31 | [key: string]: any; |
32 | + lal?: string; | |
33 | + latitude?: string | number; | |
34 | + longitude?: string | number; | |
32 | 35 | } |
33 | 36 | |
34 | 37 | export interface ExtraDataSource extends DataSource, PublicComponentOptions { | ... | ... |
... | ... | @@ -32,7 +32,6 @@ app.ws.use( |
32 | 32 | }); |
33 | 33 | ctx.websocket.send(data); |
34 | 34 | } |
35 | - console.log(message); | |
36 | 35 | }); |
37 | 36 | }) |
38 | 37 | ); |
... | ... | @@ -59,5 +58,6 @@ app.use(router.allowedMethods()); |
59 | 58 | app.use(koaStatic(path.join(__dirname))); |
60 | 59 | |
61 | 60 | app.listen(PORT, () => { |
61 | + // eslint-disable-next-line no-console | |
62 | 62 | console.log(`Application started successfully: http://localhost:${PORT}`); |
63 | 63 | }); | ... | ... |