Compare commits

...

2 Commits

5 changed files with 332 additions and 331 deletions

View File

@ -1,51 +1,55 @@
import request from '@/config/axios' import request from '@/config/axios'
// 设备 VO // 设备 VO
export interface DeviceVO { export interface DeviceVO {
id: number // 主键ID id: number // 主键ID
devicename: string // 设备名称 devicename: string // 设备名称
devicecode: string // 设备ID/编号 devicecode: number // 设备ID/编号
devicetype: string // 设备类型 devicetype: string // 设备类型
location: string // 设备位置 location: string // 设备位置
devicestatus: number // 设备状态(0:待激活 1 在线 2 离线 ,3 禁用 ) devicestatus: number // 设备状态(0:待激活 1 在线 2 离线 ,3 禁用 )
orgid: number // 机构ID orgid: number // 机构ID
orgname: string // 机构名称 orgname: string // 机构名称
description: string // 设备描述 description: string // 设备描述
createtime: Date // 创建时间 createtime: Date // 创建时间
updatetime: Date // 更新时间 updatetime: Date // 更新时间
createby: string // 创建人 createby: string // 创建人
updateby: string // 更新人 updateby: string // 更新人
} }
// 设备 API // 设备 API
export const DeviceApi = { export const DeviceApi = {
// 查询设备分页 // 查询设备分页
getDevicePage: async (params: any) => { getDevicePage: async (params: any) => {
return await request.get({ url: `/system/device/page`, params }) return await request.get({ url: `/system/device/page`, params })
}, },
// 查询设备详情 // 查询设备详情
getDevice: async (id: number) => { getDevice: async (id: number) => {
return await request.get({ url: `/system/device/get?id=` + id }) return await request.get({ url: `/system/device/get?id=` + id })
}, },
// 查询设备详情
// 新增设备 getDeviceId: async (devicecode: number) => {
createDevice: async (data: DeviceVO) => { return await request.get({ url: `/system/device/getDeviceId?devicecode=` + devicecode })
return await request.post({ url: `/system/device/create`, data }) },
},
// 新增设备
// 修改设备 createDevice: async (data: DeviceVO) => {
updateDevice: async (data: DeviceVO) => { return await request.post({ url: `/system/device/create`, data })
return await request.put({ url: `/system/device/update`, data }) },
},
// 修改设备
// 删除设备 updateDevice: async (data: DeviceVO) => {
deleteDevice: async (id: number) => { return await request.put({ url: `/system/device/update`, data })
return await request.delete({ url: `/system/device/delete?id=` + id }) },
},
// 删除设备
// 导出设备 Excel deleteDevice: async (id: number) => {
exportDevice: async (params) => { return await request.delete({ url: `/system/device/delete?id=` + id })
return await request.download({ url: `/system/device/export-excel`, params }) },
},
} // 导出设备 Excel
exportDevice: async (params) => {
return await request.download({ url: `/system/device/export-excel`, params })
},
}

View File

@ -244,5 +244,8 @@ export enum DICT_TYPE {
IOT_PLUGIN_STATUS = 'iot_plugin_status', // IOT 插件状态 IOT_PLUGIN_STATUS = 'iot_plugin_status', // IOT 插件状态
IOT_PLUGIN_TYPE = 'iot_plugin_type', // IOT 插件类型 IOT_PLUGIN_TYPE = 'iot_plugin_type', // IOT 插件类型
IOT_DATA_BRIDGE_DIRECTION_ENUM = 'iot_data_bridge_direction_enum', // 桥梁方向 IOT_DATA_BRIDGE_DIRECTION_ENUM = 'iot_data_bridge_direction_enum', // 桥梁方向
IOT_DATA_BRIDGE_TYPE_ENUM = 'iot_data_bridge_type_enum' // 桥梁类型 IOT_DATA_BRIDGE_TYPE_ENUM = 'iot_data_bridge_type_enum', // 桥梁类型
//===================设备类型===================
IOT_DEVICE_TYPE = 'iot_device_type', // 设备类型
IOT_DEVICE_STATUS = 'iot_device_status', // 设备状态
} }

