更新
This commit is contained in:
@@ -40,6 +40,11 @@ export function checkIdCard(params: any) {
|
||||
return request.post({ url: '/tcm.diagnosis/checkIdCard', params })
|
||||
}
|
||||
|
||||
// 补全身份证号(自动更新年龄)
|
||||
export function fillIdCard(params: { id: number; id_card: string }) {
|
||||
return request.post({ url: '/tcm.diagnosis/fillIdCard', params })
|
||||
}
|
||||
|
||||
// 指派医助
|
||||
export function tcmDiagnosisAssign(params: any) {
|
||||
return request.post({ url: '/tcm.diagnosis/assign', params })
|
||||
@@ -164,3 +169,8 @@ export function prescriptionListByDiagnosis(params: { diagnosis_id: number }) {
|
||||
export function prescriptionGetByAppointment(params: { appointment_id: number }) {
|
||||
return request.get({ url: '/tcm.prescription/getByAppointment', params })
|
||||
}
|
||||
|
||||
// 作废处方
|
||||
export function prescriptionVoid(params: { id: number }) {
|
||||
return request.post({ url: '/tcm.prescription/void', params })
|
||||
}
|
||||
|
||||
@@ -190,8 +190,8 @@ const open = async (data: { patientId: number; patientName: string; diagnosisId?
|
||||
visible.value = true
|
||||
posX.value = 100
|
||||
posY.value = 80
|
||||
callKitX.value = Math.max(0, (window.innerWidth - 600) / 2)
|
||||
callKitY.value = Math.max(0, (window.innerHeight - 436) / 2)
|
||||
callKitX.value = Math.max(0, (window.innerWidth - 375) / 2)
|
||||
callKitY.value = Math.max(0, (window.innerHeight - 667) / 2)
|
||||
patientName.value = data.patientName
|
||||
patientId.value = data.patientId
|
||||
diagnosisId.value = data.diagnosisId || null
|
||||
@@ -549,15 +549,15 @@ defineExpose({ open })
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* TUICallKit 可拖动容器 */
|
||||
/* TUICallKit 可拖动容器 - 手机尺寸 (375x667) */
|
||||
.chat-dialog-call-kit-wrapper {
|
||||
position: fixed;
|
||||
width: 600px;
|
||||
height: 436px;
|
||||
width: 375px;
|
||||
height: 667px;
|
||||
max-width: 90vw;
|
||||
z-index: 300000;
|
||||
background: #1a1a1a;
|
||||
border-radius: 12px;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
@@ -565,8 +565,8 @@ defineExpose({ open })
|
||||
}
|
||||
|
||||
.call-kit-drag-handle {
|
||||
height: 36px;
|
||||
padding: 0 16px;
|
||||
height: 32px;
|
||||
padding: 0 12px;
|
||||
background: #2a2a2a;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -576,7 +576,7 @@ defineExpose({ open })
|
||||
flex-shrink: 0;
|
||||
|
||||
.drag-handle-text {
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@@ -603,7 +603,7 @@ defineExpose({ open })
|
||||
transform: none !important;
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
border-radius: 0 0 12px 12px;
|
||||
border-radius: 0 0 24px 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ const emit = defineEmits<{
|
||||
const editorRef = shallowRef()
|
||||
const materialPickerRef = shallowRef<InstanceType<typeof MaterialPicker>>()
|
||||
const fileType = ref('')
|
||||
const isReady = ref(false)
|
||||
|
||||
let insertFn: any
|
||||
|
||||
@@ -88,6 +89,7 @@ const valueHtml = computed({
|
||||
return props.modelValue
|
||||
},
|
||||
set(value) {
|
||||
if (!isReady.value) return
|
||||
emit('update:modelValue', value)
|
||||
}
|
||||
})
|
||||
@@ -107,6 +109,9 @@ onBeforeUnmount(() => {
|
||||
|
||||
const handleCreated = (editor: any) => {
|
||||
editorRef.value = editor // 记录 editor 实例,重要!
|
||||
nextTick(() => {
|
||||
isReady.value = true
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@
|
||||
<div class="section-title">诊断信息</div>
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="脉象" prop="pulse">
|
||||
<el-input v-model="formData.pulse" placeholder="脉象" />
|
||||
<el-form-item label="面象" prop="pulse">
|
||||
<el-input v-model="formData.pulse" placeholder="面象" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
@@ -109,12 +109,17 @@
|
||||
|
||||
<div class="info-section">
|
||||
<el-row :gutter="16">
|
||||
<el-col :span="8">
|
||||
<el-form-item label="剂数" prop="dose_count">
|
||||
<el-input-number v-model="formData.dose_count" :min="1" :max="30" />
|
||||
<el-col :span="12">
|
||||
<el-form-item label="数量规格" prop="dose_count">
|
||||
<div class="flex gap-2 items-center">
|
||||
<el-input-number v-model="formData.dose_count" :min="1" :max="999" class="!w-28" />
|
||||
<el-select v-model="formData.dose_unit" placeholder="单位" class="!w-24">
|
||||
<el-option v-for="u in doseUnitOptions" :key="u" :label="u" :value="u" />
|
||||
</el-select>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="16">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="用法" prop="usage_instruction">
|
||||
<el-input v-model="formData.usage_instruction" placeholder="如:水煎服一日二次" />
|
||||
</el-form-item>
|
||||
@@ -158,26 +163,36 @@
|
||||
<div class="prescription-header">
|
||||
<h2 class="prescription-title">{{ templateConfig.stationName }}处方笺</h2>
|
||||
<div class="prescription-type">
|
||||
<div>普通处方</div>
|
||||
<div class="text-sm">当日有效</div>
|
||||
<el-tag v-if="savedPrescription.void_status === 1" type="danger" size="small">已作废</el-tag>
|
||||
<template v-else>
|
||||
<div>普通处方</div>
|
||||
<div class="text-sm">当日有效</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prescription-meta">
|
||||
<span>日期: {{ savedPrescription.prescription_date }}</span>
|
||||
<span class="ml-4">门诊号: {{ savedPrescription.visit_no }}</span>
|
||||
<div v-if="savedPrescription.void_status === 1" class="prescription-void-info">
|
||||
作废人:{{ savedPrescription.void_by_name || '—' }},作废时间:{{ formatVoidTime(savedPrescription.void_time) }}
|
||||
</div>
|
||||
<div class="prescription-patient">
|
||||
<span>姓名: {{ savedPrescription.patient_name }}</span>
|
||||
<span>性别: {{ savedPrescription.gender_desc }}</span>
|
||||
<span>年龄: {{ savedPrescription.age }}</span>
|
||||
<span>电话: {{ savedPrescription.phone }}</span>
|
||||
</div>
|
||||
<div class="prescription-patient">
|
||||
<span>脉象: {{ savedPrescription.pulse || '—' }}</span>
|
||||
<span>舌象: {{ savedPrescription.tongue || '—' }}</span>
|
||||
</div>
|
||||
<div class="prescription-patient">
|
||||
<span>临床诊断: {{ savedPrescription.clinical_diagnosis }}</span>
|
||||
<div class="prescription-info">
|
||||
<div class="info-row">
|
||||
<span class="info-item"><em>日期</em>{{ savedPrescription.prescription_date }}</span>
|
||||
<span class="info-item"><em>电话</em>{{ savedPrescription.phone }}</span>
|
||||
<span class="info-item"><em>门诊号</em>{{ savedPrescription.visit_no }}</span>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-item"><em>姓名</em>{{ savedPrescription.patient_name }}</span>
|
||||
<span class="info-item"><em>性别</em>{{ savedPrescription.gender_desc }}</span>
|
||||
<span class="info-item"><em>年龄</em>{{ savedPrescription.age != null ? savedPrescription.age + '岁' : '—' }}</span>
|
||||
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="info-item" v-if="savedPrescription.pulse"><em>面象</em>{{ savedPrescription.pulse || '—' }}</span>
|
||||
<span class="info-item" v-if="savedPrescription.tongue"><em>舌象</em>{{ savedPrescription.tongue || '—' }}</span>
|
||||
|
||||
</div>
|
||||
<div class="info-row info-row-full">
|
||||
<span class="info-item"><em>临床诊断</em>{{ savedPrescription.clinical_diagnosis }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="prescription-rp">
|
||||
<div class="rp-label">RP</div>
|
||||
@@ -197,7 +212,7 @@
|
||||
<div class="prescription-footer">
|
||||
<div class="footer-left">
|
||||
<div class="footer-dosage">
|
||||
共 {{ savedPrescription.dose_count }} 剂, {{ savedPrescription.usage_instruction }}
|
||||
共 {{ savedPrescription.dose_count }}{{ savedPrescription.dose_unit || '剂' }}, {{ savedPrescription.usage_instruction }}
|
||||
</div>
|
||||
<div class="footer-amount">金额 {{ savedPrescription.amount }}</div>
|
||||
</div>
|
||||
@@ -212,7 +227,7 @@
|
||||
/>
|
||||
<span v-else>{{ savedPrescription.doctor_name || '医师' }}</span>
|
||||
</span>
|
||||
<span>核对发药</span>
|
||||
<!-- <span>核对发药</span> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -226,6 +241,15 @@
|
||||
<el-icon><Document /></el-icon>
|
||||
下载PDF
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="savedPrescription.void_status !== 1"
|
||||
type="danger"
|
||||
plain
|
||||
:loading="voiding"
|
||||
@click="handleVoid"
|
||||
>
|
||||
作废处方
|
||||
</el-button>
|
||||
<el-button @click="handleNewPrescription">新建处方</el-button>
|
||||
<el-button @click="handleClose">关闭</el-button>
|
||||
</div>
|
||||
@@ -242,7 +266,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import feedback from '@/utils/feedback'
|
||||
import { prescriptionAdd, prescriptionDetail, prescriptionGetByAppointment } from '@/api/tcm'
|
||||
import { prescriptionAdd, prescriptionDetail, prescriptionGetByAppointment, prescriptionVoid } from '@/api/tcm'
|
||||
import { getDictData } from '@/api/app'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { jsPDF } from 'jspdf'
|
||||
@@ -269,6 +293,7 @@ interface PrescriptionForm {
|
||||
clinical_diagnosis: string
|
||||
herbs: Herb[]
|
||||
dose_count: number
|
||||
dose_unit: string
|
||||
usage_instruction: string
|
||||
amount: number
|
||||
doctor_name: string
|
||||
@@ -280,13 +305,14 @@ const emit = defineEmits(['success'])
|
||||
const visible = ref(false)
|
||||
const formRef = ref()
|
||||
const saving = ref(false)
|
||||
const voiding = ref(false)
|
||||
const prescriptionPrintRef = ref<HTMLElement>()
|
||||
const signatureCanvasRef = ref<HTMLCanvasElement>()
|
||||
const isDrawing = ref(false)
|
||||
const savedPrescription = ref<any>(null)
|
||||
|
||||
const templateConfig = reactive({
|
||||
stationName: '卫生服务站',
|
||||
stationName: '成都双流甄养堂互联网医院',
|
||||
showDisclaimer: true,
|
||||
disclaimer: ''
|
||||
})
|
||||
@@ -306,6 +332,7 @@ const formData = reactive<PrescriptionForm>({
|
||||
clinical_diagnosis: '',
|
||||
herbs: [],
|
||||
dose_count: 1,
|
||||
dose_unit: '剂',
|
||||
usage_instruction: '水煎服一日二次',
|
||||
amount: 0,
|
||||
doctor_name: '',
|
||||
@@ -314,6 +341,8 @@ const formData = reactive<PrescriptionForm>({
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
const doseUnitOptions = ['剂', '丸', '袋', '盒', '瓶', '膏', '贴', '包', '片', '粒']
|
||||
|
||||
const diagnosisTypeOptions = ref<any[]>([])
|
||||
const syndromeTypeOptions = ref<any[]>([])
|
||||
|
||||
@@ -381,6 +410,7 @@ const open = async (data: any, options?: { templateId?: number; stationName?: st
|
||||
formData.clinical_diagnosis = buildClinicalDiagnosis(diagnosis)
|
||||
formData.herbs = []
|
||||
formData.dose_count = 1
|
||||
formData.dose_unit = '剂'
|
||||
formData.usage_instruction = '水煎服一日二次'
|
||||
formData.amount = 0
|
||||
formData.doctor_name = userStore.userInfo?.name || ''
|
||||
@@ -527,6 +557,7 @@ const handleSave = async () => {
|
||||
clinical_diagnosis: formData.clinical_diagnosis,
|
||||
herbs: formData.herbs,
|
||||
dose_count: formData.dose_count,
|
||||
dose_unit: formData.dose_unit || '剂',
|
||||
usage_instruction: formData.usage_instruction,
|
||||
amount: formData.amount,
|
||||
doctor_name: formData.doctor_name,
|
||||
@@ -547,6 +578,30 @@ const handleSave = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const formatVoidTime = (ts: number | null | undefined) => {
|
||||
if (!ts) return '—'
|
||||
const d = new Date(ts * 1000)
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
const handleVoid = async () => {
|
||||
const id = savedPrescription.value?.id
|
||||
if (!id) return
|
||||
try {
|
||||
await feedback.confirm('确定要作废该处方吗?作废后不可恢复。')
|
||||
voiding.value = true
|
||||
await prescriptionVoid({ id })
|
||||
feedback.msgSuccess('作废成功')
|
||||
const detail = await prescriptionDetail({ id })
|
||||
savedPrescription.value = detail
|
||||
emit('success')
|
||||
} catch (e: any) {
|
||||
if (e !== 'cancel' && e?.message !== 'cancel') feedback.msgError(e?.msg || '作废失败')
|
||||
} finally {
|
||||
voiding.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const handleNewPrescription = () => {
|
||||
const saved = savedPrescription.value
|
||||
if (saved) {
|
||||
@@ -564,6 +619,7 @@ const handleNewPrescription = () => {
|
||||
formData.tongue = saved.tongue || ''
|
||||
formData.clinical_diagnosis = saved.clinical_diagnosis || ''
|
||||
formData.dose_count = 1
|
||||
formData.dose_unit = saved.dose_unit || '剂'
|
||||
formData.usage_instruction = '水煎服一日二次'
|
||||
formData.amount = 0
|
||||
formData.doctor_name = userStore.userInfo?.name || saved.doctor_name || ''
|
||||
@@ -682,9 +738,18 @@ defineExpose({
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 16px;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.prescription-void-info {
|
||||
font-size: 13px;
|
||||
color: var(--el-color-danger);
|
||||
margin-bottom: 12px;
|
||||
padding: 8px 12px;
|
||||
background: #fef0f0;
|
||||
border-radius: 4px;
|
||||
|
||||
.prescription-title {
|
||||
font-size: 20px;
|
||||
@@ -698,15 +763,43 @@ defineExpose({
|
||||
}
|
||||
}
|
||||
|
||||
.prescription-meta {
|
||||
margin-bottom: 8px;
|
||||
.prescription-info {
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
.prescription-patient {
|
||||
margin-bottom: 6px;
|
||||
.info-row {
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
|
||||
span {
|
||||
margin-right: 16px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.info-row-full {
|
||||
.info-item {
|
||||
flex: 1;
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 6px;
|
||||
font-size: 14px;
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
color: #909399;
|
||||
min-width: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<main class="main-wrap h-full bg-page">
|
||||
<el-scrollbar>
|
||||
<div class="p-4">
|
||||
<div class="px-2 py-4">
|
||||
<router-view v-if="isRouteShow" v-slot="{ Component, route }">
|
||||
<keep-alive :include="includeList" :max="20">
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
|
||||
@@ -108,7 +108,9 @@
|
||||
|
||||
<!-- 所属科室 -->
|
||||
<el-form-item label="所属科室" prop="department">
|
||||
<el-input v-model="formData.department" placeholder="如:中医科、内科" clearable />
|
||||
<el-select v-model="formData.department" placeholder="请选择所属科室" clearable class="flex-1">
|
||||
<el-option v-for="item in departmentOptions" :key="item.value" :label="item.name" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 擅长领域 -->
|
||||
@@ -209,6 +211,7 @@ import type { FormInstance } from 'element-plus'
|
||||
import { adminAdd, adminDetail, adminEdit } from '@/api/perms/admin'
|
||||
import { deptAll } from '@/api/org/department'
|
||||
import { jobsAll } from '@/api/org/post'
|
||||
import { getDictData } from '@/api/app'
|
||||
import { useDictOptions } from '@/hooks/useDictOptions'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
@@ -218,6 +221,12 @@ const visible = ref(false)
|
||||
const mode = ref('add')
|
||||
const loading = ref(false)
|
||||
|
||||
const departmentOptions = ref<any[]>([])
|
||||
const fetchDepartmentOptions = async () => {
|
||||
const data = await getDictData({ type: 'department' })
|
||||
departmentOptions.value = data?.department || []
|
||||
}
|
||||
|
||||
const drawerTitle = computed(() => {
|
||||
return mode.value == 'edit' ? '编辑医助' : '新增医助'
|
||||
})
|
||||
@@ -345,7 +354,7 @@ const handleSubmit = async () => {
|
||||
const open = (type = 'add') => {
|
||||
mode.value = type
|
||||
visible.value = true
|
||||
|
||||
fetchDepartmentOptions()
|
||||
// 重置表单
|
||||
if (type === 'add') {
|
||||
Object.assign(formData, {
|
||||
|
||||
@@ -137,7 +137,9 @@
|
||||
|
||||
<!-- 所属科室 -->
|
||||
<el-form-item label="所属科室" prop="department">
|
||||
<el-input v-model="formData.department" placeholder="如:中医科、内科" clearable />
|
||||
<el-select v-model="formData.department" placeholder="请选择所属科室" clearable class="flex-1">
|
||||
<el-option v-for="item in departmentOptions" :key="item.value" :label="item.name" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 擅长领域 -->
|
||||
@@ -238,6 +240,7 @@ import type { FormInstance } from 'element-plus'
|
||||
import { adminAdd, adminDetail, adminEdit } from '@/api/perms/admin'
|
||||
import { deptAll } from '@/api/org/department'
|
||||
import { jobsAll } from '@/api/org/post'
|
||||
import { getDictData } from '@/api/app'
|
||||
import { useDictOptions } from '@/hooks/useDictOptions'
|
||||
import feedback from '@/utils/feedback'
|
||||
|
||||
@@ -247,6 +250,12 @@ const visible = ref(false)
|
||||
const mode = ref('add')
|
||||
const loading = ref(false)
|
||||
|
||||
const departmentOptions = ref<any[]>([])
|
||||
const fetchDepartmentOptions = async () => {
|
||||
const data = await getDictData({ type: 'department' })
|
||||
departmentOptions.value = data?.department || []
|
||||
}
|
||||
|
||||
const drawerTitle = computed(() => {
|
||||
return mode.value == 'edit' ? '编辑医生' : '新增医生'
|
||||
})
|
||||
@@ -377,6 +386,7 @@ const handleSubmit = async () => {
|
||||
const open = (type = 'add') => {
|
||||
mode.value = type
|
||||
visible.value = true
|
||||
fetchDepartmentOptions()
|
||||
|
||||
// 重置表单
|
||||
if (type === 'add') {
|
||||
|
||||
@@ -24,13 +24,28 @@
|
||||
|
||||
<editor class="mb-10" v-model="formData.privacy_content" height="500"></editor>
|
||||
</el-card>
|
||||
|
||||
</div>
|
||||
<div class="xl:flex">
|
||||
<el-card class="!border-none flex-1 mb-4" shadow="never">
|
||||
<template #header>
|
||||
<span class="font-medium">卫健委备案信息</span>
|
||||
</template>
|
||||
<el-form :model="formData" label-width="80px">
|
||||
<el-form-item label="协议名称">
|
||||
<el-input v-model="formData.health_title" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<editor class="mb-10" v-model="formData.health_content" height="500"></editor>
|
||||
</el-card>
|
||||
</div>
|
||||
<footer-btns v-perms="['setting.web.web_setting/setAgreement']">
|
||||
<el-button type="primary" @click="handleProtocolEdit">保存</el-button>
|
||||
</footer-btns>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts" naem="webProtocol">
|
||||
<script setup lang="ts" name="webProtocol">
|
||||
import { getProtocol, setProtocol } from '@/api/setting/website'
|
||||
|
||||
interface formDataObj {
|
||||
@@ -38,15 +53,20 @@ interface formDataObj {
|
||||
service_content: string
|
||||
privacy_title: string
|
||||
privacy_content: string
|
||||
health_title: string
|
||||
health_content: string
|
||||
}
|
||||
const formData = ref<formDataObj>({
|
||||
service_title: '',
|
||||
service_content: '',
|
||||
privacy_title: '',
|
||||
privacy_content: ''
|
||||
privacy_content: '',
|
||||
health_title: '',
|
||||
health_content: ''
|
||||
})
|
||||
const protocolGet = async () => {
|
||||
formData.value = await getProtocol()
|
||||
const data = await getProtocol()
|
||||
Object.assign(formData.value, data)
|
||||
}
|
||||
|
||||
const handleProtocolEdit = async (): Promise<void> => {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,95 @@
|
||||
<template>
|
||||
<div class="case-record-list">
|
||||
<el-table :data="caseList" border v-loading="loading">
|
||||
<el-table-column prop="prescription_date" label="就诊日期" width="120" />
|
||||
<el-table-column prop="visit_no" label="门诊号" width="120" />
|
||||
<el-table-column prop="clinical_diagnosis" label="临床诊断" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="处方摘要" min-width="180">
|
||||
<template #default="{ row }">
|
||||
<span v-if="row.herbs && row.herbs.length">
|
||||
{{ row.herbs.slice(0, 3).map((h: any) => `${h.name}${h.dosage}克`).join('、') }}{{ row.herbs.length > 3 ? '...' : '' }}
|
||||
</span>
|
||||
<span v-else class="text-gray-400">—</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="doctor_name" label="医师" width="90" show-overflow-tooltip />
|
||||
<el-table-column label="状态" width="140" align="center">
|
||||
<template #default="{ row }">
|
||||
<template v-if="row.void_status === 1">
|
||||
<el-tag type="danger" size="small">已作废</el-tag>
|
||||
<div class="void-detail text-xs text-gray-500 mt-1">
|
||||
{{ row.void_by_name || '—' }} {{ formatVoidTime(row.void_time) }}
|
||||
</div>
|
||||
</template>
|
||||
<el-tag v-else type="success" size="small">正常</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="{ row }">
|
||||
<el-button link type="primary" size="small" @click="handleView(row)">
|
||||
查看
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-empty v-if="!loading && caseList.length === 0" description="暂无病例记录,开方后会自动显示" class="mt-4" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { prescriptionListByDiagnosis } from '@/api/tcm'
|
||||
|
||||
const props = defineProps({
|
||||
diagnosisId: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['view'])
|
||||
|
||||
const caseList = ref<any[]>([])
|
||||
const loading = ref(false)
|
||||
|
||||
const getCases = async () => {
|
||||
if (!props.diagnosisId) return
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await prescriptionListByDiagnosis({ diagnosis_id: props.diagnosisId })
|
||||
caseList.value = Array.isArray(data) ? data : []
|
||||
} catch (error) {
|
||||
console.error('获取病例记录失败:', error)
|
||||
caseList.value = []
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const formatVoidTime = (ts: number | null | undefined) => {
|
||||
if (!ts) return ''
|
||||
const d = new Date(ts * 1000)
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')} ${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
|
||||
}
|
||||
|
||||
const handleView = (row: any) => {
|
||||
emit('view', row)
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getCases()
|
||||
})
|
||||
|
||||
watch(() => props.diagnosisId, () => {
|
||||
getCases()
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
refresh: getCases
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.case-record-list {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
||||
@@ -79,19 +79,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="诊断日期" prop="diagnosis_date">
|
||||
<el-date-picker
|
||||
v-model="formData.diagnosis_date"
|
||||
type="date"
|
||||
placeholder="请选择诊断日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
class="w-full"
|
||||
:popper-options="{ strategy: 'fixed' }"
|
||||
popper-class="high-z-index"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
||||
</el-row>
|
||||
|
||||
|
||||
@@ -257,6 +245,19 @@
|
||||
<el-divider content-position="left">主诉</el-divider>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="线下诊断日期" prop="diagnosis_date">
|
||||
<el-date-picker
|
||||
v-model="formData.diagnosis_date"
|
||||
type="date"
|
||||
placeholder="请选择诊断日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
class="w-full"
|
||||
:popper-options="{ strategy: 'fixed' }"
|
||||
popper-class="high-z-index"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="发现糖尿病就患病史" prop="diabetes_discovery_year">
|
||||
<el-input-number
|
||||
@@ -289,15 +290,13 @@
|
||||
<el-divider content-position="left">现病史</el-divider>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="口腔感觉" class="compact-form-item">
|
||||
<el-radio-group v-model="formData.appetite">
|
||||
<el-radio-button v-for="item in appetiteOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
</el-radio-button>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-form-item label="口腔感觉" class="checkbox-form-item">
|
||||
<el-checkbox-group v-model="formData.appetite">
|
||||
<el-checkbox-button v-for="item in appetiteOptions" :key="item.value" :label="item.value">
|
||||
{{ item.name }}
|
||||
</el-checkbox-button>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
|
||||
</el-row>
|
||||
<el-row :gutter="20">
|
||||
@@ -413,7 +412,7 @@
|
||||
</el-checkbox-button>
|
||||
</el-checkbox-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="病逝补充" prop="symptoms">
|
||||
<el-form-item label="其他补充" prop="symptoms">
|
||||
<el-input
|
||||
v-model="formData.symptoms"
|
||||
type="textarea"
|
||||
@@ -508,7 +507,7 @@
|
||||
</el-form-item>
|
||||
|
||||
|
||||
<el-row :gutter="20">
|
||||
<!-- <el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="舌苔" prop="tongue_coating">
|
||||
<el-input
|
||||
@@ -552,7 +551,7 @@
|
||||
:rows="3"
|
||||
placeholder="请输入医嘱"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
|
||||
<el-form-item label="备注" prop="remark">
|
||||
<el-input
|
||||
@@ -574,7 +573,56 @@
|
||||
/>
|
||||
<el-empty v-else description="请先保存诊单后再添加血糖血压记录" />
|
||||
</el-tab-pane>
|
||||
<!-- 病例记录标签页(开方后自动显示) -->
|
||||
<el-tab-pane label="病例" name="bingli" :disabled="!formData.id">
|
||||
<div v-if="formData.id" class="bingli-tab-content">
|
||||
<!-- 诊断信息:舌苔照片、检查报告 -->
|
||||
<div class="bingli-diagnosis-section">
|
||||
<el-divider content-position="left">诊断信息</el-divider>
|
||||
<el-row :gutter="24">
|
||||
<el-col :span="12">
|
||||
<div class="bingli-label">舌苔照片</div>
|
||||
<div v-if="formData.tongue_images?.length" class="bingli-images">
|
||||
<el-image
|
||||
v-for="(img, idx) in formData.tongue_images"
|
||||
:key="idx"
|
||||
:src="getImageUrl(img)"
|
||||
:preview-src-list="(formData.tongue_images || []).map((u: string) => getImageUrl(u))"
|
||||
class="bingli-img"
|
||||
fit="cover"
|
||||
/>
|
||||
</div>
|
||||
<span v-else class="bingli-empty">暂无</span>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<div class="bingli-label">检查报告</div>
|
||||
<div v-if="formData.report_files?.length" class="bingli-images">
|
||||
<el-image
|
||||
v-for="(file, idx) in formData.report_files"
|
||||
:key="idx"
|
||||
:src="getImageUrl(file)"
|
||||
:preview-src-list="(formData.report_files || []).map((u: string) => getImageUrl(u))"
|
||||
class="bingli-img"
|
||||
fit="cover"
|
||||
/>
|
||||
</div>
|
||||
<span v-else class="bingli-empty">暂无</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<!-- 病例记录列表 -->
|
||||
<case-record-list
|
||||
ref="caseRecordListRef"
|
||||
:diagnosis-id="Number(formData.id)"
|
||||
@view="handleViewCase"
|
||||
/>
|
||||
</div>
|
||||
<el-empty v-else description="请先保存诊单,开方后病例将在此显示" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
<!-- 处方详情(查看病例) -->
|
||||
<tcm-prescription ref="prescriptionRef" @success="caseRecordListRef?.refresh?.()" />
|
||||
|
||||
<template #footer>
|
||||
<div class="flex justify-end gap-3 px-4 pb-4">
|
||||
@@ -599,11 +647,18 @@ import { tcmDiagnosisAdd, tcmDiagnosisEdit, tcmDiagnosisDetail, checkPhone, chec
|
||||
import { getDictData } from '@/api/app'
|
||||
import feedback from '@/utils/feedback'
|
||||
import useUserStore from '@/stores/modules/user'
|
||||
import useAppStore from '@/stores/modules/app'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||
import BloodRecordList from './components/BloodRecordList.vue'
|
||||
import CaseRecordList from './components/CaseRecordList.vue'
|
||||
import TcmPrescription from '@/components/tcm-prescription/index.vue'
|
||||
|
||||
const emit = defineEmits(['success'])
|
||||
const appStore = useAppStore()
|
||||
const getImageUrl = (url: string) => (url?.indexOf?.('http') === 0 ? url : appStore.getImageUrl(url || ''))
|
||||
const caseRecordListRef = ref()
|
||||
const prescriptionRef = ref()
|
||||
|
||||
const visible = ref(false)
|
||||
const formRef = ref()
|
||||
@@ -634,7 +689,7 @@ const formData = ref({
|
||||
systolic_pressure: undefined as number | undefined,
|
||||
diastolic_pressure: undefined as number | undefined,
|
||||
fasting_blood_sugar: undefined as number | undefined,
|
||||
appetite: '',
|
||||
appetite: [] as string[],
|
||||
water_intake: '',
|
||||
diet_condition: [],
|
||||
weight_change: '',
|
||||
@@ -811,6 +866,18 @@ const handleIdCardBlur = async () => {
|
||||
if (!formData.value.id_card || !/^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/.test(formData.value.id_card)) {
|
||||
return
|
||||
}
|
||||
|
||||
// 从身份证提取出生日期计算年龄
|
||||
const id = formData.value.id_card
|
||||
const birthYear = parseInt(id.substring(6, 10))
|
||||
const birthMonth = parseInt(id.substring(10, 12))
|
||||
const birthDay = parseInt(id.substring(12, 14))
|
||||
const today = new Date()
|
||||
let age = today.getFullYear() - birthYear
|
||||
if (today.getMonth() + 1 < birthMonth || (today.getMonth() + 1 === birthMonth && today.getDate() < birthDay)) {
|
||||
age--
|
||||
}
|
||||
formData.value.age = age
|
||||
|
||||
try {
|
||||
const result = await checkIdCard({
|
||||
@@ -876,6 +943,10 @@ const handleSubmit = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const handleViewCase = (row: any) => {
|
||||
prescriptionRef.value?.openById(row.id)
|
||||
}
|
||||
|
||||
const handleClose = () => {
|
||||
formRef.value?.resetFields()
|
||||
formData.value = {
|
||||
@@ -896,7 +967,7 @@ const handleClose = () => {
|
||||
diabetes_discovery_year: undefined as number | undefined,
|
||||
local_hospital_diagnosis: [],
|
||||
local_hospital_name: '',
|
||||
appetite: '',
|
||||
appetite: [] as string[],
|
||||
water_intake: '',
|
||||
diet_condition: [],
|
||||
weight_change: '',
|
||||
@@ -932,7 +1003,8 @@ const handleClose = () => {
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
open,
|
||||
refreshCaseList: () => caseRecordListRef.value?.refresh?.()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -1042,6 +1114,38 @@ defineExpose({
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 病例 tab 诊断信息 */
|
||||
.bingli-tab-content {
|
||||
padding: 0 4px;
|
||||
}
|
||||
.bingli-diagnosis-section {
|
||||
margin-bottom: 24px;
|
||||
padding: 16px;
|
||||
background: #f5f7fa;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.bingli-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #606266;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.bingli-images {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
.bingli-img {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
.bingli-empty {
|
||||
font-size: 13px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
// 输入框样式优化
|
||||
:deep(.el-input__inner),
|
||||
:deep(.el-textarea__inner) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user