修改了设备管理逻辑

This commit is contained in:
2025-01-14 10:02:31 +00:00
parent 7991a2b27e
commit a5b23dc37f
3 changed files with 154 additions and 78 deletions
+16 -22
View File
@@ -1051,6 +1051,9 @@
if (response.ok) {
let devices = await response.json();
// 只显示 active 状态的设备
devices = devices.filter(device => device.status === 'active');
// 应用在线设备过滤
if (onlineDevicesOnly) {
devices = devices.filter(device => device.status === 'online');
@@ -1162,42 +1165,33 @@
}
}
// Modify remove device function
async function removeDevice(deviceId, experimentId = null) {
let message = experimentId
? 'Are you sure you want to remove this device from the current experiment?'
: 'Are you sure you want to remove this device? This will remove the device from all experiments.';
if (!confirm(message)) {
// 修改移除设备的函数
async function removeDevice(deviceId) {
if (!confirm('Are you sure you want to deactivate this device?')) {
return;
}
try {
let url = `${API_BASE_URL}/user/devices/${deviceId}`;
if (experimentId) {
url = `${API_BASE_URL}/experiments/${experimentId}/devices/${deviceId}`;
}
const response = await fetch(url, {
const response = await fetch(`${API_BASE_URL}/user/devices/${deviceId}`, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
const data = await response.json();
if (response.ok) {
const result = await response.json();
alert(result.message);
if (experimentId) {
// 如果是从实验中除,只重新载该实验的设备列表
await loadExperimentDevices(experimentId);
} else {
// 如果是完全移除设备,重新加载设备列表
// 检查返回的状态
if (data.status === 'inactive') {
alert('Device deactivated successfully');
// 重新加载设备列表
loadDevices();
} else {
alert('Failed to deactivate device');
}
} else {
const error = await response.json();
alert(`Failed to remove device: ${error.detail}`);
alert(`Failed: ${data.detail}`);
}
} catch (error) {
console.error('Failed to remove device:', error);
+64 -24
View File
@@ -1546,7 +1546,6 @@
}
}
// Modify loadExperiments function's device part
async function loadExperiments(projectId) {
try {
const response = await fetch(`${API_BASE_URL}/experiments?project_id=${projectId}`, {
@@ -1558,18 +1557,14 @@
if (response.ok) {
const experiments = await response.json();
// 对实验进行排序,未完成的排在前面
experiments.sort((a, b) => {
// 如果状态不同,completed 排在后面
if (a.status !== b.status) {
return a.status === 'completed' ? 1 : -1;
}
// 如果状态相同,按创建时间倒序排列
return new Date(b.create_time) - new Date(a.create_time);
});
const experimentsHtml = await Promise.all(experiments.map(async exp => {
// Get experiment devices
const devicesResponse = await fetch(`${API_BASE_URL}/experiments/${exp._id}/devices`, {
headers: {
'Authorization': `Bearer ${token}`
@@ -1583,7 +1578,7 @@
<div id="experiment-devices-${exp._id}" class="mt-4">
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-4 g-4">
${devices.map(device => `
<div class="col">
<div class="col device-card" id="device-${device.user_device_id}">
<div class="card h-100">
<div class="card-body">
<h6 class="card-title">${device.device_name}</h6>
@@ -1604,7 +1599,6 @@
`;
}
// 根据实验状态显示同的按钮组
const buttonsHtml = exp.status === 'completed' ? `
<div class="btn-group" role="group" onclick="event.stopPropagation();">
<button class="btn btn-sm btn-info " onclick="downloadExperimentData('${exp._id}')">
@@ -1651,6 +1645,41 @@
}
}
async function removeDevice(deviceId, experimentId = null) {
let message = 'Are you sure you want to remove this device from the current experiment?';
if (!confirm(message)) {
return;
}
try {
const url = `${API_BASE_URL}/experiments/${experimentId}/devices/${deviceId}`;
const response = await fetch(url, {
method: 'DELETE',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const result = await response.json();
// 直接移除设备卡片元素
const deviceCard = document.getElementById(`device-${deviceId}`);
if (deviceCard) {
deviceCard.remove();
}
alert(result.message);
} else {
const error = await response.json();
alert(`Failed to remove device: ${error.detail}`);
}
} catch (error) {
console.error('Failed to remove device:', error);
alert('Failed to remove device, please try again');
}
}
// Create new project
async function createProject() {
const projectData = {
@@ -1680,8 +1709,6 @@
}
}
// Helper function to show create project modal
function showCreateProjectModal() {
new bootstrap.Modal(document.getElementById('createProjectModal')).show();
@@ -1810,24 +1837,37 @@
if (response.ok) {
const devices = await response.json();
// 只显示 active 状态的设备
const activeDevices = devices.filter(device => device.status === 'active');
const devicesList = document.getElementById('availableDevicesList');
devicesList.innerHTML = devices.map(device => `
<div class="card mb-2">
<div class="card-body">
<h5 class="card-title">${device.device_name}</h5>
<p class="card-text">
Serial Number: ${device.serial_number}<br>
Type: ${device.device_type}<br>
Channel Number: ${device.device_number}
</p>
<button class="btn btn-primary btn-sm"
onclick="addDeviceToExperiment('${experimentId}', '${device.user_device_id}')">
Add
</button>
// 如果没有活动设备,显示提示信息
if (activeDevices.length === 0) {
devicesList.innerHTML = `
<div class="text-center p-3">
<p class="text-muted">No active devices available</p>
</div>
</div>
`).join('');
`;
} else {
devicesList.innerHTML = activeDevices.map(device => `
<div class="card mb-2">
<div class="card-body">
<h5 class="card-title">${device.device_name}</h5>
<p class="card-text">
Serial Number: ${device.serial_number}<br>
Type: ${device.device_type}<br>
Channel Number: ${device.device_number}
</p>
<button class="btn btn-primary btn-sm"
onclick="addDeviceToExperiment('${experimentId}', '${device.user_device_id}')">
Add
</button>
</div>
</div>
`).join('');
}
// 显示模态框
const modal = new bootstrap.Modal(document.getElementById('addDeviceToExperimentModal'));
+74 -32
View File
@@ -306,14 +306,20 @@ async def add_device_to_user(
device = await db.devices.find_one({
"serial_numbers": {
"$elemMatch": {
"serial": serial_number,
"status": "available"
"serial": serial_number
}
}
})
if not device:
raise HTTPException(status_code=404, detail="Device not found or invalid serial number")
# 检查该序列号是否已被其他用户激活
active_device = await db.user_devices.find_one({
"serial_number": serial_number,
"status": "active"
})
if active_device:
raise HTTPException(status_code=400, detail="Device is already in use by another user")
# Check if this serial number has already been added
existing = await db.user_devices.find_one({
@@ -321,7 +327,27 @@ async def add_device_to_user(
"serial_number": serial_number
})
if existing:
raise HTTPException(status_code=400, detail="This device has already been added to your device list")
if existing["status"] == "active":
raise HTTPException(status_code=400, detail="This device is already active")
else:
# 如果设备存在但状态是inactive,则重新激活
await db.user_devices.update_one(
{"_id": existing["_id"]},
{"$set": {"status": "active"}}
)
return {
"message": "Device reactivated successfully",
"device": {
"user_device_id": str(existing["_id"]),
"device_id": str(existing["device_id"]),
"serial_number": serial_number,
"device_name": existing["device_name"],
"device_type": existing["device_type"],
"device_number": existing["device_number"],
"sensors": existing.get("sensors", []),
"status": "active"
}
}
# 创建新的关联记录,包含完整的设备信息、序列号和传感器信息
user_device_dict = {
@@ -331,14 +357,20 @@ async def add_device_to_user(
"device_name": device["device_name"],
"device_type": device["device_type"],
"device_number": device["device_number"],
"sensors": device.get("sensors", []) # 添加传感器信息
"sensors": device.get("sensors", []), # 添加传感器信息
"status": "active", # 添加状态字段
"add_time": datetime.now(timezone.utc) # 添加时间记录
}
# 更新设备序列号状态为已使用
# 只有当序列号状态为available时才更新为in_use
await db.devices.update_one(
{
"_id": device["_id"],
"serial_numbers.serial": serial_number
"serial_numbers": {
"$elemMatch": {
"serial": serial_number,
"status": "available" # 只匹配状态为available的序列号
}
}
},
{
"$set": {
@@ -359,7 +391,8 @@ async def add_device_to_user(
"device_name": device["device_name"],
"device_type": device["device_type"],
"device_number": device["device_number"],
"sensors": device.get("sensors", []) # 在响应中包含传感器信息
"sensors": device.get("sensors", []), # 在响应中包含传感器信息
"status": "active" # 添加状态字段"status": "active" # 添加状态字段
}
}
@@ -387,7 +420,8 @@ async def get_user_devices(current_user: UserModel = Depends(get_current_user)):
"device_name": device["device_name"],
"device_type": device["device_type"],
"device_number": device["device_number"],
"sensors": device.get("sensors", []) # 在响应中包含传感器信息
"sensors": device.get("sensors", []), # 在响应中包含传感器信息
"status": device.get("status", "active")
})
return devices
@@ -536,13 +570,14 @@ async def add_device_to_experiment(
if not project:
raise HTTPException(status_code=403, detail="Unauthorized access to this experiment")
# 验证用户设备是否存在
# 验证用户设备是否存在且状态为active
user_device = await db.user_devices.find_one({
"_id": ObjectId(user_device_id),
"user_id": current_user.id
"user_id": current_user.id,
"status": "active" # 添加状态检查
})
if not user_device:
raise HTTPException(status_code=404, detail="Device not found or unauthorized access")
raise HTTPException(status_code=404, detail="Active device not found or unauthorized access")
# 检查是否已经添加过这个设备
existing = await db.experiment_devices.find_one({
@@ -736,7 +771,7 @@ async def remove_user_device(
current_user: UserModel = Depends(get_current_user)
):
"""
移除��的设备,同时清理验中的关联记录
将设备标记为非活动状态
参数:
device_id: 用户设备的ID
@@ -745,35 +780,42 @@ async def remove_user_device(
db = await get_database()
try:
# 验证设备是否存在且属于当前用户
# 验证设备是否存在且属于当前用户,且状态为active
device = await db.user_devices.find_one({
"_id": ObjectId(device_id),
"user_id": current_user.id
"user_id": current_user.id,
"status": "active" # 只能停用活动状态的设备
})
if not device:
raise HTTPException(status_code=404, detail="Device not found or unauthorized access")
raise HTTPException(status_code=404, detail="Active device not found or unauthorized access")
# 首先删除所有实验中与该设备的关联
delete_result = await db.experiment_devices.delete_many({
"user_device_id": ObjectId(device_id)
})
# 然后删除用户设备记录
await db.user_devices.delete_one({
"_id": ObjectId(device_id),
"user_id": current_user.id
})
# 更新设备状态为非活动
result = await db.user_devices.update_one(
{
"_id": ObjectId(device_id),
"user_id": current_user.id
},
{
"$set": {
"status": "inactive",
"deactivate_time": datetime.now(timezone.utc) # 记录停用时间
}
}
)
if result.modified_count == 0:
raise HTTPException(status_code=500, detail="Failed to deactivate device")
return {
"message": "Device removed successfully",
"removed_experiment_associations": delete_result.deleted_count
"message": "Device deactivated successfully",
"device_id": device_id,
"status": "inactive", # 添加状态字段
"deactivate_time": datetime.now(timezone.utc).isoformat()
}
except Exception as e:
print(f"Error removing device: {str(e)}")
raise HTTPException(status_code=500, detail=f"Failed to remove device: {str(e)}")
print(f"Error deactivating device: {str(e)}")
raise HTTPException(status_code=500, detail=f"Failed to deactivate device: {str(e)}")
# Connection Manager for WebSocket clients
class ConnectionManager: