Showing
13 changed files
with
656 additions
and
90 deletions
... | ... | @@ -3,50 +3,53 @@ |
3 | 3 | <BasicModal |
4 | 4 | :maskClosable="false" |
5 | 5 | v-bind="$attrs" |
6 | - width="55rem" | |
6 | + width="60rem" | |
7 | 7 | @register="register" |
8 | 8 | @ok="handleSubmit" |
9 | 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 | 28 | </BasicModal> |
29 | 29 | </div> |
30 | 30 | </template> |
31 | 31 | <script lang="ts" setup> |
32 | 32 | import { ref, unref, reactive } from 'vue'; |
33 | 33 | import { BasicModal, useModalInner } from '/@/components/Modal'; |
34 | - import DeviceConfigurationStep from './step/DeviceConfigurationStep.vue'; | |
35 | - import TransportConfigurationStep from './step/TransportConfigurationStep.vue'; | |
36 | 34 | import { deviceConfigAddOrEdit, deviceConfigGetDetail } from '/@/api/device/deviceConfigApi'; |
37 | 35 | import { useMessage } from '/@/hooks/web/useMessage'; |
38 | - import { steps } from './device.profile.data'; | |
39 | 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 | 42 | const emits = defineEmits(['success', 'register']); |
43 | + const activeKey = ref('1'); | |
44 | + const size = ref('small'); | |
42 | 45 | const isEditId = ref(''); |
43 | 46 | const isEditCreatTime = ref(''); |
44 | 47 | const { createMessage } = useMessage(); |
45 | 48 | const isViewDetail = ref(false); |
46 | 49 | const isUpdate = ref(false); |
47 | - const current = ref(0); | |
48 | 50 | const DevConStRef = ref<InstanceType<typeof DeviceConfigurationStep>>(); |
49 | 51 | const TransConStRef = ref<InstanceType<typeof TransportConfigurationStep>>(); |
52 | + const PhysicalModManRef = ref<InstanceType<typeof PhysicalModelManagementStep>>(); | |
50 | 53 | const postSubmitFormData: any = reactive({ |
51 | 54 | deviceConfData: {}, |
52 | 55 | }); |
... | ... | @@ -56,7 +59,6 @@ |
56 | 59 | const transportTypeStr = ref(''); |
57 | 60 | const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { |
58 | 61 | setModalProps({ confirmLoading: false }); |
59 | - current.value = 0; | |
60 | 62 | isUpdate.value = data.isUpdate; |
61 | 63 | isViewDetail.value = data.isView; |
62 | 64 | const res = data.record !== undefined ? await deviceConfigGetDetail(data.record.id) : {}; |
... | ... | @@ -77,16 +79,17 @@ |
77 | 79 | handleStepNext(false, res); |
78 | 80 | } |
79 | 81 | }); |
82 | + const handleChange = (e) => { | |
83 | + if (e == '2') { | |
84 | + handleStepNext(true, null); | |
85 | + } | |
86 | + }; | |
80 | 87 | const handleStepNext = (e, data) => { |
81 | 88 | if (e) { |
82 | - current.value++; | |
83 | 89 | } else { |
84 | 90 | setTransConfEditFormData(data); |
85 | 91 | } |
86 | 92 | }; |
87 | - const handleStepPrev = () => { | |
88 | - current.value--; | |
89 | - }; | |
90 | 93 | |
91 | 94 | const setDeviceConfEditFormData = async (res) => { |
92 | 95 | await DevConStRef.value?.setFormData(res); |
... | ... | @@ -122,6 +125,7 @@ |
122 | 125 | |
123 | 126 | const handleCancel = () => { |
124 | 127 | closeModal(); |
128 | + activeKey.value = '1'; | |
125 | 129 | DevConStRef.value?.resetFormData(); |
126 | 130 | TransConStRef.value?.resetFormData(); |
127 | 131 | }; | ... | ... |
... | ... | @@ -3,9 +3,56 @@ import { FormSchema } from '/@/components/Table'; |
3 | 3 | import { findDictItemByCode } from '/@/api/system/dict'; |
4 | 4 | import { MessageEnum } from '/@/enums/messageEnum'; |
5 | 5 | import { numberRule } from '/@/utils/rules'; |
6 | +import { Tag } from 'ant-design-vue'; | |
7 | +import { h } from 'vue'; | |
6 | 8 | |
7 | 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 | 56 | export const step1Schemas: FormSchema[] = [ |
10 | 57 | { |
11 | 58 | field: 'image', |
... | ... | @@ -18,6 +65,7 @@ export const step1Schemas: FormSchema[] = [ |
18 | 65 | label: '配置名称', |
19 | 66 | required: true, |
20 | 67 | component: 'Input', |
68 | + colProps: { span: 14 }, | |
21 | 69 | componentProps() { |
22 | 70 | return { |
23 | 71 | disabled: false, |
... | ... | @@ -30,6 +78,8 @@ export const step1Schemas: FormSchema[] = [ |
30 | 78 | field: 'defaultRuleChainId', |
31 | 79 | label: '规则链', |
32 | 80 | component: 'ApiSelect', |
81 | + colProps: { span: 14 }, | |
82 | + | |
33 | 83 | componentProps: { |
34 | 84 | api: async () => { |
35 | 85 | const data = await deviceConfigGetRuleChain(); |
... | ... | @@ -50,6 +100,8 @@ export const step1Schemas: FormSchema[] = [ |
50 | 100 | field: 'defaultQueueName', |
51 | 101 | label: '处理队列', |
52 | 102 | component: 'ApiSelect', |
103 | + colProps: { span: 14 }, | |
104 | + | |
53 | 105 | componentProps: { |
54 | 106 | api: findDictItemByCode, |
55 | 107 | params: { |
... | ... | @@ -64,10 +116,12 @@ export const step1Schemas: FormSchema[] = [ |
64 | 116 | { |
65 | 117 | label: '描述', |
66 | 118 | field: 'description', |
119 | + colProps: { span: 14 }, | |
67 | 120 | component: 'InputTextArea', |
68 | 121 | componentProps: { |
69 | 122 | maxLength: 255, |
70 | 123 | placeholder: '请输入描述', |
124 | + rows: 6, | |
71 | 125 | }, |
72 | 126 | }, |
73 | 127 | ]; |
... | ... | @@ -132,16 +186,6 @@ export const columns: BasicColumn[] = [ |
132 | 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 | 190 | export const defaultObj = { |
147 | 191 | headers: { | ... | ... |
1 | 1 | <template> |
2 | 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 | 28 | </div> |
33 | 29 | </template> |
34 | 30 | <script lang="ts" setup> |
... | ... | @@ -41,7 +37,6 @@ |
41 | 37 | import { useMessage } from '/@/hooks/web/useMessage'; |
42 | 38 | import type { FileItem } from '/@/components/Upload/src/typing'; |
43 | 39 | |
44 | - const emits = defineEmits(['next']); | |
45 | 40 | const loading = ref(false); |
46 | 41 | const { createMessage } = useMessage(); |
47 | 42 | const deviceConfigPic = ref(''); |
... | ... | @@ -53,10 +48,8 @@ |
53 | 48 | span: 14, |
54 | 49 | }, |
55 | 50 | showResetButton: false, |
56 | - submitButtonOptions: { | |
57 | - text: '下一步', | |
58 | - }, | |
59 | - submitFunc: customSubmitFunc, | |
51 | + submitOnReset: false, | |
52 | + showActionButtonGroup: false, | |
60 | 53 | }); |
61 | 54 | const editOrAddNameStatus = (nameStatus) => |
62 | 55 | updateSchema({ |
... | ... | @@ -95,11 +88,6 @@ |
95 | 88 | setFieldsValue(v); |
96 | 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 | 92 | async function getFormData() { |
105 | 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 | 29 | <div style="margin-top: 5vh" v-else-if="isMqttType == 'SNMP'"> |
30 | 30 | <SnmpCpns ref="snmpRef" /> |
31 | 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 | 32 | </div> |
40 | 33 | </div> |
41 | 34 | </template> |
... | ... | @@ -43,13 +36,11 @@ |
43 | 36 | import { reactive, ref, onUnmounted, nextTick } from 'vue'; |
44 | 37 | import { BasicForm, useForm } from '/@/components/Form'; |
45 | 38 | import { step2Schemas } from '../device.profile.data'; |
46 | - import { Button } from '/@/components/Button'; | |
47 | 39 | import MqttCpns from './cpns/mqtt/Mqtt.vue'; |
48 | 40 | import CoapCpns from './cpns/coap/Coap.vue'; |
49 | 41 | import Lwm2mCpns from './cpns/lwm2m/index.vue'; |
50 | 42 | import SnmpCpns from './cpns/snmp/index.vue'; |
51 | 43 | |
52 | - const emits = defineEmits(['prev']); | |
53 | 44 | const mqttRef = ref<InstanceType<typeof MqttCpns>>(); |
54 | 45 | const coapRef = ref<InstanceType<typeof CoapCpns>>(); |
55 | 46 | const lwm2mRef = ref<InstanceType<typeof Lwm2mCpns>>(); |
... | ... | @@ -64,6 +55,9 @@ |
64 | 55 | actionColOptions: { |
65 | 56 | span: 14, |
66 | 57 | }, |
58 | + showResetButton: false, | |
59 | + submitOnReset: false, | |
60 | + showActionButtonGroup: false, | |
67 | 61 | }); |
68 | 62 | const setFormData = (v) => { |
69 | 63 | setFieldsValue({ |
... | ... | @@ -86,9 +80,6 @@ |
86 | 80 | snmpRef.value?.resetFormData(); |
87 | 81 | }); |
88 | 82 | }; |
89 | - async function customResetFunc() { | |
90 | - emits('prev'); | |
91 | - } | |
92 | 83 | nextTick(() => { |
93 | 84 | updateSchema({ |
94 | 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 | 25 | const isViewDetail = ref(''); |
26 | 26 | const [register, { setModalProps, closeModal }] = useModalInner(async (data) => { |
27 | 27 | setModalProps({ loading: true }); |
28 | + handleCancel(false); | |
28 | 29 | isUpdate.value = data.isUpdate; |
29 | 30 | isViewDetail.value = data.isView; |
30 | 31 | converScriptRef.value?.initEditor(data.record?.configuration?.jsScript); |
... | ... | @@ -41,9 +42,12 @@ |
41 | 42 | const handleSubmit = async () => { |
42 | 43 | const val = await converScriptRef.value?.getFormData(); |
43 | 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 | 51 | converScriptRef.value?.resetFormData(); |
48 | 52 | }; |
49 | 53 | </script> | ... | ... |