瀏覽代碼

feat: 实现曝光成功后自动接受图像功能

- 新增 judgeImage API 用于接受/拒绝图像
- 在 mqttService 中的 TASK_Success 处理中添加自动接受逻辑
- 创建 API 使用文档和功能实现文档

改动文件:
- src/domain/mqttService.ts
- src/API/exam/judgeImage.ts
- src/API/exam/judgeImage.ts.md
- docs/实现/自动接受图像功能.md
sw 1 天之前
父節點
當前提交
d040d451f0
共有 4 個文件被更改,包括 437 次插入0 次删除
  1. 219 0
      docs/实现/自动接受图像功能.md
  2. 46 0
      src/API/exam/judgeImage.ts
  3. 160 0
      src/API/exam/judgeImage.ts.md
  4. 12 0
      src/domain/mqttService.ts

+ 219 - 0
docs/实现/自动接受图像功能.md

@@ -0,0 +1,219 @@
+# 自动接受图像功能实现文档
+
+## 概述
+
+本文档描述了在曝光成功后自动接受图像的功能实现。该功能通过监听MQTT消息,在图像处理完成并成功后自动调用接受图像接口。
+
+## 需求背景
+
+在DR系统的检查流程中,当曝光完成并成功处理图像后,系统需要自动接受该图像,避免手动操作,提高工作效率。
+
+## 实现位置
+
+**文件**: `src/domain/mqttService.ts`  
+**修改内容**: 在 `handleMqttMessage` 函数的 `TASK_Success` 分支中添加自动接受逻辑
+
+## 技术方案
+
+### 1. MQTT消息流程
+
+```
+曝光触发 
+  ↓
+图像采集
+  ↓
+图像处理 (多个阶段)
+  ↓
+MQTT 推送进度状态
+  - TASK_RecvRaw (已获取原图)
+  - TASK_RecvMask (已获取mask)
+  - TASK_RecvEnhance (已完成增强)
+  - TASK_RecvForeground (已获取前景mask)
+  - TASK_RecvApply (已完成遮罩mask)
+  - TASK_Success (成功存储dcm) ✨
+  ↓
+自动接受图像
+```
+
+### 2. 关键消息格式
+
+**Topic**: `MODULE/TASK/IMGPROC/PROGRESS`
+
+**消息结构**:
+```typescript
+interface MqttMessage {
+  dcm?: string;        // dcm文件名
+  message: string;     // 消息内容
+  sop?: string;        // SOP实例UID (图像ID)
+  status: string;      // 状态
+  thumbnail?: string;  // 缩略图文件名
+}
+```
+
+**成功消息示例**:
+```json
+{
+  "dcm": "20250801150247.dcm",
+  "message": "",
+  "sop": "20250801150247",
+  "status": "TASK_Success",
+  "thumbnail": "20250801150247.webp"
+}
+```
+
+### 3. 代码实现
+
+#### 3.1 导入依赖
+
+```typescript
+import { judgeImage } from '../API/exam/judgeImage';
+```
+
+#### 3.2 自动接受逻辑
+
+在 `TASK_Success` 分支中添加:
+
+```typescript
+case 'TASK_Success':
+  console.log('Task succeeded:', message);
+  // Handle success, e.g., process DCM and thumbnail files
+  emitter.emit('TASK_SUCCESS', message);
+  emitter.emit('ACQUISITION_SUCCESS');
+
+  // 自动接受图像
+  if (message.sop) {
+    judgeImage(message.sop, true)
+      .then(() => {
+        console.log(`图像 ${message.sop} 已自动接受`);
+      })
+      .catch((error) => {
+        console.error(`自动接受图像失败:`, error);
+      });
+  }
+  break;
+```
+
+## 功能特点
+
+### ✅ 优点
+
+1. **时机准确**: 在图像处理完全成功后立即接受
+2. **无侵入性**: 不影响现有的事件触发逻辑
+3. **错误隔离**: 接受失败不影响其他功能继续执行
+4. **日志完整**: 成功和失败都有详细日志记录
+5. **异步处理**: 使用Promise处理,不阻塞主流程
+
+### 📋 工作流程
+
+1. 用户触发曝光
+2. 系统进行图像采集和处理
+3. 后端通过MQTT推送处理进度
+4. 当收到 `TASK_Success` 状态时:
+   - 触发现有的成功事件
+   - **自动调用接受图像API**
+   - 记录操作日志
+5. 图像状态更新为"已接受"
+
+## API调用详情
+
+### 接口信息
+
+- **端点**: `POST /api/v1/auth/task/inspection/judge`
+- **参数**:
+  - `instance_uid`: 图像的SOP实例UID (从MQTT消息的 `sop` 字段获取)
+  - `accept`: true (固定为接受)
+
+### 调用示例
+
+```typescript
+// 从MQTT消息中提取SOP实例UID
+const sopInstanceUid = message.sop; // 例如: "20250801150247"
+
+// 调用接受图像API
+await judgeImage(sopInstanceUid, true);
+```
+
+## 错误处理
+
+### 可能的错误场景
+
+1. **网络错误**: 无法连接到后端服务器
+2. **认证失败**: Token无效或过期
+3. **SOP为空**: MQTT消息中没有sop字段
+4. **服务器错误**: 后端处理失败
+
+### 错误处理策略
+
+- 所有错误都会被捕获并记录到控制台
+- 错误不会中断MQTT消息处理流程
+- 不会影响现有事件的触发(`TASK_SUCCESS`, `ACQUISITION_SUCCESS`)
+
+## 测试验证
+
+### 测试步骤
+
+1. 启动系统并登录
+2. 进入检查页面
+3. 触发曝光操作
+4. 观察控制台日志:
+   ```
+   Task succeeded: {dcm: "xxx.dcm", sop: "xxx", status: "TASK_Success", ...}
+   图像 xxx 已自动接受
+   ```
+5. 确认图像状态已更新为"已接受"
+
+### 验证点
+
+- ✅ 曝光成功后自动调用接受接口
+- ✅ 控制台显示接受成功日志
+- ✅ 图像状态正确更新
+- ✅ 错误情况下不影响其他功能
+
+## 相关文件
+
+- `src/domain/mqttService.ts` - MQTT消息处理(实现位置)
+- `src/API/exam/judgeImage.ts` - 接受/拒绝图像API
+- `docs/DR.md` - 后端API文档(第37、38节)
+
+## 后续优化建议
+
+### 可选功能
+
+1. **可配置开关**: 在系统设置中提供"自动接受图像"的开关选项
+2. **条件接受**: 根据图像质量评分决定是否自动接受
+3. **通知提示**: 自动接受后给用户显示Toast提示
+4. **统计记录**: 记录自动接受的成功率和失败原因
+
+### 配置化示例
+
+如果需要添加开关控制:
+
+```typescript
+// 在Redux状态中添加配置
+interface ExamSettings {
+  autoAcceptImage: boolean;
+}
+
+// 在MQTT处理中检查配置
+if (message.sop && getState().exam.settings.autoAcceptImage) {
+  judgeImage(message.sop, true)
+    .then(() => console.log(`图像 ${message.sop} 已自动接受`))
+    .catch((error) => console.error(`自动接受图像失败:`, error));
+}
+```
+
+## 注意事项
+
+1. 确保 `judgeImage` API已正确实现并测试
+2. MQTT消息的 `sop` 字段必须是有效的SOP实例UID
+3. 自动接受在曝光成功后立即执行,无法撤销
+4. 如果需要手动审核图像质量,应禁用此功能
+
+## 版本历史
+
+- **v1.0** (2025-10-13): 初始实现,在TASK_Success时自动接受图像
+
+---
+
+*文档创建时间: 2025年10月13日*  
+*最后更新: 2025年10月13日*

