增加检查报告时间轴

This commit is contained in:
2026-04-30 10:58:53 +08:00
parent bb08eeab32
commit cba04067bd
4 changed files with 112 additions and 73 deletions
@@ -10,11 +10,25 @@
</div> </div>
</div> </div>
<div v-if="note.tongue_images?.length" class="timeline-images"> <div v-if="note.tongue_images?.length" class="timeline-images">
<span class="images-label">舌苔照片</span>
<el-image <el-image
v-for="(url, idx) in note.tongue_images" v-for="(url, idx) in note.tongue_images"
:key="idx" :key="idx"
:src="url" :src="getImageUrl(url)"
:preview-src-list="note.tongue_images" :preview-src-list="note.tongue_images.map(getImageUrl)"
:initial-index="idx"
fit="cover"
class="timeline-thumb"
preview-teleported
/>
</div>
<div v-if="note.report_files?.length" class="timeline-images">
<span class="images-label">检查报告</span>
<el-image
v-for="(url, idx) in note.report_files"
:key="idx"
:src="getImageUrl(url)"
:preview-src-list="note.report_files.map(getImageUrl)"
:initial-index="idx" :initial-index="idx"
fit="cover" fit="cover"
class="timeline-thumb" class="timeline-thumb"
@@ -27,15 +41,21 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import useAppStore from '@/stores/modules/app'
export interface DoctorNoteItem { export interface DoctorNoteItem {
id: number id: number
note_date: string note_date: string
content: string | null content: string | null
tongue_images: string[] tongue_images: string[]
report_files: string[]
} }
defineProps<{ notes: DoctorNoteItem[] }>() defineProps<{ notes: DoctorNoteItem[] }>()
const appStore = useAppStore()
const getImageUrl = (url: string) => appStore.getImageUrl(url)
const splitLines = (content: string | null): string[] => { const splitLines = (content: string | null): string[] => {
if (!content) return [] if (!content) return []
return content.split('\n').filter(Boolean) return content.split('\n').filter(Boolean)
@@ -100,8 +120,14 @@ const splitLines = (content: string | null): string[] => {
.timeline-images { .timeline-images {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
align-items: center;
gap: 6px; gap: 6px;
} }
.images-label {
font-size: 12px;
color: #909399;
flex-shrink: 0;
}
.timeline-thumb { .timeline-thumb {
width: 64px; width: 64px;
height: 64px; height: 64px;
@@ -4,11 +4,12 @@ namespace app\adminapi\logic\doctor;
use app\common\logic\BaseLogic; use app\common\logic\BaseLogic;
use app\common\model\doctor\DoctorNote; use app\common\model\doctor\DoctorNote;
use app\common\service\FileService;
class DoctorNoteLogic extends BaseLogic class DoctorNoteLogic extends BaseLogic
{ {
/** /**
* 按 diagnosis_id + 当天 find-or-create,追加 content / tongue_images * 按 diagnosis_id + 当天 find-or-create,追加 content / tongue_images / report_files
*/ */
public static function addOrAppend(array $params): bool public static function addOrAppend(array $params): bool
{ {
@@ -24,10 +25,8 @@ class DoctorNoteLogic extends BaseLogic
->find(); ->find();
$newContent = trim($params['content'] ?? ''); $newContent = trim($params['content'] ?? '');
$newImages = $params['tongue_images'] ?? []; $newImages = self::parseJsonArray($params['tongue_images'] ?? []);
if (is_string($newImages)) { $newReports = self::parseJsonArray($params['report_files'] ?? []);
$newImages = json_decode($newImages, true) ?: [];
}
if ($existing) { if ($existing) {
$data = []; $data = [];
@@ -39,17 +38,17 @@ class DoctorNoteLogic extends BaseLogic
} }
if (!empty($newImages)) { if (!empty($newImages)) {
$prev = $existing->tongue_images; $prev = self::parseJsonArray($existing->tongue_images);
if (is_string($prev)) {
$prev = json_decode($prev, true) ?: [];
}
if (!is_array($prev)) {
$prev = [];
}
$merged = array_values(array_unique(array_merge($prev, $newImages))); $merged = array_values(array_unique(array_merge($prev, $newImages)));
$data['tongue_images'] = json_encode($merged, JSON_UNESCAPED_UNICODE); $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)) { if (!empty($data)) {
$existing->save($data); $existing->save($data);
} }
@@ -63,6 +62,9 @@ class DoctorNoteLogic extends BaseLogic
'tongue_images' => !empty($newImages) 'tongue_images' => !empty($newImages)
? json_encode($newImages, JSON_UNESCAPED_UNICODE) ? json_encode($newImages, JSON_UNESCAPED_UNICODE)
: null, : null,
'report_files' => !empty($newReports)
? json_encode($newReports, JSON_UNESCAPED_UNICODE)
: null,
]); ]);
} }
@@ -91,14 +93,12 @@ class DoctorNoteLogic extends BaseLogic
->toArray(); ->toArray();
foreach ($records as &$record) { foreach ($records as &$record) {
$images = $record['tongue_images'] ?? []; $record['tongue_images'] = array_map(function ($url) {
if (is_string($images)) { return empty($url) ? $url : FileService::getFileUrl($url);
$images = json_decode($images, true) ?: []; }, self::parseJsonArray($record['tongue_images'] ?? []));
} $record['report_files'] = array_map(function ($url) {
if (!is_array($images)) { return empty($url) ? $url : FileService::getFileUrl($url);
$images = []; }, self::parseJsonArray($record['report_files'] ?? []));
}
$record['tongue_images'] = $images;
} }
return $records; return $records;
@@ -107,4 +107,14 @@ class DoctorNoteLogic extends BaseLogic
return []; return [];
} }
} }
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 [];
}
} }
@@ -19,6 +19,8 @@ use app\common\model\tcm\Diagnosis;
use app\common\model\tcm\DiagnosisAssignLog; use app\common\model\tcm\DiagnosisAssignLog;
use app\common\model\tcm\ImChatMessage; use app\common\model\tcm\ImChatMessage;
use app\common\model\DiagnosisViewRecord; use app\common\model\DiagnosisViewRecord;
use app\adminapi\logic\doctor\DoctorNoteLogic;
use app\common\service\FileService;
use think\facade\Db; use think\facade\Db;
/** /**
* 中医辨房病因诊单逻辑 * 中医辨房病因诊单逻辑
@@ -192,14 +194,37 @@ class DiagnosisLogic extends BaseLogic
$params['diagnosis_date'] = strtotime($params['diagnosis_date']); $params['diagnosis_date'] = strtotime($params['diagnosis_date']);
} }
// 保存前记录旧的检查报告,用于对比新增
$oldReportFiles = [];
if (isset($params['report_files'])) {
$old = Diagnosis::where('id', $params['id'])->value('report_files');
if ($old) {
$oldReportFiles = is_string($old) ? (json_decode($old, true) ?: []) : (array) $old;
}
}
Diagnosis::update($params); Diagnosis::update($params);
// 检查报告有新增时同步到医生备注
if (isset($params['report_files'])) {
$newReportFiles = is_string($params['report_files'])
? (json_decode($params['report_files'], true) ?: [])
: (array) $params['report_files'];
$added = array_values(array_diff($newReportFiles, $oldReportFiles));
if (!empty($added)) {
DoctorNoteLogic::addOrAppend([
'diagnosis_id' => (int) $params['id'],
'report_files' => $added,
]);
}
}
// 如果是编辑,也确保患者有 TRTC 账号 // 如果是编辑,也确保患者有 TRTC 账号
$diagnosis = Diagnosis::find($params['id']); $diagnosis = Diagnosis::find($params['id']);
if ($diagnosis) { if ($diagnosis) {
self::createPatientTrtcAccount($diagnosis->patient_id); self::createPatientTrtcAccount($diagnosis->patient_id);
} }
return true; return true;
} catch (\Exception $e) { } catch (\Exception $e) {
self::setError($e->getMessage()); self::setError($e->getMessage());
@@ -256,57 +281,30 @@ class DiagnosisLogic extends BaseLogic
if (!empty($diagnosis['tongue_images'])) { if (!empty($diagnosis['tongue_images'])) {
// 先尝试 JSON 解析(兼容旧数据) $files = json_decode($diagnosis['tongue_images'], true);
$files = json_decode($diagnosis['tongue_images'], true); if (is_array($files)) {
if (is_array($files)) { $diagnosis['tongue_images'] = $files;
$diagnosis['tongue_images'] = $files; } else {
} else { $diagnosis['tongue_images'] = array_filter(explode(',', $diagnosis['tongue_images'])) ?: [];
// JSON 解析失败则按逗号分割 }
$diagnosis['tongue_images'] = array_filter(explode(',', $diagnosis['tongue_images'])) ?: []; $diagnosis['tongue_images'] = array_map(function($url) {
} return empty($url) ? $url : FileService::getFileUrl($url);
}, $diagnosis['tongue_images']);
// 为没有 http 前缀的图片添加域名 } else {
$domain = request()->domain(); $diagnosis['tongue_images'] = [];
$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'] = [];
}
// 处理检查报告(JSON转数组) if (!empty($diagnosis['report_files'])) {
if (!empty($diagnosis['report_files'])) { $files = json_decode($diagnosis['report_files'], true);
// 先尝试 JSON 解析(兼容旧数据) if (is_array($files)) {
$files = json_decode($diagnosis['report_files'], true); $diagnosis['report_files'] = $files;
if (is_array($files)) { } else {
$diagnosis['report_files'] = $files; $diagnosis['report_files'] = array_filter(explode(',', $diagnosis['report_files'])) ?: [];
} else { }
// JSON 解析失败则按逗号分割 $diagnosis['report_files'] = array_map(function($url) {
$diagnosis['report_files'] = array_filter(explode(',', $diagnosis['report_files'])) ?: []; return empty($url) ? $url : FileService::getFileUrl($url);
} }, $diagnosis['report_files']);
} else {
// 为没有 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'] = []; $diagnosis['report_files'] = [];
} }
// 处理诊断日期格式 // 处理诊断日期格式
@@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS `zyt_doctor_note` (
`note_date` date NOT NULL COMMENT '记录日期', `note_date` date NOT NULL COMMENT '记录日期',
`content` text DEFAULT NULL COMMENT '备注文字(多次追加以换行分隔,带时间戳前缀)', `content` text DEFAULT NULL COMMENT '备注文字(多次追加以换行分隔,带时间戳前缀)',
`tongue_images` json DEFAULT NULL COMMENT '舌苔/截屏照片路径数组', `tongue_images` json DEFAULT NULL COMMENT '舌苔/截屏照片路径数组',
`report_files` json DEFAULT NULL COMMENT '检查报告图片路径数组',
`create_time` int(10) unsigned NOT NULL DEFAULT 0, `create_time` int(10) unsigned NOT NULL DEFAULT 0,
`update_time` int(10) unsigned NOT NULL DEFAULT 0, `update_time` int(10) unsigned NOT NULL DEFAULT 0,
`delete_time` int(10) unsigned DEFAULT NULL, `delete_time` int(10) unsigned DEFAULT NULL,
@@ -14,3 +15,7 @@ CREATE TABLE IF NOT EXISTS `zyt_doctor_note` (
UNIQUE KEY `uk_diagnosis_date` (`diagnosis_id`, `note_date`), UNIQUE KEY `uk_diagnosis_date` (`diagnosis_id`, `note_date`),
KEY `idx_doctor` (`doctor_id`) KEY `idx_doctor` (`doctor_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='医生接诊备注'; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='医生接诊备注';
ALTER TABLE `zyt_doctor_note` ADD COLUMN `report_files` json DEFAULT NULL COMMENT
'检查报告图片路径数组' AFTER `tongue_images`;