607 【门诊术中安排-医嘱】医师电子签名核验异常(签名医师显示账号名而非姓名、签名时间缺失)

606 门诊术中安排-医嘱】预览列表字段显示及逻辑异常(涉及单位、频次、执行时间)

605
【门诊手术安排-计费】新增计费项目保存后,明细列表的“总量”列单位错误显示为字典ID数字(如“瓶”显示为“8”
604 【门诊手术安排-医嘱】编辑临时医嘱保存后,需额外二次操作方能提交,与实际业务符合,交互体验不佳
This commit is contained in:
wangjian963
2026-05-29 18:00:55 +08:00
parent ba5ac84d96
commit b946a8a143
3 changed files with 125 additions and 46 deletions

View File

@@ -375,7 +375,7 @@
> >
<template #default="scope"> <template #default="scope">
<span v-if="!scope.row.isEdit"> <span v-if="!scope.row.isEdit">
{{ scope.row.quantity ? scope.row.quantity + ' ' + scope.row.unitCode_dictText : '' }} {{ formatUnitText(scope.row) }}
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
@@ -613,6 +613,26 @@ function getRowDisabled(row) {
return row.isEdit; return row.isEdit;
} }
function formatUnitText(row) {
if (!row.quantity) return ''
const unitText = row.unitCode_dictText
// unitCode_dictText 为有效文本时直接使用
if (unitText && !/^\d+$/.test(unitText)) return row.quantity + ' ' + unitText
// 优先从行级 unitCodeList 查找
const list = row.unitCodeList
if (list && list.length) {
const match = list.find(u => u.value === row.unitCode)
if (match) return row.quantity + ' ' + match.label
}
// 回退:从字典 unit_code 查找
if (unit_code.value && unit_code.value.length) {
const dictMatch = unit_code.value.find(d => d.value === row.unitCode)
if (dictMatch) return row.quantity + ' ' + dictMatch.label
}
// 最后兜底用 unitCode
return row.quantity + ' ' + (row.unitCode || '')
}
/** /**
* 是否已由医生接诊(非待诊) * 是否已由医生接诊(非待诊)
* EncounterStatus: 1=待诊 2=在诊 3=暂离 … * EncounterStatus: 1=待诊 2=在诊 3=暂离 …

View File

@@ -2339,6 +2339,10 @@ function handleMedicalAdvice(row) {
const draftItems = filteredItems.filter(item => item.statusEnum === 1) const draftItems = filteredItems.filter(item => item.statusEnum === 1)
const activeItems = filteredItems.filter(item => item.statusEnum === 2) const activeItems = filteredItems.filter(item => item.statusEnum === 2)
if (activeItems.length > 0) {
temporarySigned.value = true
}
// 🔧 修复限制返回数量最多显示前100条避免数据过多导致页面卡死 // 🔧 修复限制返回数量最多显示前100条避免数据过多导致页面卡死
const maxItems = 100 const maxItems = 100
if (draftItems.length > maxItems) { if (draftItems.length > maxItems) {
@@ -2414,9 +2418,9 @@ function handleMedicalAdvice(row) {
const contentData = jsonContent ? JSON.parse(jsonContent) : {}; const contentData = jsonContent ? JSON.parse(jsonContent) : {};
const medicineName = contentData.adviceName || contentData.advice_name || item.adviceName || item.advice_name || ''; const medicineName = contentData.adviceName || contentData.advice_name || item.adviceName || item.advice_name || '';
const spec = contentData.volume || contentData.specification || item.volume || item.specification || ''; const spec = contentData.volume || contentData.specification || item.volume || item.specification || '';
const specMatch = spec.match(/(\d+)(\D+)/) const specMatch = spec.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/)
const specValue = specMatch ? parseInt(specMatch[1]) : 1 const specValue = specMatch ? parseFloat(specMatch[1]) : 1
const specUnit = specMatch ? specMatch[2] : 'ml' const specUnit = specMatch ? specMatch[2] : ''
const dosage = specValue * (contentData.quantity || item.quantity || 1) const dosage = specValue * (contentData.quantity || item.quantity || 1)
let usageCode = contentData.methodCode || 'iv' let usageCode = contentData.methodCode || 'iv'
@@ -2434,8 +2438,8 @@ function handleMedicalAdvice(row) {
unit: specUnit, unit: specUnit,
usage: usageCode, usage: usageCode,
usageLabel, usageLabel,
frequency: '临时', frequency: '立即',
executeTime: new Date().toLocaleString('zh-CN'), executeTime: '',
originalMedicine: { originalMedicine: {
...item, ...item,
medicineName: medicineName, medicineName: medicineName,
@@ -2449,8 +2453,8 @@ function handleMedicalAdvice(row) {
id: index + 1, id: index + 1,
adviceName: item.adviceName || item.advice_name || '', adviceName: item.adviceName || item.advice_name || '',
dosage: 1, unit: 'ml', usage: 'iv', usageLabel: '静脉注射', dosage: 1, unit: 'ml', usage: 'iv', usageLabel: '静脉注射',
frequency: '临时', frequency: '立即',
executeTime: new Date().toLocaleString('zh-CN'), executeTime: '',
originalMedicine: { originalMedicine: {
...item, ...item,
medicineName: item.adviceName || item.advice_name || '', medicineName: item.adviceName || item.advice_name || '',
@@ -2584,14 +2588,14 @@ function handleTemporaryMedicalSubmit(data) {
let usageCode = contentData.methodCode || 'iv' let usageCode = contentData.methodCode || 'iv'
return { return {
id: index + 1, adviceName: medicineName, dosage, unit: specUnit, id: index + 1, adviceName: medicineName, dosage, unit: specUnit,
usage: usageCode, frequency: '临时', usage: usageCode, frequency: '立即',
executeTime: new Date().toLocaleString('zh-CN'), executeTime: '',
originalMedicine: { ...item, medicineName, specification: spec, quantity: contentData.quantity || item.quantity || 1, encounterId: row.visitId } originalMedicine: { ...item, medicineName, specification: spec, quantity: contentData.quantity || item.quantity || 1, encounterId: row.visitId }
} }
} catch (e) { } catch (e) {
return { return {
id: index + 1, adviceName: item.adviceName || '', dosage: 1, unit: 'ml', id: index + 1, adviceName: item.adviceName || '', dosage: 1, unit: 'ml',
usage: 'iv', frequency: '临时', executeTime: new Date().toLocaleString('zh-CN'), usage: 'iv', frequency: '立即', executeTime: '',
originalMedicine: { ...item, medicineName: item.adviceName || '', specification: item.volume || '', quantity: item.quantity || 1, encounterId: row.visitId } originalMedicine: { ...item, medicineName: item.adviceName || '', specification: item.volume || '', quantity: item.quantity || 1, encounterId: row.visitId }
} }
} }
@@ -2705,8 +2709,8 @@ function handleQuoteBilling() {
else if (usageCode === 'po' && (medicineName.includes('片') || medicineName.includes('胶囊'))) { usageLabel = '口服' } else if (usageCode === 'po' && (medicineName.includes('片') || medicineName.includes('胶囊'))) { usageLabel = '口服' }
return { return {
id: index + 1, adviceName: medicineName, dosage, unit: specUnit, id: index + 1, adviceName: medicineName, dosage, unit: specUnit,
usage: usageCode, usageLabel, frequency: '临时', usage: usageCode, usageLabel, frequency: '立即',
executeTime: new Date().toLocaleString('zh-CN'), executeTime: '',
originalMedicine: { originalMedicine: {
...item, ...item,
medicineName: medicineName, medicineName: medicineName,
@@ -2719,7 +2723,7 @@ function handleQuoteBilling() {
return { return {
id: index + 1, adviceName: item.adviceName || item.advice_name || '', id: index + 1, adviceName: item.adviceName || item.advice_name || '',
dosage: 1, unit: 'ml', usage: 'iv', usageLabel: '静脉注射', dosage: 1, unit: 'ml', usage: 'iv', usageLabel: '静脉注射',
frequency: '临时', executeTime: new Date().toLocaleString('zh-CN'), frequency: '立即', executeTime: '',
originalMedicine: { originalMedicine: {
...item, ...item,
medicineName: item.adviceName || item.advice_name || '', medicineName: item.adviceName || item.advice_name || '',

View File

@@ -173,6 +173,8 @@
border border
style="width: 100%;" style="width: 100%;"
fit fit
highlight-current-row
@row-click="handleAdviceRowClick"
> >
<el-table-column <el-table-column
label="序号" label="序号"
@@ -257,7 +259,7 @@
<span <span
class="info-value" class="info-value"
:class="{ 'unsigned': !isSigned }" :class="{ 'unsigned': !isSigned }"
>{{ isSigned ? currentUser.name : '未签名' }}</span> >{{ isSigned ? signatureDoctor : '未签名' }}</span>
</div> </div>
<div class="signature-info"> <div class="signature-info">
<span class="info-label">签名时间</span> <span class="info-label">签名时间</span>
@@ -398,6 +400,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
import useUserStore from '@/store/modules/user' import useUserStore from '@/store/modules/user'
import { checkPassword } from '@/api/surgicalschedule' import { checkPassword } from '@/api/surgicalschedule'
import { savePrescription } from '@/views/clinicmanagement/bargain/component/api.js' import { savePrescription } from '@/views/clinicmanagement/bargain/component/api.js'
import { parseTime } from '@/utils/openhis'
// 定义props // 定义props
const props = defineProps({ const props = defineProps({
@@ -507,16 +510,11 @@ const displayAdvicesList = computed(() => {
return advicesExpanded.value ? all : all.slice(0, PAGE_SIZE) return advicesExpanded.value ? all : all.slice(0, PAGE_SIZE)
}) })
// 响应式数据 - isSigned 从父组件传入的 prop 初始化 const isSigned = ref(false)
const isSigned = ref(props.isSignedProp)
// 🔧 修复 Bug #446: 同步父组件 isSignedProp 的变化到本地 isSigned
// ref(props.isSignedProp) 只在初始化时读取一次,父组件后续更新不会自动同步
watch(() => props.isSignedProp, (newVal) => {
isSigned.value = newVal
})
const signatureDoctor = ref(userStore.nickName || userStore.name || '未知用户')
const signatureTime = ref('') const signatureTime = ref('')
const showSignDialog = ref(false) const showSignDialog = ref(false)
const signPassword = ref('') const signPassword = ref('')
const showEditDialog = ref(false) const showEditDialog = ref(false)
@@ -531,7 +529,7 @@ const editForm = ref({
// 计算属性 // 计算属性
const currentUser = computed(() => ({ const currentUser = computed(() => ({
name: userStore.name || '未知用户', name: userStore.nickName || userStore.name || '未知用户',
id: userStore.id id: userStore.id
})) }))
@@ -554,10 +552,10 @@ const totalAmount = computed(() => {
// 将计费药品转换为临时医嘱数据 // 将计费药品转换为临时医嘱数据
const convertedAdvices = computed(() => { const convertedAdvices = computed(() => {
return props.billingMedicines.map((medicine, index) => { return props.billingMedicines.map((medicine, index) => {
// 解析规格中的数值和单位 // 解析规格中的数值和单位(支持小数,去除 ×、:、/、* 等多余字符)
const specMatch = medicine.specification ? medicine.specification.match(/(\d+)(\D+)/) : null const specMatch = medicine.specification ? medicine.specification.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/) : null
const specValue = specMatch ? parseInt(specMatch[1]) : 1 const specValue = specMatch ? parseFloat(specMatch[1]) : 1
const specUnit = specMatch ? specMatch[2] : 'ml' const specUnit = specMatch ? specMatch[2] : ''
// 计算剂量 = 规格数值 × 数量 // 计算剂量 = 规格数值 × 数量
const dosage = specValue * (medicine.quantity || 1) const dosage = specValue * (medicine.quantity || 1)
@@ -583,8 +581,8 @@ const convertedAdvices = computed(() => {
unit: specUnit, unit: specUnit,
usage: usageCode, // 🔧 修复:使用后端字典的正确编码 usage: usageCode, // 🔧 修复:使用后端字典的正确编码
usageLabel: usageLabel, // 🔧 新增:保存显示名称 usageLabel: usageLabel, // 🔧 新增:保存显示名称
frequency: '临时', frequency: '立即',
executeTime: new Date().toLocaleString('zh-CN'), executeTime: '',
originalMedicine: medicine originalMedicine: medicine
} }
}) })
@@ -640,6 +638,24 @@ const handleSign = () => {
showSignDialog.value = true showSignDialog.value = true
} }
// 点击已生成列表行 → 回显该行的签名信息
const handleAdviceRowClick = (row) => {
const om = row?.originalMedicine
if (!om) return
const contentJson = om.contentJson || om.content_json
if (!contentJson) return
try {
const cd = typeof contentJson === 'string' ? JSON.parse(contentJson) : contentJson
if (cd.signDoctorName) {
signatureDoctor.value = cd.signDoctorName
}
if (cd.signDate) {
signatureTime.value = cd.signDate
}
isSigned.value = true
} catch (e) {}
}
// 编辑医嘱 // 编辑医嘱
const handleEditAdvice = (index) => { const handleEditAdvice = (index) => {
const advice = displayAdvices.value[index] const advice = displayAdvices.value[index]
@@ -662,7 +678,7 @@ const handleEditAdvice = (index) => {
} }
// 保存编辑 // 保存编辑
const handleSaveEdit = () => { const handleSaveEdit = async () => {
if (!editForm.value.dosage && editForm.value.dosage !== 0) { if (!editForm.value.dosage && editForm.value.dosage !== 0) {
ElMessage.warning('请填写剂量') ElMessage.warning('请填写剂量')
return return
@@ -720,8 +736,8 @@ const handleSaveEdit = () => {
// 如果用户修改了剂量,重新计算数量 // 如果用户修改了剂量,重新计算数量
if (originalMedicine.specification) { if (originalMedicine.specification) {
const specMatch = originalMedicine.specification.match(/(\d+)(\D+)/) const specMatch = originalMedicine.specification.match(/([\d.]+)\s*([a-zA-Z一-龥]+)/)
const specValue = specMatch ? parseInt(specMatch[1]) : 1 const specValue = specMatch ? parseFloat(specMatch[1]) : 1
if (specValue > 0) { if (specValue > 0) {
const newQuantity = editForm.value.dosage / specValue const newQuantity = editForm.value.dosage / specValue
contentData.quantity = newQuantity contentData.quantity = newQuantity
@@ -732,11 +748,8 @@ const handleSaveEdit = () => {
} }
} }
// 更新 contentJson // 🔧 修复:原地修改 contentJson,保存使用最新数据
updatedAdvice.originalMedicine = { originalMedicine.contentJson = JSON.stringify(contentData)
...originalMedicine,
contentJson: JSON.stringify(contentData)
}
} catch (e) { } catch (e) {
console.error('解析 originalMedicine.contentJson 失败', e) console.error('解析 originalMedicine.contentJson 失败', e)
} }
@@ -750,7 +763,49 @@ const handleSaveEdit = () => {
emit('update:temporary-advices', updatedAdvices) emit('update:temporary-advices', updatedAdvices)
showEditDialog.value = false showEditDialog.value = false
ElMessage.success('编辑成功(已暂存本地,请点击"一键签名并生成医嘱"按钮提交到服务器)')
// 🔧 修复 Bug #604: 编辑保存后直接提交到服务器
const editMedicine = updatedAdvice.originalMedicine
if (editMedicine) {
let contentJsonData = {}
try { contentJsonData = JSON.parse(editMedicine.contentJson || '{}') } catch (e) {}
const quantity = editMedicine.quantity || contentJsonData.quantity || 1
const unitPrice = editMedicine.unitPrice || contentJsonData.unitPrice || 0
contentJsonData.dose = editForm.value.dosage
contentJsonData.doseUnitCode = editForm.value.unit
contentJsonData.methodCode = updatedAdvice.usage
contentJsonData.quantity = quantity
contentJsonData.totalPrice = unitPrice * quantity
contentJsonData.adviceName = updatedAdvice.adviceName
const saveItem = {
...contentJsonData,
dbOpType: editMedicine.requestId ? '2' : '1',
adviceType: editMedicine.adviceType || 1,
requestId: editMedicine.requestId,
chargeItemId: editMedicine.chargeItemId,
contentJson: JSON.stringify(contentJsonData),
quantity,
unitCode: editMedicine.unitCode || editForm.value.unit,
unitPrice,
totalPrice: unitPrice * quantity,
adviceName: updatedAdvice.adviceName,
patientId: props.patientInfo.patientId,
encounterId: props.patientInfo.visitId,
orgId: props.patientInfo.orgId,
methodCode: updatedAdvice.usage,
dose: editForm.value.dosage,
doseUnitCode: editForm.value.unit,
generateSourceEnum: 6,
sourceBillNo: props.patientInfo?.operCode || ''
}
try {
await savePrescription({ organizationId: props.patientInfo.orgId || 1, adviceSaveList: [saveItem] }, '2')
ElMessage.success('医嘱修改已保存到服务器')
} catch (e) {
ElMessage.error('保存失败,请重试')
}
}
} }
// 取消编辑 // 取消编辑
@@ -762,7 +817,7 @@ const handleCancelEdit = () => {
dosage: '', dosage: '',
unit: '', unit: '',
usage: '', usage: '',
frequency: '临时' frequency: '立即'
} }
} }
@@ -777,10 +832,10 @@ const confirmSign = async () => {
const response = await checkPassword({ const response = await checkPassword({
password: signPassword.value password: signPassword.value
}) })
if (response.code === 200 && response.data) { if (response.code === 200 && response.data) {
isSigned.value = true isSigned.value = true
signatureTime.value = new Date().toLocaleString('zh-CN') signatureDoctor.value = userStore.nickName || userStore.name
signatureTime.value = parseTime(new Date())
showSignDialog.value = false showSignDialog.value = false
signPassword.value = '' signPassword.value = ''
ElMessage.success('签名成功') ElMessage.success('签名成功')
@@ -799,10 +854,8 @@ const confirmSign = async () => {
const handleSignAndSubmit = () => { const handleSignAndSubmit = () => {
if (isSigned.value) { if (isSigned.value) {
// 如果已经签名,直接提交
handleSubmit() handleSubmit()
} else { } else {
// 如果未签名,打开签名弹窗
handleSign() handleSign()
} }
} }
@@ -907,6 +960,8 @@ const handleSubmit = async () => {
contentJsonData.dose = advice.dosage; contentJsonData.dose = advice.dosage;
contentJsonData.doseUnitCode = advice.unit; contentJsonData.doseUnitCode = advice.unit;
contentJsonData.rateCode = advice.frequency; contentJsonData.rateCode = advice.frequency;
contentJsonData.signDoctorName = signatureDoctor.value
contentJsonData.signDate = signatureTime.value
// 重新序列化contentJson // 重新序列化contentJson
const updatedContentJson = JSON.stringify(contentJsonData); const updatedContentJson = JSON.stringify(contentJsonData);
@@ -993,7 +1048,7 @@ const handleSubmit = async () => {
billingMedicines: props.billingMedicines, billingMedicines: props.billingMedicines,
temporaryAdvices: itemsToSign, temporaryAdvices: itemsToSign,
signature: { signature: {
doctorName: currentUser.value.name, doctorName: signatureDoctor.value,
signatureTime: signatureTime.value signatureTime: signatureTime.value
} }
} }