diff --git a/TUICallKit-Vue3/App.vue b/TUICallKit-Vue3/App.vue index 7e93b46a..2b1d73f6 100644 --- a/TUICallKit-Vue3/App.vue +++ b/TUICallKit-Vue3/App.vue @@ -46,7 +46,7 @@ const wxcode = async (code) => { uni.setStorageSync('token', res.data.token) uni.setStorageSync('userData', res.data) if(res.code==1 &&res.data.diagnosis){ - video(res.data) + //video(res.data) } console.log('请求结果:', res.data) } catch (err) { @@ -69,7 +69,7 @@ const userinfo = async (code) => { } uni.setStorageSync('userData', res.data) if(res.code==1 && res.data.diagnosis){ - video(res.data) + //video(res.data) } } catch (err) { diff --git a/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue b/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue index 40deeeb0..4c06c085 100644 --- a/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue +++ b/TUICallKit-Vue3/TUIKit/pages/chat/chat.vue @@ -14,6 +14,28 @@ @scroll="onScroll" > + + + + + + + + + {{ doctorInfo.name || '医生' }} + {{ doctorInfo.title || '主任医师' }} + {{ doctorInfo.hospital || '甄养堂医院' }} + + + + 等待中 + + + + + 请等待医生,医生即将进入诊室 + + @@ -84,16 +106,16 @@ 表情 --> - + 文字 语音 - + 图片 - + 文件 @@ -181,20 +203,27 @@ - + diff --git a/server/server.zip b/server/server.zip index 3be45a9e..73769e93 100644 Binary files a/server/server.zip and b/server/server.zip differ diff --git a/server/sql/add_doctor_qualification_images.sql b/server/sql/add_doctor_qualification_images.sql new file mode 100644 index 00000000..dec17bb9 --- /dev/null +++ b/server/sql/add_doctor_qualification_images.sql @@ -0,0 +1,8 @@ +-- 医生表新增资质图片字段 +-- 若项目使用 zyt_ 前缀,请将 la_admin 替换为 zyt_admin 后执行 + +-- 添加医生资质图片字段(支持多张图片,JSON格式存储) +ALTER TABLE `la_admin` ADD COLUMN `qualification_images` text NULL COMMENT '医生资质图片(JSON数组格式)' AFTER `license_no`; + +-- 示例数据格式: +-- ["https://example.com/image1.jpg", "https://example.com/image2.jpg"] diff --git a/医生资质图片功能说明.md b/医生资质图片功能说明.md new file mode 100644 index 00000000..d5b49a24 --- /dev/null +++ b/医生资质图片功能说明.md @@ -0,0 +1,362 @@ +# 医生资质图片功能说明 + +## 功能概述 +为医生档案添加资质图片上传功能,支持上传多张资质证书、荣誉证书等图片,并在医生详情页面展示。 + +## 实现内容 + +### 1. 数据库修改 +**文件**: `server/sql/add_doctor_qualification_images.sql` + +添加了 `qualification_images` 字段到医生表(la_admin/zyt_admin): +- 字段类型:text +- 存储格式:JSON数组 +- 示例数据:`["https://example.com/image1.jpg", "https://example.com/image2.jpg"]` + +**执行SQL**: +```sql +ALTER TABLE `la_admin` ADD COLUMN `qualification_images` text NULL COMMENT '医生资质图片(JSON数组格式)' AFTER `license_no`; +``` + +如果使用 `zyt_` 前缀,请将 `la_admin` 替换为 `zyt_admin`。 + +### 2. 后端修改 + +#### 2.1 管理员逻辑层 +**文件**: `server/app/adminapi/logic/auth/AdminLogic.php` + +在 `add`、`edit` 和 `detail` 方法中添加 `qualification_images` 字段处理: + +**添加方法 (add)**: +```php +// 处理资质图片:如果是数组则转为JSON字符串 +$qualificationImages = ''; +if (isset($params['qualification_images'])) { + if (is_array($params['qualification_images'])) { + $qualificationImages = json_encode($params['qualification_images'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + } else { + $qualificationImages = $params['qualification_images']; + } +} + +$admin = Admin::create([ + // ... 其他字段 + 'qualification_images' => $qualificationImages, + // ... 其他字段 +]); +``` + +**编辑方法 (edit)**: +```php +// 处理资质图片:如果是数组则转为JSON字符串 +$qualificationImages = ''; +if (isset($params['qualification_images'])) { + if (is_array($params['qualification_images'])) { + $qualificationImages = json_encode($params['qualification_images'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + } else { + $qualificationImages = $params['qualification_images']; + } +} + +$data = [ + // ... 其他字段 + 'qualification_images' => $qualificationImages, + // ... 其他字段 +]; +``` + +**数据处理说明**: +- 前端提交的数据格式:`["https://example.com/image1.jpg", "https://example.com/image2.jpg"]`(数组) +- 后端存储格式:`["https://example.com/image1.jpg","https://example.com/image2.jpg"]`(JSON字符串) +- 使用 `JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES` 确保中文和URL正确编码 + +**详情方法 (detail)**: +```php +$admin = Admin::field([ + // ... 其他字段 + 'qualification_images', + // ... 其他字段 +])->findOrEmpty($params['id'])->toArray(); + +// 将资质图片JSON字符串转换为数组,供前端组件使用 +if (!empty($admin['qualification_images'])) { + try { + $images = json_decode($admin['qualification_images'], true); + if (is_array($images)) { + $admin['qualification_images'] = $images; + } + } catch (\Exception $e) { + // 解析失败时保持原值 + Log::error('解析资质图片失败: ' . $e->getMessage()); + } +} +``` + +**数据流转说明**: +1. **前端提交** → 数组格式 `["url1", "url2"]` +2. **后端接收** → 转换为JSON字符串存储到数据库 +3. **后端返回** → 将JSON字符串转换回数组格式 +4. **前端接收** → 数组格式,`material-picker` 组件可直接使用 + +#### 2.2 医生详情接口 +**文件**: `server/app/api/logic/DoctorLogic.php` + +修改 `getDoctorDetail` 方法: +- 在查询字段中添加 `qualification_images` +- 在返回数据中包含 `qualification_images` 字段 + +```php +$doctor = Admin::where('id', $doctorId) + ->where('disable', 0) + ->field(['id', 'name', 'account', 'avatar','specialty','license_no','qualification_images','enable_image_consult','enable_video_consult','enable_charge']) + ->find(); + +return [ + // ... 其他字段 + 'qualification_images' => $doctorData['qualification_images'] ?? '', + // ... 其他字段 +]; +``` + +### 3. 前端修改 + +#### 3.1 管理后台 - 医生编辑页面 +**文件**: `admin/src/views/consumer/doctor/edit.vue` + +**新增内容**: +1. 在"执业证书编号"字段后添加"资质图片"上传组件 +2. 使用 `material-picker` 组件,支持最多上传9张图片 +3. 在 `formData` 中添加 `qualification_images` 字段 + +**代码示例**: +```vue + + +
+
+ +
+
上传医生资质证书、荣誉证书等图片,最多9张,建议尺寸:800*600px
+
+
+``` + +#### 3.2 小程序端 - 医生详情页面 +**文件**: `TUICallKit-Vue3/doctor/pages/doctor/doctor.vue` + +**新增内容**: +1. 在"擅长领域"和"专业领域"之间添加"医生资质"展示区域 +2. 使用3列网格布局展示资质图片 +3. 点击图片可预览大图 +4. 使用 computed 属性解析 JSON 格式的图片数据 + +**代码示例**: +```vue + +
+ 医生资质 + + + +
+``` + +**JavaScript逻辑**: +```javascript +// 医生资质图片 +const qualificationImages = computed(() => { + if (!doctor.value?.qualification_images) return [] + try { + const images = typeof doctor.value.qualification_images === 'string' + ? JSON.parse(doctor.value.qualification_images) + : doctor.value.qualification_images + return Array.isArray(images) ? images : [] + } catch (e) { + console.error('解析资质图片失败:', e) + return [] + } +}) + +// 预览资质图片 +const previewImage = (current) => { + uni.previewImage({ + current: current, + urls: qualificationImages.value + }) +} +``` + +**样式**: +```scss +.qualification-section { + margin-bottom: 96rpx; +} + +.qualification-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24rpx; +} + +.qualification-image { + width: 100%; + height: 200rpx; + border-radius: 16rpx; + background: $surface-high; + object-fit: cover; +} +``` + +## 相关接口 + +### 管理后台接口 + +#### 1. 添加医生 +- **接口**: `POST /adminapi/auth.admin/add` +- **参数**: + - `qualification_images`: 资质图片(字符串,多个图片URL用逗号分隔或JSON数组格式) + - 其他医生信息字段... + +#### 2. 编辑医生 +- **接口**: `POST /adminapi/auth.admin/edit` +- **参数**: + - `id`: 医生ID + - `qualification_images`: 资质图片 + - 其他医生信息字段... + +#### 3. 医生详情 +- **接口**: `GET /adminapi/auth.admin/detail` +- **参数**: + - `id`: 医生ID +- **返回**: 包含 `qualification_images` 字段 + +### 小程序端接口 + +#### 医生详情 +- **接口**: `GET /api/doctor/detail` +- **参数**: + - `id`: 医生ID +- **返回**: 包含 `qualification_images` 字段 + +## 使用流程 + +### 管理员操作流程 +1. 登录管理后台 +2. 进入"医生管理"页面 +3. 点击"编辑"或"新增"医生 +4. 在"专业信息"部分找到"资质图片"字段 +5. 点击上传按钮,选择资质证书图片(最多9张) +6. 保存医生信息 + +### 用户查看流程 +1. 打开小程序 +2. 进入医生详情页面 +3. 在"擅长领域"下方查看"医生资质"部分 +4. 点击任意资质图片可放大预览 +5. 左右滑动可查看所有资质图片 + +## 数据格式 + +### 前端提交格式(管理后台) +前端 `material-picker` 组件提交的数据格式: +```javascript +// 单张图片 +["https://www.d.com/uploads/images/20260317/20260317111180ffc63266.png"] + +// 多张图片 +[ + "https://www.d.com/uploads/images/20260317/image1.png", + "https://www.d.com/uploads/images/20260317/image2.png", + "https://www.d.com/uploads/images/20260317/image3.png" +] +``` + +### 后端存储格式 +后端将数组转换为JSON字符串存储在数据库中: +```json +["https://www.d.com/uploads/images/20260317/20260317111180ffc63266.png"] +``` + +**转换代码**: +```php +if (is_array($params['qualification_images'])) { + $qualificationImages = json_encode($params['qualification_images'], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); +} +``` + +### API返回格式 + +#### 管理后台详情接口返回 +```json +{ + "code": 1, + "msg": "success", + "data": { + "id": 1, + "name": "李医生", + "qualification_images": [ + "https://www.d.com/uploads/images/20260317/image1.png", + "https://www.d.com/uploads/images/20260317/image2.png" + ], + // ... 其他字段 + } +} +``` +注意:管理后台返回的是数组格式,方便 `material-picker` 组件直接使用 + +#### 小程序端详情接口返回 +```json +{ + "code": 1, + "msg": "success", + "data": { + "id": 1, + "name": "李医生", + "qualification_images": "[\"https://www.d.com/uploads/images/20260317/image1.png\",\"https://www.d.com/uploads/images/20260317/image2.png\"]", + // ... 其他字段 + } +} +``` +注意:小程序端返回的是JSON字符串格式,需要前端解析 + +### 小程序端解析 +小程序端需要将JSON字符串解析为数组: +```javascript +const qualificationImages = computed(() => { + if (!doctor.value?.qualification_images) return [] + try { + const images = typeof doctor.value.qualification_images === 'string' + ? JSON.parse(doctor.value.qualification_images) + : doctor.value.qualification_images + return Array.isArray(images) ? images : [] + } catch (e) { + console.error('解析资质图片失败:', e) + return [] + } +}) +``` + +## 注意事项 + +1. **图片数量限制**: 最多支持上传9张资质图片 +2. **图片格式**: 建议使用 jpg、jpeg、png 格式 +3. **图片尺寸**: 建议尺寸为 800*600px,以保证清晰度 +4. **存储格式**: 后端以JSON数组格式存储,前端需要解析 +5. **容错处理**: 前端已添加JSON解析失败的容错处理 +6. **显示条件**: 只有当医生有资质图片时才显示"医生资质"区域 +7. **预览功能**: 使用uni.previewImage实现图片预览和滑动查看 + +## 扩展建议 + +1. **图片压缩**: 可以在上传时对图片进行压缩,减少存储空间 +2. **水印添加**: 可以为资质图片添加水印,防止盗用 +3. **审核机制**: 可以添加资质图片审核功能,确保真实性 +4. **过期提醒**: 可以为资质证书添加有效期,到期前提醒更新 +5. **分类管理**: 可以将资质图片分类(如执业证书、荣誉证书等) diff --git a/医生资质图片功能部署指南.md b/医生资质图片功能部署指南.md new file mode 100644 index 00000000..e69de29b diff --git a/医生资质图片数据流转说明.md b/医生资质图片数据流转说明.md new file mode 100644 index 00000000..f4b0da61 --- /dev/null +++ b/医生资质图片数据流转说明.md @@ -0,0 +1,277 @@ +# 医生资质图片数据流转说明 + +## 完整数据流转过程 + +### 1. 添加/编辑医生(管理后台) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 前端(Vue3) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 用户上传图片 │ +│ ↓ │ +│ material-picker 组件 │ +│ ↓ │ +│ formData.qualification_images = [ │ +│ "https://www.d.com/uploads/images/20260317/image1.png", │ +│ "https://www.d.com/uploads/images/20260317/image2.png" │ +│ ] │ +│ ↓ │ +│ 提交表单(POST请求) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 后端接口(AdminController) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 接收参数: │ +│ $params['qualification_images'] = [ │ +│ "https://www.d.com/uploads/images/20260317/image1.png", │ +│ "https://www.d.com/uploads/images/20260317/image2.png" │ +│ ] │ +│ ↓ │ +│ 调用 AdminLogic::add() 或 AdminLogic::edit() │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 业务逻辑层(AdminLogic) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ // 数据转换处理 │ +│ if (is_array($params['qualification_images'])) { │ +│ $qualificationImages = json_encode( │ +│ $params['qualification_images'], │ +│ JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES │ +│ ); │ +│ } │ +│ ↓ │ +│ 转换后的数据: │ +│ $qualificationImages = '["https://www.d.com/uploads/images/ │ +│ 20260317/image1.png","https://www.d.com/uploads/images/ │ +│ 20260317/image2.png"]' │ +│ ↓ │ +│ 保存到数据库 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 数据库(MySQL) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ la_admin 表 │ +│ ┌──────────────────────────────────────────────────────────┐ │ +│ │ qualification_images (text) │ │ +│ ├──────────────────────────────────────────────────────────┤ │ +│ │ ["https://www.d.com/uploads/images/20260317/image1.png",│ │ +│ │ "https://www.d.com/uploads/images/20260317/image2.png"] │ │ +│ └──────────────────────────────────────────────────────────┘ │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 2. 查看医生详情(管理后台) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 前端(Vue3) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 点击编辑按钮 │ +│ ↓ │ +│ 调用 adminDetail({ id: 1 }) │ +│ ↓ │ +│ GET /adminapi/auth.admin/detail?id=1 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 后端接口(AdminController) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 调用 AdminLogic::detail(['id' => 1]) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 业务逻辑层(AdminLogic) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ // 从数据库查询 │ +│ $admin = Admin::field([...])->find()->toArray(); │ +│ ↓ │ +│ 查询结果: │ +│ $admin['qualification_images'] = '["https://www.d.com/uploads/ │ +│ images/20260317/image1.png","https://www.d.com/uploads/images/ │ +│ 20260317/image2.png"]' │ +│ ↓ │ +│ // 转换为数组格式 │ +│ if (!empty($admin['qualification_images'])) { │ +│ $images = json_decode($admin['qualification_images'], true);│ +│ if (is_array($images)) { │ +│ $admin['qualification_images'] = $images; │ +│ } │ +│ } │ +│ ↓ │ +│ 转换后的数据: │ +│ $admin['qualification_images'] = [ │ +│ "https://www.d.com/uploads/images/20260317/image1.png", │ +│ "https://www.d.com/uploads/images/20260317/image2.png" │ +│ ] │ +│ ↓ │ +│ 返回给前端 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 前端(Vue3) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 接收响应数据: │ +│ formData.qualification_images = [ │ +│ "https://www.d.com/uploads/images/20260317/image1.png", │ +│ "https://www.d.com/uploads/images/20260317/image2.png" │ +│ ] │ +│ ↓ │ +│ material-picker 组件直接使用数组数据 │ +│ ↓ │ +│ 显示图片列表 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### 3. 小程序端查看医生详情 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 小程序前端(uni-app) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 进入医生详情页 │ +│ ↓ │ +│ GET /api/doctor/detail?id=1 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 后端接口(DoctorController) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 调用 DoctorLogic::getDoctorDetail($doctorId) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 业务逻辑层(DoctorLogic) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ // 从数据库查询 │ +│ $doctor = Admin::field([...])->find()->toArray(); │ +│ ↓ │ +│ 查询结果(保持JSON字符串格式): │ +│ $doctorData['qualification_images'] = '["https://www.d.com/ │ +│ uploads/images/20260317/image1.png","https://www.d.com/uploads/ │ +│ images/20260317/image2.png"]' │ +│ ↓ │ +│ 直接返回(不转换) │ +│ │ +└─────────────────────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────────────────────┐ +│ 小程序前端(uni-app) │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ 接收响应数据: │ +│ doctor.value.qualification_images = '["https://www.d.com/ │ +│ uploads/images/20260317/image1.png","https://www.d.com/uploads/ │ +│ images/20260317/image2.png"]' │ +│ ↓ │ +│ // 使用 computed 解析 │ +│ const qualificationImages = computed(() => { │ +│ if (!doctor.value?.qualification_images) return [] │ +│ try { │ +│ const images = typeof doctor.value.qualification_images │ +│ === 'string' │ +│ ? JSON.parse(doctor.value.qualification_images) │ +│ : doctor.value.qualification_images │ +│ return Array.isArray(images) ? images : [] │ +│ } catch (e) { │ +│ return [] │ +│ } │ +│ }) │ +│ ↓ │ +│ 解析后的数据: │ +│ qualificationImages.value = [ │ +│ "https://www.d.com/uploads/images/20260317/image1.png", │ +│ "https://www.d.com/uploads/images/20260317/image2.png" │ +│ ] │ +│ ↓ │ +│ 渲染图片网格 │ +│ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## 关键点总结 + +### 1. 数据格式转换时机 + +| 场景 | 输入格式 | 输出格式 | 转换位置 | +|------|---------|---------|---------| +| 添加医生 | 数组 | JSON字符串 | AdminLogic::add() | +| 编辑医生 | 数组 | JSON字符串 | AdminLogic::edit() | +| 管理后台查看 | JSON字符串 | 数组 | AdminLogic::detail() | +| 小程序端查看 | JSON字符串 | JSON字符串 | 不转换,前端解析 | + +### 2. 为什么管理后台要转换回数组? + +因为 `material-picker` 组件需要数组格式的数据: +```vue + +``` + +如果传入JSON字符串,组件无法正确显示已上传的图片。 + +### 3. 为什么小程序端不转换? + +1. 保持API返回数据的一致性 +2. 减少后端处理逻辑 +3. 前端有完善的解析和容错机制 +4. 便于缓存和传输 + +### 4. JSON编码参数说明 + +```php +json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) +``` + +- `JSON_UNESCAPED_UNICODE`: 不转义中文字符 +- `JSON_UNESCAPED_SLASHES`: 不转义URL中的斜杠 `/` + +这样可以保证: +- URL正确性:`https://` 不会变成 `https:\/\/` +- 中文文件名正确显示 +- 减少字符串长度 + +## 测试验证 + +### 验证数据转换是否正确 + +```php +// 测试代码 +$testData = [ + "https://www.d.com/uploads/images/20260317/测试图片1.png", + "https://www.d.com/uploads/images/20260317/测试图片2.png" +]; + +// 编码 +$encoded = json_encode($testData, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); +echo "编码后: " . $encoded . "\n"; +// 输出: ["https://www.d.com/uploads/images/20260317/测试图片1.png","https://www.d.com/uploads/images/20260317/测试图片2.png"] + +// 解码 +$decoded = json_decode($encoded, true); +var_dump($decoded); +// 输出: array(2) { [0]=> string(...) [1]=> string(...) } +``` diff --git a/测试医生资质图片功能.md b/测试医生资质图片功能.md new file mode 100644 index 00000000..992edc7a --- /dev/null +++ b/测试医生资质图片功能.md @@ -0,0 +1,267 @@ +# 测试医生资质图片功能 + +## 测试步骤 + +### 1. 数据库准备 + +首先执行SQL文件添加字段: + +```bash +# 如果使用 la_ 前缀 +mysql -u root -p your_database < server/sql/add_doctor_qualification_images.sql + +# 如果使用 zyt_ 前缀,先修改SQL文件中的表名 +# 将 la_admin 替换为 zyt_admin +``` + +验证字段是否添加成功: +```sql +DESC la_admin; +-- 或 +DESC zyt_admin; + +-- 应该能看到 qualification_images 字段 +``` + +### 2. 管理后台测试 + +#### 2.1 添加医生并上传资质图片 + +1. 登录管理后台 +2. 进入"医生管理"页面 +3. 点击"新增医生"按钮 +4. 填写基本信息: + - 账号:test_doctor + - 姓名:测试医生 + - 密码:123456 + - 其他必填字段... +5. 在"专业信息"部分找到"资质图片"字段 +6. 点击上传按钮,选择1-3张测试图片 +7. 点击"确定"保存 + +#### 2.2 编辑医生资质图片 + +1. 在医生列表中找到刚创建的医生 +2. 点击"编辑"按钮 +3. 在"资质图片"字段中: + - 可以删除已有图片 + - 可以添加新图片 + - 可以调整图片顺序 +4. 点击"确定"保存 + +#### 2.3 查看医生详情 + +1. 点击医生列表中的"详情"按钮 +2. 确认能看到 `qualification_images` 字段 +3. 确认图片URL格式正确 + +### 3. API接口测试 + +#### 3.1 测试添加医生接口 + +```bash +curl -X POST "http://your-domain/adminapi/auth.admin/add" \ + -H "Content-Type: application/json" \ + -H "token: your_admin_token" \ + -d '{ + "account": "test_doctor2", + "name": "测试医生2", + "password": "123456", + "password_confirm": "123456", + "gender": 1, + "role_id": [1], + "dept_id": [1], + "qualification_images": "[\"https://example.com/cert1.jpg\",\"https://example.com/cert2.jpg\"]", + "disable": 0, + "multipoint_login": 1 + }' +``` + +#### 3.2 测试编辑医生接口 + +```bash +curl -X POST "http://your-domain/adminapi/auth.admin/edit" \ + -H "Content-Type: application/json" \ + -H "token: your_admin_token" \ + -d '{ + "id": 1, + "account": "test_doctor", + "name": "测试医生", + "qualification_images": "[\"https://example.com/cert1.jpg\",\"https://example.com/cert2.jpg\",\"https://example.com/cert3.jpg\"]", + "disable": 0, + "multipoint_login": 1 + }' +``` + +#### 3.3 测试医生详情接口 + +```bash +curl -X GET "http://your-domain/adminapi/auth.admin/detail?id=1" \ + -H "token: your_admin_token" +``` + +预期返回: +```json +{ + "code": 1, + "msg": "success", + "data": { + "id": 1, + "name": "测试医生", + "qualification_images": "[\"https://example.com/cert1.jpg\",\"https://example.com/cert2.jpg\"]", + ... + } +} +``` + +#### 3.4 测试小程序端医生详情接口 + +```bash +curl -X GET "http://your-domain/api/doctor/detail?id=1" +``` + +预期返回: +```json +{ + "code": 1, + "msg": "success", + "data": { + "id": 1, + "name": "测试医生", + "qualification_images": "[\"https://example.com/cert1.jpg\",\"https://example.com/cert2.jpg\"]", + ... + } +} +``` + +### 4. 小程序端测试 + +#### 4.1 查看医生详情页 + +1. 打开小程序 +2. 进入医生列表页面 +3. 点击任意医生进入详情页 +4. 滚动到"擅长领域"下方 +5. 应该能看到"医生资质"区域(如果该医生有资质图片) +6. 资质图片以3列网格布局展示 + +#### 4.2 测试图片预览 + +1. 点击任意资质图片 +2. 应该弹出图片预览界面 +3. 可以左右滑动查看所有资质图片 +4. 可以双指缩放查看图片细节 +5. 点击关闭按钮或返回键退出预览 + +### 5. 边界情况测试 + +#### 5.1 无资质图片 +- 医生没有上传资质图片时,小程序端不显示"医生资质"区域 +- 管理后台显示空的上传区域 + +#### 5.2 单张图片 +- 上传1张图片,正常显示 +- 预览时只有1张图片 + +#### 5.3 多张图片 +- 上传9张图片(最大限制) +- 所有图片都能正常显示 +- 预览时可以滑动查看所有图片 + +#### 5.4 图片格式 +- 测试 JPG 格式 ✓ +- 测试 PNG 格式 ✓ +- 测试 JPEG 格式 ✓ + +#### 5.5 错误数据处理 +- 空字符串:不显示资质区域 +- null:不显示资质区域 +- 无效JSON:不显示资质区域(有容错处理) +- 非数组JSON:不显示资质区域 + +### 6. 性能测试 + +#### 6.1 图片加载速度 +- 测试3张图片的加载时间 +- 测试9张图片的加载时间 +- 确认图片懒加载是否生效 + +#### 6.2 预览性能 +- 测试预览大图的加载速度 +- 测试滑动切换的流畅度 + +## 测试检查清单 + +- [ ] 数据库字段添加成功 +- [ ] 管理后台可以上传资质图片 +- [ ] 管理后台可以编辑资质图片 +- [ ] 管理后台可以删除资质图片 +- [ ] 添加医生接口正常工作 +- [ ] 编辑医生接口正常工作 +- [ ] 医生详情接口返回资质图片 +- [ ] 小程序端正常显示资质图片 +- [ ] 小程序端图片预览功能正常 +- [ ] 无资质图片时不显示该区域 +- [ ] 支持多种图片格式 +- [ ] 错误数据有容错处理 +- [ ] 图片加载性能良好 + +## 常见问题排查 + +### 问题1:管理后台上传图片后不显示 +**排查步骤**: +1. 检查浏览器控制台是否有错误 +2. 检查图片上传接口是否成功 +3. 检查 `material-picker` 组件是否正常工作 +4. 检查 `formData.qualification_images` 是否有值 + +### 问题2:小程序端不显示资质图片 +**排查步骤**: +1. 检查医生详情接口返回的数据 +2. 检查 `qualification_images` 字段是否有值 +3. 检查 `qualificationImages` computed 是否正确解析 +4. 检查图片URL是否可访问 +5. 检查小程序域名白名单配置 + +### 问题3:图片预览失败 +**排查步骤**: +1. 检查 `uni.previewImage` 是否正常调用 +2. 检查图片URL格式是否正确 +3. 检查小程序权限配置 +4. 查看小程序控制台错误信息 + +### 问题4:数据库字段不存在 +**排查步骤**: +1. 确认是否执行了SQL文件 +2. 确认表名前缀是否正确(la_ 或 zyt_) +3. 手动执行 `DESC` 命令检查字段 +4. 检查数据库连接是否正确 + +## 测试数据示例 + +### 示例1:单张图片 +```json +["https://example.com/doctor-cert-1.jpg"] +``` + +### 示例2:多张图片 +```json +[ + "https://example.com/doctor-cert-1.jpg", + "https://example.com/doctor-cert-2.jpg", + "https://example.com/doctor-cert-3.jpg" +] +``` + +### 示例3:完整医生数据 +```json +{ + "id": 1, + "name": "李医生", + "title": "主任医师", + "license_no": "110101199001011234", + "qualification_images": "[\"https://example.com/cert1.jpg\",\"https://example.com/cert2.jpg\"]", + "enable_image_consult": 1, + "enable_video_consult": 1 +} +```