mirror of
https://github.com/yudaocode/yudao-ui-admin-vue3.git
synced 2026-03-29 23:25:52 +00:00
feat(iot):【网关设备:20%】增加网关设备绑定能力(未完成),基于 breezy-doodling-starlight.md 规划
This commit is contained in:
@@ -158,5 +158,31 @@ export const DeviceApi = {
|
||||
// 发送设备消息
|
||||
sendDeviceMessage: async (params: IotDeviceMessageSendReqVO) => {
|
||||
return await request.post({ url: `/iot/device/message/send`, data: params })
|
||||
},
|
||||
|
||||
// 绑定子设备到网关
|
||||
bindDeviceGateway: async (data: { ids: number[]; gatewayId: number }) => {
|
||||
return await request.put({ url: `/iot/device/bind-gateway`, data })
|
||||
},
|
||||
|
||||
// 解绑子设备与网关
|
||||
unbindDeviceGateway: async (data: { ids: number[] }) => {
|
||||
return await request.put({ url: `/iot/device/unbind-gateway`, data })
|
||||
},
|
||||
|
||||
// 获取网关的子设备列表
|
||||
getSubDeviceList: async (gatewayId: number) => {
|
||||
return await request.get<DeviceVO[]>({
|
||||
url: `/iot/device/sub-device-list`,
|
||||
params: { gatewayId }
|
||||
})
|
||||
},
|
||||
|
||||
// 获取可绑定到网关的子设备列表
|
||||
getBindableSubDeviceList: async (gatewayId?: number) => {
|
||||
return await request.get<DeviceVO[]>({
|
||||
url: `/iot/device/bindable-sub-device-list`,
|
||||
params: { gatewayId }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
210
src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue
Normal file
210
src/views/iot/device/device/detail/DeviceDetailsSubDevice.vue
Normal file
@@ -0,0 +1,210 @@
|
||||
<!-- 子设备管理 -->
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<!-- 操作按钮 -->
|
||||
<div class="mb-4">
|
||||
<el-button type="primary" plain @click="openBindDialog" v-hasPermi="['iot:device:update']">
|
||||
<Icon icon="ep:plus" class="mr-5px" /> 添加子设备
|
||||
</el-button>
|
||||
<el-button
|
||||
type="danger"
|
||||
plain
|
||||
@click="handleUnbindBatch"
|
||||
:disabled="selectedIds.length === 0"
|
||||
v-hasPermi="['iot:device:update']"
|
||||
>
|
||||
<Icon icon="ep:delete" class="mr-5px" /> 批量解绑
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<!-- 子设备列表 -->
|
||||
<el-table
|
||||
v-loading="loading"
|
||||
:data="subDeviceList"
|
||||
:stripe="true"
|
||||
:show-overflow-tooltip="true"
|
||||
@selection-change="handleSelectionChange"
|
||||
>
|
||||
<el-table-column type="selection" width="55" />
|
||||
<el-table-column label="DeviceName" align="center" prop="deviceName">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click="openDeviceDetail(row.id)">{{ row.deviceName }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<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-column
|
||||
label="最后上线时间"
|
||||
align="center"
|
||||
prop="onlineTime"
|
||||
:formatter="dateFormatter"
|
||||
width="180px"
|
||||
/>
|
||||
<el-table-column label="操作" align="center" width="120px">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" @click="openDeviceDetail(row.id)"> 查看 </el-button>
|
||||
<el-button
|
||||
link
|
||||
type="danger"
|
||||
@click="handleUnbind(row.id)"
|
||||
v-hasPermi="['iot:device:update']"
|
||||
>
|
||||
解绑
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</ContentWrap>
|
||||
|
||||
<!-- 添加子设备弹窗 -->
|
||||
<!-- TODO @AI:需要增加检索:产品、设备等检索,可以一起讨论下; -->
|
||||
<Dialog title="添加子设备" v-model="bindDialogVisible" width="800px">
|
||||
<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>
|
||||
<template #footer>
|
||||
<el-button @click="bindDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="handleBindSubmit" :loading="bindFormLoading">
|
||||
确定(已选 {{ bindSelectedIds.length }} 个)
|
||||
</el-button>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DeviceApi, DeviceVO } from '@/api/iot/device/device'
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { dateFormatter } from '@/utils/formatTime'
|
||||
|
||||
const props = defineProps<{
|
||||
gatewayId: number
|
||||
}>()
|
||||
|
||||
const message = useMessage()
|
||||
const { push } = useRouter()
|
||||
|
||||
// TODO @AI:注释使用尾注释;
|
||||
// 列表数据
|
||||
const loading = ref(false)
|
||||
const subDeviceList = ref<DeviceVO[]>([])
|
||||
const selectedIds = ref<number[]>([])
|
||||
|
||||
// 绑定弹窗数据
|
||||
const bindDialogVisible = ref(false)
|
||||
const bindFormLoading = ref(false)
|
||||
const bindTableRef = ref()
|
||||
const bindableDevices = ref<DeviceVO[]>([])
|
||||
const bindSelectedIds = ref<number[]>([])
|
||||
|
||||
/** 获取子设备列表 */
|
||||
const getSubDeviceList = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
subDeviceList.value = await DeviceApi.getSubDeviceList(props.gatewayId)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 打开设备详情 */
|
||||
const openDeviceDetail = (id: number) => {
|
||||
push({ name: 'IoTDeviceDetail', params: { id } })
|
||||
}
|
||||
|
||||
/** 多选框选中数据 */
|
||||
const handleSelectionChange = (selection: DeviceVO[]) => {
|
||||
selectedIds.value = selection.map((item) => item.id)
|
||||
}
|
||||
|
||||
/** 打开绑定弹窗 */
|
||||
const openBindDialog = async () => {
|
||||
bindSelectedIds.value = []
|
||||
bindDialogVisible.value = true
|
||||
bindFormLoading.value = true
|
||||
try {
|
||||
// 获取可绑定的子设备列表
|
||||
const list = await DeviceApi.getBindableSubDeviceList(props.gatewayId)
|
||||
// 排除已绑定到当前网关的设备
|
||||
// TODO @AI:不用排除,后端已经排除;
|
||||
bindableDevices.value = list.filter((device: DeviceVO) => device.gatewayId !== props.gatewayId)
|
||||
} finally {
|
||||
bindFormLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 绑定弹窗多选框选中数据 */
|
||||
const handleBindSelectionChange = (selection: DeviceVO[]) => {
|
||||
bindSelectedIds.value = selection.map((item) => item.id)
|
||||
}
|
||||
|
||||
/** 提交绑定 */
|
||||
const handleBindSubmit = async () => {
|
||||
if (bindSelectedIds.value.length === 0) {
|
||||
message.warning('请选择要绑定的子设备')
|
||||
return
|
||||
}
|
||||
bindFormLoading.value = true
|
||||
try {
|
||||
await DeviceApi.bindDeviceGateway({
|
||||
ids: bindSelectedIds.value,
|
||||
gatewayId: props.gatewayId
|
||||
})
|
||||
message.success('绑定成功')
|
||||
bindDialogVisible.value = false
|
||||
await getSubDeviceList()
|
||||
} finally {
|
||||
bindFormLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 解绑单个设备 */
|
||||
const handleUnbind = async (id: number) => {
|
||||
try {
|
||||
await message.confirm('确定要解绑该子设备吗?')
|
||||
await DeviceApi.unbindDeviceGateway({ ids: [id] })
|
||||
message.success('解绑成功')
|
||||
await getSubDeviceList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 批量解绑 */
|
||||
const handleUnbindBatch = async () => {
|
||||
try {
|
||||
await message.confirm(`确定要解绑选中的 ${selectedIds.value.length} 个子设备吗?`)
|
||||
await DeviceApi.unbindDeviceGateway({ ids: selectedIds.value })
|
||||
message.success('批量解绑成功')
|
||||
selectedIds.value = []
|
||||
await getSubDeviceList()
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/** 初始化 */
|
||||
onMounted(async () => {
|
||||
await getSubDeviceList()
|
||||
})
|
||||
|
||||
// 暴露刷新方法
|
||||
// TODO @AI:refresh 需要提供么?
|
||||
defineExpose({ refresh: getSubDeviceList })
|
||||
</script>
|
||||
@@ -17,7 +17,13 @@
|
||||
:thing-model-list="thingModelList"
|
||||
/>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="子设备管理" v-if="product.deviceType === DeviceTypeEnum.GATEWAY" />
|
||||
<el-tab-pane
|
||||
label="子设备管理"
|
||||
name="subDevice"
|
||||
v-if="product.deviceType === DeviceTypeEnum.GATEWAY"
|
||||
>
|
||||
<DeviceDetailsSubDevice v-if="activeTab === 'subDevice'" :gateway-id="device.id" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="设备消息" name="log">
|
||||
<DeviceDetailsMessage v-if="activeTab === 'log'" :device-id="device.id" />
|
||||
</el-tab-pane>
|
||||
@@ -50,6 +56,7 @@ import DeviceDetailsThingModel from './DeviceDetailsThingModel.vue'
|
||||
import DeviceDetailsMessage from './DeviceDetailsMessage.vue'
|
||||
import DeviceDetailsSimulator from './DeviceDetailsSimulator.vue'
|
||||
import DeviceDetailConfig from './DeviceDetailConfig.vue'
|
||||
import DeviceDetailsSubDevice from './DeviceDetailsSubDevice.vue'
|
||||
|
||||
defineOptions({ name: 'IoTDeviceDetail' })
|
||||
|
||||
|
||||
Reference in New Issue
Block a user