Compare commits

..

2 Commits

Author SHA1 Message Date
iven
9319203e09 docs(qa): 更新联合调试报告 — 标记已修复/误报/已验证状态 2026-05-15 15:26:44 +08:00
iven
4ca9027cd6 fix: 联合调试问题修复 — 预约错误提示 + request 错误提取 + copilot 解包
- ISSUE-APPOINTMENT-001: 后端 DoctorNotFound 改为 Validation 错误(400)
  + 改善错误消息"所选医生暂无医护档案,请联系管理员"
  + 小程序预约创建 catch 传递实际错误消息(不再硬编码"预约失败")
  + 小程序 request.ts 提取后端 message 字段作为用户提示
- copilot API: listInsights/listRules/getPatientRisk 补齐 data.data 解包
- 移除 error.rs 重复的 AppointmentNotFound 分支
2026-05-15 15:25:26 +08:00
5 changed files with 29 additions and 21 deletions

View File

@@ -130,8 +130,9 @@ export default function AppointmentCreate() {
} catch { /* 用户拒绝 */ }
}
safeSetTimeout(() => Taro.navigateBack(), 1500);
} catch {
Taro.showToast({ title: '预约失败', icon: 'none' });
} catch (err: any) {
const msg = err?.message || '预约失败';
Taro.showToast({ title: msg.length > 20 ? msg.slice(0, 20) : msg, icon: 'none' });
} finally {
setLoading(false);
}

View File

@@ -278,9 +278,11 @@ async function request<T>(method: string, path: string, data?: unknown, timeout?
throw new Error('服务器错误');
}
const body = res.data as ApiResponse<T>;
const body = res.data as ApiResponse<T> & { message?: string };
if (!body.success) {
const userMsg = body.error_code ? (ERROR_CODE_MAP[body.error_code] || '操作失败,请稍后重试') : '操作失败,请稍后重试';
const userMsg = body.error_code
? (ERROR_CODE_MAP[body.error_code] || body.message || '操作失败,请稍后重试')
: (body.message || '操作失败,请稍后重试');
throw new Error(userMsg);
}
return body.data as T;

View File

