From 0fff9953029dfc8a08eaf309346d7613bfdee623 Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 16 Apr 2026 11:32:03 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DIAGNOSIS_IMAGE_URL_PREFIX_FIX.md | 259 ++++++++++++++++++ .../app/adminapi/logic/tcm/DiagnosisLogic.php | 28 ++ 2 files changed, 287 insertions(+) create mode 100644 DIAGNOSIS_IMAGE_URL_PREFIX_FIX.md diff --git a/DIAGNOSIS_IMAGE_URL_PREFIX_FIX.md b/DIAGNOSIS_IMAGE_URL_PREFIX_FIX.md new file mode 100644 index 00000000..b17ee92f --- /dev/null +++ b/DIAGNOSIS_IMAGE_URL_PREFIX_FIX.md @@ -0,0 +1,259 @@ +# Diagnosis Image URL Prefix Fix (诊断图片URL前缀修复) + +## Issue +Image URLs in the diagnosis detail (tongue_images and report_files) were stored as relative paths without the domain prefix, causing issues when accessing them from external sources or different domains. + +## Solution +Added logic to automatically prepend the current domain to image URLs that don't already have an `http://` or `https://` prefix. + +## Changes Made + +### File: `server/app/adminapi/logic/tcm/DiagnosisLogic.php` + +#### 1. Updated tongue_images Processing +Added domain prefix logic after parsing the images array: + +```php +if (!empty($diagnosis['tongue_images'])) { + // 先尝试 JSON 解析(兼容旧数据) + $files = json_decode($diagnosis['tongue_images'], true); + if (is_array($files)) { + $diagnosis['tongue_images'] = $files; + } else { + // JSON 解析失败则按逗号分割 + $diagnosis['tongue_images'] = array_filter(explode(',', $diagnosis['tongue_images'])) ?: []; + } + + // 为没有 http 前缀的图片添加域名 + $domain = request()->domain(); + $diagnosis['tongue_images'] = array_map(function($url) use ($domain) { + if (empty($url)) { + return $url; + } + // 如果已经包含 http:// 或 https://,则跳过 + if (stripos($url, 'http://') === 0 || stripos($url, 'https://') === 0) { + return $url; + } + // 添加域名前缀 + return $domain . $url; + }, $diagnosis['tongue_images']); +} else { + $diagnosis['tongue_images'] = []; +} +``` + +#### 2. Updated report_files Processing +Applied the same logic to report files: + +```php +if (!empty($diagnosis['report_files'])) { + // 先尝试 JSON 解析(兼容旧数据) + $files = json_decode($diagnosis['report_files'], true); + if (is_array($files)) { + $diagnosis['report_files'] = $files; + } else { + // JSON 解析失败则按逗号分割 + $diagnosis['report_files'] = array_filter(explode(',', $diagnosis['report_files'])) ?: []; + } + + // 为没有 http 前缀的文件添加域名 + $domain = request()->domain(); + $diagnosis['report_files'] = array_map(function($url) use ($domain) { + if (empty($url)) { + return $url; + } + // 如果已经包含 http:// 或 https://,则跳过 + if (stripos($url, 'http://') === 0 || stripos($url, 'https://') === 0) { + return $url; + } + // 添加域名前缀 + return $domain . $url; + }, $diagnosis['report_files']); +} else { + $diagnosis['report_files'] = []; +} +``` + +## Logic Flow + +### URL Processing Logic: +1. Parse the images/files array (JSON or comma-separated) +2. Get current domain using `request()->domain()` +3. For each URL in the array: + - Check if URL is empty → skip + - Check if URL starts with `http://` or `https://` → skip (already has protocol) + - Otherwise → prepend domain to the URL + +### Examples: + +#### Relative Path (Needs Domain): +```php +Input: "/uploads/images/tongue/2024/01/image.jpg" +Domain: "https://admin.zhenyangtang.com.cn" +Output: "https://admin.zhenyangtang.com.cn/uploads/images/tongue/2024/01/image.jpg" +``` + +#### Absolute URL (Skip): +```php +Input: "https://cdn.example.com/images/tongue.jpg" +Output: "https://cdn.example.com/images/tongue.jpg" +``` + +#### HTTP URL (Skip): +```php +Input: "http://example.com/image.jpg" +Output: "http://example.com/image.jpg" +``` + +#### Empty URL (Skip): +```php +Input: "" +Output: "" +``` + +## Benefits + +### 1. Cross-Domain Compatibility +Images can now be accessed from different domains or external applications without path issues. + +### 2. API Response Consistency +API responses always return complete, accessible URLs regardless of how they were stored. + +### 3. Backward Compatibility +- Existing relative paths are automatically converted +- Existing absolute URLs are preserved +- No database migration required + +### 4. Flexible Storage +- Database can store either relative or absolute paths +- System handles both formats transparently +- Future-proof for CDN integration + +## Use Cases + +### 1. Mobile App Access +Mobile apps can directly use the returned URLs without needing to construct them. + +### 2. Third-Party Integration +External systems can access images using the complete URLs from API responses. + +### 3. CDN Migration +When migrating to CDN, images with absolute CDN URLs will work alongside local relative paths. + +### 4. Multi-Domain Setup +System works correctly across different domains (dev, staging, production). + +## Testing Steps + +### 1. Test Relative Path URLs +1. Create a diagnosis with tongue images stored as relative paths: + ``` + /uploads/images/tongue/2024/01/image.jpg + ``` +2. Fetch diagnosis detail via API +3. Verify response contains: + ```json + { + "tongue_images": [ + "https://admin.zhenyangtang.com.cn/uploads/images/tongue/2024/01/image.jpg" + ] + } + ``` + +### 2. Test Absolute URLs +1. Create a diagnosis with absolute URL: + ``` + https://cdn.example.com/images/tongue.jpg + ``` +2. Fetch diagnosis detail +3. Verify URL is unchanged: + ```json + { + "tongue_images": [ + "https://cdn.example.com/images/tongue.jpg" + ] + } + ``` + +### 3. Test Mixed URLs +1. Create a diagnosis with both relative and absolute URLs: + ``` + [ + "/uploads/local.jpg", + "https://cdn.example.com/remote.jpg" + ] + ``` +2. Fetch diagnosis detail +3. Verify correct processing: + ```json + { + "tongue_images": [ + "https://admin.zhenyangtang.com.cn/uploads/local.jpg", + "https://cdn.example.com/remote.jpg" + ] + } + ``` + +### 4. Test Empty/Null Values +1. Create a diagnosis with empty images +2. Fetch diagnosis detail +3. Verify empty array is returned: + ```json + { + "tongue_images": [] + } + ``` + +### 5. Test Report Files +Repeat all tests above for `report_files` field. + +## Technical Details + +### Domain Detection +Uses `request()->domain()` which returns the current request domain including protocol: +- Development: `http://localhost:8000` +- Production: `https://admin.zhenyangtang.com.cn` + +### Case-Insensitive Protocol Check +Uses `stripos()` for case-insensitive checking: +- Matches: `http://`, `HTTP://`, `Http://` +- Matches: `https://`, `HTTPS://`, `Https://` + +### Array Processing +Uses `array_map()` for efficient processing of all URLs in the array. + +## Related Files + +### Backend: +- `server/app/adminapi/logic/tcm/DiagnosisLogic.php` + - Updated `tongue_images` processing + - Updated `report_files` processing + +### Database: +- `tcm_diagnosis` table + - `tongue_images` column (stores JSON or comma-separated paths) + - `report_files` column (stores JSON or comma-separated paths) + +## Notes + +### Storage Format +The database continues to store paths as-is (relative or absolute). The conversion happens only when reading data for API responses. + +### Performance +The `array_map()` operation is efficient and adds minimal overhead. For typical diagnosis records with 1-5 images, the performance impact is negligible. + +### Future Enhancements +If needed, this logic could be extracted into a helper function for reuse across other file/image fields in the system. + +## Summary + +✅ Automatically adds domain prefix to relative image URLs +✅ Preserves absolute URLs (http/https) +✅ Handles both tongue_images and report_files +✅ Backward compatible with existing data +✅ Case-insensitive protocol detection +✅ Handles empty/null values gracefully +✅ No database migration required +✅ Works across different domains + +Image URLs in diagnosis details are now always complete and accessible, improving API usability and cross-domain compatibility! diff --git a/server/app/adminapi/logic/tcm/DiagnosisLogic.php b/server/app/adminapi/logic/tcm/DiagnosisLogic.php index b3c30ed1..a03b7238 100644 --- a/server/app/adminapi/logic/tcm/DiagnosisLogic.php +++ b/server/app/adminapi/logic/tcm/DiagnosisLogic.php @@ -255,6 +255,20 @@ class DiagnosisLogic extends BaseLogic // JSON 解析失败则按逗号分割 $diagnosis['tongue_images'] = array_filter(explode(',', $diagnosis['tongue_images'])) ?: []; } + + // 为没有 http 前缀的图片添加域名 + $domain = request()->domain(); + $diagnosis['tongue_images'] = array_map(function($url) use ($domain) { + if (empty($url)) { + return $url; + } + // 如果已经包含 http:// 或 https://,则跳过 + if (stripos($url, 'http://') === 0 || stripos($url, 'https://') === 0) { + return $url; + } + // 添加域名前缀 + return $domain .'/'. $url; + }, $diagnosis['tongue_images']); } else { $diagnosis['tongue_images'] = []; } @@ -269,6 +283,20 @@ class DiagnosisLogic extends BaseLogic // JSON 解析失败则按逗号分割 $diagnosis['report_files'] = array_filter(explode(',', $diagnosis['report_files'])) ?: []; } + + // 为没有 http 前缀的文件添加域名 + $domain = request()->domain(); + $diagnosis['report_files'] = array_map(function($url) use ($domain) { + if (empty($url)) { + return $url; + } + // 如果已经包含 http:// 或 https://,则跳过 + if (stripos($url, 'http://') === 0 || stripos($url, 'https://') === 0) { + return $url; + } + // 添加域名前缀 + return $domain . $url; + }, $diagnosis['report_files']); } else { $diagnosis['report_files'] = []; }