增加检查报告时间轴
This commit is contained in:
@@ -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`;
|
||||||
Reference in New Issue
Block a user