+ 46 - 0
src/API/exam/judgeImage.ts

@@ -0,0 +1,46 @@
+import axiosInstance from '../interceptor';
+
+// 定义请求参数接口
+interface JudgeImageRequest {
+    instance_uid: string;
+    accept: boolean;
+}
+
+// 定义响应接口
+interface JudgeImageResponse {
+    code: string;
+    description: string;
+    solution: string;
+    data: {
+        '@type': string;
+        value: object;
+    };
+}
+
+/**
+ * 接受或拒绝图像
+ * @param instanceUid - 图像的SOP实例UID
+ * @param accept - 是否接受图像 (true: 接受, false: 拒绝)
+ * @returns 包含操作结果的Promise
+ * @throws 请求失败时抛出错误
+ */
+const judgeImage = async (
+    instanceUid: string,
+    accept: boolean
+): Promise<JudgeImageResponse> => {
+    try {
+        const response = await axiosInstance.post('/auth/task/inspection/judge', {
+            instance_uid: instanceUid,
+            accept: accept,
+        });
+        if (response.data.code !== '0x000000') {
+            throw new Error('接受或拒绝图像,返回码不是0x000000');
+        }
+        return response.data;
+    } catch (error) {
+        throw new Error(`Failed to judge image: ${error}`);
+    }
+};
+
+export { judgeImage };
+export type { JudgeImageRequest, JudgeImageResponse };

+ 160 - 0
src/API/exam/judgeImage.ts.md

