# 医生资质图片数据流转说明 ## 完整数据流转过程 ### 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(...) } ```