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 | 41 | import RegisterAddressInput from '/@/views/task/center/components/PollCommandInput/RegisterAddressInput.vue'; | 
| 42 | 42 | import DeviceProfileForm from '/@/components/Form/src/components/DeviceProfileForm/index.vue'; | 
| 43 | 43 | import { Segmented } from './components/Segmented'; | 
| 44 | +import FormInputGroup from './components/FormInputGroup.vue'; | |
| 44 | 45 | |
| 45 | 46 | const componentMap = new Map<ComponentType, Component>(); | 
| 46 | 47 | |
| ... | ... | @@ -89,6 +90,7 @@ componentMap.set('ApiSelectScrollLoad', ApiSelectScrollLoad); | 
| 89 | 90 | componentMap.set('InputGroup', InputGroup); | 
| 90 | 91 | componentMap.set('RegisterAddressInput', RegisterAddressInput); | 
| 91 | 92 | componentMap.set('DeviceProfileForm', DeviceProfileForm); | 
| 93 | +componentMap.set('FormInputGroup', FormInputGroup); | |
| 92 | 94 | |
| 93 | 95 | export function add(compName: ComponentType, component: Component) { | 
| 94 | 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 | 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 | 227 | export const CameraVideoStreamUrl: Rule[] = [ | 
| 212 | 228 | { | 
| 213 | 229 | required: true, | 
| ... | ... | @@ -423,3 +439,6 @@ export const MediaTypeValidate: Rule[] = [ | 
| 423 | 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> | ... | ... |