@@ -0,0 +1,160 @@
+# judgeImage API 文档
+
+## 概述
+
+`judgeImage` 函数用于在曝光后接受或拒绝当前图像。这是检查流程中的关键步骤,允许操作员对采集的图像进行质量判断。
+
+## API 端点
+
+- **路径**: `/api/v1/auth/task/inspection/judge`
+- **方法**: POST
+- **认证**: 需要
+
+## 函数签名
+
+```typescript
+const judgeImage = async (
+  instanceUid: string,
+  accept: boolean
+): Promise<JudgeImageResponse>
+```
+
+## 参数
+
+### instanceUid (必需)
+- **类型**: `string`
+- **描述**: 图像的 SOP 实例 UID
+- **示例**: `'1.2.276.0.1000000.5.1.4.701601461.19649.1749545373.668671'`
+
+### accept (必需)
+- **类型**: `boolean`
+- **描述**: 是否接受图像
+  - `true`: 接受图像
+  - `false`: 拒绝图像
+
+## 返回值
+
+返回一个 Promise,resolve 为 `JudgeImageResponse` 对象:
+
+```typescript
+interface JudgeImageResponse {
+  code: string;           // 响应代码,成功为 "0x000000"
+  description: string;    // 描述信息
+  solution: string;       // 解决方案说明
+  data: {
+    '@type': string;
+    value: object;
+  };
+}
+```
+
+## 使用示例
+
+### 接受图像
+
+```typescript
+import { judgeImage } from '@/API/exam/judgeImage';
+
+try {
+  const response = await judgeImage(
+    '1.2.276.0.1000000.5.1.4.701601461.19649.1749545373.668671',
+    true
+  );
+  console.log('图像已接受', response);
+} catch (error) {
+  console.error('接受图像失败:', error);
+}
+```
+
+### 拒绝图像
+
+```typescript
+import { judgeImage } from '@/API/exam/judgeImage';
+
+try {
+  const response = await judgeImage(
+    '1.2.276.0.1000000.5.1.4.701601461.19649.1749545373.668671',
+    false
+  );
+  console.log('图像已拒绝', response);
+} catch (error) {
+  console.error('拒绝图像失败:', error);
+}
+```
+
+### 在 React 组件中使用
+
+```typescript
+import { judgeImage } from '@/API/exam/judgeImage';
+import { useState } from 'react';
+
+const ImageJudgementPanel = ({ imageUid }: { imageUid: string }) => {
+  const [loading, setLoading] = useState(false);
+
+  const handleAccept = async () => {
+    setLoading(true);
+    try {
+      await judgeImage(imageUid, true);
+      // 显示成功提示
+      alert('图像已接受');
+    } catch (error) {
+      console.error('操作失败:', error);
+      alert('接受图像失败');
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  const handleReject = async () => {
+    setLoading(true);
+    try {
+      await judgeImage(imageUid, false);
+      // 显示成功提示
+      alert('图像已拒绝');
+    } catch (error) {
+      console.error('操作失败:', error);
+      alert('拒绝图像失败');
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  return (
+    <div>
+      <button onClick={handleAccept} disabled={loading}>
+        接受图像
+      </button>
+      <button onClick={handleReject} disabled={loading}>
+        拒绝图像
+      </button>
+    </div>
+  );
+};
+```
+
+## 错误处理
+
+函数在以下情况会抛出错误:
+
+1. **网络错误**: 无法连接到服务器
+2. **认证失败**: Token 无效或过期
+3. **服务器错误**: 后端处理失败
+
+建议使用 try-catch 块捕获并处理这些错误。
+
+## 相关接口
+
+- `startInspection`: 开始检查
+- `triggerInspection`: 触发曝光
+- `leaveInspection`: 挂起或完成检查
+
+## 注意事项
+
+1. 调用此接口前,确保已经完成曝光并获取了图像
+2. `instance_uid` 必须是有效的 SOP 实例 UID
+3. 建议在操作前添加用户确认对话框
+4. 拒绝图像后,可能需要重新曝光
+
+## 相关文档
+
+参考 `docs/DR.md` 第 38 节了解更多详情。

+ 12 - 0
src/domain/mqttService.ts

@@ -1,6 +1,7 @@
 import mqtt from 'mqtt';
 import { MQTT_BROKER_URL } from '../API/config';
 import emitter from '../utils/eventEmitter';
+import { judgeImage } from '../API/exam/judgeImage';
 
 export interface MqttMessage {
   dcm?: string;
@@ -35,6 +36,17 @@ const handleMqttMessage = (message: MqttMessage) => {
       // Handle success, e.g., process DCM and thumbnail files
       emitter.emit('TASK_SUCCESS', message);
       emitter.emit('ACQUISITION_SUCCESS');
+
+      // 自动接受图像
+      if (message.sop) {
+        judgeImage(message.sop, true)
+          .then(() => {
+            console.log(`图像 ${message.sop} 已自动接受`);
+          })
+          .catch((error) => {
+            console.error(`自动接受图像失败:`, error);
+          });
+      }
       break;
     case 'TASK_Failure':
       console.error('Task failed:', message);