feat(iot):【网关设备:30%】增加网关设备绑定能力(优化代码),基于 optimized-pondering-dragon.md 规划

pull/858/head
YunaiV 2026-01-22 09:53:01 +08:00
parent 2515caed35
commit 2076a27a26
3 changed files with 100 additions and 49 deletions

View File

@ -178,11 +178,8 @@ export const DeviceApi = {
}) })
}, },
// 获取可绑定到网关的子设备列表 // 获取未绑定网关的子设备分页
getBindableSubDeviceList: async (gatewayId?: number) => { getUnboundSubDevicePage: async (params: any) => {
return await request.get<DeviceVO[]>({ return await request.get({ url: `/iot/device/unbound-sub-device-page`, params })
url: `/iot/device/bindable-sub-device-list`,
params: { gatewayId }
})
} }
} }

View File

@ -68,8 +68,8 @@ export const ProductApi = {
}, },
// 查询产品(精简)列表 // 查询产品(精简)列表
getSimpleProductList() { getSimpleProductList(deviceType?: number) {
return request.get({ url: '/iot/product/simple-list' }) return request.get({ url: '/iot/product/simple-list', params: { deviceType } })
}, },
// 根据 ProductKey 获取产品信息 // 根据 ProductKey 获取产品信息

View File

@ -62,40 +62,82 @@
</ContentWrap> </ContentWrap>
<!-- 添加子设备弹窗 --> <!-- 添加子设备弹窗 -->
<!-- TODO @AI需要增加检索产品设备等检索可以一起讨论下 --> <Dialog title="添加子设备" v-model="bindDialogVisible" width="900px">
<Dialog title="添加子设备" v-model="bindDialogVisible" width="800px"> <ContentWrap>
<el-table <!-- 搜索区域 -->
ref="bindTableRef" <el-form :model="bindQueryParams" ref="bindQueryFormRef" :inline="true" class="-mb-15px">
v-loading="bindFormLoading" <el-form-item label="产品" prop="productId">
:data="bindableDevices" <ProductSelect
:stripe="true" v-model="bindQueryParams.productId"
:show-overflow-tooltip="true" :device-type="DeviceTypeEnum.GATEWAY_SUB"
@selection-change="handleBindSelectionChange" class="!w-200px"
max-height="400px" />
> </el-form-item>
<el-table-column type="selection" width="55" /> <el-form-item label="设备名称" prop="deviceName">
<el-table-column label="DeviceName" align="center" prop="deviceName" /> <el-input
<el-table-column label="备注名称" align="center" prop="nickname" /> v-model="bindQueryParams.deviceName"
<el-table-column label="产品名称" align="center" prop="productName" /> placeholder="请输入设备名称"
<el-table-column label="设备状态" align="center" prop="state"> clearable
<template #default="{ row }"> class="!w-200px"
<dict-tag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="row.state" /> />
</template> </el-form-item>
</el-table-column> <el-form-item>
</el-table> <el-button type="primary" @click="getBindableDevicePage">
<Icon icon="ep:search" class="mr-5px" /> 搜索
</el-button>
<el-button @click="resetBindQuery">
<Icon icon="ep:refresh" class="mr-5px" /> 重置
</el-button>
</el-form-item>
</el-form>
</ContentWrap>
<ContentWrap>
<!-- 分页表格 -->
<el-table
ref="bindTableRef"
v-loading="bindFormLoading"
:data="bindableDevices"
:stripe="true"
:show-overflow-tooltip="true"
@selection-change="handleBindSelectionChange"
max-height="400px"
>
<el-table-column type="selection" width="55" />
<el-table-column label="DeviceName" align="center" prop="deviceName" />
<el-table-column label="备注名称" align="center" prop="nickname" />
<el-table-column label="产品名称" align="center" prop="productName" />
<el-table-column label="设备状态" align="center" prop="state">
<template #default="{ row }">
<dict-tag :type="DICT_TYPE.IOT_DEVICE_STATE" :value="row.state" />
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<Pagination
v-model:page="bindQueryParams.pageNo"
v-model:limit="bindQueryParams.pageSize"
:total="bindTotal"
@pagination="getBindableDevicePage"
/>
</ContentWrap>
<template #footer> <template #footer>
<el-button @click="bindDialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleBindSubmit" :loading="bindFormLoading"> <el-button type="primary" @click="handleBindSubmit" :loading="bindFormLoading">
确定已选 {{ bindSelectedIds.length }} 确定已选 {{ bindSelectedIds.length }}
</el-button> </el-button>
<el-button @click="bindDialogVisible = false">取消</el-button>
</template> </template>
</Dialog> </Dialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { DeviceApi, DeviceVO } from '@/api/iot/device/device' import { DeviceApi, DeviceVO } from '@/api/iot/device/device'
import { DeviceTypeEnum } from '@/api/iot/product/product'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime' import { dateFormatter } from '@/utils/formatTime'
import ProductSelect from '@/views/iot/product/product/components/ProductSelect.vue'
const props = defineProps<{ const props = defineProps<{
gatewayId: number gatewayId: number
@ -104,18 +146,23 @@ const props = defineProps<{
const message = useMessage() const message = useMessage()
const { push } = useRouter() const { push } = useRouter()
// TODO @AI使 const loading = ref(false) //
// const subDeviceList = ref<DeviceVO[]>([]) //
const loading = ref(false) const selectedIds = ref<number[]>([]) // ID
const subDeviceList = ref<DeviceVO[]>([])
const selectedIds = ref<number[]>([])
// const bindDialogVisible = ref(false) //
const bindDialogVisible = ref(false) const bindFormLoading = ref(false) //
const bindFormLoading = ref(false)
const bindTableRef = ref() const bindTableRef = ref()
const bindableDevices = ref<DeviceVO[]>([]) const bindQueryFormRef = ref()
const bindSelectedIds = ref<number[]>([]) const bindableDevices = ref<DeviceVO[]>([]) //
const bindSelectedIds = ref<number[]>([]) // ID
const bindTotal = ref(0) //
const bindQueryParams = reactive({
pageNo: 1,
pageSize: 10,
productId: undefined as number | undefined,
deviceName: ''
})
/** 获取子设备列表 */ /** 获取子设备列表 */
const getSubDeviceList = async () => { const getSubDeviceList = async () => {
@ -141,18 +188,29 @@ const handleSelectionChange = (selection: DeviceVO[]) => {
const openBindDialog = async () => { const openBindDialog = async () => {
bindSelectedIds.value = [] bindSelectedIds.value = []
bindDialogVisible.value = true bindDialogVisible.value = true
await getBindableDevicePage()
}
/** 获取可绑定设备分页 */
const getBindableDevicePage = async () => {
bindFormLoading.value = true bindFormLoading.value = true
try { try {
// const result = await DeviceApi.getUnboundSubDevicePage(bindQueryParams)
const list = await DeviceApi.getBindableSubDeviceList(props.gatewayId) bindableDevices.value = result.list
// bindTotal.value = result.total
// TODO @AI
bindableDevices.value = list.filter((device: DeviceVO) => device.gatewayId !== props.gatewayId)
} finally { } finally {
bindFormLoading.value = false bindFormLoading.value = false
} }
} }
/** 重置绑定弹窗搜索条件 */
const resetBindQuery = () => {
bindQueryParams.pageNo = 1
bindQueryParams.productId = undefined
bindQueryParams.deviceName = ''
getBindableDevicePage()
}
/** 绑定弹窗多选框选中数据 */ /** 绑定弹窗多选框选中数据 */
const handleBindSelectionChange = (selection: DeviceVO[]) => { const handleBindSelectionChange = (selection: DeviceVO[]) => {
bindSelectedIds.value = selection.map((item) => item.id) bindSelectedIds.value = selection.map((item) => item.id)
@ -203,8 +261,4 @@ const handleUnbindBatch = async () => {
onMounted(async () => { onMounted(async () => {
await getSubDeviceList() await getSubDeviceList()
}) })
//
// TODO @AIrefresh
defineExpose({ refresh: getSubDeviceList })
</script> </script>