Commit 26f450d6f00403e3db08e3ff38942cd8e36b41c9
Merge branch 'ft_local_dev' into 'main'
feat:设备配置新增物模型静态页面 See merge request huang/yun-teng-iot-front!356
Showing
14 changed files
with
660 additions
and
93 deletions
@@ -11,12 +11,12 @@ import projectSetting from '/@/settings/projectSetting'; | @@ -11,12 +11,12 @@ import projectSetting from '/@/settings/projectSetting'; | ||
11 | import { PermissionModeEnum } from '/@/enums/appEnum'; | 11 | import { PermissionModeEnum } from '/@/enums/appEnum'; |
12 | import { asyncRoutes } from '/@/router/routes'; | 12 | import { asyncRoutes } from '/@/router/routes'; |
13 | import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; | 13 | import { ERROR_LOG_ROUTE, PAGE_NOT_FOUND_ROUTE } from '/@/router/routes/basic'; |
14 | -import { filter, forEach } from '/@/utils/helper/treeHelper'; | 14 | +import { filter } from '/@/utils/helper/treeHelper'; |
15 | import { getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; | 15 | import { getMenuList, getMenusIdsByRoleId } from '/@/api/sys/menu'; |
16 | import { getPermCode } from '/@/api/sys/user'; | 16 | import { getPermCode } from '/@/api/sys/user'; |
17 | import { useMessage } from '/@/hooks/web/useMessage'; | 17 | import { useMessage } from '/@/hooks/web/useMessage'; |
18 | import { PageEnum } from '/@/enums/pageEnum'; | 18 | import { PageEnum } from '/@/enums/pageEnum'; |
19 | -import { MENU_LIST, USER_INFO_KEY } from '/@/enums/cacheEnum'; | 19 | +import { USER_INFO_KEY } from '/@/enums/cacheEnum'; |
20 | import { getAuthCache, setAuthCache } from '/@/utils/auth'; | 20 | import { getAuthCache, setAuthCache } from '/@/utils/auth'; |
21 | import { createStorage } from '/@/utils/cache/index'; | 21 | import { createStorage } from '/@/utils/cache/index'; |
22 | 22 | ||
@@ -89,7 +89,8 @@ export const usePermissionStore = defineStore({ | @@ -89,7 +89,8 @@ export const usePermissionStore = defineStore({ | ||
89 | this.lastBuildMenuTime = 0; | 89 | this.lastBuildMenuTime = 0; |
90 | }, | 90 | }, |
91 | async changePermissionCode() { | 91 | async changePermissionCode() { |
92 | - const filterMenu = (allMenuList, menuIdsList) => { | 92 | + //判空处理,如果没有数据则为空,空数组.filter是不会报错的 |
93 | + const filterMenu = (allMenuList: Recordable[] = [], menuIdsList) => { | ||
93 | return allMenuList | 94 | return allMenuList |
94 | .filter((item) => { | 95 | .filter((item) => { |
95 | return menuIdsList.indexOf(item.id) > -1; | 96 | return menuIdsList.indexOf(item.id) > -1; |
@@ -3,50 +3,53 @@ | @@ -3,50 +3,53 @@ | ||
3 | <BasicModal | 3 | <BasicModal |
4 | :maskClosable="false" | 4 | :maskClosable="false" |
5 | v-bind="$attrs" | 5 | v-bind="$attrs" |
6 | - width="55rem" | 6 | + width="60rem" |
7 | @register="register" | 7 | @register="register" |
8 | @ok="handleSubmit" | 8 | @ok="handleSubmit" |
9 | @cancel="handleCancel" | 9 | @cancel="handleCancel" |
10 | > | 10 | > |
11 | - <div class="step-form-form"> | ||
12 | - <a-steps :current="current"> | ||
13 | - <a-step v-for="item in steps" :key="item.title" :title="item.title" /> | ||
14 | - </a-steps> | ||
15 | - </div> | ||
16 | - <div class="mt-5"> | ||
17 | - <DeviceConfigurationStep | ||
18 | - v-show="current === 0" | ||
19 | - ref="DevConStRef" | ||
20 | - @next="handleStepNext(true, null)" | ||
21 | - /> | ||
22 | - <TransportConfigurationStep | ||
23 | - v-show="current === 1" | ||
24 | - ref="TransConStRef" | ||
25 | - @prev="handleStepPrev" | ||
26 | - /> | ||
27 | - </div> | 11 | + <Tabs |
12 | + type="card" | ||
13 | + :animated="true" | ||
14 | + v-model:activeKey="activeKey" | ||
15 | + :size="size" | ||
16 | + @change="handleChange" | ||
17 | + > | ||
18 | + <TabPane forceRender key="1" tab="设备配置"> | ||
19 | + <DeviceConfigurationStep v-show="activeKey === '1'" ref="DevConStRef" /> | ||
20 | + </TabPane> | ||
21 | + <TabPane forceRender key="2" tab="传输配置"> | ||
22 | + <TransportConfigurationStep v-show="activeKey === '2'" ref="TransConStRef" /> | ||
23 | + </TabPane> | ||
24 | + <TabPane forceRender key="3" v-show="activeKey === '3'" tab="物模型管理"> | ||
25 | + <PhysicalModelManagementStep v-show="activeKey === '3'" ref="PhysicalModManRef" /> | ||
26 | + </TabPane> | ||
27 | + </Tabs> | ||
28 | </BasicModal> | 28 | </BasicModal> |
29 | </div> | 29 | </div> |
30 | </template> | 30 | </template> |
31 | <script lang="ts" setup> | 31 | <script lang="ts" setup> |
32 | import { ref, unref, reactive } from 'vue'; | 32 | import { ref, unref, reactive } from 'vue'; |
33 | import { BasicModal, useModalInner } from '/@/components/Modal'; | 33 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
34 | - import DeviceConfigurationStep from './step/DeviceConfigurationStep.vue'; | ||
35 | - import TransportConfigurationStep from './step/TransportConfigurationStep.vue'; | ||
36 | import { deviceConfigAddOrEdit, deviceConfigGetDetail } from '/@/api/device/deviceConfigApi'; | 34 | import { deviceConfigAddOrEdit, deviceConfigGetDetail } from '/@/api/device/deviceConfigApi'; |
37 | import { useMessage } from '/@/hooks/web/useMessage'; | 35 | import { useMessage } from '/@/hooks/web/useMessage'; |
38 | - import { steps } from './device.profile.data'; | ||
39 | import { isEmpty } from '/@/utils/is'; | 36 | import { isEmpty } from '/@/utils/is'; |
37 | + import { Tabs, TabPane } from 'ant-design-vue'; | ||
38 | + import DeviceConfigurationStep from './step/DeviceConfigurationStep.vue'; | ||
39 | + import TransportConfigurationStep from './step/TransportConfigurationStep.vue'; | ||
40 | + import PhysicalModelManagementStep from './step/PhysicalModelManagementStep.vue'; | ||
40 | 41 | ||
41 | const emits = defineEmits(['success', 'register']); | 42 | const emits = defineEmits(['success', 'register']); |
43 | + const activeKey = ref('1'); | ||
44 | + const size = ref('small'); | ||
42 | const isEditId = ref(''); | 45 | const isEditId = ref(''); |
43 | const isEditCreatTime = ref(''); | 46 | const isEditCreatTime = ref(''); |
44 | const { createMessage } = useMessage(); | 47 | const { createMessage } = useMessage(); |
45 | const isViewDetail = ref(false); | 48 | const isViewDetail = ref(false); |
46 | const isUpdate = ref(false); | 49 | const isUpdate = ref(false); |
47 | - const current = ref(0); | ||
48 | const DevConStRef = ref<InstanceType<typeof DeviceConfigurationStep>>(); | 50 | const DevConStRef = ref<InstanceType<typeof DeviceConfigurationStep>>(); |
49 | const TransConStRef = ref<InstanceType<typeof TransportConfigurationStep>>(); | 51 | const TransConStRef = ref<InstanceType<typeof TransportConfigurationStep>>(); |
52 | + const PhysicalModManRef = ref<InstanceType<typeof PhysicalModelManagementStep>>(); | ||
50 | const postSubmitFormData: any = reactive({ | 53 | const postSubmitFormData: any = reactive({ |
51 | deviceConfData: {}, | 54 | deviceConfData: {}, |
52 | }); | 55 | }); |
@@ -56,7 +59,6 @@ | @@ -56,7 +59,6 @@ | ||
56 | const transportTypeStr = ref(''); | 59 | const transportTypeStr = ref(''); |
57 | const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { | 60 | const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { |
58 | setModalProps({ confirmLoading: false }); | 61 | setModalProps({ confirmLoading: false }); |
59 | - current.value = 0; | ||
60 | isUpdate.value = data.isUpdate; | 62 | isUpdate.value = data.isUpdate; |
61 | isViewDetail.value = data.isView; | 63 | isViewDetail.value = data.isView; |
62 | const res = data.record !== undefined ? await deviceConfigGetDetail(data.record.id) : {}; | 64 | const res = data.record !== undefined ? await deviceConfigGetDetail(data.record.id) : {}; |
@@ -77,16 +79,17 @@ | @@ -77,16 +79,17 @@ | ||
77 | handleStepNext(false, res); | 79 | handleStepNext(false, res); |
78 | } | 80 | } |
79 | }); | 81 | }); |
82 | + const handleChange = (e) => { | ||
83 | + if (e == '2') { | ||
84 | + handleStepNext(true, null); | ||
85 | + } | ||
86 | + }; | ||
80 | const handleStepNext = (e, data) => { | 87 | const handleStepNext = (e, data) => { |
81 | if (e) { | 88 | if (e) { |
82 | - current.value++; | ||
83 | } else { | 89 | } else { |
84 | setTransConfEditFormData(data); | 90 | setTransConfEditFormData(data); |
85 | } | 91 | } |
86 | }; | 92 | }; |
87 | - const handleStepPrev = () => { | ||
88 | - current.value--; | ||
89 | - }; | ||
90 | 93 | ||
91 | const setDeviceConfEditFormData = async (res) => { | 94 | const setDeviceConfEditFormData = async (res) => { |
92 | await DevConStRef.value?.setFormData(res); | 95 | await DevConStRef.value?.setFormData(res); |
@@ -122,6 +125,7 @@ | @@ -122,6 +125,7 @@ | ||
122 | 125 | ||
123 | const handleCancel = () => { | 126 | const handleCancel = () => { |
124 | closeModal(); | 127 | closeModal(); |
128 | + activeKey.value = '1'; | ||
125 | DevConStRef.value?.resetFormData(); | 129 | DevConStRef.value?.resetFormData(); |
126 | TransConStRef.value?.resetFormData(); | 130 | TransConStRef.value?.resetFormData(); |
127 | }; | 131 | }; |
@@ -3,9 +3,56 @@ import { FormSchema } from '/@/components/Table'; | @@ -3,9 +3,56 @@ import { FormSchema } from '/@/components/Table'; | ||
3 | import { findDictItemByCode } from '/@/api/system/dict'; | 3 | import { findDictItemByCode } from '/@/api/system/dict'; |
4 | import { MessageEnum } from '/@/enums/messageEnum'; | 4 | import { MessageEnum } from '/@/enums/messageEnum'; |
5 | import { numberRule } from '/@/utils/rules'; | 5 | import { numberRule } from '/@/utils/rules'; |
6 | +import { Tag } from 'ant-design-vue'; | ||
7 | +import { h } from 'vue'; | ||
6 | 8 | ||
7 | import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi'; | 9 | import { deviceConfigGetRuleChain } from '/@/api/device/deviceConfigApi'; |
8 | 10 | ||
11 | +export const physicalColumn: BasicColumn[] = [ | ||
12 | + { | ||
13 | + title: '功能名称', | ||
14 | + dataIndex: 'name', | ||
15 | + width: 80, | ||
16 | + }, | ||
17 | + { | ||
18 | + title: '标识符', | ||
19 | + dataIndex: 'type', | ||
20 | + width: 80, | ||
21 | + }, | ||
22 | + { | ||
23 | + title: '数据类型', | ||
24 | + dataIndex: 'transportType', | ||
25 | + width: 80, | ||
26 | + }, | ||
27 | + { | ||
28 | + title: '单位', | ||
29 | + dataIndex: 'description1', | ||
30 | + width: 70, | ||
31 | + }, | ||
32 | + { | ||
33 | + title: '读写类型', | ||
34 | + dataIndex: 'default', | ||
35 | + width: 70, | ||
36 | + customRender: ({ record }) => { | ||
37 | + const status = record.actionStatus; | ||
38 | + const enable = status === 'SUCCESS' ? '读写' : '只读'; | ||
39 | + const color = enable === '读写' ? 'blue' : 'blue'; | ||
40 | + const text = enable === '读写' ? '读写' : '只读'; | ||
41 | + return h(Tag, { color }, () => text); | ||
42 | + }, | ||
43 | + }, | ||
44 | + { | ||
45 | + title: '创建人', | ||
46 | + dataIndex: 'description', | ||
47 | + width: 90, | ||
48 | + }, | ||
49 | + { | ||
50 | + title: '创建时间', | ||
51 | + dataIndex: 'createTime', | ||
52 | + width: 140, | ||
53 | + }, | ||
54 | +]; | ||
55 | + | ||
9 | export const step1Schemas: FormSchema[] = [ | 56 | export const step1Schemas: FormSchema[] = [ |
10 | { | 57 | { |
11 | field: 'image', | 58 | field: 'image', |
@@ -18,6 +65,7 @@ export const step1Schemas: FormSchema[] = [ | @@ -18,6 +65,7 @@ export const step1Schemas: FormSchema[] = [ | ||
18 | label: '配置名称', | 65 | label: '配置名称', |
19 | required: true, | 66 | required: true, |
20 | component: 'Input', | 67 | component: 'Input', |
68 | + colProps: { span: 14 }, | ||
21 | componentProps() { | 69 | componentProps() { |
22 | return { | 70 | return { |
23 | disabled: false, | 71 | disabled: false, |
@@ -30,6 +78,8 @@ export const step1Schemas: FormSchema[] = [ | @@ -30,6 +78,8 @@ export const step1Schemas: FormSchema[] = [ | ||
30 | field: 'defaultRuleChainId', | 78 | field: 'defaultRuleChainId', |
31 | label: '规则链', | 79 | label: '规则链', |
32 | component: 'ApiSelect', | 80 | component: 'ApiSelect', |
81 | + colProps: { span: 14 }, | ||
82 | + | ||
33 | componentProps: { | 83 | componentProps: { |
34 | api: async () => { | 84 | api: async () => { |
35 | const data = await deviceConfigGetRuleChain(); | 85 | const data = await deviceConfigGetRuleChain(); |
@@ -50,6 +100,8 @@ export const step1Schemas: FormSchema[] = [ | @@ -50,6 +100,8 @@ export const step1Schemas: FormSchema[] = [ | ||
50 | field: 'defaultQueueName', | 100 | field: 'defaultQueueName', |
51 | label: '处理队列', | 101 | label: '处理队列', |
52 | component: 'ApiSelect', | 102 | component: 'ApiSelect', |
103 | + colProps: { span: 14 }, | ||
104 | + | ||
53 | componentProps: { | 105 | componentProps: { |
54 | api: findDictItemByCode, | 106 | api: findDictItemByCode, |
55 | params: { | 107 | params: { |
@@ -64,10 +116,12 @@ export const step1Schemas: FormSchema[] = [ | @@ -64,10 +116,12 @@ export const step1Schemas: FormSchema[] = [ | ||
64 | { | 116 | { |
65 | label: '描述', | 117 | label: '描述', |
66 | field: 'description', | 118 | field: 'description', |
119 | + colProps: { span: 14 }, | ||
67 | component: 'InputTextArea', | 120 | component: 'InputTextArea', |
68 | componentProps: { | 121 | componentProps: { |
69 | maxLength: 255, | 122 | maxLength: 255, |
70 | placeholder: '请输入描述', | 123 | placeholder: '请输入描述', |
124 | + rows: 6, | ||
71 | }, | 125 | }, |
72 | }, | 126 | }, |
73 | ]; | 127 | ]; |
@@ -132,16 +186,6 @@ export const columns: BasicColumn[] = [ | @@ -132,16 +186,6 @@ export const columns: BasicColumn[] = [ | ||
132 | width: 120, | 186 | width: 120, |
133 | }, | 187 | }, |
134 | ]; | 188 | ]; |
135 | -export const steps = [ | ||
136 | - { | ||
137 | - title: '设备配置', | ||
138 | - content: 'First-content', | ||
139 | - }, | ||
140 | - { | ||
141 | - title: '传输配置', | ||
142 | - content: 'Second-content', | ||
143 | - }, | ||
144 | -]; | ||
145 | 189 | ||
146 | export const defaultObj = { | 190 | export const defaultObj = { |
147 | headers: { | 191 | headers: { |
1 | <template> | 1 | <template> |
2 | <div class="step1"> | 2 | <div class="step1"> |
3 | - <div class="step1-form"> | ||
4 | - <div> | ||
5 | - <BasicForm @register="register"> | ||
6 | - <template #imageSelect> | ||
7 | - <Upload | ||
8 | - style="width: 20vw" | ||
9 | - name="avatar" | ||
10 | - list-type="picture-card" | ||
11 | - class="avatar-uploader" | ||
12 | - :show-upload-list="false" | ||
13 | - :customRequest="customUploadqrcodePic" | ||
14 | - :before-upload="beforeUploadqrcodePic" | ||
15 | - > | ||
16 | - <img | ||
17 | - v-if="deviceConfigPic" | ||
18 | - :src="deviceConfigPic" | ||
19 | - alt="" | ||
20 | - style="width: 6.25rem; height: 6.25rem" | ||
21 | - /> | ||
22 | - <div v-else> | ||
23 | - <LoadingOutlined v-if="loading" /> | ||
24 | - <PlusOutlined v-else /> | ||
25 | - <div class="ant-upload-text">图片上传</div> | ||
26 | - </div> | ||
27 | - </Upload> | ||
28 | - </template> | ||
29 | - </BasicForm> | ||
30 | - </div> | ||
31 | - </div> | 3 | + <BasicForm @register="register"> |
4 | + <template #imageSelect> | ||
5 | + <Upload | ||
6 | + style="width: 20vw" | ||
7 | + name="avatar" | ||
8 | + list-type="picture-card" | ||
9 | + class="avatar-uploader" | ||
10 | + :show-upload-list="false" | ||
11 | + :customRequest="customUploadqrcodePic" | ||
12 | + :before-upload="beforeUploadqrcodePic" | ||
13 | + > | ||
14 | + <img | ||
15 | + v-if="deviceConfigPic" | ||
16 | + :src="deviceConfigPic" | ||
17 | + alt="" | ||
18 | + style="width: 6.25rem; height: 6.25rem" | ||
19 | + /> | ||
20 | + <div v-else> | ||
21 | + <LoadingOutlined v-if="loading" /> | ||
22 | + <PlusOutlined v-else /> | ||
23 | + <div class="ant-upload-text">图片上传</div> | ||
24 | + </div> | ||
25 | + </Upload> | ||
26 | + </template> | ||
27 | + </BasicForm> | ||
32 | </div> | 28 | </div> |
33 | </template> | 29 | </template> |
34 | <script lang="ts" setup> | 30 | <script lang="ts" setup> |
@@ -41,7 +37,6 @@ | @@ -41,7 +37,6 @@ | ||
41 | import { useMessage } from '/@/hooks/web/useMessage'; | 37 | import { useMessage } from '/@/hooks/web/useMessage'; |
42 | import type { FileItem } from '/@/components/Upload/src/typing'; | 38 | import type { FileItem } from '/@/components/Upload/src/typing'; |
43 | 39 | ||
44 | - const emits = defineEmits(['next']); | ||
45 | const loading = ref(false); | 40 | const loading = ref(false); |
46 | const { createMessage } = useMessage(); | 41 | const { createMessage } = useMessage(); |
47 | const deviceConfigPic = ref(''); | 42 | const deviceConfigPic = ref(''); |
@@ -53,10 +48,8 @@ | @@ -53,10 +48,8 @@ | ||
53 | span: 14, | 48 | span: 14, |
54 | }, | 49 | }, |
55 | showResetButton: false, | 50 | showResetButton: false, |
56 | - submitButtonOptions: { | ||
57 | - text: '下一步', | ||
58 | - }, | ||
59 | - submitFunc: customSubmitFunc, | 51 | + submitOnReset: false, |
52 | + showActionButtonGroup: false, | ||
60 | }); | 53 | }); |
61 | const editOrAddNameStatus = (nameStatus) => | 54 | const editOrAddNameStatus = (nameStatus) => |
62 | updateSchema({ | 55 | updateSchema({ |
@@ -95,11 +88,6 @@ | @@ -95,11 +88,6 @@ | ||
95 | setFieldsValue(v); | 88 | setFieldsValue(v); |
96 | deviceConfigPic.value = v.image; | 89 | deviceConfigPic.value = v.image; |
97 | }; | 90 | }; |
98 | - async function customSubmitFunc() { | ||
99 | - const values = await validate(); | ||
100 | - if (!values) return; | ||
101 | - emits('next', true, null); | ||
102 | - } | ||
103 | //获取数据 | 91 | //获取数据 |
104 | async function getFormData() { | 92 | async function getFormData() { |
105 | const values = await validate(); | 93 | const values = await validate(); |
1 | +<template> | ||
2 | + <div> | ||
3 | + <BasicTable | ||
4 | + :rowSelection="{ type: 'checkbox' }" | ||
5 | + :clickToRowSelect="false" | ||
6 | + @register="registerTable" | ||
7 | + > | ||
8 | + <template #toolbar> | ||
9 | + <div style="display: flex; justify-content: space-between; width: 773px"> | ||
10 | + <div> | ||
11 | + <Authority value=""> | ||
12 | + <div style="display: flex"> | ||
13 | + <a-button | ||
14 | + style="margin-left: -20px" | ||
15 | + type="primary" | ||
16 | + @click="handleCreateOrEdit(null)" | ||
17 | + > | ||
18 | + 新增物模型 | ||
19 | + </a-button> | ||
20 | + <a-button class="ml-2" type="primary" @click="handleOpenTsl"> 物模型TSL </a-button> | ||
21 | + </div> | ||
22 | + </Authority> | ||
23 | + </div> | ||
24 | + <div> | ||
25 | + <Authority value=""> | ||
26 | + <div style="display: flex"> | ||
27 | + <a-button type="primary"> 发布上线 </a-button> | ||
28 | + <a-button class="ml-2" type="text"> 返回 </a-button> | ||
29 | + <Popconfirm | ||
30 | + title="您确定要批量删除数据" | ||
31 | + ok-text="确定" | ||
32 | + cancel-text="取消" | ||
33 | + @confirm="handleDeleteOrBatchDelete(null)" | ||
34 | + > | ||
35 | + <a-button | ||
36 | + style="display: none" | ||
37 | + type="primary" | ||
38 | + color="error" | ||
39 | + :disabled="hasBatchDelete" | ||
40 | + > | ||
41 | + 批量删除 | ||
42 | + </a-button> | ||
43 | + </Popconfirm> | ||
44 | + </div> | ||
45 | + </Authority> | ||
46 | + </div> | ||
47 | + </div> | ||
48 | + </template> | ||
49 | + <template #action="{ record }"> | ||
50 | + <TableAction | ||
51 | + :actions="[ | ||
52 | + { | ||
53 | + label: '查看', | ||
54 | + icon: 'ant-design:eye-outlined', | ||
55 | + onClick: handleViewDetail.bind(null, record), | ||
56 | + }, | ||
57 | + { | ||
58 | + label: '编辑', | ||
59 | + icon: 'clarity:note-edit-line', | ||
60 | + auth: '', | ||
61 | + onClick: handleCreateOrEdit.bind(null, record), | ||
62 | + }, | ||
63 | + { | ||
64 | + label: '删除', | ||
65 | + icon: 'ant-design:delete-outlined', | ||
66 | + auth: '', | ||
67 | + color: 'error', | ||
68 | + popConfirm: { | ||
69 | + title: '是否确认删除', | ||
70 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
71 | + }, | ||
72 | + }, | ||
73 | + ]" | ||
74 | + /> | ||
75 | + </template> | ||
76 | + </BasicTable> | ||
77 | + <PhysicalModelModal @register="registerModal" @success="handleSuccess" /> | ||
78 | + <PhysicalModelTsl @register="registerModalTsl" /> | ||
79 | + </div> | ||
80 | +</template> | ||
81 | +<script lang="ts" setup> | ||
82 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | ||
83 | + import { useModal } from '/@/components/Modal'; | ||
84 | + import { physicalColumn } from '../device.profile.data'; | ||
85 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
86 | + import { deleteReportManage } from '/@/api/report/reportManager'; | ||
87 | + import { Authority } from '/@/components/Authority'; | ||
88 | + import { deviceConfigGetQuery } from '/@/api/device/deviceConfigApi'; | ||
89 | + import PhysicalModelModal from './cpns/physical/PhysicalModelModal.vue'; | ||
90 | + import PhysicalModelTsl from './cpns/physical/PhysicalModelTsl.vue'; | ||
91 | + import { Popconfirm } from 'ant-design-vue'; | ||
92 | + | ||
93 | + defineEmits(['register']); | ||
94 | + const [registerModal, { openModal }] = useModal(); | ||
95 | + const [registerModalTsl, { openModal: openModalTsl }] = useModal(); | ||
96 | + | ||
97 | + const [registerTable, { reload, setProps }] = useTable({ | ||
98 | + api: deviceConfigGetQuery, | ||
99 | + columns: physicalColumn, | ||
100 | + showIndexColumn: false, | ||
101 | + clickToRowSelect: false, | ||
102 | + useSearchForm: false, | ||
103 | + rowKey: 'id', | ||
104 | + showTableSetting: true, | ||
105 | + bordered: true, | ||
106 | + actionColumn: { | ||
107 | + width: 200, | ||
108 | + title: '操作', | ||
109 | + dataIndex: 'action', | ||
110 | + slots: { customRender: 'action' }, | ||
111 | + fixed: 'right', | ||
112 | + }, | ||
113 | + }); | ||
114 | + // 刷新 | ||
115 | + const handleSuccess = () => { | ||
116 | + reload(); | ||
117 | + }; | ||
118 | + | ||
119 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | ||
120 | + deleteReportManage, | ||
121 | + handleSuccess, | ||
122 | + setProps | ||
123 | + ); | ||
124 | + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | ||
125 | + // Demo:status为1的选择框禁用 | ||
126 | + if (record.status === 1) { | ||
127 | + return { disabled: true }; | ||
128 | + } else { | ||
129 | + return { disabled: false }; | ||
130 | + } | ||
131 | + }; | ||
132 | + const handleViewDetail = (record: Recordable | null) => { | ||
133 | + if (record) { | ||
134 | + openModal(true, { | ||
135 | + isUpdate: true, | ||
136 | + record, | ||
137 | + isView: true, | ||
138 | + }); | ||
139 | + } | ||
140 | + }; | ||
141 | + // 新增或编辑 | ||
142 | + const handleCreateOrEdit = (record: Recordable | null) => { | ||
143 | + if (record) { | ||
144 | + openModal(true, { | ||
145 | + isUpdate: false, | ||
146 | + record, | ||
147 | + isView: false, | ||
148 | + }); | ||
149 | + } else { | ||
150 | + openModal(true, { | ||
151 | + isUpdate: true, | ||
152 | + isView: false, | ||
153 | + }); | ||
154 | + } | ||
155 | + }; | ||
156 | + const handleOpenTsl = () => { | ||
157 | + openModalTsl(true, { | ||
158 | + isUpdate: true, | ||
159 | + }); | ||
160 | + }; | ||
161 | + defineExpose({}); | ||
162 | +</script> | ||
163 | +<style lang="less" scoped> | ||
164 | + :deep(.ant-table-body) { | ||
165 | + height: auto !important; | ||
166 | + } | ||
167 | +</style> |
@@ -29,13 +29,6 @@ | @@ -29,13 +29,6 @@ | ||
29 | <div style="margin-top: 5vh" v-else-if="isMqttType == 'SNMP'"> | 29 | <div style="margin-top: 5vh" v-else-if="isMqttType == 'SNMP'"> |
30 | <SnmpCpns ref="snmpRef" /> | 30 | <SnmpCpns ref="snmpRef" /> |
31 | </div> | 31 | </div> |
32 | - <div class="btn-style"> | ||
33 | - <div style="display: flex; width: 4vw; height: 4vh; margin-top: 1.65vh"> | ||
34 | - <Button type="default" style="border-radius: 2px" class="mt-5" @click="customResetFunc" | ||
35 | - >上一步</Button | ||
36 | - > | ||
37 | - </div> | ||
38 | - </div> | ||
39 | </div> | 32 | </div> |
40 | </div> | 33 | </div> |
41 | </template> | 34 | </template> |
@@ -43,13 +36,11 @@ | @@ -43,13 +36,11 @@ | ||
43 | import { reactive, ref, onUnmounted, nextTick } from 'vue'; | 36 | import { reactive, ref, onUnmounted, nextTick } from 'vue'; |
44 | import { BasicForm, useForm } from '/@/components/Form'; | 37 | import { BasicForm, useForm } from '/@/components/Form'; |
45 | import { step2Schemas } from '../device.profile.data'; | 38 | import { step2Schemas } from '../device.profile.data'; |
46 | - import { Button } from '/@/components/Button'; | ||
47 | import MqttCpns from './cpns/mqtt/Mqtt.vue'; | 39 | import MqttCpns from './cpns/mqtt/Mqtt.vue'; |
48 | import CoapCpns from './cpns/coap/Coap.vue'; | 40 | import CoapCpns from './cpns/coap/Coap.vue'; |
49 | import Lwm2mCpns from './cpns/lwm2m/index.vue'; | 41 | import Lwm2mCpns from './cpns/lwm2m/index.vue'; |
50 | import SnmpCpns from './cpns/snmp/index.vue'; | 42 | import SnmpCpns from './cpns/snmp/index.vue'; |
51 | 43 | ||
52 | - const emits = defineEmits(['prev']); | ||
53 | const mqttRef = ref<InstanceType<typeof MqttCpns>>(); | 44 | const mqttRef = ref<InstanceType<typeof MqttCpns>>(); |
54 | const coapRef = ref<InstanceType<typeof CoapCpns>>(); | 45 | const coapRef = ref<InstanceType<typeof CoapCpns>>(); |
55 | const lwm2mRef = ref<InstanceType<typeof Lwm2mCpns>>(); | 46 | const lwm2mRef = ref<InstanceType<typeof Lwm2mCpns>>(); |
@@ -64,6 +55,9 @@ | @@ -64,6 +55,9 @@ | ||
64 | actionColOptions: { | 55 | actionColOptions: { |
65 | span: 14, | 56 | span: 14, |
66 | }, | 57 | }, |
58 | + showResetButton: false, | ||
59 | + submitOnReset: false, | ||
60 | + showActionButtonGroup: false, | ||
67 | }); | 61 | }); |
68 | const setFormData = (v) => { | 62 | const setFormData = (v) => { |
69 | setFieldsValue({ | 63 | setFieldsValue({ |
@@ -86,9 +80,6 @@ | @@ -86,9 +80,6 @@ | ||
86 | snmpRef.value?.resetFormData(); | 80 | snmpRef.value?.resetFormData(); |
87 | }); | 81 | }); |
88 | }; | 82 | }; |
89 | - async function customResetFunc() { | ||
90 | - emits('prev'); | ||
91 | - } | ||
92 | nextTick(() => { | 83 | nextTick(() => { |
93 | updateSchema({ | 84 | updateSchema({ |
94 | field: 'transportType', | 85 | field: 'transportType', |
1 | +<template> | ||
2 | + <div> | ||
3 | + <BasicModal | ||
4 | + :maskClosable="false" | ||
5 | + v-bind="$attrs" | ||
6 | + width="55rem" | ||
7 | + @register="register" | ||
8 | + @ok="handleSubmit" | ||
9 | + @cancel="handleCancel" | ||
10 | + > | ||
11 | + <Tabs v-model:activeKey="activeKey" :size="size"> | ||
12 | + <TabPane key="1" tab="属性"> | ||
13 | + <Attr v-show="activeKey === '1'" ref="AttrRef" /> | ||
14 | + </TabPane> | ||
15 | + <TabPane disabled key="2" tab="服务"> | ||
16 | + <Service v-show="activeKey === '2'" ref="ServiceRef" /> | ||
17 | + </TabPane> | ||
18 | + <TabPane disabled key="3" v-show="activeKey === '3'" tab="事件"> | ||
19 | + <Events v-show="activeKey === '3'" ref="EventsRef" /> | ||
20 | + </TabPane> | ||
21 | + </Tabs> | ||
22 | + </BasicModal> | ||
23 | + </div> | ||
24 | +</template> | ||
25 | +<script lang="ts" setup> | ||
26 | + import { ref, unref } from 'vue'; | ||
27 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
28 | + import { Tabs, TabPane } from 'ant-design-vue'; | ||
29 | + import Attr from './cpns/Attr.vue'; | ||
30 | + import Service from './cpns/Service.vue'; | ||
31 | + import Events from './cpns/Events.vue'; | ||
32 | + | ||
33 | + defineEmits(['register']); | ||
34 | + const activeKey = ref('1'); | ||
35 | + const size = ref('small'); | ||
36 | + const AttrRef = ref<InstanceType<typeof Attr>>(); | ||
37 | + const ServiceRef = ref<InstanceType<typeof Service>>(); | ||
38 | + const EventsRef = ref<InstanceType<typeof Events>>(); | ||
39 | + const isUpdate = ref(false); | ||
40 | + const isViewDetail = ref(''); | ||
41 | + const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { | ||
42 | + setModalProps({ loading: true }); | ||
43 | + isUpdate.value = data.isUpdate; | ||
44 | + isViewDetail.value = data.isView; | ||
45 | + // AttrRef.value?.setFormData() | ||
46 | + setModalProps({ loading: false }); | ||
47 | + if (!unref(isViewDetail)) { | ||
48 | + const title = !unref(isUpdate) ? '编辑物模型' : '新增物模型'; | ||
49 | + setModalProps({ title, showOkBtn: true, showCancelBtn: true }); | ||
50 | + if (!unref(isUpdate)) { | ||
51 | + } | ||
52 | + } else { | ||
53 | + setModalProps({ showOkBtn: false, showCancelBtn: false, title: '查看物模型' }); | ||
54 | + } | ||
55 | + }); | ||
56 | + const handleCancel = () => { | ||
57 | + AttrRef.value?.resetFormData(); | ||
58 | + closeModal(); | ||
59 | + }; | ||
60 | + const handleSubmit = async () => { | ||
61 | + const value = await AttrRef.value?.getFormData(); | ||
62 | + if (!value) return; | ||
63 | + console.log('搜集值', value); | ||
64 | + }; | ||
65 | +</script> | ||
66 | + | ||
67 | +<style lang="less" scope></style> |
1 | +<template> | ||
2 | + <div> | ||
3 | + <BasicModal | ||
4 | + title="物模型TSL" | ||
5 | + :maskClosable="false" | ||
6 | + v-bind="$attrs" | ||
7 | + width="55rem" | ||
8 | + @register="register" | ||
9 | + @ok="handleSubmit" | ||
10 | + @cancel="handleCancel" | ||
11 | + > | ||
12 | + <TslContent ref="TslConRef" /> | ||
13 | + </BasicModal> | ||
14 | + </div> | ||
15 | +</template> | ||
16 | +<script lang="ts" setup> | ||
17 | + import { ref } from 'vue'; | ||
18 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
19 | + // import { useMessage } from '/@/hooks/web/useMessage'; | ||
20 | + import TslContent from './cpns/TslContent.vue'; | ||
21 | + | ||
22 | + defineEmits(['register']); | ||
23 | + // const { createMessage } = useMessage(); | ||
24 | + const TslConRef = ref<InstanceType<typeof TslContent>>(); | ||
25 | + | ||
26 | + const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { | ||
27 | + setModalProps({ confirmLoading: true }); | ||
28 | + console.log(data); | ||
29 | + setModalProps({ confirmLoading: false }); | ||
30 | + }); | ||
31 | + const handleCancel = () => { | ||
32 | + TslConRef.value?.resetFormData(); | ||
33 | + closeModal(); | ||
34 | + }; | ||
35 | + | ||
36 | + const handleSubmit = () => { | ||
37 | + const value = TslConRef.value?.getFormData(); | ||
38 | + if (!value) return; | ||
39 | + console.log('搜集值', value); | ||
40 | + }; | ||
41 | +</script> | ||
42 | + | ||
43 | +<style lang="less" scope> | ||
44 | + #jsoneditor { | ||
45 | + width: 100%; | ||
46 | + height: 450px; | ||
47 | + } | ||
48 | +</style> |
1 | +<template> | ||
2 | + <div> | ||
3 | + <BasicForm @register="register" /> | ||
4 | + </div> | ||
5 | +</template> | ||
6 | +<script lang="ts" setup> | ||
7 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
8 | + import { attrSchemas } from './config'; | ||
9 | + | ||
10 | + const [register, { validate, setFieldsValue, resetFields }] = useForm({ | ||
11 | + labelWidth: 100, | ||
12 | + schemas: attrSchemas, | ||
13 | + actionColOptions: { | ||
14 | + span: 14, | ||
15 | + }, | ||
16 | + showResetButton: false, | ||
17 | + submitOnReset: false, | ||
18 | + showActionButtonGroup: false, | ||
19 | + }); | ||
20 | + | ||
21 | + //回显数据 | ||
22 | + const setFormData = (v) => { | ||
23 | + setFieldsValue(v); | ||
24 | + }; | ||
25 | + //获取数据 | ||
26 | + async function getFormData() { | ||
27 | + const values = await validate(); | ||
28 | + if (!values) return; | ||
29 | + return values; | ||
30 | + } | ||
31 | + //清空数据 | ||
32 | + const resetFormData = () => { | ||
33 | + resetFields(); | ||
34 | + }; | ||
35 | + | ||
36 | + defineExpose({ | ||
37 | + setFormData, | ||
38 | + resetFormData, | ||
39 | + getFormData, | ||
40 | + }); | ||
41 | +</script> | ||
42 | +<style lang="less" scoped></style> |
1 | +<template> | ||
2 | + <div> | ||
3 | + <div style="display: flex; justify-content: space-between"> | ||
4 | + <div>模型内容</div> | ||
5 | + <div> | ||
6 | + <Button @click="handlePremitter"> | ||
7 | + <template #icon> | ||
8 | + <SortAscendingOutlined /> | ||
9 | + </template> | ||
10 | + 格式化 | ||
11 | + </Button> | ||
12 | + <Button class="ml-2" @click="handleCopy"> | ||
13 | + <template #icon> | ||
14 | + <CopyOutlined /> | ||
15 | + </template> | ||
16 | + copy | ||
17 | + </Button> | ||
18 | + </div> | ||
19 | + </div> | ||
20 | + <div class="mt-4"> | ||
21 | + <div id="jsoneditor" ref="jsoneditorRef"></div> | ||
22 | + </div> | ||
23 | + </div> | ||
24 | +</template> | ||
25 | +<script lang="ts" setup> | ||
26 | + import { ref, unref, onMounted, nextTick } from 'vue'; | ||
27 | + import { CopyOutlined, SortAscendingOutlined } from '@ant-design/icons-vue'; | ||
28 | + import { useCopyToClipboard } from '/@/hooks/web/useCopyToClipboard'; | ||
29 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
30 | + import jsoneditor from 'jsoneditor'; | ||
31 | + import 'jsoneditor/dist/jsoneditor.min.css'; | ||
32 | + import { Button } from 'ant-design-vue'; | ||
33 | + import { defaultTslContent } from './config'; | ||
34 | + | ||
35 | + const { createMessage } = useMessage(); | ||
36 | + const jsonValue = ref(defaultTslContent); | ||
37 | + const jsonInstance = ref(); | ||
38 | + const jsoneditorRef = ref(); | ||
39 | + onMounted(() => { | ||
40 | + nextTick(() => { | ||
41 | + let options = { | ||
42 | + mode: 'code', | ||
43 | + mainMenuBar: false, | ||
44 | + statusBar: false, | ||
45 | + }; | ||
46 | + let editor = new jsoneditor(jsoneditorRef.value, options); | ||
47 | + editor.set(jsonValue.value); | ||
48 | + jsonInstance.value = editor; | ||
49 | + }); | ||
50 | + }); | ||
51 | + const { clipboardRef, copiedRef } = useCopyToClipboard(); | ||
52 | + const handleCopy = () => { | ||
53 | + try { | ||
54 | + const valueRef = unref(jsonInstance).get(); | ||
55 | + const value = JSON.stringify(unref(valueRef)); | ||
56 | + if (!value) { | ||
57 | + createMessage.warning('请输入要拷贝的内容!'); | ||
58 | + return; | ||
59 | + } | ||
60 | + clipboardRef.value = value; | ||
61 | + if (unref(copiedRef)) { | ||
62 | + createMessage.success('复制成功!'); | ||
63 | + } | ||
64 | + } catch (e) { | ||
65 | + console.log(e); | ||
66 | + } | ||
67 | + }; | ||
68 | + | ||
69 | + const getFormData = () => { | ||
70 | + const value = unref(jsonInstance).get(); | ||
71 | + if (!value) return; | ||
72 | + return value; | ||
73 | + }; | ||
74 | + const resetFormData = () => { | ||
75 | + unref(jsonInstance).set(defaultTslContent); | ||
76 | + }; | ||
77 | + const handlePremitter = () => { | ||
78 | + const value = unref(jsonInstance).get(); | ||
79 | + return unref(jsonInstance).set(value); | ||
80 | + }; | ||
81 | + defineExpose({ | ||
82 | + getFormData, | ||
83 | + resetFormData, | ||
84 | + }); | ||
85 | +</script> | ||
86 | + | ||
87 | +<style lang="less" scope> | ||
88 | + #jsoneditor { | ||
89 | + width: 100%; | ||
90 | + height: 450px; | ||
91 | + } | ||
92 | +</style> |
1 | +import { FormSchema } from '/@/components/Table'; | ||
2 | +import { findDictItemByCode } from '/@/api/system/dict'; | ||
3 | + | ||
4 | +export const defaultTslContent = { | ||
5 | + schema: 'https://iotx-tsl.oss-ap-southeast-1.aliyuncs.com/schema.json', | ||
6 | + profile: { | ||
7 | + version: '1.5', | ||
8 | + productKey: 'glzlnU7azMO', | ||
9 | + }, | ||
10 | + properties: [ | ||
11 | + { | ||
12 | + identifier: 'LightStatus', | ||
13 | + name: '工作状态', | ||
14 | + accessMode: 'rw', | ||
15 | + required: true, | ||
16 | + dataType: { | ||
17 | + type: 'bool', | ||
18 | + specs: { | ||
19 | + '0': '关闭', | ||
20 | + '1': '打开', | ||
21 | + }, | ||
22 | + }, | ||
23 | + }, | ||
24 | + ], | ||
25 | +}; | ||
26 | + | ||
27 | +export const attrSchemas: FormSchema[] = [ | ||
28 | + { | ||
29 | + field: 'configName', | ||
30 | + label: '功能名称', | ||
31 | + required: true, | ||
32 | + component: 'Input', | ||
33 | + colProps: { | ||
34 | + span: 18, | ||
35 | + }, | ||
36 | + componentProps: { | ||
37 | + maxLength: 255, | ||
38 | + placeholder: '请输入功能名称', | ||
39 | + }, | ||
40 | + }, | ||
41 | + { | ||
42 | + field: 'configName1', | ||
43 | + label: '标识符', | ||
44 | + required: true, | ||
45 | + component: 'Input', | ||
46 | + colProps: { | ||
47 | + span: 18, | ||
48 | + }, | ||
49 | + componentProps: { | ||
50 | + maxLength: 255, | ||
51 | + placeholder: '请输入标识符', | ||
52 | + }, | ||
53 | + }, | ||
54 | + { | ||
55 | + field: 'platformType', | ||
56 | + label: '数据类型', | ||
57 | + required: true, | ||
58 | + component: 'ApiSelect', | ||
59 | + colProps: { | ||
60 | + span: 9, | ||
61 | + }, | ||
62 | + componentProps: { | ||
63 | + placeholder: '请选择数据类型', | ||
64 | + api: findDictItemByCode, | ||
65 | + params: { | ||
66 | + dictCode: 'data_type', | ||
67 | + }, | ||
68 | + labelField: 'itemText', | ||
69 | + valueField: 'itemValue', | ||
70 | + }, | ||
71 | + }, | ||
72 | + { | ||
73 | + field: 'accessKeyId', | ||
74 | + label: '单位', | ||
75 | + required: true, | ||
76 | + component: 'ApiSelect', | ||
77 | + colProps: { | ||
78 | + span: 9, | ||
79 | + }, | ||
80 | + componentProps: { | ||
81 | + placeholder: '请选择单位', | ||
82 | + api: findDictItemByCode, | ||
83 | + params: { | ||
84 | + dictCode: 'attribute_unit', | ||
85 | + }, | ||
86 | + labelField: 'itemText', | ||
87 | + valueField: 'itemValue', | ||
88 | + }, | ||
89 | + }, | ||
90 | + { | ||
91 | + field: 'brand', | ||
92 | + component: 'ApiRadioGroup', | ||
93 | + label: '读写类型', | ||
94 | + required: true, | ||
95 | + colProps: { | ||
96 | + span: 24, | ||
97 | + }, | ||
98 | + defaultValue: 'readonly', | ||
99 | + componentProps: { | ||
100 | + placeholder: '请选择读写类型', | ||
101 | + api: findDictItemByCode, | ||
102 | + params: { | ||
103 | + dictCode: 'read_write_type', | ||
104 | + }, | ||
105 | + labelField: 'itemText', | ||
106 | + valueField: 'itemValue', | ||
107 | + }, | ||
108 | + }, | ||
109 | + { | ||
110 | + label: '描述', | ||
111 | + field: 'description', | ||
112 | + component: 'InputTextArea', | ||
113 | + componentProps: { | ||
114 | + rows: 6, | ||
115 | + maxLength: 255, | ||
116 | + placeholder: '请输入描述', | ||
117 | + }, | ||
118 | + }, | ||
119 | +]; |
@@ -25,6 +25,7 @@ | @@ -25,6 +25,7 @@ | ||
25 | const isViewDetail = ref(''); | 25 | const isViewDetail = ref(''); |
26 | const [register, { setModalProps, closeModal }] = useModalInner(async (data) => { | 26 | const [register, { setModalProps, closeModal }] = useModalInner(async (data) => { |
27 | setModalProps({ loading: true }); | 27 | setModalProps({ loading: true }); |
28 | + handleCancel(false); | ||
28 | isUpdate.value = data.isUpdate; | 29 | isUpdate.value = data.isUpdate; |
29 | isViewDetail.value = data.isView; | 30 | isViewDetail.value = data.isView; |
30 | converScriptRef.value?.initEditor(data.record?.configuration?.jsScript); | 31 | converScriptRef.value?.initEditor(data.record?.configuration?.jsScript); |
@@ -41,9 +42,12 @@ | @@ -41,9 +42,12 @@ | ||
41 | const handleSubmit = async () => { | 42 | const handleSubmit = async () => { |
42 | const val = await converScriptRef.value?.getFormData(); | 43 | const val = await converScriptRef.value?.getFormData(); |
43 | console.log(val); | 44 | console.log(val); |
45 | + handleCancel(true); | ||
44 | }; | 46 | }; |
45 | - const handleCancel = () => { | ||
46 | - closeModal(); | 47 | + const handleCancel = (flag) => { |
48 | + if (flag) { | ||
49 | + closeModal(); | ||
50 | + } | ||
47 | converScriptRef.value?.resetFormData(); | 51 | converScriptRef.value?.resetFormData(); |
48 | }; | 52 | }; |
49 | </script> | 53 | </script> |