Commit 3f7fc1aaa1f29c6a492d736e32f183c66a729528
Merge branch 'feat_device_access' into 'main_dev'
feat: 新增设备接入信息功能 See merge request yunteng/thingskit-front!1217
Showing
10 changed files
with
639 additions
and
0 deletions
src/api/device/deviceAccess.ts
0 → 100644
1 | +import { defHttp } from '/@/utils/http/axios'; | ||
2 | + | ||
3 | +enum Api { | ||
4 | + DEVICE_PROFILE_ACCESS_INFORMATIION = '/device_profile/access_information', | ||
5 | +} | ||
6 | + | ||
7 | +/** | ||
8 | + * 新增设备接入信息 | ||
9 | + */ | ||
10 | +export const deviceProfileAccessInformation = (params) => { | ||
11 | + return defHttp.post<any>({ | ||
12 | + url: `${Api.DEVICE_PROFILE_ACCESS_INFORMATIION}`, | ||
13 | + params, | ||
14 | + }); | ||
15 | +}; | ||
16 | + | ||
17 | +/** | ||
18 | + * 获取设备接入信息列表 | ||
19 | + */ | ||
20 | +export const getDeviceAccessInformationList = (params) => { | ||
21 | + return defHttp.get<any>({ | ||
22 | + url: Api.DEVICE_PROFILE_ACCESS_INFORMATIION, | ||
23 | + params, | ||
24 | + }); | ||
25 | +}; | ||
26 | + | ||
27 | +/** | ||
28 | + * 删除设备接入信息 | ||
29 | + */ | ||
30 | +export const deleteDeviceAccessInformation = (params) => { | ||
31 | + return defHttp.delete<any>({ | ||
32 | + url: Api.DEVICE_PROFILE_ACCESS_INFORMATIION, | ||
33 | + params, | ||
34 | + }); | ||
35 | +}; |
@@ -41,6 +41,7 @@ import InputGroup from './components/InputGroup.vue'; | @@ -41,6 +41,7 @@ import InputGroup from './components/InputGroup.vue'; | ||
41 | import RegisterAddressInput from '/@/views/task/center/components/PollCommandInput/RegisterAddressInput.vue'; | 41 | import RegisterAddressInput from '/@/views/task/center/components/PollCommandInput/RegisterAddressInput.vue'; |
42 | import DeviceProfileForm from '/@/components/Form/src/components/DeviceProfileForm/index.vue'; | 42 | import DeviceProfileForm from '/@/components/Form/src/components/DeviceProfileForm/index.vue'; |
43 | import { Segmented } from './components/Segmented'; | 43 | import { Segmented } from './components/Segmented'; |
44 | +import FormInputGroup from './components/FormInputGroup.vue'; | ||
44 | 45 | ||
45 | const componentMap = new Map<ComponentType, Component>(); | 46 | const componentMap = new Map<ComponentType, Component>(); |
46 | 47 | ||
@@ -89,6 +90,7 @@ componentMap.set('ApiSelectScrollLoad', ApiSelectScrollLoad); | @@ -89,6 +90,7 @@ componentMap.set('ApiSelectScrollLoad', ApiSelectScrollLoad); | ||
89 | componentMap.set('InputGroup', InputGroup); | 90 | componentMap.set('InputGroup', InputGroup); |
90 | componentMap.set('RegisterAddressInput', RegisterAddressInput); | 91 | componentMap.set('RegisterAddressInput', RegisterAddressInput); |
91 | componentMap.set('DeviceProfileForm', DeviceProfileForm); | 92 | componentMap.set('DeviceProfileForm', DeviceProfileForm); |
93 | +componentMap.set('FormInputGroup', FormInputGroup); | ||
92 | 94 | ||
93 | export function add(compName: ComponentType, component: Component) { | 95 | export function add(compName: ComponentType, component: Component) { |
94 | componentMap.set(compName, component); | 96 | componentMap.set(compName, component); |
1 | +<template> | ||
2 | + <div class="form-input"> | ||
3 | + <!-- 简易封装InputGroup --> | ||
4 | + <!-- 待完善封装InputGroup --> | ||
5 | + <InputGroup compact> | ||
6 | + <Input | ||
7 | + :placeholder="inputPlaceholder" | ||
8 | + v-model:value="inputReactive.inputIp" | ||
9 | + @change="emitChange" | ||
10 | + style="width: 42%" | ||
11 | + :maxlength="255" | ||
12 | + /> | ||
13 | + <InputNumber | ||
14 | + :min="1" | ||
15 | + :max="65535" | ||
16 | + :placeholder="inputNumberPlaceholder" | ||
17 | + v-model:value="inputReactive.inputPort" | ||
18 | + @change="emitChange" | ||
19 | + /> | ||
20 | + </InputGroup> | ||
21 | + </div> | ||
22 | +</template> | ||
23 | +<script lang="ts" setup> | ||
24 | + import { PropType, reactive, watch } from 'vue'; | ||
25 | + import { InputGroup, Input, InputNumber } from 'ant-design-vue'; | ||
26 | + | ||
27 | + interface inputReactive { | ||
28 | + inputIp: string; | ||
29 | + inputPort: number | string | undefined; | ||
30 | + } | ||
31 | + | ||
32 | + const props = defineProps({ | ||
33 | + value: Object as PropType<{}>, | ||
34 | + inputPlaceholder: { | ||
35 | + type: String, | ||
36 | + default: '请输入ip', | ||
37 | + }, | ||
38 | + inputNumberPlaceholder: { | ||
39 | + type: String, | ||
40 | + default: '端口', | ||
41 | + }, | ||
42 | + }); | ||
43 | + | ||
44 | + const emits = defineEmits(['change', 'update:value']); | ||
45 | + | ||
46 | + const inputReactive = reactive<inputReactive>({ | ||
47 | + inputIp: '', | ||
48 | + inputPort: undefined, | ||
49 | + }); | ||
50 | + | ||
51 | + watch( | ||
52 | + () => props.value, | ||
53 | + () => { | ||
54 | + setValues(); | ||
55 | + }, | ||
56 | + { | ||
57 | + immediate: true, | ||
58 | + } | ||
59 | + ); | ||
60 | + | ||
61 | + function setValues() { | ||
62 | + if (props?.value) for (let i in props.value) Reflect.set(inputReactive, i, props.value[i]); | ||
63 | + } | ||
64 | + | ||
65 | + function emitChange() { | ||
66 | + emits('change', inputReactive); | ||
67 | + emits('update:value', inputReactive); | ||
68 | + } | ||
69 | +</script> | ||
70 | + | ||
71 | +<style lang="less" scoped> | ||
72 | + .form-input { | ||
73 | + :deep .ant-input-number { | ||
74 | + width: 29% !important; | ||
75 | + } | ||
76 | + } | ||
77 | +</style> |
@@ -208,6 +208,22 @@ export const CameraChannelNoRule: Rule[] = [ | @@ -208,6 +208,22 @@ export const CameraChannelNoRule: Rule[] = [ | ||
208 | }, | 208 | }, |
209 | ]; | 209 | ]; |
210 | 210 | ||
211 | +// 验证ip地址正则 | ||
212 | +export const IpRule: Rule[] = [ | ||
213 | + { | ||
214 | + required: true, | ||
215 | + validator: (_, value: string) => { | ||
216 | + const ipRegex = | ||
217 | + /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; | ||
218 | + if (!ipRegex.test(value)) { | ||
219 | + return Promise.reject('请输入正确格式的ip'); | ||
220 | + } | ||
221 | + return Promise.resolve(); | ||
222 | + }, | ||
223 | + validateTrigger: 'blur', | ||
224 | + }, | ||
225 | +]; | ||
226 | + | ||
211 | export const CameraVideoStreamUrl: Rule[] = [ | 227 | export const CameraVideoStreamUrl: Rule[] = [ |
212 | { | 228 | { |
213 | required: true, | 229 | required: true, |
@@ -423,3 +439,6 @@ export const MediaTypeValidate: Rule[] = [ | @@ -423,3 +439,6 @@ export const MediaTypeValidate: Rule[] = [ | ||
423 | validateTrigger: 'blur', | 439 | validateTrigger: 'blur', |
424 | }, | 440 | }, |
425 | ]; | 441 | ]; |
442 | + | ||
443 | +export const ipRegex = | ||
444 | + /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/; |
1 | +<template> | ||
2 | + <BasicDrawer v-bind="$attrs" @register="registerDrawer" title="设备接入信息详情" width="25%"> | ||
3 | + <Description :column="3" size="middle" @register="registeDesc" /> | ||
4 | + </BasicDrawer> | ||
5 | +</template> | ||
6 | +<script lang="ts" setup> | ||
7 | + import { detailSchema } from '../index'; | ||
8 | + import { BasicDrawer, useDrawerInner } from '/@/components/Drawer'; | ||
9 | + import { Description } from '/@/components/Description/index'; | ||
10 | + import { useDescription } from '/@/components/Description'; | ||
11 | + | ||
12 | + defineEmits(['success', 'register']); | ||
13 | + | ||
14 | + const [registeDesc, { setDescProps }] = useDescription({ | ||
15 | + schema: detailSchema, | ||
16 | + column: 2, | ||
17 | + layout: 'vertical', | ||
18 | + }); | ||
19 | + | ||
20 | + const [registerDrawer, { setDrawerProps }] = useDrawerInner(async (data) => { | ||
21 | + setDrawerProps({ confirmLoading: false }); | ||
22 | + const dataValue = { | ||
23 | + ...data, | ||
24 | + ...data.sipExtend, | ||
25 | + }; | ||
26 | + setDescProps({ data: dataValue }); | ||
27 | + }); | ||
28 | +</script> |
1 | +<script setup lang="ts"> | ||
2 | + import { computed, unref } from 'vue'; | ||
3 | + import { ref } from 'vue'; | ||
4 | + import { BasicModal, useModalInner } from '/@/components/Modal'; | ||
5 | + import { deleteFormField, schemas } from '../index'; | ||
6 | + import { useForm, BasicForm } from '/@/components/Form'; | ||
7 | + import { deviceProfileAccessInformation } from '/@/api/device/deviceAccess'; | ||
8 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
9 | + import { ipRegex } from '/@/utils/rules'; | ||
10 | + | ||
11 | + const emit = defineEmits(['handleReload', 'register']); | ||
12 | + | ||
13 | + const isUpdate = ref<Boolean>(false); | ||
14 | + | ||
15 | + const getTitle = computed(() => (!unref(isUpdate) ? '新增设备接入信息' : '编辑设备接入信息')); | ||
16 | + | ||
17 | + const { createMessage } = useMessage(); | ||
18 | + | ||
19 | + const [registerForm, { getFieldsValue, setFieldsValue, validate }] = useForm({ | ||
20 | + labelWidth: 150, | ||
21 | + schemas, | ||
22 | + actionColOptions: { | ||
23 | + span: 14, | ||
24 | + }, | ||
25 | + showActionButtonGroup: false, | ||
26 | + }); | ||
27 | + | ||
28 | + const recordInfo = ref<Recordable>({}); | ||
29 | + | ||
30 | + const [register, { closeModal, setModalProps }] = useModalInner(async (data) => { | ||
31 | + setModalProps({ confirmLoading: false, loading: true }); | ||
32 | + isUpdate.value = data?.isUpdate; | ||
33 | + recordInfo.value = data?.record; | ||
34 | + if (data?.record) { | ||
35 | + const intranetIpAndPort = { | ||
36 | + inputIp: data?.record.intranetIp, | ||
37 | + inputPort: data?.record.intranetPort, | ||
38 | + }; | ||
39 | + const outerIpAndPort = { | ||
40 | + inputIp: data?.record.outerNetIp, | ||
41 | + inputPort: data?.record.outerNetPort, | ||
42 | + }; | ||
43 | + setFieldsValue(data?.record); | ||
44 | + setFieldsValue({ ...data?.record?.sipExtend }); | ||
45 | + setFieldsValue({ intranetIpAndPort, outerIpAndPort }); | ||
46 | + } | ||
47 | + setModalProps({ loading: false }); | ||
48 | + }); | ||
49 | + | ||
50 | + const handleCancel = () => closeModal(); | ||
51 | + | ||
52 | + const handleOk = async () => { | ||
53 | + await validate(); | ||
54 | + let values = getFieldsValue(); | ||
55 | + if (unref(isUpdate)) { | ||
56 | + values = { ...values, id: unref(recordInfo).id }; | ||
57 | + } | ||
58 | + const { intranetIpAndPort, outerIpAndPort } = values; | ||
59 | + values.intranetIp = intranetIpAndPort.inputIp; | ||
60 | + values.intranetPort = intranetIpAndPort.inputPort; | ||
61 | + values.outerNetIp = outerIpAndPort.inputIp; | ||
62 | + values.outerNetPort = outerIpAndPort.inputPort; | ||
63 | + if (!ipRegex.test(values.intranetIp)) { | ||
64 | + return createMessage.error('请输入正确格式的ip'); | ||
65 | + } | ||
66 | + if (!ipRegex.test(values.outerNetIp)) { | ||
67 | + return createMessage.error('请输入正确格式的ip'); | ||
68 | + } | ||
69 | + if (!values.intranetPort) { | ||
70 | + return createMessage.error('请输入内网端口'); | ||
71 | + } | ||
72 | + if (!values.outerNetPort) { | ||
73 | + return createMessage.error('请输入外网端口'); | ||
74 | + } | ||
75 | + const sipExtend = { | ||
76 | + serverId: values['serverId'], | ||
77 | + serverDomain: values['serverDomain'], | ||
78 | + serverPassword: values['serverPassword'], | ||
79 | + }; | ||
80 | + values.sipExtend = sipExtend; | ||
81 | + deleteFormField.forEach((deleteItem) => { | ||
82 | + Reflect.deleteProperty(values, deleteItem); | ||
83 | + }); | ||
84 | + await deviceProfileAccessInformation(values); | ||
85 | + createMessage.success('操作成功'); | ||
86 | + emit('handleReload'); | ||
87 | + handleCancel(); | ||
88 | + }; | ||
89 | +</script> | ||
90 | + | ||
91 | +<template> | ||
92 | + <div> | ||
93 | + <BasicModal | ||
94 | + v-bind="$attrs" | ||
95 | + width="35rem" | ||
96 | + :title="getTitle" | ||
97 | + @register="register" | ||
98 | + @cancel="handleCancel" | ||
99 | + @ok="handleOk" | ||
100 | + destroyOnClose | ||
101 | + > | ||
102 | + <div> | ||
103 | + <BasicForm @register="registerForm" /> | ||
104 | + </div> | ||
105 | + </BasicModal> | ||
106 | + </div> | ||
107 | +</template> |
src/views/device/deviceaccess/index.ts
0 → 100644
1 | +import { DescItem } from '/@/components/Description/src/typing'; | ||
2 | +import { BasicColumn, FormSchema } from '/@/components/Table'; | ||
3 | + | ||
4 | +//设备接入信息权限标识枚举 | ||
5 | +export enum DEVICE_ACCESS_PERMISSION_ENUM { | ||
6 | + CREATE = 'api:yt:device_profile:access_information:post', | ||
7 | + UPDATE = 'api:yt:device_profile:access_information:update', | ||
8 | + DELETE = 'api:yt:device_profile:access_information:delete', | ||
9 | + GET = 'api:yt:device_profile:access_information:get', | ||
10 | +} | ||
11 | + | ||
12 | +//要删除的表单字段 | ||
13 | +export const deleteFormField = [ | ||
14 | + 'serverId', | ||
15 | + 'serverDomain', | ||
16 | + 'serverPassword', | ||
17 | + 'intranetIpAndPort', | ||
18 | + 'outerIpAndPort', | ||
19 | +]; | ||
20 | + | ||
21 | +//表格字段 | ||
22 | +export const columns: BasicColumn[] = [ | ||
23 | + { | ||
24 | + title: '内网ip', | ||
25 | + dataIndex: 'intranetIp', | ||
26 | + }, | ||
27 | + { | ||
28 | + title: '内网端口', | ||
29 | + dataIndex: 'intranetPort', | ||
30 | + }, | ||
31 | + { | ||
32 | + title: '外网ip', | ||
33 | + dataIndex: 'outerNetIp', | ||
34 | + }, | ||
35 | + { | ||
36 | + title: '外网端口', | ||
37 | + dataIndex: 'outerNetPort', | ||
38 | + }, | ||
39 | + { | ||
40 | + title: '接入协议', | ||
41 | + dataIndex: 'deviceAgreement', | ||
42 | + }, | ||
43 | +]; | ||
44 | + | ||
45 | +//表单查询 | ||
46 | +export const searchFormSchema: FormSchema[] = [ | ||
47 | + { | ||
48 | + field: 'intranetIp', | ||
49 | + label: '内网ip', | ||
50 | + component: 'Input', | ||
51 | + colProps: { span: 6 }, | ||
52 | + componentProps: { | ||
53 | + maxLength: 255, | ||
54 | + placeholder: '请输入内网ip', | ||
55 | + }, | ||
56 | + }, | ||
57 | + { | ||
58 | + field: 'outerNetIp', | ||
59 | + label: '外网ip', | ||
60 | + component: 'Input', | ||
61 | + colProps: { span: 6 }, | ||
62 | + componentProps: { | ||
63 | + maxLength: 255, | ||
64 | + placeholder: '请输入外网ip', | ||
65 | + }, | ||
66 | + }, | ||
67 | + { | ||
68 | + field: 'deviceAgreement', | ||
69 | + label: '接入协议', | ||
70 | + component: 'Select', | ||
71 | + colProps: { span: 6 }, | ||
72 | + componentProps() { | ||
73 | + return { | ||
74 | + options: [ | ||
75 | + { label: '默认', value: 'DEFAULT' }, | ||
76 | + { label: 'MQTT', value: 'MQTT' }, | ||
77 | + { label: 'CoAP', value: 'COAP' }, | ||
78 | + { label: 'TCP', value: 'TCP' }, | ||
79 | + { label: 'GBT28181', value: 'GBT28181' }, | ||
80 | + ], | ||
81 | + getPopupContainer: () => document.body, | ||
82 | + placeholder: '请选择接入协议', | ||
83 | + }; | ||
84 | + }, | ||
85 | + }, | ||
86 | +]; | ||
87 | + | ||
88 | +//表单字段 | ||
89 | +export const schemas: FormSchema[] = [ | ||
90 | + { | ||
91 | + field: 'intranetIpAndPort', | ||
92 | + label: '内网ip&端口', | ||
93 | + component: 'FormInputGroup', | ||
94 | + required: true, | ||
95 | + componentProps: { | ||
96 | + inputPlaceholder: '请输入内网ip', | ||
97 | + inputNumberPlaceholder: '内网端口', | ||
98 | + }, | ||
99 | + colProps: { span: 24 }, | ||
100 | + }, | ||
101 | + { | ||
102 | + field: 'outerIpAndPort', | ||
103 | + label: '外网ip&端口', | ||
104 | + component: 'FormInputGroup', | ||
105 | + required: true, | ||
106 | + componentProps: { | ||
107 | + inputPlaceholder: '请输入外网ip', | ||
108 | + inputNumberPlaceholder: '外网端口', | ||
109 | + }, | ||
110 | + colProps: { span: 24 }, | ||
111 | + }, | ||
112 | + { | ||
113 | + field: 'deviceAgreement', | ||
114 | + component: 'Select', | ||
115 | + required: true, | ||
116 | + label: '接入协议', | ||
117 | + componentProps() { | ||
118 | + return { | ||
119 | + options: [ | ||
120 | + { label: '默认', value: 'DEFAULT' }, | ||
121 | + { label: 'MQTT', value: 'MQTT' }, | ||
122 | + { label: 'CoAP', value: 'COAP' }, | ||
123 | + { label: 'TCP', value: 'TCP' }, | ||
124 | + { label: 'GBT28181', value: 'GBT28181' }, | ||
125 | + ], | ||
126 | + getPopupContainer: () => document.body, | ||
127 | + placeholder: '请选择接入协议', | ||
128 | + }; | ||
129 | + }, | ||
130 | + colProps: { span: 19 }, | ||
131 | + }, | ||
132 | + { | ||
133 | + field: 'serverId', | ||
134 | + label: '服务器ID', | ||
135 | + required: false, | ||
136 | + colProps: { span: 19 }, | ||
137 | + component: 'Input', | ||
138 | + componentProps: { | ||
139 | + maxLength: 255, | ||
140 | + placeholder: '请输入服务器ID', | ||
141 | + }, | ||
142 | + ifShow({ values }) { | ||
143 | + return values.deviceAgreement === 'GBT28181'; | ||
144 | + }, | ||
145 | + }, | ||
146 | + { | ||
147 | + field: 'serverDomain', | ||
148 | + label: '服务器域', | ||
149 | + required: false, | ||
150 | + colProps: { span: 19 }, | ||
151 | + component: 'Input', | ||
152 | + componentProps: { | ||
153 | + maxLength: 255, | ||
154 | + placeholder: '请输入服务器域', | ||
155 | + }, | ||
156 | + ifShow({ values }) { | ||
157 | + return values.deviceAgreement === 'GBT28181'; | ||
158 | + }, | ||
159 | + }, | ||
160 | + { | ||
161 | + field: 'serverPassword', | ||
162 | + label: '密码', | ||
163 | + required: false, | ||
164 | + colProps: { span: 19 }, | ||
165 | + component: 'InputPassword', | ||
166 | + componentProps: { | ||
167 | + maxLength: 255, | ||
168 | + placeholder: '请输入密码', | ||
169 | + }, | ||
170 | + ifShow({ values }) { | ||
171 | + return values.deviceAgreement === 'GBT28181'; | ||
172 | + }, | ||
173 | + }, | ||
174 | +]; | ||
175 | + | ||
176 | +//详情字段 | ||
177 | +export const detailSchema: DescItem[] = [ | ||
178 | + { | ||
179 | + field: 'intranetIp', | ||
180 | + label: '内网ip', | ||
181 | + }, | ||
182 | + { | ||
183 | + field: 'intranetPort', | ||
184 | + label: '内网端口', | ||
185 | + }, | ||
186 | + { | ||
187 | + field: 'outerNetIp', | ||
188 | + label: '外网ip', | ||
189 | + }, | ||
190 | + { | ||
191 | + field: 'outerNetPort', | ||
192 | + label: '外网端口', | ||
193 | + }, | ||
194 | + { | ||
195 | + field: 'deviceAgreement', | ||
196 | + label: '接入协议', | ||
197 | + }, | ||
198 | + { | ||
199 | + field: 'serverId', | ||
200 | + label: '服务器ID', | ||
201 | + }, | ||
202 | + { | ||
203 | + field: 'serverDomain', | ||
204 | + label: '服务器域', | ||
205 | + }, | ||
206 | + { | ||
207 | + field: 'serverPassword', | ||
208 | + label: '密码', | ||
209 | + }, | ||
210 | +]; |
src/views/device/deviceaccess/index.vue
0 → 100644
1 | +<script setup lang="ts" name="deviceAccess"> | ||
2 | + import { columns, searchFormSchema, DEVICE_ACCESS_PERMISSION_ENUM } from '.'; | ||
3 | + import { BasicTable, useTable, TableAction } from '/@/components/Table'; | ||
4 | + import { Button, Popconfirm } from 'ant-design-vue'; | ||
5 | + import { useBatchOperation } from '/@/utils/useBatchOperation'; | ||
6 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
7 | + import { Authority } from '/@/components/Authority'; | ||
8 | + import { useModal } from '/@/components/Modal'; | ||
9 | + import { deviceAccessModal, deviceAccessDetailDrawer } from './components/index'; | ||
10 | + import { useDrawer } from '/@/components/Drawer'; | ||
11 | + import { USER_INFO_KEY } from '/@/enums/cacheEnum'; | ||
12 | + import { getAuthCache } from '/@/utils/auth'; | ||
13 | + import { authBtn } from '/@/enums/roleEnum'; | ||
14 | + import { | ||
15 | + getDeviceAccessInformationList, | ||
16 | + deleteDeviceAccessInformation, | ||
17 | + } from '/@/api/device/deviceAccess'; | ||
18 | + | ||
19 | + const [ | ||
20 | + registerTable, | ||
21 | + { reload, setLoading, getSelectRowKeys, setSelectedRowKeys, getRowSelection }, | ||
22 | + ] = useTable({ | ||
23 | + title: '设备接入信息列表', | ||
24 | + api: getDeviceAccessInformationList, | ||
25 | + columns, | ||
26 | + beforeFetch: (params) => { | ||
27 | + for (let i in params) if (!params[i]) Reflect.deleteProperty(params, i); // 如果没有值,则此字段也不传 | ||
28 | + return params; | ||
29 | + }, | ||
30 | + formConfig: { | ||
31 | + labelWidth: 100, | ||
32 | + schemas: searchFormSchema, | ||
33 | + }, | ||
34 | + immediate: true, | ||
35 | + useSearchForm: true, | ||
36 | + showTableSetting: true, | ||
37 | + bordered: true, | ||
38 | + showIndexColumn: false, | ||
39 | + clickToRowSelect: false, | ||
40 | + rowKey: 'id', | ||
41 | + actionColumn: { | ||
42 | + width: 230, | ||
43 | + title: '操作', | ||
44 | + slots: { customRender: 'action' }, | ||
45 | + fixed: 'right', | ||
46 | + }, | ||
47 | + rowSelection: { | ||
48 | + type: 'checkbox', | ||
49 | + }, | ||
50 | + }); | ||
51 | + | ||
52 | + const [registerModal, { openModal }] = useModal(); | ||
53 | + | ||
54 | + const [registerDetailDrawer, { openDrawer }] = useDrawer(); | ||
55 | + | ||
56 | + const { createMessage } = useMessage(); | ||
57 | + | ||
58 | + const { isExistOption } = useBatchOperation(getRowSelection, setSelectedRowKeys); | ||
59 | + | ||
60 | + const userInfo: Recordable = getAuthCache(USER_INFO_KEY); | ||
61 | + | ||
62 | + const role: string = userInfo.roles[0]; | ||
63 | + | ||
64 | + const handleReload = () => { | ||
65 | + setSelectedRowKeys([]); | ||
66 | + reload(); | ||
67 | + }; | ||
68 | + | ||
69 | + //新增或编辑 | ||
70 | + const handleCreateOrEdit = (record) => { | ||
71 | + const data = { isUpdate: !record ? false : true, record }; | ||
72 | + openModal(true, data); | ||
73 | + }; | ||
74 | + | ||
75 | + const handleDetail = (record?: Recordable) => { | ||
76 | + openDrawer(true, record); | ||
77 | + }; | ||
78 | + | ||
79 | + // 删除 | ||
80 | + const handleDelete = async (record?: Recordable) => { | ||
81 | + let ids: string[] = []; | ||
82 | + if (record) { | ||
83 | + ids = [record.id]; | ||
84 | + } else { | ||
85 | + ids = getSelectRowKeys(); | ||
86 | + } | ||
87 | + try { | ||
88 | + setLoading(true); | ||
89 | + await deleteDeviceAccessInformation({ ids }); | ||
90 | + createMessage.success('删除成功'); | ||
91 | + handleReload(); | ||
92 | + } catch (error) { | ||
93 | + throw error; | ||
94 | + } finally { | ||
95 | + setLoading(false); | ||
96 | + } | ||
97 | + }; | ||
98 | +</script> | ||
99 | +<template> | ||
100 | + <div> | ||
101 | + <BasicTable style="flex: auto" @register="registerTable"> | ||
102 | + <template #toolbar> | ||
103 | + <Authority :value="DEVICE_ACCESS_PERMISSION_ENUM.CREATE"> | ||
104 | + <Button type="primary" @click="handleCreateOrEdit(null)"> 新增设备接入信息 </Button> | ||
105 | + </Authority> | ||
106 | + <Authority :value="DEVICE_ACCESS_PERMISSION_ENUM.DELETE"> | ||
107 | + <Popconfirm | ||
108 | + title="您确定要批量删除数据" | ||
109 | + ok-text="确定" | ||
110 | + cancel-text="取消" | ||
111 | + @confirm="handleDelete()" | ||
112 | + > | ||
113 | + <a-button color="error" :disabled="!isExistOption"> 批量删除 </a-button> | ||
114 | + </Popconfirm> | ||
115 | + </Authority> | ||
116 | + </template> | ||
117 | + <template #action="{ record }"> | ||
118 | + <TableAction | ||
119 | + :actions="[ | ||
120 | + { | ||
121 | + label: '详情', | ||
122 | + icon: 'ant-design:eye-outlined', | ||
123 | + auth: DEVICE_ACCESS_PERMISSION_ENUM.GET, | ||
124 | + onClick: handleDetail.bind(null, record), | ||
125 | + }, | ||
126 | + { | ||
127 | + label: '编辑', | ||
128 | + auth: DEVICE_ACCESS_PERMISSION_ENUM.UPDATE, | ||
129 | + icon: 'clarity:note-edit-line', | ||
130 | + ifShow: authBtn(role), | ||
131 | + onClick: handleCreateOrEdit.bind(null, record), | ||
132 | + }, | ||
133 | + { | ||
134 | + label: '删除', | ||
135 | + auth: DEVICE_ACCESS_PERMISSION_ENUM.DELETE, | ||
136 | + icon: 'ant-design:delete-outlined', | ||
137 | + ifShow: authBtn(role), | ||
138 | + color: 'error', | ||
139 | + popConfirm: { | ||
140 | + title: '是否确认删除', | ||
141 | + confirm: handleDelete.bind(null, record), | ||
142 | + }, | ||
143 | + }, | ||
144 | + ]" | ||
145 | + /> | ||
146 | + </template> | ||
147 | + </BasicTable> | ||
148 | + <deviceAccessModal @register="registerModal" @handleReload="handleReload" /> | ||
149 | + <deviceAccessDetailDrawer | ||
150 | + title="设备接入信息详情" | ||
151 | + @register="registerDetailDrawer" | ||
152 | + width="40%" | ||
153 | + destroy-on-close | ||
154 | + /> | ||
155 | + </div> | ||
156 | +</template> |