@@ -380,7 +380,7 @@ const form = ref({
prescriptionList : prescriptionList . value ,
} ) ;
const adviceQueryParams = ref ( {
adviceType : '' ,
adviceType : 1 ,
categoryCode : '' , // 初始为空,等待加载配置后动态设置
searchKey : '' ,
} ) ;
@@ -533,7 +533,6 @@ const statusOption = [
let loadingInstance = undefined ;
onMounted ( ( ) => {
document . addEventListener ( 'keydown' , escKeyListener ) ;
getList ( ) ;
} ) ;
onBeforeUnmount ( ( ) => {
@@ -574,6 +573,7 @@ function handleTotalAmount() {
}
} , new Decimal ( 0 ) ) ;
}
getList ( ) ;
function getList ( ) {
getDiagnosisDefinitionList ( queryParams . value ) . then ( ( res ) => {
// prescriptionList.value = res.data.records;
@@ -585,11 +585,6 @@ function refresh() {
}
// 获取列表信息
function getListInfo ( addNewRow ) {
// 守护:未选择患者时不发起 API 请求,避免页面加载时循环报错
if ( ! patientInfo . value || ! patientInfo . value . encounterId ) {
console . warn ( '⚠️ getListInfo 跳过:未选择患者' ) ;
return ;
}
loadingInstance = ElLoading . service ( { fullscreen : true } ) ;
setTimeout ( ( ) => {
loadingInstance . close ( ) ;
@@ -691,7 +686,7 @@ function loadConfiguredCategories() {
nextTick ( ( ) => {
// 创建新对象触发响应式更新
adviceQueryParams . value = {
adviceType : '' ,
adviceType : 1 ,
categoryCode : defaultCategoryCode ,
searchKey : '' ,
} ;
@@ -715,17 +710,9 @@ function loadConfiguredCategories() {
// 数据过滤
const filterPrescriptionList = computed ( ( ) => {
const pList = prescriptionList . value . filter ( ( item ) => {
// 修复 Bug #488: orderClassCode 可能是复合值 '1-2',需提取 adviceType 部分进行比较
let matchAdviceType = true ;
if ( orderClassCode . value ) {
const filterAdviceType = String ( orderClassCode . value ) . includes ( '-' )
? parseInt ( String ( orderClassCode . value ) . split ( '-' ) [ 0 ] )
: orderClassCode . value ;
matchAdviceType = filterAdviceType == item . adviceType ;
}
return (
( ! therapyEnum . value || therapyEnum . value == item . therapyEnum ) &&
matchA dviceType &&
( ! orderClassCode . value || orderClassCode . value == item . a dviceType) &&
( ! orderStatus . value || ( orderStatus . value == item . statusEnum && item . requestId ) )
) ;
} ) ;
@@ -753,28 +740,12 @@ function getRowDisabled(row) {
/**
* 将行的 adviceType + categoryCode 映射为 el-select 的选中值
* 药品子分类使用复合值如 '1-2'( adviceType-categoryCode) , 诊疗/手术/全部使用原始值
* 修复 Bug #488: 当行的 adviceType 在当前配置中找不到匹配选项时,返回最接近的可用值,避免回显为纯数字
*/
function getRowSelectValue ( row ) {
if ( row . adviceType == 1 && row . categoryCode ) {
const compositeValue = '1-' + row . categoryCode ;
// 检查复合值是否在选项列表中
if ( adviceTypeList . value . some ( item => item . value === compositeValue ) ) {
return compositeValue ;
}
// 配置的 categoryCode 已变更,回退到第一个药品选项
const firstPharmacy = adviceTypeList . value . find ( item => String ( item . value ) . startsWith ( '1-' ) ) ;
if ( firstPharmacy ) {
return firstPharmacy . value ;
}
return row . adviceType ;
return '1-' + row . categoryCode ;
}
// 诊疗/手术等非药品类型,检查其值是否在选项列表中
if ( adviceTypeList . value . some ( item => item . value === row . adviceType ) ) {
return row . adviceType ;
}
// 不在选项中的值(如已废弃的 adviceType) , 返回 undefined 让 el-select 显示为空
return undefined ;
return row . adviceType ;
}
// 新增医嘱
@@ -831,8 +802,8 @@ function clickRowDb(row, column, event) {
return ;
}
row . showPopover = false ;
// 仅” 待签发(statusEnum==1 )”允许编辑;”已签发(statusEnum==2)”及之后状态不 允许编辑
if ( row . statusEnum == 1 ) {
// “ 待签发(已保存 requestId存在 )”不 允许再 编辑;仅“待保存(无requestId)” 允许编辑
if ( row . statusEnum == 1 && ! row . requestId ) {
// 确保治疗类型为字符串,方便与单选框 label 对齐,默认为长期医嘱('1')
row . therapyEnum = String ( row . therapyEnum ? ? '1' ) ;
row . isEdit = true ;
@@ -910,9 +881,9 @@ function handleFocus(row, index) {
// 用 adviceType + categoryCode 组合查找匹配的选项
const selectValue = ( adviceType == 1 && row . categoryCode ) ? '1-' + row . categoryCode : adviceType ;
const selectedItem = adviceTypeList . value . find ( item => item . value === selectValue ) || adviceTypeList . value . find ( item => item . adviceType === adviceType ) ;
// 修复Bug #486: 当行没有显式选择医嘱类型时( row.adviceType为undefined) ,
// 不传categoryCode, 让搜索在全药库中进行; 只有行已选择类型时才用对应categoryCode过滤
const categoryCode = row . adviceType !== undefined ? ( selectedItem ? selectedItem . categoryCode : '' ) : '' ;
// If the row has an explicit adviceType (saved/existing row), use its own categoryCode.
// If no type is selected (new row), use empty string for global search across all categories.
const categoryCode = selectedItem ? selectedItem . categoryCode : ( row. adviceType != null ? ( row . categoryCode || '' ) : '' ) ;
const searchKey = row . adviceName || '' ;
nextTick ( ( ) => {
@@ -949,12 +920,9 @@ function handleChange(value) {
// 用 adviceType + categoryCode 组合查找匹配的选项
const selectValue = ( adviceType == 1 && row ? . categoryCode ) ? '1-' + row . categoryCode : adviceType ;
const selectedItem = adviceTypeList . value . find ( item => item . value === selectValue ) || adviceTypeList . value . find ( item => item . adviceType === adviceType ) ;
// 修复Bug #486: 当行没有显式选择医嘱类型时( row?.adviceType为undefined) ,
// 不传 categoryCode, 让搜索在全药库中进行; 只有行已选择类型时才用对应categoryCode过滤
const categoryCode = row ? . adviceType !== undefined ? ( selectedItem ? selectedItem . categoryCode : '' ) : '' ;
// 修复Bug #453: 当adviceType为空字符串或NaN时, 不传具体类型, 让refresh函数根据searchKey决定搜索范围
const effectiveAdviceType = ( adviceType && ! isNaN ( Number ( adviceType ) ) ) ? adviceType : '' ;
tableRef . refresh ( effectiveAdviceType , categoryCode , value ) ;
// 修复Bug #486: 当行没有显式选择医嘱类型时, 不传categoryCode, 让搜索在全药库中进行
const categoryCode = selectedItem ? selectedItem . categoryCode : ( row ? . adviceType !== undefined ? ( adviceQueryParams . value . categoryCode || '' ) : '' ) ;
tableRef . refresh ( adviceType , categoryCode , value ) ;
}
}
}
@@ -1213,27 +1181,19 @@ function handleSave() {
} ) ;
// 此处签发处方和单行保存处方传参相同, 后台已经将传参存为JSON字符串, 此处直接转换为JSON即可
loading . value = true ;
let list = [ ] ;
try {
list = saveList . map ( ( item ) => {
const parsedContent = item . contentJson ? JSON . parse ( item . contentJson ) || { } : { } ;
return {
... parsedContent ,
adviceType : item . adviceType ,
request Id : item . request Id,
dbOpType : '1' ,
groupId : item . groupId ,
uniqueKey : undefined ,
// 确保 therapyEnum 被正确传递
therapyEnum : parsedContent ? . therapyEnum || item . therapyEnum || '1' ,
} ;
} ) ;
} catch ( error ) {
loading . value = false ;
isSaving . value = false ;
proxy . $modal . msgError ( '医嘱内容解析失败,请检查待签发医嘱' ) ;
return ;
}
let list = saveList . map ( ( item ) => {
const parsedContent = JSON . parse ( item . contentJson ) ;
return {
... parsedContent ,
adviceType : item . adviceType ,
requestId : item . requestId ,
dbOpType : '1' ,
group Id: item . group Id,
uniqueKey : undefined ,
// 确保 therapyEnum 被正确传递
therapyEnum : parsedContent . therapyEnum || item . therapyEnum || '1' ,
} ;
} ) ;
// 保存签发按钮
isSaving . value = true ;
console . log ( '签发处方参数:' , {
@@ -1248,16 +1208,9 @@ function handleSave() {
if ( res . code === 200 ) {
proxy . $modal . msgSuccess ( '签发成功' ) ;
isSaving . value = false ;
// 乐观更新:立即将已签发医嘱的状态设为"已签发",确保列表实时刷新
saveList . forEach ( ( item ) => {
const row = prescriptionList . value . find ( ( r ) => r . requestId && r . requestId === item . requestId ) ;
if ( row ) {
row . statusEnum = 2 ;
}
} ) ;
getListInfo ( false ) ;
bindMethod . value = { } ;
nextId . value = 1 ;
nextId . value == 1 ;
} else {
proxy . $modal . msgError ( res . message ) ;
isSaving . value = false ;
@@ -1358,12 +1311,11 @@ function handleCancelEdit(row, index) {
function handleSaveSign ( row , index ) {
if ( row . adviceType != 2 ) {
// 修复 Bug #488: 严格校验 itemNo, 确保非空且为有效字符串才发起请求
let itemNo = row . adviceType == 1 ? row . methodCode : row . adviceDefinitionId ;
if ( ! itemNo || String ( itemNo ) . trim ( ) === '' ) {
if ( ! itemNo ) {
console . warn ( '绑定设备检查跳过: itemNo为空( adviceType=' + row . adviceType + ', adviceName=' + row . adviceName + ') ' ) ;
} else {
getBindDevice ( { typeCode : row . adviceType , itemNo : String ( itemNo ) } ) . then ( ( res ) => {
getBindDevice ( { typeCode : row . adviceType , itemNo : itemNo } ) . then ( ( res ) => {
if ( res . data . length == 0 ) {
return ;
}
@@ -1424,21 +1376,13 @@ function handleSaveSign(row, index) {
savePrescription ( { regAdviceSaveList : [ row ] } ) . then ( ( res ) => {
if ( res . code === 200 ) {
proxy . $modal . msgSuccess ( '保存成功' ) ;
nextId . value = 1 ;
nextId . value == 1 ;
}
} ) ;
} else {
// 新增行:调用保存接口将数据持久化到后端
row . dbOpType = '1' ;
savePrescription ( { regAdviceSaveList : [ row ] } ) . then ( ( res ) => {
if ( res . code === 200 ) {
proxy . $modal . msgSuccess ( '保存成功' ) ;
nextId . value = 1 ;
// 保存成功后刷新列表,确保后端返回的数据带 requestId
getListInfo ( false ) ;
}
} ) ;
// 不需要再添加空行,保存成功后由 getListInfo 处理
if ( prescriptionList . value [ 0 ] . adviceName ) {
handleAddPrescription ( ) ;
}
}
adviceQueryParams . value . adviceType = undefined ;
}
@@ -1479,40 +1423,32 @@ function handleSaveBatch() {
. then ( ( res ) => {
if ( res . code === 200 ) {
proxy . $modal . msgSuccess ( '保存成功' ) ;
// 修复 Bug #405: 保存成功后锁定 所有待保存行,避免医嘱条目仍处于可编辑状态
// saveList 中的 item 与 prescriptionList 是同一对象引用,直接修改即可
// 修复【 #405】 :保存成功后重置 所有待保存行的 isEdit 为 false, 锁定医嘱不再编辑
saveList . forEach ( item => {
item . isEdit = false ;
const row = prescriptionList . value . find ( r => r . uniqueKey === item . uniqueKey ) ;
if ( row ) row . isEdit = false ;
} ) ;
// 兜底:锁定所有 statusEnum == 1 的行,确保没有遗漏
prescriptionList . value . forEach ( row => {
if ( row . statusEnum == 1 ) {
row . isEdit = false ;
}
} ) ;
expandOrder . value = [ ] ;
getListInfo ( false ) ;
nextId . value = 1 ;
nextId . value == 1 ;
isSaving . value = false ;
}
} )
. catch ( ( error ) => {
isSaving . value = false ;
proxy . $modal . msgError ( error ? . msg || '保存失败,请重试' ) ;
} ) ;
}
function setValue ( row ) {
// 构造单位列表,确保 value 始终为 String 类型,避免 el-select 值类型不匹配
// 构造单位列表
unitCodeList . value = [
{ value : String ( row . unitCode ? ? '' ) , label : row . unitCode _dictText , type : 'unit' } ,
{ value : row . unitCode , label : row . unitCode _dictText , type : 'unit' } ,
{
value : String ( row . doseUnitCode ? ? '' ) ,
value : row . doseUnitCode ,
label : row . doseUnitCode _dictText ,
type : 'dose' ,
} ,
{
value : String ( row . minUnitCode ? ? '' ) ,
value : row . minUnitCode ,
label : row . minUnitCode _dictText ,
type : 'minUnit' ,
} ,
@@ -1577,9 +1513,9 @@ function setValue(row) {
orgName : row . adviceType != 3 ? undefined : ( findOrgName ( row . orgId || row . positionId || patientInfo . value ? . inHospitalOrgId ) || row . orgName || patientInfo . value ? . inHospitalOrgName || '' ) ,
// dose: undefined, Removed to preserve dose value from group package
unitCodeList : unitCodeList . value ,
doseUnitCode : String ( row . doseUnitCode ? ? '' ) ,
minUnitCode : String ( row . minUnitCode ? ? '' ) ,
unitCode : row . partAttributeEnum == 1 ? String ( row . minUnitCode ? ? '' ) : String ( row . unitCode ? ? '' ) ,
doseUnitCode : row . doseUnitCode ,
minUnitCode : row . minUnitCode ,
unitCode : row . partAttributeEnum == 1 ? row . minUnitCode : row . unitCode ,
categoryEnum : row . categoryCode ,
definitionId : row . chargeItemDefinitionId ,
executeNum : 1 ,
@@ -1595,10 +1531,6 @@ function setValue(row) {
? new Decimal ( selectedStock . price ) . div ( row . partPercent ) . toFixed ( 6 )
: prevRow . minUnitPrice ,
positionName : selectedStock ? . locationName ,
// 🔧 Bug #523 修复:初始化 totalPrice 为 0, 避免总金额列显示为横杠
totalPrice : row . quantity
? new Decimal ( row . quantity ) . mul ( selectedStock ? . price ? ? 0 ) . toFixed ( 6 )
: '0' ,
}
: {
quantity : 1 ,
@@ -1630,21 +1562,17 @@ function handleSaveGroup(orderGroupList) {
// 🔥 新版组件已经预处理了数据,优先使用 mergedDetail
const mergedDetail = item . mergedDetail || {
... ( item . orderDetailInfos || { } ) ,
adviceName : item . orderDefinition Name || item . orderDetailInfos ? . advice Name || '未知项目' ,
adviceName : item . orderDetailInfos ? . advice Name || item . orderDefinition Name || '未知项目' ,
adviceType : item . orderDetailInfos ? . adviceType ,
adviceDefinitionId : item . orderDefinitionId || item . orderDetailInfos ? . adviceDefinitionId ,
quantity : item . quantity ,
unitCode : item . unitCode || item . orderDetailInfos ? . unitCode ,
unitCodeName : item . unitCodeName ,
// 🔧 Bug #403 修复: dose/doseQuantity/dispensePerDuration 需用 null 检查,
// 避免组套中值为 null 时回退到医嘱库的 orderDetailInfos
dose : item . dose !== undefined && item . dose !== null ? item . dose : item . orderDetailInfos ? . dose ,
dose : item . dose || item . orderDetailInfos ? . dose ,
rateCode : item . rateCode || item . orderDetailInfos ? . rateCode ,
methodCode : item . methodCode || item . orderDetailInfos ? . methodCode ,
dispensePerDuration : item . dispensePerDuration !== undefined && item . dispensePerDuration !== null
? item . dispensePerDuration : item . orderDetailInfos ? . dispensePerDuration ,
doseQuantity : item . doseQuantity !== undefined && item . doseQuantity !== null
? item . doseQuantity : item . orderDetailInfos ? . doseQuantity ,
dispensePerDuration : item . dispensePerDuration || item . orderDetailInfos ? . dispensePerDuration ,
doseQuantity : item . doseQuantity ,
inventoryList : item . orderDetailInfos ? . inventoryList || [ ] ,
priceList : item . orderDetailInfos ? . priceList || [ ] ,
partPercent : item . orderDetailInfos ? . partPercent || 1 ,
@@ -1663,69 +1591,41 @@ function handleSaveGroup(orderGroupList) {
setValue ( mergedDetail ) ;
// 创建新的处方项目
// 🔧 Bug #403 修复:关键字段使用 null-safe 回退到 mergedDetail( 已由 setValue 填充完整数据)
// 先取 setValue 填充的行数据作为基础
const baseRow = prescriptionList . value [ rowIndex . value ] ;
const newRow = {
... baseRow ,
isEdit : false ,
... prescriptionList . value [ rowIndex . value ] ,
patientId : patientInfo . value . patientId ,
encounterId : patientInfo . value . encounterId ,
accountId : accountId . value ,
quantity : item . quantity ,
methodCode : item . methodCode ,
rateCode : item . rateCode ,
dispensePerDuration : item . dispensePerDuration ,
dose : item . dose ,
doseQuantity : item . doseQuantity ,
executeNum : 1 ,
unitCode : item . unitCode ,
unitCode _dictText : item . unitCodeName || '' ,
statusEnum : 1 ,
orgId : resolveOrgId (
( item . orderDetailInfos ? . orgId || mergedDetail . orgId )
? ( item . orderDetailInfos ? . orgId || mergedDetail . orgId )
: patientInfo . value ? . inHospitalOrgId
) || '' ,
orgName : findOrgName (
( item . orderDetailInfos ? . orgId || mergedDetail . orgId )
? ( item . orderDetailInfos ? . orgId || mergedDetail . orgId )
: patientInfo . value ? . inHospitalOrgId
) || item . orderDetailInfos ? . orgName || mergedDetail . orgName || patientInfo . value ? . inHospitalOrgName || '' ,
orgId : resolveOrgId ( item . orderDetailInfos ? . orgId || mergedDetail . orgId || patientInfo . value ? . inHospitalOrgId ) || '' ,
// 🔧 修复:同时保存 orgName, 确保树匹配不到时仍有中文名称可显示
orgName : findOrgName ( item . orderDetailInfos ? . orgId || mergedDetail . orgId || patientInfo . value ? . inHospitalOrgId ) || item . orderDetailInfos ? . orgName || mergedDetail . orgName || patientInfo . value ? . inHospitalOrgName || '' ,
dbOpType : prescriptionList . value [ rowIndex . value ] . requestId ? '2' : '1' ,
conditionId : conditionId . value ,
conditionDefinitionId : conditionDefinitionId . value ,
encounterDiagnosisId : encounterDiagnosisId . value ,
diagnosisName : diagnosisName . value ,
therapyEnum : baseRow ? . therapyEnum || '1' ,
therapyEnum : prescriptionList . value [ rowIndex . value ] ? . therapyEnum || '1' ,
} ;
// 覆盖关键字段:优先使用 item 的值,其次 mergedDetail( 已由 setValue 填充),最后 baseRow
newRow . quantity = item . quantity ? ? mergedDetail . quantity ? ? baseRow . quantity ;
newRow . methodCode = item . methodCode ? ? mergedDetail . methodCode ? ? baseRow . methodCode ;
newRow . rateCode = item . rateCode ? ? mergedDetail . rateCode ? ? baseRow . rateCode ;
newRow . dispensePerDuration = item . dispensePerDuration ? ? mergedDetail . dispensePerDuration ? ? baseRow . dispensePerDuration ;
newRow . dose = item . dose ? ? mergedDetail . dose ? ? baseRow . dose ;
newRow . doseQuantity = item . doseQuantity ? ? mergedDetail . doseQuantity ? ? baseRow . doseQuantity ;
newRow . unitCode = item . unitCode ? ? mergedDetail . unitCode ? ? baseRow . unitCode ;
newRow . unitCode _dictText = item . unitCodeName || mergedDetail . unitCodeName || baseRow . unitCode _dictText || '' ;
// 确保价格字段有兜底值( setValue 可能因库存不足提前 return 导致未设置)
newRow . unitPrice = baseRow . unitPrice ? ? mergedDetail . unitPrice ? ? 0 ;
newRow . minUnitPrice = baseRow . minUnitPrice ? ? mergedDetail . minUnitPrice ? ? 0 ;
newRow . unitTempPrice = newRow . unitPrice ;
newRow . methodCode _dictText = mergedDetail . methodCode _dictText || item . methodCode _dictText || '' ;
newRow . rateCode _dictText = mergedDetail . rateCode _dictText || item . rateCode _dictText || '' ;
newRow . doseUnitCode = mergedDetail . doseUnitCode || item . doseUnitCode || baseRow . doseUnitCode ;
newRow . doseUnitCode _dictText = mergedDetail . doseUnitCode _dictText || item . doseUnitCode _dictText || '' ;
newRow . orgId = mergedDetail . orgId || mergedDetail . positionId || baseRow . orgId || '' ;
newRow . positionName = mergedDetail . orgName || mergedDetail . positionName || baseRow . positionName || '' ;
// 计算价格和总量
// 🔧 Bug #403 修复:使用 newRow.unitCode( 已由 setValue 填充)而非 item. unitCode
// 使用 ?? 替代 || 计算 partPercent, 确保值为 0 时不会被错误替换
const finalUnitCode = newRow . unitCode ;
const unitInfo = unitCodeList . value . find ( ( k ) => k . value == finalUnitCode ) ;
const finalQuantity = newRow . quantity ;
const partPercent = item . orderDetailInfos ? . partPercent ? ? mergedDetail . partPercent ? ? baseRow . partPercent ? ? 1 ;
const unitInfo = unitCodeList . value . find ( ( k ) => k . value == item . unitCode) ;
if ( unitInfo && unitInfo . type == 'minUnit' ) {
newRow . price = newRow . minUnitPrice ;
newRow . totalPrice = ( ( finalQuantity || 0 ) * newRow . minUnitPrice ) . toFixed ( 6 ) ;
newRow . minUnitQuantity = finalQuantity || 0 ;
newRow . totalPrice = ( item . quantity * newRow . minUnitPrice ) . toFixed ( 6 ) ;
newRow . minUnitQuantity = item . quantity ;
} else {
newRow . price = newRow . unitPrice ;
newRow . totalPrice = ( ( finalQuantity || 0 ) * newRow . unitPrice ) . toFixed ( 6 ) ;
newRow . minUnitQuantity = ( finalQuantity || 0 ) * partPercent ;
newRow . totalPrice = ( item . quantity * newRow . unitPrice ) . toFixed ( 6 ) ;
newRow . minUnitQuantity = item . quantity * ( item . orderDetailInfos ? . partPercent || mergedDetail . partPercent || 1 ) ;
}
newRow . contentJson = JSON . stringify ( newRow ) ;