Files
zyt/admin/src/views/tcm/diagnosis/components/TrackingNoteTimeline.vue
T
2026-05-05 17:52:35 +08:00

180 lines
4.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="tracking-timeline-wrap">
<!-- 编辑模式输入新备注 -->
<div v-if="!readonly && diagnosisId" class="timeline-input">
<el-input
v-model="draft"
type="textarea"
:rows="2"
placeholder="输入跟踪备注,回车换行;保存后将以「[HH:MM] 内容」追加到当天记录"
maxlength="1000"
show-word-limit
resize="none"
:disabled="saving"
/>
<div class="input-actions">
<el-button
type="primary"
size="small"
:loading="saving"
:disabled="!draft.trim()"
@click="handleSave"
>
添加
</el-button>
</div>
</div>
<!-- 时间轴 -->
<div v-if="notes.length" class="tracking-timeline">
<div v-for="note in notes" :key="note.id" class="timeline-node">
<div class="timeline-dot"></div>
<div class="timeline-date">{{ note.note_date }}</div>
<div class="timeline-body">
<div v-if="note.content" class="timeline-content">
<div
v-for="(line, idx) in splitLines(note.content)"
:key="idx"
class="content-line"
>
{{ line }}
</div>
</div>
</div>
</div>
</div>
<el-empty v-if="!notes.length && readonly" description="暂无跟踪备注" :image-size="48" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { diagnosisAddTrackingNote } from '@/api/tcm'
import feedback from '@/utils/feedback'
export interface TrackingNoteItem {
id: number
note_date: string
content: string | null
}
const props = defineProps<{
notes: TrackingNoteItem[]
diagnosisId?: number
readonly?: boolean
}>()
const emit = defineEmits<{ refresh: [] }>()
const draft = ref('')
const saving = ref(false)
const splitLines = (content: string | null): string[] => {
if (!content) return []
return content.split('\n').filter(Boolean)
}
const handleSave = async () => {
if (!props.diagnosisId) return
const content = draft.value.trim()
if (!content) return
saving.value = true
try {
await diagnosisAddTrackingNote({
diagnosis_id: props.diagnosisId,
tracking_content: content,
})
feedback.msgSuccess('已添加')
draft.value = ''
emit('refresh')
} finally {
saving.value = false
}
}
</script>
<style scoped lang="scss">
.tracking-timeline-wrap {
display: flex;
flex-direction: column;
gap: 14px;
}
.timeline-input {
display: flex;
flex-direction: column;
gap: 8px;
padding-bottom: 12px;
border-bottom: 1px dashed #ebeef5;
}
.input-actions {
display: flex;
justify-content: flex-end;
}
.tracking-timeline {
position: relative;
padding-left: 22px;
}
.tracking-timeline::before {
content: '';
position: absolute;
left: 6px;
top: 4px;
bottom: 4px;
width: 2px;
background: #ebeef5;
border-radius: 1px;
}
.timeline-node {
position: relative;
padding-bottom: 16px;
}
.timeline-node:last-child {
padding-bottom: 0;
}
.timeline-dot {
position: absolute;
left: -19px;
top: 5px;
width: 10px;
height: 10px;
border-radius: 50%;
background: #16a34a;
border: 2px solid #dcfce7;
}
.timeline-date {
font-size: 13px;
font-weight: 600;
color: #303133;
margin-bottom: 6px;
font-family: 'IBM Plex Mono', Consolas, monospace;
}
.timeline-body {
display: flex;
flex-direction: column;
gap: 6px;
}
.timeline-content {
display: flex;
flex-direction: column;
gap: 2px;
}
.content-line {
font-size: 12.5px;
color: #606266;
line-height: 1.6;
word-break: break-word;
}
</style>