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 | 2 | import { |
3 | 3 | TDeviceConfigParams, |
4 | 4 | IDeviceConfigAddOrEditModel, |
5 | + ProfileRecord, | |
5 | 6 | } from '/@/api/device/model/deviceConfigModel'; |
7 | +import { PaginationResult } from '/#/axios'; | |
6 | 8 | |
7 | 9 | enum EDeviceConfigApi { |
8 | 10 | /** |
... | ... | @@ -52,7 +54,7 @@ export const alarmContactGetPage = () => { |
52 | 54 | * 分页查询设备配置页面 |
53 | 55 | */ |
54 | 56 | export const deviceConfigGetQuery = (params?: TDeviceConfigParams) => { |
55 | - return defHttp.get({ | |
57 | + return defHttp.get<PaginationResult<ProfileRecord>>({ | |
56 | 58 | url: EDeviceConfigApi.DEVICE_CONFIG_GET_PAGE, |
57 | 59 | params, |
58 | 60 | }); | ... | ... |
... | ... | @@ -199,3 +199,45 @@ export interface AlarmLogItem { |
199 | 199 | organizationId: string; |
200 | 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 | 9 | import { h } from 'vue'; |
10 | 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 | 23 | export enum ModelOfMatterPermission { |
13 | 24 | CREATE = 'api:yt:things_model:post', |
14 | 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 | 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 | 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> | ... | ... |