修改了设备管理逻辑
This commit is contained in:
+16
-22
@@ -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);
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user