@@ -36,18 +36,20 @@ export interface CopilotInsight {
// --- API Functions ---
export function getPatientRisk(patientId: string) {
return client.get<RiskScore>(`/copilot/patients/${patientId}/risk`);
export async function getPatientRisk(patientId: string) {
const { data } = await client.get<{ success: boolean; data: RiskScore }>(`/copilot/patients/${patientId}/risk`);
return data.data;
}
export function listInsights(params: {
export async function listInsights(params: {
patient_id?: string;
insight_type?: string;
severity?: string;
page?: number;
page_size?: number;
}) {
return client.get<PaginatedResponse<CopilotInsight>>('/copilot/insights', { params });
const { data } = await client.get<{ success: boolean; data: PaginatedResponse<CopilotInsight> }>('/copilot/insights', { params });
return data.data;
}
export function dismissInsight(id: string) {
@@ -58,6 +60,7 @@ export function listAlerts(params?: { severity?: string; page?: number; page_siz
return listInsights({ insight_type: 'anomaly', ...params });
}
export function listRules(params?: { page?: number; page_size?: number }) {
return client.get<PaginatedResponse<Record<string, unknown>>>('/copilot/rules', { params });
export async function listRules(params?: { page?: number; page_size?: number }) {
const { data } = await client.get<{ success: boolean; data: PaginatedResponse<Record<string, unknown>> }>('/copilot/rules', { params });
return data.data;
}

View File

@@ -8,7 +8,7 @@ pub enum HealthError {
#[error("患者不存在")]
PatientNotFound,
#[error("医护档案不存在")]
#[error("所选医生暂无医护档案,请联系管理员")]
DoctorNotFound,
#[error("预约不存在")]
@@ -124,9 +124,10 @@ impl From<HealthError> for AppError {
fn from(err: HealthError) -> Self {
match err {
HealthError::Validation(s) => AppError::Validation(s),
HealthError::PatientNotFound
| HealthError::DoctorNotFound
| HealthError::AppointmentNotFound
HealthError::PatientNotFound | HealthError::DoctorNotFound => {
AppError::Validation(err.to_string())
}
HealthError::AppointmentNotFound
| HealthError::ScheduleNotFound
| HealthError::VitalSignsNotFound
| HealthError::LabReportNotFound

View File

@@ -155,17 +155,17 @@
| ID | 级别 | 模块 | 描述 | 影响 |
|----|------|------|------|------|
| ISSUE-APPOINTMENT-001 | MEDIUM | 预约管理 | 创建预约需要患者先有医护档案关联,缺少时错误信息不明确 | 用户体验 |
| ISSUE-ARTICLE-001 | MEDIUM | 内容管理 | 部分文章标题在 API 中乱码(测试数据编码问题) | 数据展示 |
| ISSUE-RESPONSE-FORMAT | MEDIUM | 全局 | 所有列表 API 使用 `data.data` 双层嵌套,与前端 PaginatedResponse<T> 的 `data.items` 不匹配 | 前端适配层需处理 |
| ISSUE-PUBLIC-ENDPOINTS | MEDIUM | 公开端点 | `/public/articles``/public/banners` 需要 `tenant_id` 查询参数,小程序访客模式需确保传递 | 小程序首页 |
| ISSUE-APPOINTMENT-001 | MEDIUM | 预约管理 | 创建预约需要医护档案,错误信息不明确 | 用户体验 | **已修复** |
| ISSUE-ARTICLE-001 | MEDIUM | 内容管理 | 部分文章标题在 API 中乱码(测试数据编码问题) | 数据展示 | 测试数据问题 |
| ~~ISSUE-RESPONSE-FORMAT~~ | ~~MEDIUM~~ | ~~全局~~ | ~~API data.data 与前端不匹配~~ | ~~误报~~ | **误报**前端 PaginatedResponse 字段就是 `data`,一致 |
| ISSUE-PUBLIC-ENDPOINTS | MEDIUM | 公开端点 | `/public/articles``/public/banners` 需要 `tenant_id` | 小程序首页 | **已验证**`.env` 配置了默认 tenant_id + 代码有完整回退 |
### LOW建议优化
| ID | 级别 | 模块 | 描述 | 影响 |
|----|------|------|------|------|
| LOW-DIALYSIS-PATH | LOW | 透析管理 | `/health/dialysis/stats` 路径 404正确路径为 `/health/admin/statistics/dialysis` | API 路径不一致 |
| LOW-ARTICLE-ENCODING | LOW | 文章 | 文章列表第 2 页及以后出现 JSON 解析错误特殊字符转义 | 大量文章时可能崩溃 |
| ~~LOW-DIALYSIS-PATH~~ | ~~LOW~~ | ~~透析管理~~ | ~~路径 404~~ | ~~测试时 curl 用错路径~~ | **误报** — 前端/小程序已用正确路径 |
| LOW-ARTICLE-ENCODING | LOW | 文章 | 文章列表第 2 页出现 JSON 解析错误 | 特殊字符转义 | 测试数据编码问题 |
## 5. 数据一致性验证
@@ -290,7 +290,8 @@
| Phase 1 API 测试 | 40+ 端点通过 |
| Phase 2 Web UI 测试 | 8/9 页面正常 |
| Phase 2 小程序 UI 测试 | 7/7 页面正常 |
| 发现问题 | 7 → 1 已修复 + 1 误报 + 5 待处理 |
| 发现问题 | 7 → 3 已修复 + 3 误报 + 1 测试数据问题 |
| 额外发现 | copilot API 缺少 data.data 解包(已修复) |
| 安全测试 | 8/8 通过 |
| DevTools 控制台报错 | 均为非代码 Bug未登录/环境限制/外部来源) |