Commit dbb85690e5ee7e65af6e972722a8faf760fd547f
1 parent
6c0755f1
feat: device profile add card mode
Showing
10 changed files
with
764 additions
and
311 deletions
@@ -2,7 +2,9 @@ import { defHttp } from '/@/utils/http/axios'; | @@ -2,7 +2,9 @@ import { defHttp } from '/@/utils/http/axios'; | ||
2 | import { | 2 | import { |
3 | TDeviceConfigParams, | 3 | TDeviceConfigParams, |
4 | IDeviceConfigAddOrEditModel, | 4 | IDeviceConfigAddOrEditModel, |
5 | + ProfileRecord, | ||
5 | } from '/@/api/device/model/deviceConfigModel'; | 6 | } from '/@/api/device/model/deviceConfigModel'; |
7 | +import { PaginationResult } from '/#/axios'; | ||
6 | 8 | ||
7 | enum EDeviceConfigApi { | 9 | enum EDeviceConfigApi { |
8 | /** | 10 | /** |
@@ -52,7 +54,7 @@ export const alarmContactGetPage = () => { | @@ -52,7 +54,7 @@ export const alarmContactGetPage = () => { | ||
52 | * 分页查询设备配置页面 | 54 | * 分页查询设备配置页面 |
53 | */ | 55 | */ |
54 | export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => { | 56 | export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => { |
55 | - return defHttp.get({ | 57 | + return defHttp.get<PaginationResult<ProfileRecord>>({ |
56 | url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE, | 58 | url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE, |
57 | params, | 59 | params, |
58 | }); | 60 | }); |
@@ -199,3 +199,45 @@ export interface AlarmLogItem { | @@ -199,3 +199,45 @@ export interface AlarmLogItem { | ||
199 | organizationId: string; | 199 | organizationId: string; |
200 | organizationName: string; | 200 | organizationName: string; |
201 | } | 201 | } |
202 | + | ||
203 | +export interface Configuration { | ||
204 | + type: string; | ||
205 | +} | ||
206 | + | ||
207 | +export interface TransportConfiguration { | ||
208 | + type: string; | ||
209 | +} | ||
210 | + | ||
211 | +export interface ProvisionConfiguration { | ||
212 | + type: string; | ||
213 | + provisionDeviceSecret?: any; | ||
214 | +} | ||
215 | + | ||
216 | +export interface ProfileData { | ||
217 | + configuration: Configuration; | ||
218 | + transportConfiguration: TransportConfiguration; | ||
219 | + provisionConfiguration: ProvisionConfiguration; | ||
220 | + alarms?: any; | ||
221 | +} | ||
222 | + | ||
223 | +export interface ProfileRecord { | ||
224 | + id: string; | ||
225 | + creator: string; | ||
226 | + createTime: string; | ||
227 | + updater: string; | ||
228 | + updateTime: string; | ||
229 | + name: string; | ||
230 | + tenantId: string; | ||
231 | + transportType: string; | ||
232 | + provisionType: string; | ||
233 | + deviceType: string; | ||
234 | + tbProfileId: string; | ||
235 | + profileData: ProfileData; | ||
236 | + defaultRuleChainId: string; | ||
237 | + defaultQueueName: string; | ||
238 | + image: string; | ||
239 | + type: string; | ||
240 | + default: boolean; | ||
241 | + | ||
242 | + checked?: boolean; | ||
243 | +} |
src/components/Widget/CardLayoutButton.vue
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | + import { Popover, Slider, Button } from 'ant-design-vue'; | ||
3 | + import { LayoutOutlined } from '@ant-design/icons-vue'; | ||
4 | + import { computed } from 'vue'; | ||
5 | + | ||
6 | + const props = withDefaults( | ||
7 | + defineProps<{ | ||
8 | + min?: number; | ||
9 | + max?: number; | ||
10 | + value?: number; | ||
11 | + }>(), | ||
12 | + { | ||
13 | + min: 4, | ||
14 | + max: 12, | ||
15 | + value: 4, | ||
16 | + } | ||
17 | + ); | ||
18 | + | ||
19 | + const emit = defineEmits(['change', 'update:value']); | ||
20 | + | ||
21 | + const generateLayoutMarks = (min: number, max: number) => { | ||
22 | + const marks = {}; | ||
23 | + Array.from({ length: max - min + 1 }).forEach((_, index) => { | ||
24 | + const key = index + min; | ||
25 | + marks[key] = key; | ||
26 | + }); | ||
27 | + return marks; | ||
28 | + }; | ||
29 | + | ||
30 | + const getMarks = computed(() => { | ||
31 | + const { min, max } = props; | ||
32 | + return generateLayoutMarks(min, max); | ||
33 | + }); | ||
34 | + | ||
35 | + const handleChange = (value: number) => { | ||
36 | + emit('update:value', value); | ||
37 | + emit('change', value); | ||
38 | + }; | ||
39 | +</script> | ||
40 | + | ||
41 | +<template> | ||
42 | + <Popover :trigger="['hover']"> | ||
43 | + <template #content> | ||
44 | + <div class="w-60"> | ||
45 | + <div>每行显示数量</div> | ||
46 | + <Slider | ||
47 | + :value="props.value" | ||
48 | + :max="props.max" | ||
49 | + :min="props.min" | ||
50 | + :marks="getMarks" | ||
51 | + @change="handleChange" | ||
52 | + /> | ||
53 | + </div> | ||
54 | + </template> | ||
55 | + <Button type="primary"> | ||
56 | + <LayoutOutlined /> | ||
57 | + </Button> | ||
58 | + </Popover> | ||
59 | +</template> |
src/components/Widget/ModeSwitchButton.vue
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | + import { RadioButton, RadioGroup, Tooltip } from 'ant-design-vue'; | ||
3 | + import { AppstoreOutlined, UnorderedListOutlined } from '@ant-design/icons-vue'; | ||
4 | + import { Mode } from './const'; | ||
5 | + const props = defineProps<{ | ||
6 | + value: Mode; | ||
7 | + }>(); | ||
8 | + | ||
9 | + const emit = defineEmits(['change']); | ||
10 | + | ||
11 | + const handleChange = (event: Event) => { | ||
12 | + const value = (event.target as HTMLInputElement).value; | ||
13 | + emit('change', value); | ||
14 | + }; | ||
15 | +</script> | ||
16 | + | ||
17 | +<template> | ||
18 | + <RadioGroup :value="props.value" button-style="solid" @change="handleChange"> | ||
19 | + <Tooltip title="卡片模式"> | ||
20 | + <RadioButton class="cursor-pointer" :value="Mode.CARD"> | ||
21 | + <AppstoreOutlined /> | ||
22 | + </RadioButton> | ||
23 | + </Tooltip> | ||
24 | + <Tooltip title="列表模式"> | ||
25 | + <RadioButton class="cursor-pointer" :value="Mode.TABLE"> | ||
26 | + <UnorderedListOutlined /> | ||
27 | + </RadioButton> | ||
28 | + </Tooltip> | ||
29 | + </RadioGroup> | ||
30 | +</template> |
src/components/Widget/const.ts
0 → 100644
src/components/Widget/index.ts
0 → 100644
src/views/device/profiles/CardMode.vue
0 → 100644
1 | +<script lang="ts" setup> | ||
2 | + import { PageWrapper } from '/@/components/Page'; | ||
3 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
4 | + import { List, Button, Tooltip, Card, PaginationProps, Image } from 'ant-design-vue'; | ||
5 | + import { ReloadOutlined, EyeOutlined, FormOutlined, MoreOutlined } from '@ant-design/icons-vue'; | ||
6 | + import { computed, onMounted, reactive, ref, unref } from 'vue'; | ||
7 | + import { CardLayoutButton, Mode, ModeSwitchButton } from '/@/components/Widget'; | ||
8 | + import { Authority } from '/@/components/Authority'; | ||
9 | + import { | ||
10 | + deviceConfigDelete, | ||
11 | + deviceConfigGetQuery, | ||
12 | + setDeviceProfileIsDefaultApi, | ||
13 | + } from '/@/api/device/deviceConfigApi'; | ||
14 | + import { ProfileRecord } from '/@/api/device/model/deviceConfigModel'; | ||
15 | + import { Dropdown } from '/@/components/Dropdown'; | ||
16 | + import { defaultObj, searchFormSchema, DeviceTypeName } from './device.profile.data'; | ||
17 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
18 | + import { useSyncConfirm } from '/@/hooks/component/useSyncConfirm'; | ||
19 | + import DeviceProfileModal from './DeviceProfileModal.vue'; | ||
20 | + import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; | ||
21 | + import { useModal } from '/@/components/Modal'; | ||
22 | + import { useDrawer } from '/@/components/Drawer'; | ||
23 | + | ||
24 | + defineProps<{ | ||
25 | + mode: Mode; | ||
26 | + }>(); | ||
27 | + | ||
28 | + const emit = defineEmits(['changeMode']); | ||
29 | + | ||
30 | + enum DropMenuEvent { | ||
31 | + SET_DEFAULT = 'setDefault', | ||
32 | + DELETE = 'delete', | ||
33 | + } | ||
34 | + const IMAGE_FALLBACK = | ||
35 | + 'data:image/png;base64,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'; | ||
36 | + | ||
37 | + const { createMessage } = useMessage(); | ||
38 | + const { createSyncConfirm } = useSyncConfirm(); | ||
39 | + | ||
40 | + const [register, { getFieldsValue }] = useForm({ | ||
41 | + showAdvancedButton: true, | ||
42 | + labelWidth: 100, | ||
43 | + compact: true, | ||
44 | + baseColProps: { span: 8 }, | ||
45 | + schemas: searchFormSchema, | ||
46 | + submitFunc: async () => { | ||
47 | + getDataSource(); | ||
48 | + }, | ||
49 | + }); | ||
50 | + | ||
51 | + const [registerModal, { openModal }] = useModal(); | ||
52 | + const [registerDrawer, { openDrawer }] = useDrawer(); | ||
53 | + | ||
54 | + const loading = ref(false); | ||
55 | + | ||
56 | + const pagination = reactive<PaginationProps>({ | ||
57 | + size: 'small', | ||
58 | + showTotal: (total: number) => `共 ${total} 条数据`, | ||
59 | + current: 1, | ||
60 | + onChange: (page: number) => { | ||
61 | + pagination.current = page; | ||
62 | + getDataSource(); | ||
63 | + }, | ||
64 | + }); | ||
65 | + | ||
66 | + const dataSource = ref<ProfileRecord[]>([]); | ||
67 | + | ||
68 | + const colNumber = ref(4); | ||
69 | + | ||
70 | + const getSelectAllFlag = computed(() => { | ||
71 | + return unref(dataSource).every((item) => item.checked); | ||
72 | + }); | ||
73 | + | ||
74 | + const getCheckedRecord = computed(() => { | ||
75 | + return unref(dataSource) | ||
76 | + .filter((item) => item.checked) | ||
77 | + .map((item) => item.id); | ||
78 | + }); | ||
79 | + | ||
80 | + const getDataSource = async () => { | ||
81 | + try { | ||
82 | + loading.value = true; | ||
83 | + const params = getFieldsValue(); | ||
84 | + const { items, total } = await deviceConfigGetQuery({ | ||
85 | + page: pagination.current, | ||
86 | + pageSize: unref(colNumber) * 2, | ||
87 | + ...params, | ||
88 | + }); | ||
89 | + pagination.total = total; | ||
90 | + dataSource.value = items.map((item) => ({ ...item, checked: false })); | ||
91 | + } catch (error) { | ||
92 | + } finally { | ||
93 | + loading.value = false; | ||
94 | + } | ||
95 | + }; | ||
96 | + | ||
97 | + const handleModeChange = (mode: Mode) => { | ||
98 | + emit('changeMode', mode); | ||
99 | + }; | ||
100 | + | ||
101 | + const handleCheckCard = (item: ProfileRecord) => { | ||
102 | + item.checked = !item.checked; | ||
103 | + }; | ||
104 | + | ||
105 | + const handleSelectAll = () => { | ||
106 | + dataSource.value = unref(dataSource).map((item) => { | ||
107 | + return { | ||
108 | + ...item, | ||
109 | + checked: !unref(getSelectAllFlag), | ||
110 | + }; | ||
111 | + }); | ||
112 | + }; | ||
113 | + | ||
114 | + const handleCreate = () => { | ||
115 | + openModal(true, { | ||
116 | + isUpdate: false, | ||
117 | + }); | ||
118 | + }; | ||
119 | + | ||
120 | + const handleShowDetail = (record: ProfileRecord) => { | ||
121 | + openDrawer(true, { record }); | ||
122 | + }; | ||
123 | + | ||
124 | + const handleUpdate = (record: ProfileRecord) => { | ||
125 | + openModal(true, { | ||
126 | + record, | ||
127 | + isUpdate: true, | ||
128 | + }); | ||
129 | + }; | ||
130 | + | ||
131 | + const handleDelete = async (id: string[]) => { | ||
132 | + try { | ||
133 | + await createSyncConfirm({ iconType: 'warning', content: '是否确认删除操作?' }); | ||
134 | + await deviceConfigDelete(id); | ||
135 | + createMessage.success('删除成功'); | ||
136 | + await getDataSource(); | ||
137 | + } catch (error) { | ||
138 | + throw error; | ||
139 | + } | ||
140 | + }; | ||
141 | + | ||
142 | + const handleSetDefault = async (record: ProfileRecord) => { | ||
143 | + try { | ||
144 | + const { tbProfileId } = record; | ||
145 | + const data = await setDeviceProfileIsDefaultApi(tbProfileId, 'default', defaultObj); | ||
146 | + if (!data) return createMessage.error('设置该产品为默认失败'); | ||
147 | + createMessage.success('设置该产品为默认成功'); | ||
148 | + await getDataSource(); | ||
149 | + } catch (error) { | ||
150 | + throw error; | ||
151 | + } | ||
152 | + }; | ||
153 | + | ||
154 | + onMounted(() => { | ||
155 | + getDataSource(); | ||
156 | + }); | ||
157 | +</script> | ||
158 | + | ||
159 | +<template> | ||
160 | + <PageWrapper dense contentFullHeight contentClass="flex"> | ||
161 | + <section class="flex-auto p-4 w-full profile-list"> | ||
162 | + <div class="flex-auto w-full bg-light-50 dark:bg-dark-900 p-4"> | ||
163 | + <BasicForm @register="register" /> | ||
164 | + </div> | ||
165 | + <List | ||
166 | + ref="listEl" | ||
167 | + :loading="loading" | ||
168 | + class="flex-auto bg-light-50 dark:bg-dark-900 !p-2 !mt-4" | ||
169 | + position="bottom" | ||
170 | + :pagination="pagination" | ||
171 | + :data-source="dataSource" | ||
172 | + :grid="{ gutter: 4, column: colNumber }" | ||
173 | + > | ||
174 | + <template #header> | ||
175 | + <div class="flex gap-3 justify-end"> | ||
176 | + <Button type="primary" @click="handleCreate">新增产品</Button> | ||
177 | + <Button type="primary" @click="handleSelectAll"> | ||
178 | + {{ getSelectAllFlag ? '反选' : '全选' }} | ||
179 | + </Button> | ||
180 | + <Button | ||
181 | + type="primary" | ||
182 | + danger | ||
183 | + :disabled="!getCheckedRecord.length" | ||
184 | + @click="handleDelete(getCheckedRecord)" | ||
185 | + > | ||
186 | + 批量删除 | ||
187 | + </Button> | ||
188 | + <ModeSwitchButton :value="$props.mode" @change="handleModeChange" /> | ||
189 | + <CardLayoutButton v-model:value="colNumber" @change="getDataSource" /> | ||
190 | + <Tooltip title="刷新"> | ||
191 | + <Button type="primary" @click="getDataSource"> | ||
192 | + <ReloadOutlined :spin="loading" /> | ||
193 | + </Button> | ||
194 | + </Tooltip> | ||
195 | + </div> | ||
196 | + </template> | ||
197 | + <template #renderItem="{ item }"> | ||
198 | + <List.Item> | ||
199 | + <Card | ||
200 | + hoverable | ||
201 | + @click="handleCheckCard(item)" | ||
202 | + :class="item.checked ? '!border-blue-500 !border-2' : ''" | ||
203 | + > | ||
204 | + <template #cover> | ||
205 | + <div class="h-full w-full !flex justify-center items-center text-center"> | ||
206 | + <Image | ||
207 | + @click.stop | ||
208 | + :height="144" | ||
209 | + :src="item.image" | ||
210 | + placeholder | ||
211 | + :fallback="IMAGE_FALLBACK" | ||
212 | + /> | ||
213 | + </div> | ||
214 | + </template> | ||
215 | + <template class="ant-card-actions" #actions> | ||
216 | + <Authority> | ||
217 | + <Tooltip title="详情"> | ||
218 | + <EyeOutlined key="setting" @click.stop="handleShowDetail(item)" /> | ||
219 | + </Tooltip> | ||
220 | + </Authority> | ||
221 | + <Authority> | ||
222 | + <Tooltip title="编辑"> | ||
223 | + <FormOutlined key="edit" @click.stop="handleUpdate(item)" /> | ||
224 | + </Tooltip> | ||
225 | + </Authority> | ||
226 | + <Dropdown | ||
227 | + :trigger="['hover']" | ||
228 | + :drop-menu-list="[ | ||
229 | + { | ||
230 | + text: '默认', | ||
231 | + event: DropMenuEvent.SET_DEFAULT, | ||
232 | + icon: 'ant-design:unordered-list-outlined', | ||
233 | + onClick: handleSetDefault.bind(null, item), | ||
234 | + }, | ||
235 | + { | ||
236 | + text: '删除', | ||
237 | + event: DropMenuEvent.DELETE, | ||
238 | + icon: 'ant-design:delete-outlined', | ||
239 | + onClick: handleDelete.bind(null, [item.id]), | ||
240 | + }, | ||
241 | + ]" | ||
242 | + > | ||
243 | + <MoreOutlined @click.stop class="transform rotate-90" /> | ||
244 | + </Dropdown> | ||
245 | + </template> | ||
246 | + <Card.Meta> | ||
247 | + <template #title> | ||
248 | + <span class="truncate"> {{ item.name }} </span> | ||
249 | + </template> | ||
250 | + <template #description> | ||
251 | + <div class="truncate h-11"> | ||
252 | + <div class="truncate">{{ DeviceTypeName[item.deviceType] }} </div> | ||
253 | + <div class="truncate">{{ item.transportType }} </div> | ||
254 | + </div> | ||
255 | + </template> | ||
256 | + </Card.Meta> | ||
257 | + </Card> | ||
258 | + </List.Item> | ||
259 | + </template> | ||
260 | + </List> | ||
261 | + </section> | ||
262 | + <DeviceProfileModal @register="registerModal" @success="getDataSource" /> | ||
263 | + <DeviceProfileDrawer @register="registerDrawer" /> | ||
264 | + </PageWrapper> | ||
265 | +</template> | ||
266 | + | ||
267 | +<style lang="less" scoped> | ||
268 | + .profile-list:deep(.ant-image-img) { | ||
269 | + width: 100% !important; | ||
270 | + height: 100% !important; | ||
271 | + } | ||
272 | +</style> |
src/views/device/profiles/TableMode.vue
0 → 100644
1 | +<template> | ||
2 | + <div> | ||
3 | + <BasicTable | ||
4 | + class="devide-profiles" | ||
5 | + @register="registerTable" | ||
6 | + :rowSelection="{ type: 'checkbox' }" | ||
7 | + :clickToRowSelect="false" | ||
8 | + > | ||
9 | + <template #toolbar> | ||
10 | + <Authority value="api:yt:deviceProfile:post"> | ||
11 | + <a-button type="primary" @click="handleCreate"> 新增产品 </a-button> | ||
12 | + </Authority> | ||
13 | + <Authority value="api:yt:deviceProfile:import"> | ||
14 | + <ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD"> | ||
15 | + <a-button @click="handleImport"> 导入产品 </a-button> | ||
16 | + </ImpExcel> | ||
17 | + </Authority> | ||
18 | + <Authority value="api:yt:deviceProfile:delete"> | ||
19 | + <Popconfirm | ||
20 | + title="您确定要批量删除数据" | ||
21 | + ok-text="确定" | ||
22 | + cancel-text="取消" | ||
23 | + @confirm="handleDeleteOrBatchDelete(null)" | ||
24 | + > | ||
25 | + <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | ||
26 | + </Popconfirm> | ||
27 | + </Authority> | ||
28 | + <ModeSwitchButton :value="$props.mode" @change="handleModeChange" /> | ||
29 | + </template> | ||
30 | + <template #img="{ record }"> | ||
31 | + <TableImg | ||
32 | + :size="30" | ||
33 | + :showBadge="false" | ||
34 | + :simpleShow="true" | ||
35 | + :imgList=" | ||
36 | + typeof record.image !== 'undefined' && record.image !== '' && record.image != null | ||
37 | + ? [record.image] | ||
38 | + : null | ||
39 | + " | ||
40 | + /> | ||
41 | + </template> | ||
42 | + <template #action="{ record }"> | ||
43 | + <TableAction | ||
44 | + :actions="[ | ||
45 | + { | ||
46 | + label: '详情', | ||
47 | + auth: 'api:yt:deviceProfile:get', | ||
48 | + icon: 'ant-design:eye-outlined', | ||
49 | + onClick: handleDetailView.bind(null, record), | ||
50 | + }, | ||
51 | + { | ||
52 | + label: '编辑', | ||
53 | + auth: 'api:yt:deviceProfile:update', | ||
54 | + icon: 'clarity:note-edit-line', | ||
55 | + onClick: handleEdit.bind(null, record), | ||
56 | + ifShow: () => { | ||
57 | + return record.name !== 'default' ? true : false; | ||
58 | + }, | ||
59 | + }, | ||
60 | + ]" | ||
61 | + :drop-down-actions="[ | ||
62 | + { | ||
63 | + label: '默认', | ||
64 | + icon: 'ant-design:profile-outlined', | ||
65 | + onClick: handleSetDefault.bind(null, record), | ||
66 | + ifShow: () => { | ||
67 | + return record.default === false; | ||
68 | + }, | ||
69 | + }, | ||
70 | + { | ||
71 | + label: '导出', | ||
72 | + auth: 'api:yt:deviceProfile:export', | ||
73 | + icon: 'ant-design:login-outlined', | ||
74 | + onClick: handleExport.bind(null, record), | ||
75 | + }, | ||
76 | + { | ||
77 | + label: '删除', | ||
78 | + auth: 'api:yt:deviceProfile:delete', | ||
79 | + icon: 'ant-design:delete-outlined', | ||
80 | + color: 'error', | ||
81 | + popConfirm: { | ||
82 | + title: '是否确认删除', | ||
83 | + confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
84 | + }, | ||
85 | + ifShow: () => { | ||
86 | + return record.default === false && record.name !== 'default'; | ||
87 | + }, | ||
88 | + }, | ||
89 | + ]" | ||
90 | + /> | ||
91 | + </template> | ||
92 | + </BasicTable> | ||
93 | + <DeviceProfileModal @register="registerModal" @success="handleSuccess" /> | ||
94 | + <DeviceProfileDrawer @register="registerDrawer" /> | ||
95 | + <ExpExcelModal | ||
96 | + ref="expExcelModalRef" | ||
97 | + @register="registerExportModal" | ||
98 | + @success="defaultHeader" | ||
99 | + /> | ||
100 | + </div> | ||
101 | +</template> | ||
102 | +<script lang="ts" setup> | ||
103 | + import { ref, nextTick, onUnmounted } from 'vue'; | ||
104 | + import { BasicTable, TableImg, useTable, TableAction, BasicColumn } from '/@/components/Table'; | ||
105 | + import { columns, searchFormSchema, defaultObj } from './device.profile.data'; | ||
106 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
107 | + import { | ||
108 | + deviceConfigGetQuery, | ||
109 | + deviceConfigDelete, | ||
110 | + setDeviceProfileIsDefaultApi, | ||
111 | + } from '/@/api/device/deviceConfigApi'; | ||
112 | + import { useModal } from '/@/components/Modal'; | ||
113 | + import { useDrawer } from '/@/components/Drawer'; | ||
114 | + import DeviceProfileModal from '/@/views/device/profiles/DeviceProfileModal.vue'; | ||
115 | + import { ImpExcel, ExcelData } from '/@/components/Excel'; | ||
116 | + import { jsonToSheetXlsx, ExpExcelModal, ExportModalResult } from '/@/components/Excel'; | ||
117 | + import { Authority } from '/@/components/Authority'; | ||
118 | + import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
119 | + import { Popconfirm } from 'ant-design-vue'; | ||
120 | + import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; | ||
121 | + import { Mode, ModeSwitchButton } from '/@/components/Widget'; | ||
122 | + | ||
123 | + defineProps<{ | ||
124 | + mode: Mode; | ||
125 | + }>(); | ||
126 | + | ||
127 | + const emit = defineEmits(['changeMode']); | ||
128 | + | ||
129 | + const exportData: any = ref([]); | ||
130 | + const expExcelModalRef: any = ref(null); | ||
131 | + const getPathUrl = ref(''); | ||
132 | + const getPathUrlName = ref(''); | ||
133 | + const disabled = ref(true); | ||
134 | + const onCloseVal = ref(0); | ||
135 | + const immediateStatus = ref(false); | ||
136 | + const { createMessage } = useMessage(); | ||
137 | + const [registerModal, { openModal }] = useModal(); | ||
138 | + const [registerExportModal, { openModal: openModalExcel }] = useModal(); | ||
139 | + const [registerTable, { setProps, reload, setTableData, getForm }] = useTable({ | ||
140 | + title: '产品列表', | ||
141 | + clickToRowSelect: false, | ||
142 | + api: deviceConfigGetQuery, | ||
143 | + immediate: immediateStatus.value, | ||
144 | + columns, | ||
145 | + formConfig: { | ||
146 | + labelWidth: 120, | ||
147 | + schemas: searchFormSchema, | ||
148 | + }, | ||
149 | + rowKey: 'id', | ||
150 | + useSearchForm: true, | ||
151 | + showTableSetting: true, | ||
152 | + bordered: true, | ||
153 | + showIndexColumn: false, | ||
154 | + actionColumn: { | ||
155 | + width: 200, | ||
156 | + title: '操作', | ||
157 | + dataIndex: 'action', | ||
158 | + slots: { customRender: 'action' }, | ||
159 | + fixed: 'right', | ||
160 | + }, | ||
161 | + }); | ||
162 | + const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | ||
163 | + deviceConfigDelete, | ||
164 | + handleSuccess, | ||
165 | + setProps | ||
166 | + ); | ||
167 | + selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | ||
168 | + // Demo:status为1的选择框禁用 | ||
169 | + if (record.default === true) { | ||
170 | + return { disabled: true }; | ||
171 | + } else if (record.name == 'default') { | ||
172 | + return { disabled: true }; | ||
173 | + } else { | ||
174 | + return { disabled: false }; | ||
175 | + } | ||
176 | + }; | ||
177 | + nextTick(() => { | ||
178 | + setProps(selectionOptions); | ||
179 | + }); | ||
180 | + /** | ||
181 | + *@param url,name | ||
182 | + **/ | ||
183 | + function getParam(url, name) { | ||
184 | + try { | ||
185 | + let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)'); | ||
186 | + let r = url.split('?')[1].match(reg); | ||
187 | + if (r != null) { | ||
188 | + return r[2]; | ||
189 | + } | ||
190 | + return ''; //如果此处只写return;则返回的是undefined | ||
191 | + } catch (e) { | ||
192 | + return ''; //如果此处只写return;则返回的是undefined | ||
193 | + } | ||
194 | + } | ||
195 | + getPathUrl.value = window.location.href; | ||
196 | + const name = 'name'; | ||
197 | + const getName = getParam(getPathUrl.value, name); | ||
198 | + getPathUrlName.value = decodeURIComponent(getName); | ||
199 | + | ||
200 | + const setRowClassName = async () => { | ||
201 | + if (getPathUrlName.value !== '') { | ||
202 | + const { items } = await deviceConfigGetQuery({ | ||
203 | + page: 1, | ||
204 | + pageSize: 10, | ||
205 | + name: getPathUrlName.value, | ||
206 | + }); | ||
207 | + nextTick(() => { | ||
208 | + setTableData(items); | ||
209 | + const { setFieldsValue, resetFields } = getForm(); | ||
210 | + setFieldsValue({ | ||
211 | + name: getPathUrlName.value, | ||
212 | + }); | ||
213 | + if (onCloseVal.value == 1) { | ||
214 | + resetFields(); | ||
215 | + } | ||
216 | + }); | ||
217 | + } else { | ||
218 | + setTimeout(() => { | ||
219 | + reload(); | ||
220 | + }, 80); | ||
221 | + } | ||
222 | + }; | ||
223 | + setRowClassName(); | ||
224 | + onUnmounted(() => { | ||
225 | + getPathUrlName.value = ''; | ||
226 | + onCloseVal.value = 1; | ||
227 | + }); | ||
228 | + const tableListRef = ref< | ||
229 | + { | ||
230 | + title: string; | ||
231 | + columns?: any[]; | ||
232 | + dataSource?: any[]; | ||
233 | + }[] | ||
234 | + >([]); | ||
235 | + | ||
236 | + function loadDataSuccess(excelDataList: ExcelData[]) { | ||
237 | + tableListRef.value = []; | ||
238 | + console.log(excelDataList); | ||
239 | + for (const excelData of excelDataList) { | ||
240 | + const { | ||
241 | + header, | ||
242 | + results, | ||
243 | + meta: { sheetName }, | ||
244 | + } = excelData; | ||
245 | + const columns: BasicColumn[] = []; | ||
246 | + for (const title of header) { | ||
247 | + columns.push({ title, dataIndex: title }); | ||
248 | + } | ||
249 | + tableListRef.value.push({ title: sheetName, dataSource: results, columns }); | ||
250 | + } | ||
251 | + } | ||
252 | + //新增 | ||
253 | + function handleCreate() { | ||
254 | + openModal(true, { | ||
255 | + isUpdate: false, | ||
256 | + }); | ||
257 | + } | ||
258 | + //编辑 | ||
259 | + function handleEdit(record: Recordable) { | ||
260 | + openModal(true, { | ||
261 | + record, | ||
262 | + isUpdate: true, | ||
263 | + }); | ||
264 | + } | ||
265 | + | ||
266 | + const [registerDrawer, { openDrawer }] = useDrawer(); | ||
267 | + //详情 | ||
268 | + function handleDetailView(record: Recordable) { | ||
269 | + openDrawer(true, { record }); | ||
270 | + } | ||
271 | + | ||
272 | + function defaultHeader({ filename, bookType }: ExportModalResult) { | ||
273 | + // 默认Object.keys(data[0])作为header | ||
274 | + const data = exportData.value; | ||
275 | + jsonToSheetXlsx({ | ||
276 | + data, | ||
277 | + filename, | ||
278 | + write2excelOpts: { | ||
279 | + bookType, | ||
280 | + }, | ||
281 | + }); | ||
282 | + } | ||
283 | + //导出 | ||
284 | + const handleExport = (record: Recordable) => { | ||
285 | + exportData.value = []; | ||
286 | + exportData.value.push({ | ||
287 | + createTime: record.createTime, | ||
288 | + description: record.description, | ||
289 | + name: record.name, | ||
290 | + }); | ||
291 | + nextTick(() => { | ||
292 | + openModalExcel(); | ||
293 | + expExcelModalRef.value?.clearFieldFunc(); | ||
294 | + }); | ||
295 | + }; | ||
296 | + //导入 | ||
297 | + function handleImport() { | ||
298 | + console.log('record'); | ||
299 | + } | ||
300 | + function handleSuccess() { | ||
301 | + reload(); | ||
302 | + } | ||
303 | + | ||
304 | + const handleSetDefault = async (record: Recordable) => { | ||
305 | + let id = record.tbProfileId; | ||
306 | + const data = await setDeviceProfileIsDefaultApi(id, 'default', defaultObj); | ||
307 | + if (!data) return createMessage.error('设置该产品为默认失败'); | ||
308 | + createMessage.success('设置该产品为默认成功'); | ||
309 | + reload(); | ||
310 | + disabled.value = true; | ||
311 | + }; | ||
312 | + | ||
313 | + const handleModeChange = (value: Mode) => { | ||
314 | + emit('changeMode', value); | ||
315 | + }; | ||
316 | +</script> | ||
317 | + | ||
318 | +<style lang="css"> | ||
319 | + .devide-profiles .rowcolor { | ||
320 | + color: red; | ||
321 | + } | ||
322 | + | ||
323 | + .devide-profiles .rowcolor2 { | ||
324 | + background: #a2c3e6; | ||
325 | + } | ||
326 | +</style> |
@@ -9,6 +9,17 @@ import { FormField, FunctionType } from './step/cpns/physical/cpns/config'; | @@ -9,6 +9,17 @@ import { FormField, FunctionType } from './step/cpns/physical/cpns/config'; | ||
9 | import { h } from 'vue'; | 9 | import { h } from 'vue'; |
10 | import { Tag } from 'ant-design-vue'; | 10 | import { Tag } from 'ant-design-vue'; |
11 | 11 | ||
12 | +export enum Mode { | ||
13 | + CARD = 'card', | ||
14 | + TABLE = 'table', | ||
15 | +} | ||
16 | + | ||
17 | +export enum DeviceTypeName { | ||
18 | + DIRECT_CONNECTION = '直连设备', | ||
19 | + GATEWAY = '网关设备', | ||
20 | + SENSOR = '网关子设备', | ||
21 | +} | ||
22 | + | ||
12 | export enum ModelOfMatterPermission { | 23 | export enum ModelOfMatterPermission { |
13 | CREATE = 'api:yt:things_model:post', | 24 | CREATE = 'api:yt:things_model:post', |
14 | UPDATE = 'api:yt:things_model:put', | 25 | UPDATE = 'api:yt:things_model:put', |
1 | -<template> | ||
2 | - <div> | ||
3 | - <BasicTable | ||
4 | - class="devide-profiles" | ||
5 | - @register="registerTable" | ||
6 | - :rowSelection="{ type: 'checkbox' }" | ||
7 | - :clickToRowSelect="false" | ||
8 | - > | ||
9 | - <template #toolbar> | ||
10 | - <Authority value="api:yt:deviceProfile:post"> | ||
11 | - <a-button type="primary" @click="handleCreate"> 新增产品 </a-button> | ||
12 | - </Authority> | ||
13 | - <Authority value="api:yt:deviceProfile:import"> | ||
14 | - <ImpExcel @success="loadDataSuccess" dateFormat="YYYY-MM-DD"> | ||
15 | - <a-button @click="handleImport"> 导入产品 </a-button> | ||
16 | - </ImpExcel> | ||
17 | - </Authority> | ||
18 | - <Authority value="api:yt:deviceProfile:delete"> | ||
19 | - <Popconfirm | ||
20 | - title="您确定要批量删除数据" | ||
21 | - ok-text="确定" | ||
22 | - cancel-text="取消" | ||
23 | - @confirm="handleDeleteOrBatchDelete(null)" | ||
24 | - > | ||
25 | - <a-button type="primary" color="error" :disabled="hasBatchDelete"> 批量删除 </a-button> | ||
26 | - </Popconfirm> | ||
27 | - </Authority> | ||
28 | - </template> | ||
29 | - <template #img="{ record }"> | ||
30 | - <TableImg | ||
31 | - :size="30" | ||
32 | - :showBadge="false" | ||
33 | - :simpleShow="true" | ||
34 | - :imgList=" | ||
35 | - typeof record.image !== 'undefined' && record.image !== '' && record.image != null | ||
36 | - ? [record.image] | ||
37 | - : null | ||
38 | - " | ||
39 | - /> | ||
40 | - </template> | ||
41 | - <template #action="{ record }"> | ||
42 | - <TableAction | ||
43 | - :actions="[ | ||
44 | - { | ||
45 | - label: '详情', | ||
46 | - auth: 'api:yt:deviceProfile:get', | ||
47 | - icon: 'ant-design:eye-outlined', | ||
48 | - onClick: handleDetailView.bind(null, record), | ||
49 | - }, | ||
50 | - { | ||
51 | - label: '编辑', | ||
52 | - auth: 'api:yt:deviceProfile:update', | ||
53 | - icon: 'clarity:note-edit-line', | ||
54 | - onClick: handleEdit.bind(null, record), | ||
55 | - ifShow: () => { | ||
56 | - return record.name !== 'default' ? true : false; | ||
57 | - }, | ||
58 | - }, | ||
59 | - ]" | ||
60 | - :drop-down-actions="[ | ||
61 | - { | ||
62 | - label: '默认', | ||
63 | - icon: 'ant-design:profile-outlined', | ||
64 | - onClick: handleSetDefault.bind(null, record), | ||
65 | - ifShow: () => { | ||
66 | - return record.default === false; | ||
67 | - }, | ||
68 | - }, | ||
69 | - { | ||
70 | - label: '导出', | ||
71 | - auth: 'api:yt:deviceProfile:export', | ||
72 | - icon: 'ant-design:login-outlined', | ||
73 | - onClick: handleExport.bind(null, record), | ||
74 | - }, | ||
75 | - { | ||
76 | - label: '删除', | ||
77 | - auth: 'api:yt:deviceProfile:delete', | ||
78 | - icon: 'ant-design:delete-outlined', | ||
79 | - color: 'error', | ||
80 | - popConfirm: { | ||
81 | - title: '是否确认删除', | ||
82 | - confirm: handleDeleteOrBatchDelete.bind(null, record), | ||
83 | - }, | ||
84 | - ifShow: () => { | ||
85 | - return record.default === false && record.name !== 'default'; | ||
86 | - }, | ||
87 | - }, | ||
88 | - ]" | ||
89 | - /> | ||
90 | - </template> | ||
91 | - </BasicTable> | ||
92 | - <DeviceProfileModal @register="registerModal" @success="handleSuccess" /> | ||
93 | - <DeviceProfileDrawer @register="registerDrawer" /> | ||
94 | - <ExpExcelModal | ||
95 | - ref="expExcelModalRef" | ||
96 | - @register="registerExportModal" | ||
97 | - @success="defaultHeader" | ||
98 | - /> | ||
99 | - </div> | ||
100 | -</template> | ||
101 | <script lang="ts" setup> | 1 | <script lang="ts" setup> |
102 | - import { ref, nextTick, onUnmounted } from 'vue'; | ||
103 | - import { BasicTable, TableImg, useTable, TableAction, BasicColumn } from '/@/components/Table'; | ||
104 | - import { columns, searchFormSchema, defaultObj } from './device.profile.data'; | ||
105 | - import { useMessage } from '/@/hooks/web/useMessage'; | ||
106 | - import { | ||
107 | - deviceConfigGetQuery, | ||
108 | - deviceConfigDelete, | ||
109 | - setDeviceProfileIsDefaultApi, | ||
110 | - } from '/@/api/device/deviceConfigApi'; | ||
111 | - import { useModal } from '/@/components/Modal'; | ||
112 | - import { useDrawer } from '/@/components/Drawer'; | ||
113 | - import DeviceProfileModal from '/@/views/device/profiles/DeviceProfileModal.vue'; | ||
114 | - import { ImpExcel, ExcelData } from '/@/components/Excel'; | ||
115 | - import { jsonToSheetXlsx, ExpExcelModal, ExportModalResult } from '/@/components/Excel'; | ||
116 | - import { Authority } from '/@/components/Authority'; | ||
117 | - import { useBatchDelete } from '/@/hooks/web/useBatchDelete'; | ||
118 | - import { Popconfirm } from 'ant-design-vue'; | ||
119 | - import DeviceProfileDrawer from './DeviceProfileDrawer.vue'; | ||
120 | - | ||
121 | - const exportData: any = ref([]); | ||
122 | - const expExcelModalRef: any = ref(null); | ||
123 | - const getPathUrl = ref(''); | ||
124 | - const getPathUrlName = ref(''); | ||
125 | - const disabled = ref(true); | ||
126 | - const onCloseVal = ref(0); | ||
127 | - const immediateStatus = ref(false); | ||
128 | - const { createMessage } = useMessage(); | ||
129 | - const [registerModal, { openModal }] = useModal(); | ||
130 | - const [registerExportModal, { openModal: openModalExcel }] = useModal(); | ||
131 | - const [registerTable, { setProps, reload, setTableData, getForm }] = useTable({ | ||
132 | - title: '产品列表', | ||
133 | - clickToRowSelect: false, | ||
134 | - api: deviceConfigGetQuery, | ||
135 | - immediate: immediateStatus.value, | ||
136 | - columns, | ||
137 | - formConfig: { | ||
138 | - labelWidth: 120, | ||
139 | - schemas: searchFormSchema, | ||
140 | - }, | ||
141 | - rowKey: 'id', | ||
142 | - useSearchForm: true, | ||
143 | - showTableSetting: true, | ||
144 | - bordered: true, | ||
145 | - showIndexColumn: false, | ||
146 | - actionColumn: { | ||
147 | - width: 200, | ||
148 | - title: '操作', | ||
149 | - dataIndex: 'action', | ||
150 | - slots: { customRender: 'action' }, | ||
151 | - fixed: 'right', | ||
152 | - }, | ||
153 | - }); | ||
154 | - const { hasBatchDelete, handleDeleteOrBatchDelete, selectionOptions } = useBatchDelete( | ||
155 | - deviceConfigDelete, | ||
156 | - handleSuccess, | ||
157 | - setProps | ||
158 | - ); | ||
159 | - selectionOptions.rowSelection.getCheckboxProps = (record: Recordable) => { | ||
160 | - // Demo:status为1的选择框禁用 | ||
161 | - if (record.default === true) { | ||
162 | - return { disabled: true }; | ||
163 | - } else if (record.name == 'default') { | ||
164 | - return { disabled: true }; | ||
165 | - } else { | ||
166 | - return { disabled: false }; | ||
167 | - } | ||
168 | - }; | ||
169 | - nextTick(() => { | ||
170 | - setProps(selectionOptions); | ||
171 | - }); | ||
172 | - /** | ||
173 | - *@param url,name | ||
174 | - **/ | ||
175 | - function getParam(url, name) { | ||
176 | - try { | ||
177 | - let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)'); | ||
178 | - let r = url.split('?')[1].match(reg); | ||
179 | - if (r != null) { | ||
180 | - return r[2]; | ||
181 | - } | ||
182 | - return ''; //如果此处只写return;则返回的是undefined | ||
183 | - } catch (e) { | ||
184 | - return ''; //如果此处只写return;则返回的是undefined | ||
185 | - } | ||
186 | - } | ||
187 | - getPathUrl.value = window.location.href; | ||
188 | - const name = 'name'; | ||
189 | - const getName = getParam(getPathUrl.value, name); | ||
190 | - getPathUrlName.value = decodeURIComponent(getName); | ||
191 | - | ||
192 | - const setRowClassName = async () => { | ||
193 | - if (getPathUrlName.value !== '') { | ||
194 | - const { items } = await deviceConfigGetQuery({ | ||
195 | - page: 1, | ||
196 | - pageSize: 10, | ||
197 | - name: getPathUrlName.value, | ||
198 | - }); | ||
199 | - nextTick(() => { | ||
200 | - setTableData(items); | ||
201 | - const { setFieldsValue, resetFields } = getForm(); | ||
202 | - setFieldsValue({ | ||
203 | - name: getPathUrlName.value, | ||
204 | - }); | ||
205 | - if (onCloseVal.value == 1) { | ||
206 | - resetFields(); | ||
207 | - } | ||
208 | - }); | ||
209 | - } else { | ||
210 | - setTimeout(() => { | ||
211 | - reload(); | ||
212 | - }, 80); | ||
213 | - } | ||
214 | - }; | ||
215 | - setRowClassName(); | ||
216 | - onUnmounted(() => { | ||
217 | - getPathUrlName.value = ''; | ||
218 | - onCloseVal.value = 1; | ||
219 | - }); | ||
220 | - const tableListRef = ref< | ||
221 | - { | ||
222 | - title: string; | ||
223 | - columns?: any[]; | ||
224 | - dataSource?: any[]; | ||
225 | - }[] | ||
226 | - >([]); | ||
227 | - | ||
228 | - function loadDataSuccess(excelDataList: ExcelData[]) { | ||
229 | - tableListRef.value = []; | ||
230 | - console.log(excelDataList); | ||
231 | - for (const excelData of excelDataList) { | ||
232 | - const { | ||
233 | - header, | ||
234 | - results, | ||
235 | - meta: { sheetName }, | ||
236 | - } = excelData; | ||
237 | - const columns: BasicColumn[] = []; | ||
238 | - for (const title of header) { | ||
239 | - columns.push({ title, dataIndex: title }); | ||
240 | - } | ||
241 | - tableListRef.value.push({ title: sheetName, dataSource: results, columns }); | ||
242 | - } | ||
243 | - } | ||
244 | - //新增 | ||
245 | - function handleCreate() { | ||
246 | - openModal(true, { | ||
247 | - isUpdate: false, | ||
248 | - }); | ||
249 | - } | ||
250 | - //编辑 | ||
251 | - function handleEdit(record: Recordable) { | ||
252 | - openModal(true, { | ||
253 | - record, | ||
254 | - isUpdate: true, | ||
255 | - }); | ||
256 | - } | ||
257 | - | ||
258 | - const [registerDrawer, { openDrawer }] = useDrawer(); | ||
259 | - //详情 | ||
260 | - function handleDetailView(record: Recordable) { | ||
261 | - openDrawer(true, { record }); | ||
262 | - } | ||
263 | - | ||
264 | - function defaultHeader({ filename, bookType }: ExportModalResult) { | ||
265 | - // 默认Object.keys(data[0])作为header | ||
266 | - const data = exportData.value; | ||
267 | - jsonToSheetXlsx({ | ||
268 | - data, | ||
269 | - filename, | ||
270 | - write2excelOpts: { | ||
271 | - bookType, | ||
272 | - }, | ||
273 | - }); | ||
274 | - } | ||
275 | - //导出 | ||
276 | - const handleExport = (record: Recordable) => { | ||
277 | - exportData.value = []; | ||
278 | - exportData.value.push({ | ||
279 | - createTime: record.createTime, | ||
280 | - description: record.description, | ||
281 | - name: record.name, | ||
282 | - }); | ||
283 | - nextTick(() => { | ||
284 | - openModalExcel(); | ||
285 | - expExcelModalRef.value?.clearFieldFunc(); | ||
286 | - }); | ||
287 | - }; | ||
288 | - //导入 | ||
289 | - function handleImport() { | ||
290 | - console.log('record'); | ||
291 | - } | ||
292 | - function handleSuccess() { | ||
293 | - reload(); | ||
294 | - } | ||
295 | - | ||
296 | - const handleSetDefault = async (record: Recordable) => { | ||
297 | - let id = record.tbProfileId; | ||
298 | - const data = await setDeviceProfileIsDefaultApi(id, 'default', defaultObj); | ||
299 | - if (!data) return createMessage.error('设置该产品为默认失败'); | ||
300 | - createMessage.success('设置该产品为默认成功'); | ||
301 | - reload(); | ||
302 | - disabled.value = true; | 2 | + import { ref } from 'vue'; |
3 | + import TableMode from './TableMode.vue'; | ||
4 | + import CardMode from './CardMode.vue'; | ||
5 | + import { Mode } from '/@/components/Widget'; | ||
6 | + const mode = ref(Mode.CARD); | ||
7 | + | ||
8 | + const handleChangeMode = (flag: Mode) => { | ||
9 | + mode.value = flag; | ||
303 | }; | 10 | }; |
304 | </script> | 11 | </script> |
305 | 12 | ||
306 | -<style lang="css"> | ||
307 | - .devide-profiles .rowcolor { | ||
308 | - color: red; | ||
309 | - } | ||
310 | - | ||
311 | - .devide-profiles .rowcolor2 { | ||
312 | - background: #a2c3e6; | ||
313 | - } | ||
314 | -</style> | 13 | +<template> |
14 | + <section> | ||
15 | + <CardMode v-if="mode === Mode.CARD" :mode="mode" @change-mode="handleChangeMode" /> | ||
16 | + <TableMode v-if="mode === Mode.TABLE" :mode="mode" @change-mode="handleChangeMode" /> | ||
17 | + </section> | ||
18 | +</template> |