View File

@ -8,25 +8,25 @@
:disabled="true" :disabled="true"
> >
<el-form-item label="设备ID"> <el-form-item label="设备ID">
<span>{{ formData.deviceKey }}</span> <span>{{ formData.devicecode }}</span>
</el-form-item> </el-form-item>
<el-form-item label="设备名称"> <el-form-item label="设备名称">
<span>{{ formData.deviceName }}</span> <span>{{ formData.devicename }}</span>
</el-form-item> </el-form-item>
<el-form-item label="所属机构"> <el-form-item label="所属机构">
<span>{{ getOrgName(formData.productId) }}</span> <span>{{ formData.orgname }}</span>
</el-form-item> </el-form-item>
<el-form-item label="设备类型"> <el-form-item label="设备类型">
<span>{{ getDeviceTypeName(formData.deviceType) }}</span> <span>{{ getDeviceTypeName(formData.devicetype) }}</span>
</el-form-item> </el-form-item>
<el-form-item label="设备位置"> <el-form-item label="设备位置">
<span>{{ formData.address }}</span> <span>{{ formData.location }}</span>
</el-form-item> </el-form-item>
<el-form-item label="设备状态"> <el-form-item label="设备状态">
<span>{{ getDeviceStateName(formData.state) }}</span> <span>{{ getDeviceStatusName(formData.devicestatus) }}</span>
</el-form-item> </el-form-item>
<el-form-item label="设备描述"> <el-form-item label="设备描述">
<span>{{ formData.description || '-' }}</span> <span>{{ formData.description }}</span>
</el-form-item> </el-form-item>
</el-form> </el-form>
<template #footer> <template #footer>
@ -36,67 +36,46 @@
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict' import { DeviceApi } from '@/api/device'
import * as DeviceApi from '@/api/iot/device/device' import { ElMessage } from 'element-plus'
import * as ProductApi from '@/api/iot/product/product'
import { DeviceStateEnum } from '@/api/iot/device/device'
defineOptions({ name: 'DeviceDetailsForm' }) defineOptions({ name: 'DeviceDetailsForm' })
//
const getDeviceTypeName = (type: string) => {
const typeMap: Record<string, string> = {
'ECG': '心电设备',
'BP': '血压设备',
'SPO2': '血氧设备',
'TEMP': '体温设备',
'WEIGHT': '体重设备'
}
return typeMap[type] || type
}
//
const getDeviceStatusName = (status: string | number) => {
const statusMap: Record<string | number, string> = {
0: '待激活',
1: '在线',
2: '离线'
}
return statusMap[status] || '未知状态'
}
const dialogVisible = ref(false) // const dialogVisible = ref(false) //
const dialogTitle = ref('') // const dialogTitle = ref('') //
const formLoading = ref(false) // const formLoading = ref(false) //
const formData = ref<DeviceApi.DeviceVO>({ const formData = ref({
id: 0, devicecode: undefined,
deviceKey: '', devicename: '',
deviceName: '', orgname: '',
productId: 0, devicetype: '',
productKey: '', location: '',
deviceType: 0, devicestatus: '',
nickname: '', description: ''
gatewayId: 0,
state: DeviceStateEnum.INACTIVE,
onlineTime: new Date(),
offlineTime: new Date(),
activeTime: new Date(),
createTime: new Date(),
ip: '',
firmwareVersion: '',
deviceSecret: '',
mqttClientId: '',
mqttUsername: '',
mqttPassword: '',
authType: '',
latitude: 0,
longitude: 0,
areaId: 0,
address: '',
serialNumber: '',
config: '',
description: '',
groupIds: []
}) })
const productList = ref<ProductApi.ProductVO[]>([]) //
//
const getOrgName = (productId: number) => {
const product = productList.value.find(item => item.id === productId)
return product?.name || '-'
}
//
const getDeviceTypeName = (type: number) => {
const dict = getIntDictOptions(DICT_TYPE.IOT_DEVICE_TYPE).find(item => item.value === type)
return dict?.label || '-'
}
//
const getDeviceStateName = (state: number) => {
const dict = getIntDictOptions(DICT_TYPE.IOT_DEVICE_STATE).find(item => item.value === state)
return dict?.label || '-'
}
/** 打开弹窗 */ /** 打开弹窗 */
const open = async (id: number) => { const open = async (id: number) => {
dialogVisible.value = true dialogVisible.value = true
@ -106,38 +85,8 @@ const open = async (id: number) => {
if (id) { if (id) {
formLoading.value = true formLoading.value = true
try { try {
// API const res = await DeviceApi.getDeviceId(id)
const mockDeviceData = { formData.value = res
id: id,
deviceKey: 'Device' + id,
deviceName: '测试设备' + id,
deviceType: 1,
state: DeviceStateEnum.INACTIVE,
address: '北京市/海淀区/中关村',
description: '这是一个测试设备的描述信息',
productId: 1,
productKey: 'product_key_' + id,
nickname: '设备昵称' + id,
gatewayId: 1,
onlineTime: new Date(),
offlineTime: new Date(),
activeTime: new Date(),
createTime: new Date(),
ip: '192.168.1.1',
firmwareVersion: '1.0.0',
deviceSecret: 'secret_' + id,
mqttClientId: 'client_' + id,
mqttUsername: 'username_' + id,
mqttPassword: 'password_' + id,
authType: 'password',
latitude: 39.123456,
longitude: 117.123456,
areaId: 1,
serialNumber: 'SN' + id,
config: '{}',
groupIds: []
}
formData.value = mockDeviceData
} finally { } finally {
formLoading.value = false formLoading.value = false
} }
@ -148,34 +97,13 @@ defineExpose({ open }) // 提供 open 方法,用于打开弹窗
/** 重置表单 */ /** 重置表单 */
const resetForm = () => { const resetForm = () => {
formData.value = { formData.value = {
id: 0, devicecode: undefined,
deviceKey: '', devicename: '',
deviceName: '', orgname: '',
productId: 0, devicetype: '',
productKey: '', location: '',
deviceType: 0, devicestatus: '',
nickname: '', description: ''
gatewayId: 0,
state: DeviceStateEnum.INACTIVE,
onlineTime: new Date(),
offlineTime: new Date(),
activeTime: new Date(),
createTime: new Date(),
ip: '',
firmwareVersion: '',
deviceSecret: '',
mqttClientId: '',
mqttUsername: '',
mqttPassword: '',
authType: '',
latitude: 0,
longitude: 0,
areaId: 0,
address: '',
serialNumber: '',
config: '',
description: '',
groupIds: []
} }
} }
</script> </script>

View File

@ -1,64 +1,77 @@
<template> <template>
<el-card class="device-card" :body-style="{ padding: '20px' }" :data-status="deviceInfo.status"> <!-- 设备卡片组件 -->
<el-card class="device-card" :body-style="{ padding: '20px' }" :data-status="deviceInfo.devicestatus">
<div class="card-content"> <div class="card-content">
<!-- 设备基本信息区域 -->
<div class="device-info"> <div class="device-info">
<!-- 设备名称和操作按钮区域 -->
<div class="name-section"> <div class="name-section">
<h3 class="device-name">{{ deviceInfo.name }}</h3> <h3 class="device-name">{{ deviceInfo.devicename }}</h3>
<el-button <!-- 详情和数据按钮 -->
type="primary" <div class="button-group">
size="small" <el-button
class="detail-btn" type="primary"
text size="small"
@click="handleAction('details')" class="detail-btn"
> text
详情 @click="handleAction('details')"
</el-button> >
<el-button 详情
type="primary" </el-button>
size="small" <el-button
class="data-btn" type="primary"
text size="small"
@click="handleAction('data')" class="data-btn"
> text
数据 @click="handleAction('data')"
</el-button> >
数据
</el-button>
</div>
</div> </div>
<p class="device-status" :class="deviceInfo.status"> <!-- 设备状态显示 -->
{{ deviceInfo.statusText }} <p class="device-status" :class="getStatusClass(deviceInfo.devicestatus)">
{{ getStatusText(deviceInfo.devicestatus) }}
</p> </p>
</div> </div>
<!-- 设备详细信息区域 -->
<div class="device-details"> <div class="device-details">
<p class="detail-item"> <p class="detail-item">
<span class="label">设备ID</span> <span class="label">设备ID</span>
<span class="value">{{ deviceInfo.id }}</span> <span class="value">{{ deviceInfo.devicecode }}</span>
</p> </p>
<p class="detail-item"> <p class="detail-item">
<span class="label">类型</span> <span class="label">类型</span>
<span class="value">{{ deviceInfo.type }}</span> <span class="value">{{ getDeviceTypeName(deviceInfo.devicetype) }}</span>
</p> </p>
<p class="detail-item"> <p class="detail-item">
<span class="label">位置</span> <span class="label">位置</span>
<span class="value">{{ deviceInfo.address }}</span> <span class="value">{{ deviceInfo.location }}</span>
</p> </p>
</div> </div>
<!-- 分隔线 -->
<div class="divider"></div> <div class="divider"></div>
<!-- 设备操作按钮区域 -->
<div class="action-buttons"> <div class="action-buttons">
<!-- 启用按钮 -->
<el-button <el-button
type="primary" type="primary"
size="small" size="small"
:disabled="deviceInfo.status === 'normal'" :disabled="deviceInfo.devicestatus === 1"
@click="handleAction('enable')" @click="handleAction('enable')"
> >
启用 启用
</el-button> </el-button>
<!-- 停用按钮 -->
<el-button <el-button
type="warning" type="warning"
size="small" size="small"
:disabled="deviceInfo.status === 'error'" :disabled="deviceInfo.devicestatus === 2"
@click="handleAction('disable')" @click="handleAction('disable')"
> >
停用 停用
</el-button> </el-button>
<!-- 设置按钮 -->
<el-button <el-button
type="success" type="success"
size="small" size="small"
@ -66,6 +79,7 @@
> >
设置 设置
</el-button> </el-button>
<!-- 删除按钮 -->
<el-button <el-button
type="danger" type="danger"
plain plain
@ -79,27 +93,73 @@
</el-card> </el-card>
</template> </template>
<script setup> <script lang="ts" setup>
import { defineProps, defineEmits } from 'vue' import { defineProps, defineEmits } from 'vue'
import { Delete } from '@element-plus/icons-vue' import { Delete } from '@element-plus/icons-vue'
//
const props = defineProps({ const props = defineProps({
deviceInfo: { deviceInfo: {
type: Object, type: Object,
required: true, required: true,
default: () => ({ default: () => ({
id: '', id: '', // ID
name: '', devicename: '', //
type: '', devicetype: '', //
address: '', location: '', //
status: 'normal', devicestatus: 0, // 0-1-线2-线3-
statusText: '正常' statusText: '待激活' //
}) })
} }
}) })
//
const emit = defineEmits(['action']) const emit = defineEmits(['action'])
/**
* 获取设备状态文本
* @param {number} status - 设备状态码
* @returns {string} 状态文本
*/
const getStatusText = (status) => {
switch (status) {
case 0:
return '待激活'
case 1:
return '在线'
case 2:
return '离线'
case 3:
return '禁用'
default:
return '未知'
}
}
/**
* 获取设备状态对应的样式类名
* @param {number} status - 设备状态码
* @returns {string} 样式类名
*/
const getStatusClass = (status) => {
switch (status) {
case 0:
return 'warning' // -
case 1:
return 'normal' // 线 - 绿
case 2:
return 'error' // 线 -
case 3:
return 'disabled' // -
default:
return ''
}
}
/**
* 处理设备操作事件
* @param {string} action - 操作类型
*/
const handleAction = (action) => { const handleAction = (action) => {
if (action === 'data') { if (action === 'data') {
// //
@ -111,13 +171,26 @@ const handleAction = (action) => {
} else { } else {
emit('action', { emit('action', {
action, action,
deviceId: props.deviceInfo.id deviceId: props.deviceInfo.devicecode
}) })
} }
} }
//
const getDeviceTypeName = (type: string) => {
const typeMap: Record<string, string> = {
'ECG': '心电设备',
'BP': '血压设备',
'SPO2': '血氧设备',
'TEMP': '体温设备',
'WEIGHT': '体重设备'
}
return typeMap[type] || type
}
</script> </script>
<style scoped> <style scoped>
/* 设备卡片基础样式 */
.device-card { .device-card {
width: 300px; width: 300px;
margin: 10px; margin: 10px;
@ -128,70 +201,94 @@ const handleAction = (action) => {
border: 1px solid rgba(255, 255, 255, 0.18); border: 1px solid rgba(255, 255, 255, 0.18);
} }
/* 卡片悬停效果 */
.device-card:hover { .device-card:hover {
transform: translateY(-5px); transform: translateY(-5px);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12); box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
} }
/* 卡片内容布局 */
.card-content { .card-content {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 15px;
position: relative; position: relative;
z-index: 1; z-index: 1;
} }
/* 设备信息区域样式 */
.device-info { .device-info {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: flex-start;
padding: 5px 0; padding: 5px 0;
} }
/* 名称区域样式 */
.name-section { .name-section {
display: flex; display: flex;
align-items: center; flex-direction: column;
gap: 10px; gap: 10px;
flex: 1;
min-width: 0; /* 防止子元素溢出 */
} }
/* 设备名称样式 */
.device-name { .device-name {
margin: 0; margin: 0;
font-size: 20px; font-size: 20px;
color: #303133; color: #303133;
font-weight: 600; font-weight: 600;
transition: color 0.3s ease; transition: color 0.3s ease;
white-space: nowrap; /* 防止文字换行 */
overflow: hidden; /* 超出部分隐藏 */
text-overflow: ellipsis; /* 显示省略号 */
max-width: 150px; /* 最大宽度 */
} }
/* 设备名称悬停效果 */
.device-card:hover .device-name { .device-card:hover .device-name {
color: #409EFF; color: #409EFF;
} }
/* 设备状态基础样式 */
.device-status { .device-status {
padding: 6px 12px; padding: 6px 12px;
border-radius: 20px; border-radius: 20px;
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
transition: all 0.3s ease; transition: all 0.3s ease;
white-space: nowrap; /* 防止文字换行 */
} }
/* 在线状态样式 */
.device-status.normal { .device-status.normal {
background-color: #67C23A; background-color: #67C23A;
color: white; color: white;
box-shadow: 0 2px 8px rgba(103, 194, 58, 0.3); box-shadow: 0 2px 8px rgba(103, 194, 58, 0.3);
} }
/* 待激活状态样式 */
.device-status.warning { .device-status.warning {
background-color: #F7BA2A; background-color: #F7BA2A;
color: white; color: white;
box-shadow: 0 2px 8px rgba(247, 186, 42, 0.3); box-shadow: 0 2px 8px rgba(247, 186, 42, 0.3);
} }
/* 离线状态样式 */
.device-status.error { .device-status.error {
background-color: #909399; background-color: #909399;
color: white; color: white;
box-shadow: 0 2px 8px rgba(144, 147, 153, 0.3); box-shadow: 0 2px 8px rgba(144, 147, 153, 0.3);
} }
/* 禁用状态样式 */
.device-status.disabled {
background-color: #F56C6C;
color: white;
box-shadow: 0 2px 8px rgba(245, 108, 108, 0.3);
}
/* 设备详情区域样式 */
.device-details { .device-details {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -199,6 +296,7 @@ const handleAction = (action) => {
padding: 10px 0; padding: 10px 0;
} }
/* 详情项样式 */
.detail-item { .detail-item {
margin: 0; margin: 0;
font-size: 14px; font-size: 14px;
@ -206,128 +304,91 @@ const handleAction = (action) => {
transition: transform 0.3s ease; transition: transform 0.3s ease;
} }
/* 详情项悬停效果 */
.device-card:hover .detail-item { .device-card:hover .detail-item {
transform: translateX(5px); transform: translateX(5px);
} }
/* 标签样式 */
.label { .label {
color: #909399; color: #909399;
margin-right: 8px; margin-right: 8px;
font-weight: 500;
} }
/* 值样式 */
.value { .value {
color: #303133; color: #303133;
font-weight: 500; font-weight: 500;
} }
/* 分隔线样式 */
.divider { .divider {
height: 1px; height: 1px;
background: linear-gradient(to right, transparent, #b7b7bb, transparent); background: linear-gradient(to right, transparent, #DCDFE6, transparent);
margin: 5px 0; margin: 10px 0;
} }
/* 操作按钮区域样式 */
.action-buttons { .action-buttons {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
gap: 8px; gap: 8px;
padding: 5px 0;
} }
.action-buttons .el-button { /* 按钮图标样式 */
flex: 1; .el-icon {
transition: all 0.3s ease; margin-right: 4px;
}
.action-buttons .el-button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.delete-btn {
width: 24px !important;
height: 24px !important;
padding: 0 !important;
background-color: #f38787 !important;
border: none !important;
}
.delete-btn:hover {
background-color: #f38787 !important;
}
.delete-btn .el-icon {
font-size: 14px;
color: #ffffff;
}
.detail-btn {
padding: 0;
font-size: 14px;
height: auto;
background: none;
border: none;
color: #409EFF;
}
.detail-btn:hover {
color: #79bbff;
background: none;
border: none;
}
.data-btn {
padding: 0;
font-size: 14px;
height: auto;
background: none;
border: none;
color: #67C23A;
}
.data-btn:hover {
color: #71d440;
background: none;
border: none;
} }
/* 在线状态卡片样式 */ /* 在线状态卡片样式 */
.device-card[data-status="normal"] { .device-card[data-status="1"] {
background: linear-gradient(145deg, #e6f3ff, #fafafa); background: linear-gradient(145deg, #e6f3ff, #fafafa);
border: 1px solid rgba(64, 158, 255, 0.2); border: 1px solid rgba(64, 158, 255, 0.2);
} }
/* 在线状态卡片悬停效果 */ /* 在线状态卡片悬停效果 */
.device-card[data-status="normal"]:hover { .device-card[data-status="1"]:hover {
background: linear-gradient(145deg, #d9edff, #fafafa); background: linear-gradient(145deg, #d9edff, #fafafa);
box-shadow: 0 8px 30px rgba(64, 158, 255, 0.15); box-shadow: 0 8px 30px rgba(64, 158, 255, 0.15);
} }
/* 待激活状态卡片样式 */ /* 待激活状态卡片样式 */
.device-card[data-status="warning"] { .device-card[data-status="0"] {
/* 淡粉色渐变背景,从淡粉色过渡到纯白色 */
background: linear-gradient(145deg, #f7ecec, #fafafa); background: linear-gradient(145deg, #f7ecec, #fafafa);
/* 淡粉色边框 */
border: 1px solid rgba(247, 186, 42, 0.2); border: 1px solid rgba(247, 186, 42, 0.2);
} }
/* 待激活状态卡片悬停效果 */ /* 待激活状态卡片悬停效果 */
.device-card[data-status="warning"]:hover { .device-card[data-status="0"]:hover {
/* 悬停时加深粉色渐变效果 */
background: linear-gradient(145deg, #f7ecec, #fafafa); background: linear-gradient(145deg, #f7ecec, #fafafa);
/* 添加淡粉色阴影效果 */
box-shadow: 0 8px 30px rgba(247, 186, 42, 0.15); box-shadow: 0 8px 30px rgba(247, 186, 42, 0.15);
} }
/* 离线状态卡片样式 */ /* 离线状态卡片样式 */
.device-card[data-status="error"] { .device-card[data-status="2"] {
background: linear-gradient(145deg, #e4e4e4, #fafafa); background: linear-gradient(145deg, #e4e4e4, #fafafa);
border: 1px solid rgba(247, 186, 42, 0.2); border: 1px solid rgba(247, 186, 42, 0.2);
} }
/* 离线状态卡片悬停效果 */ /* 离线状态卡片悬停效果 */
.device-card[data-status="error"]:hover { .device-card[data-status="2"]:hover {
background: linear-gradient(145deg, #e4e4e4, #fafafa); background: linear-gradient(145deg, #e4e4e4, #fafafa);
box-shadow: 0 8px 30px rgba(247, 186, 42, 0.15); box-shadow: 0 8px 30px rgba(247, 186, 42, 0.15);
} }
/* 禁用状态卡片样式 */
.device-card[data-status="3"] {
background: linear-gradient(145deg, #f09393, #fafafa);
border: 1px solid rgba(245, 108, 108, 0.2);
}
/* 禁用状态卡片悬停效果 */
.device-card[data-status="3"]:hover {
background: linear-gradient(145deg, #f09393, #fafafa);
box-shadow: 0 8px 30px rgba(245, 108, 108, 0.15);
}
.button-group {
display: flex;
gap: 10px;
}
</style> </style>

View File

@ -10,7 +10,7 @@
> >
<el-form-item label="设备名称" prop="name"> <el-form-item label="设备名称" prop="name">
<el-input <el-input
v-model="queryParams.name" v-model="queryParams.devicename"
placeholder="请输入设备名称" placeholder="请输入设备名称"
clearable clearable
@keyup.enter="handleQuery" @keyup.enter="handleQuery"
@ -19,13 +19,13 @@
</el-form-item> </el-form-item>
<el-form-item label="设备状态" prop="status"> <el-form-item label="设备状态" prop="status">
<el-select <el-select
v-model="queryParams.status" v-model="queryParams.devicestatus"
placeholder="请选择设备状态" placeholder="请选择设备状态"
clearable clearable
class="!w-240px" class="!w-240px"
> >
<el-option <el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" v-for="dict in getIntDictOptions(DICT_TYPE.IOT_DEVICE_STATUS)"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
:value="dict.value" :value="dict.value"
@ -35,13 +35,13 @@
<!-- 设备类型 --> <!-- 设备类型 -->
<el-form-item label="设备类型" prop="type"> <el-form-item label="设备类型" prop="type">
<el-select <el-select
v-model="queryParams.type" v-model="queryParams.devicetype"
placeholder="请选择设备类型" placeholder="请选择设备类型"
clearable clearable
class="!w-240px" class="!w-240px"
> >
<el-option <el-option
v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)" v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_TYPE)"
:key="dict.value" :key="dict.value"
:label="dict.label" :label="dict.label"
:value="dict.value" :value="dict.value"
@ -72,6 +72,13 @@
@action="handleDeviceAction" @action="handleDeviceAction"
/> />
</div> </div>
<!-- 分页组件 -->
<Pagination
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="handleQuery"
/>
</ContentWrap> </ContentWrap>
<!-- 设备表单 --> <!-- 设备表单 -->
@ -84,61 +91,40 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, reactive, onMounted } from 'vue' import { ref, reactive, onMounted } from 'vue'
import { ElForm, ElFormItem, ElInput, ElSelect, ElOption, ElButton } from 'element-plus' import { ElForm, ElFormItem, ElInput, ElSelect, ElOption, ElButton } from 'element-plus'
import { getIntDictOptions } from '@/utils/dict' import { getIntDictOptions,getStrDictOptions } from '@/utils/dict'
import { DICT_TYPE } from '@/utils/dict' import { DICT_TYPE } from '@/utils/dict'
import DeviceCard from '../devices/devices_cards.vue' import DeviceCard from '../devices/devices_cards.vue'
import DeviceForm from './DevFrom.vue' import DeviceForm from './DevFrom.vue'
import DetailsForm from './DetailsForm.vue' import DetailsForm from './DetailsForm.vue'
import { DeviceApi } from '@/api/device'
import { getUserProfile } from '@/api/system/user/profile'
import ECG_datas from './Device_Data_Components/ECG_datas.vue' import ECG_datas from './Device_Data_Components/ECG_datas.vue'
// //
interface QueryParams { interface QueryParams {
name: string devicename: string
status: number | undefined devicestatus: number | undefined
type: number | undefined devicetype: string | undefined
pageNo: number
pageSize: number
orgid: number
} }
const queryParams = reactive<QueryParams>({ const queryParams = reactive<QueryParams>({
name: '', devicename: '',
status: undefined, devicestatus: undefined,
type: undefined devicetype: '',
pageNo: 1,
pageSize: 10,
orgid: 0
}) })
//
const total = ref(0)
//
  const userProfile = ref()
// //
const deviceList = ref([ const deviceList = ref([])
{
id: 'ECG001',
name: '心电设备',
type: '心电设备',
address: '北京市/市辖区/西城区',
status: 'normal',
statusText: '在线'
},
{
id: 'Blood001',
name: '血压仪',
type: '血压仪',
address: '天津市/市辖区/西青区/精武镇',
status: 'normal',
statusText: '在线'
},
{
id: 'Glucose001',
name: '血糖仪',
type: '血糖仪',
address: '河北省/廊坊市/安次区',
status: 'warning',
statusText: '待激活'
},
{
id: 'Oxygen001',
name: '血氧仪',
type: '血氧仪',
address: '四川省/绵阳市/涪城区',
status: 'error',
statusText: '离线'
}
])
// //
const queryFormRef = ref() const queryFormRef = ref()
@ -150,14 +136,25 @@ const detailsFormRef = ref()
const ecgDataRef = ref() const ecgDataRef = ref()
// //
const handleQuery = () => { const handleQuery = async () => {
// TODO: try {
console.log('查询参数:', queryParams) //ID
queryParams.orgid = userProfile.value.dept.id
const res = await DeviceApi.getDevicePage(queryParams)
deviceList.value = res.list
total.value = res.total
} catch (error) {
console.error('获取设备列表失败:', error)
}
} }
// //
const resetQuery = () => { const resetQuery = () => {
queryFormRef.value?.resetFields() queryFormRef.value?.resetFields()
queryParams.devicename = ''
queryParams.devicestatus = undefined
queryParams.devicetype = ''
queryParams.pageNo = 1
handleQuery() handleQuery()
} }
@ -168,6 +165,7 @@ const openForm = (type: string) => {
// //
const handleDeviceAction = (action: any) => { const handleDeviceAction = (action: any) => {
console.log('设备操作:', action)
if (action.action === 'details') { if (action.action === 'details') {
// //
detailsFormRef.value?.open(action.deviceId) detailsFormRef.value?.open(action.deviceId)
@ -180,9 +178,10 @@ const handleDeviceAction = (action: any) => {
} }
// //
onMounted(() => { onMounted(async () => {
// TODO: //
// API   userProfile.value = await getUserProfile()
handleQuery()
}) })
</script> </script>
@ -193,4 +192,10 @@ onMounted(() => {
gap: 20px; gap: 20px;
padding: 20px; padding: 20px;
} }
.pagination-container {
display: flex;
justify-content: center;
margin-top: 20px;
}
</style> </style>