where('note_date', $today) ->whereNull('delete_time') ->find(); $newContent = trim($params['content'] ?? ''); $newImages = array_map([self::class, 'toRelativePath'], self::parseJsonArray($params['tongue_images'] ?? [])); $newReports = array_map([self::class, 'toRelativePath'], self::parseJsonArray($params['report_files'] ?? [])); if ($existing) { $data = []; if ($newContent !== '') { $prev = trim($existing->content ?? ''); $line = "[{$time}] {$newContent}"; $data['content'] = $prev !== '' ? ($prev . "\n" . $line) : $line; } if (!empty($newImages)) { $prev = self::parseJsonArray($existing->tongue_images); $merged = array_values(array_unique(array_merge($prev, $newImages))); $data['tongue_images'] = json_encode($merged, JSON_UNESCAPED_UNICODE); } if (!empty($newReports)) { $prev = self::parseJsonArray($existing->report_files); $merged = array_values(array_unique(array_merge($prev, $newReports))); $data['report_files'] = json_encode($merged, JSON_UNESCAPED_UNICODE); } if (!empty($data)) { $existing->save($data); } } else { $content = $newContent !== '' ? "[{$time}] {$newContent}" : ''; DoctorNote::create([ 'diagnosis_id' => $diagnosisId, 'doctor_id' => $doctorId, 'note_date' => $today, 'content' => $content, 'tongue_images' => !empty($newImages) ? json_encode($newImages, JSON_UNESCAPED_UNICODE) : null, 'report_files' => !empty($newReports) ? json_encode($newReports, JSON_UNESCAPED_UNICODE) : null, ]); } return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * 按 diagnosis_id 获取备注列表(note_date DESC) */ public static function getByDiagnosis(int $diagnosisId, int $limit = 30): array { try { if ($diagnosisId <= 0) { return []; } $records = DoctorNote::where('diagnosis_id', $diagnosisId) ->whereNull('delete_time') ->order('note_date', 'desc') ->limit($limit) ->select() ->toArray(); foreach ($records as &$record) { $record['tongue_images'] = array_map(function ($url) { return empty($url) ? $url : FileService::getFileUrl($url); }, self::parseJsonArray($record['tongue_images'] ?? [])); $record['report_files'] = array_map(function ($url) { return empty($url) ? $url : FileService::getFileUrl($url); }, self::parseJsonArray($record['report_files'] ?? [])); } return $records; } catch (\Exception $e) { self::setError($e->getMessage()); return []; } } /** * 删除备注中的单张图片 */ public static function deleteImage(int $noteId, string $imageType, string $imagePath): bool { try { $note = DoctorNote::where('id', $noteId)->whereNull('delete_time')->find(); if (!$note) { self::setError('记录不存在'); return false; } if (!in_array($imageType, ['tongue_images', 'report_files'])) { self::setError('类型无效'); return false; } $images = self::parseJsonArray($note->$imageType); // 统一转为相对路径再匹配 $targetPath = self::toRelativePath($imagePath); $images = array_values(array_filter($images, fn($url) => self::toRelativePath($url) !== $targetPath)); $note->$imageType = empty($images) ? null : json_encode($images, JSON_UNESCAPED_UNICODE); $note->save(); return true; } catch (\Exception $e) { self::setError($e->getMessage()); return false; } } /** * 聚合某诊单所有备注中的图片(供 DiagnosisLogic::detail 使用) */ public static function getAggregatedImages(int $diagnosisId): array { $records = DoctorNote::where('diagnosis_id', $diagnosisId) ->whereNull('delete_time') ->select(); $tongueImages = []; $reportFiles = []; foreach ($records as $r) { $tongueImages = array_merge($tongueImages, self::parseJsonArray($r->tongue_images)); $reportFiles = array_merge($reportFiles, self::parseJsonArray($r->report_files)); } return [ 'tongue_images' => array_map( fn($u) => empty($u) ? $u : FileService::getFileUrl($u), array_values(array_unique($tongueImages)) ), 'report_files' => array_map( fn($u) => empty($u) ? $u : FileService::getFileUrl($u), array_values(array_unique($reportFiles)) ), ]; } /** * 如果 URL 的域名是当前配置的存储域名则去掉,否则原样保留 */ private static function toRelativePath(string $url): string { if (empty($url)) return $url; if (stripos($url, 'http://') !== 0 && stripos($url, 'https://') !== 0) { return $url; } // 获取当前存储域名 $domain = self::getStorageDomain(); if ($domain && stripos($url, rtrim($domain, '/')) === 0) { $relative = substr($url, strlen(rtrim($domain, '/'))); return ltrim($relative, '/'); } // 非当前存储域名,保留完整 URL return $url; } private static function getStorageDomain(): string { $default = \app\common\service\ConfigService::get('storage', 'default', 'local'); if ($default === 'local') { return request()->domain() . '/'; } $storage = \app\common\service\ConfigService::get('storage', $default); return $storage ? ($storage['domain'] ?? '') : ''; } private static function parseJsonArray($value): array { if (is_array($value)) return $value; if (is_string($value)) { $decoded = json_decode($value, true); return is_array($decoded) ? $decoded : []; } return []; } }