Merge remote-tracking branch 'origin/develop' into develop
# Conflicts: # healthlink-his-ui/src/views/inpatientDoctor/home/components/diagnosis/chineseMedicineDialog.vue # healthlink-his-ui/src/views/inpatientDoctor/home/components/diagnosis/diagnosis.vue
This commit is contained in:
5
.claude/settings.json
Normal file
5
.claude/settings.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"enabledPlugins": {
|
||||
"agent-sdk-dev@claude-plugins-official": true
|
||||
}
|
||||
}
|
||||
@@ -35,9 +35,10 @@ public interface IOutpatientChargeAppService {
|
||||
* 根据就诊id查询患者处方列表
|
||||
*
|
||||
* @param encounterId 就诊id
|
||||
* @param statusEnum 收费状态过滤(可选,不传则返回全部状态)
|
||||
* @return 患者处方列表
|
||||
*/
|
||||
List<EncounterPatientPrescriptionDto> getEncounterPatientPrescription(Long encounterId);
|
||||
List<EncounterPatientPrescriptionDto> getEncounterPatientPrescription(Long encounterId, Integer statusEnum);
|
||||
|
||||
/**
|
||||
* 根据就诊id查询患者处方列表并新增字段:实收金额、应收金额、优惠金额、折扣率
|
||||
|
||||
@@ -111,10 +111,11 @@ public class OutpatientChargeAppServiceImpl implements IOutpatientChargeAppServi
|
||||
* 根据就诊id查询患者处方列表
|
||||
*
|
||||
* @param encounterId 就诊id
|
||||
* @param statusEnum 收费状态过滤(可选,不传则返回全部状态)
|
||||
* @return 患者处方列表
|
||||
*/
|
||||
@Override
|
||||
public List<EncounterPatientPrescriptionDto> getEncounterPatientPrescription(Long encounterId) {
|
||||
public List<EncounterPatientPrescriptionDto> getEncounterPatientPrescription(Long encounterId, Integer statusEnum) {
|
||||
List<EncounterPatientPrescriptionDto> prescriptionDtoList
|
||||
= outpatientChargeAppMapper.selectEncounterPatientPrescription(encounterId,
|
||||
ChargeItemContext.ACTIVITY.getValue(), ChargeItemContext.MEDICATION.getValue(),
|
||||
@@ -123,7 +124,7 @@ public class OutpatientChargeAppServiceImpl implements IOutpatientChargeAppServi
|
||||
ChargeItemStatus.PLANNED.getValue(), ChargeItemStatus.BILLABLE.getValue(),
|
||||
ChargeItemStatus.BILLED.getValue(), ChargeItemStatus.REFUNDING.getValue(),
|
||||
ChargeItemStatus.REFUNDED.getValue(), ChargeItemStatus.PART_REFUND.getValue(),
|
||||
CommonConstants.TableName.WOR_DEVICE_REQUEST);
|
||||
CommonConstants.TableName.WOR_DEVICE_REQUEST, statusEnum);
|
||||
prescriptionDtoList.forEach(e -> {
|
||||
// 收费状态枚举
|
||||
e.setStatusEnum_enumText(EnumUtils.getInfoByValue(ChargeItemStatus.class, e.getStatusEnum()));
|
||||
|
||||
@@ -61,11 +61,13 @@ public class OutpatientChargeController {
|
||||
* 根据就诊id查询患者处方列表
|
||||
*
|
||||
* @param encounterId 就诊id
|
||||
* @param statusEnum 收费状态过滤(可选,不传则返回全部状态)
|
||||
* @return 患者处方列表
|
||||
*/
|
||||
@GetMapping(value = "/patient-prescription")
|
||||
public R<?> getEncounterPatientPrescription(@RequestParam Long encounterId) {
|
||||
return R.ok(outpatientChargeAppService.getEncounterPatientPrescription(encounterId));
|
||||
public R<?> getEncounterPatientPrescription(@RequestParam Long encounterId,
|
||||
@RequestParam(required = false) Integer statusEnum) {
|
||||
return R.ok(outpatientChargeAppService.getEncounterPatientPrescription(encounterId, statusEnum));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -59,7 +59,8 @@ public interface OutpatientChargeAppMapper {
|
||||
@Param("chinesePatentMedicine") Integer chinesePatentMedicine,
|
||||
@Param("planned") Integer planned, @Param("billable") Integer billable,
|
||||
@Param("billed") Integer billed, @Param("refunding") Integer refunding, @Param("refunded") Integer refunded,
|
||||
@Param("partRefund") Integer partRefund, @Param("worDeviceRequest") String worDeviceRequest);
|
||||
@Param("partRefund") Integer partRefund, @Param("worDeviceRequest") String worDeviceRequest,
|
||||
@Param("filterStatus") Integer filterStatus);
|
||||
|
||||
/**
|
||||
* 根据就诊id查询患者处方列表并新增字段:应收金额,实收金额,优惠金额,折扣率
|
||||
|
||||
@@ -521,9 +521,9 @@ public class CommonServiceImpl implements ICommonService {
|
||||
}
|
||||
}
|
||||
|
||||
// 方式 3:如果仍然没有病区,且 currentOrgId 为空,尝试获取所有病区
|
||||
if (wardList.isEmpty() && currentOrgId == null) {
|
||||
log.info("getPractitionerWard - 尝试获取所有病区");
|
||||
// 方式 3:如果仍然没有病区,尝试获取所有活动病区
|
||||
if (wardList.isEmpty()) {
|
||||
log.info("getPractitionerWard - 未查到指定病区,获取所有病区");
|
||||
List<Location> allWards = locationService.getWardList(null);
|
||||
log.info("getPractitionerWard - 所有病区数:{}", allWards != null ? allWards.size() : 0);
|
||||
if (allWards != null && !allWards.isEmpty()) {
|
||||
|
||||
@@ -140,8 +140,8 @@ public class DoctorStationChineseMedicalAppServiceImpl implements IDoctorStation
|
||||
.setSourceEnum(ConditionDefinitionSource.TRADITIONAL_CHINESE_MEDICINE_SYNDROME_CATALOG.getValue());
|
||||
QueryWrapper<ConditionDefinition> queryWrapper = HisQueryUtils.buildQueryWrapper(conditionDefinition, searchKey,
|
||||
new HashSet<>(Arrays.asList("name", "py_str", "wb_str")), null);
|
||||
// 设置排序
|
||||
queryWrapper.orderByDesc("update_time");
|
||||
// 设置排序(与诊断目录页保持一致,按编码升序,确保取到原始标准编码记录)
|
||||
queryWrapper.orderByAsc("condition_code");
|
||||
// 诊断信息
|
||||
Page<ConditionDefinitionMetadata> conditionDefinitionMetadataPage = HisPageUtils
|
||||
.selectPage(conditionDefinitionMapper, queryWrapper, pageNo, pageSize, ConditionDefinitionMetadata.class);
|
||||
|
||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.core.common.core.domain.R;
|
||||
import com.core.common.enums.DelFlag;
|
||||
import com.core.common.exception.ServiceException;
|
||||
import com.core.common.utils.*;
|
||||
import com.core.common.utils.bean.BeanUtils;
|
||||
@@ -87,6 +88,12 @@ public class InHospitalRegisterAppServiceImpl implements IInHospitalRegisterAppS
|
||||
@Resource
|
||||
private IChargeItemService iChargeItemService;
|
||||
|
||||
@Resource
|
||||
private ILocationService iLocationService;
|
||||
|
||||
@Resource
|
||||
private IOrganizationService iOrganizationService;
|
||||
|
||||
/**
|
||||
* 门诊医生开住院申请
|
||||
*
|
||||
@@ -357,17 +364,38 @@ public class InHospitalRegisterAppServiceImpl implements IInHospitalRegisterAppS
|
||||
*/
|
||||
@Override
|
||||
public List<LocationDto> getWardList(Long orgId) {
|
||||
List<Location> wardList = inHospitalRegisterAppMapper.selectWardList(orgId, LocationForm.WARD.getValue(),
|
||||
LocationStatus.ACTIVE.getValue());
|
||||
|
||||
// 2. 转换为 LocationDto(逻辑与原代码完全一致)
|
||||
List<LocationDto> locationDtoList = new ArrayList<>();
|
||||
for (Location location : wardList) {
|
||||
LocationDto locationDto = new LocationDto();
|
||||
BeanUtils.copyProperties(location, locationDto);
|
||||
locationDtoList.add(locationDto);
|
||||
Set<Long> orgIds = new LinkedHashSet<>();
|
||||
if (orgId != null) {
|
||||
orgIds.add(orgId);
|
||||
// 通过 busNo 层级查找所有子孙科室(busNo 用 "." 分隔层级,如 "1" → "1.1" → "1.1.1")
|
||||
Organization org = iOrganizationService.getById(orgId);
|
||||
if (org != null && StringUtils.isNotEmpty(org.getBusNo())) {
|
||||
List<Organization> children = iOrganizationService.list(
|
||||
new LambdaQueryWrapper<Organization>()
|
||||
.likeRight(Organization::getBusNo, org.getBusNo() + ".")
|
||||
.eq(Organization::getDeleteFlag, DelFlag.NO.getCode()));
|
||||
for (Organization child : children) {
|
||||
orgIds.add(child.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询所有关联科室下的病区
|
||||
List<Location> wardList = new ArrayList<>();
|
||||
for (Long id : orgIds) {
|
||||
wardList.addAll(iLocationService.getWardList(id));
|
||||
}
|
||||
|
||||
// 按 ID 去重
|
||||
List<LocationDto> locationDtoList = new ArrayList<>();
|
||||
Set<Long> seen = new HashSet<>();
|
||||
for (Location location : wardList) {
|
||||
if (seen.add(location.getId())) {
|
||||
LocationDto dto = new LocationDto();
|
||||
BeanUtils.copyProperties(location, dto);
|
||||
locationDtoList.add(dto);
|
||||
}
|
||||
}
|
||||
return locationDtoList;
|
||||
}
|
||||
|
||||
|
||||
@@ -268,15 +268,9 @@ public class AdviceProcessAppServiceImpl implements IAdviceProcessAppService {
|
||||
e.setSingleDose(doseStr + unitStr);
|
||||
}
|
||||
|
||||
// 总量:剂量 × 数量 + 单位(仅药品医嘱)
|
||||
if (e.getDose() != null && e.getQuantity() != null) {
|
||||
BigDecimal total = e.getDose().multiply(BigDecimal.valueOf(e.getQuantity()));
|
||||
String totalStr = total.stripTrailingZeros().toPlainString();
|
||||
String unitStr = e.getUnitCode_dictText() != null ? e.getUnitCode_dictText() : "";
|
||||
e.setTotalAmount(totalStr + unitStr);
|
||||
} else if (e.getQuantity() != null) {
|
||||
String unitStr = e.getUnitCode_dictText() != null ? e.getUnitCode_dictText() : "";
|
||||
e.setTotalAmount(e.getQuantity() + unitStr);
|
||||
// 总量:数量(总量就是数量,不需要乘以剂量,单位由前端显示)
|
||||
if (e.getQuantity() != null) {
|
||||
e.setTotalAmount(String.valueOf(e.getQuantity()));
|
||||
}
|
||||
|
||||
// 频次/用法组合
|
||||
|
||||
@@ -72,6 +72,10 @@ public interface IChargeBillService {
|
||||
*/
|
||||
R<?> checkYbNo();
|
||||
|
||||
|
||||
/**
|
||||
* 分页查询收费账单列表
|
||||
*/
|
||||
Map<String, Object> getBillPage(String searchKey, String billType, String payStatus,
|
||||
String startTime, String endTime, Integer pageNo, Integer pageSize);
|
||||
|
||||
}
|
||||
|
||||
@@ -608,4 +608,221 @@ public class ChargeBillQueryService {
|
||||
map.put("insutype", "自费");
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询收费账单列表
|
||||
*/
|
||||
public Map<String, Object> getBillPage(String searchKey, String billType, String payStatus,
|
||||
String startTime, String endTime, Integer pageNo, Integer pageSize) {
|
||||
// 预解析searchKey,避免后续重复查询
|
||||
List<Long> searchPatientIds = null;
|
||||
List<Long> searchEncounterIds = null;
|
||||
if (StringUtils.isNotEmpty(searchKey)) {
|
||||
searchPatientIds = iPatientService.list(new LambdaQueryWrapper<Patient>()
|
||||
.like(Patient::getName, searchKey)
|
||||
.eq(Patient::getDeleteFlag, DelFlag.NO.getCode())
|
||||
.select(Patient::getId))
|
||||
.stream().map(Patient::getId).collect(Collectors.toList());
|
||||
searchEncounterIds = iEncounterService.list(new LambdaQueryWrapper<Encounter>()
|
||||
.like(Encounter::getBusNo, searchKey)
|
||||
.eq(Encounter::getDeleteFlag, DelFlag.NO.getCode())
|
||||
.select(Encounter::getId))
|
||||
.stream().map(Encounter::getId).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
// 分页查询
|
||||
LambdaQueryWrapper<PaymentReconciliation> pageWrapper = buildBillQueryWrapper(
|
||||
billType, payStatus, startTime, endTime, searchPatientIds, searchEncounterIds);
|
||||
pageWrapper.orderByDesc(PaymentReconciliation::getBillDate);
|
||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<PaymentReconciliation> page =
|
||||
new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNo, pageSize);
|
||||
List<PaymentReconciliation> billList = paymentReconciliationService.page(page, pageWrapper).getRecords();
|
||||
|
||||
// 总数
|
||||
long total = paymentReconciliationService.count(buildBillQueryWrapper(
|
||||
billType, payStatus, startTime, endTime, searchPatientIds, searchEncounterIds));
|
||||
|
||||
// 转换为DTO
|
||||
List<BillListDto> records = convertToDtoList(billList);
|
||||
|
||||
// 汇总:查询全部匹配记录(不受分页限制)
|
||||
Map<String, Object> summary = computeBillSummary(billType, payStatus, startTime, endTime,
|
||||
searchPatientIds, searchEncounterIds, total);
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("records", records);
|
||||
result.put("total", total);
|
||||
result.put("summary", summary);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将账单实体列表转换为DTO列表
|
||||
*/
|
||||
private List<BillListDto> convertToDtoList(List<PaymentReconciliation> billList) {
|
||||
List<BillListDto> records = new ArrayList<>();
|
||||
if (billList.isEmpty()) {
|
||||
return records;
|
||||
}
|
||||
|
||||
List<Long> patientIds = billList.stream().map(PaymentReconciliation::getPatientId).distinct().collect(Collectors.toList());
|
||||
List<Long> encounterIds = billList.stream().map(PaymentReconciliation::getEncounterId).distinct().collect(Collectors.toList());
|
||||
List<Long> entererIds = billList.stream().map(PaymentReconciliation::getEntererId).distinct().collect(Collectors.toList());
|
||||
|
||||
Map<Long, Patient> patientMap = listToMap(iPatientService.listByIds(patientIds), Patient::getId);
|
||||
Map<Long, Encounter> encounterMap = listToMap(iEncounterService.listByIds(encounterIds), Encounter::getId);
|
||||
Map<Long, Practitioner> practitionerMap = listToMap(iPractitionerService.listByIds(entererIds), Practitioner::getId);
|
||||
|
||||
// 查询当前页账单的退费金额
|
||||
List<Long> paymentIds = billList.stream().map(PaymentReconciliation::getId).collect(Collectors.toList());
|
||||
Map<Long, BigDecimal> refundMap = new HashMap<>();
|
||||
if (!paymentIds.isEmpty()) {
|
||||
List<PaymentReconciliation> refunds = paymentReconciliationService.list(
|
||||
new LambdaQueryWrapper<PaymentReconciliation>()
|
||||
.in(PaymentReconciliation::getRelationId, paymentIds)
|
||||
.eq(PaymentReconciliation::getDeleteFlag, DelFlag.NO.getCode())
|
||||
.in(PaymentReconciliation::getStatusEnum,
|
||||
PaymentStatus.REFUND_ALL.getValue(), PaymentStatus.REFUND_PART.getValue()));
|
||||
for (PaymentReconciliation refund : refunds) {
|
||||
refundMap.merge(refund.getRelationId(), refund.getTenderedAmount(), BigDecimal::add);
|
||||
}
|
||||
}
|
||||
|
||||
for (PaymentReconciliation bill : billList) {
|
||||
BillListDto dto = new BillListDto();
|
||||
dto.setId(bill.getId());
|
||||
dto.setBillNo(bill.getPaymentNo());
|
||||
dto.setPatientId(bill.getPatientId());
|
||||
dto.setEncounterId(bill.getEncounterId());
|
||||
dto.setTotalAmount(bill.getTenderedAmount() != null ? bill.getTenderedAmount() : BigDecimal.ZERO);
|
||||
dto.setRefundAmount(refundMap.getOrDefault(bill.getId(), BigDecimal.ZERO));
|
||||
dto.setPayStatus(bill.getStatusEnum());
|
||||
dto.setOperatorId(bill.getEntererId());
|
||||
dto.setPayTime(bill.getBillDate());
|
||||
dto.setContractNo(bill.getContractNo());
|
||||
|
||||
Patient patient = patientMap.get(bill.getPatientId());
|
||||
if (patient != null) {
|
||||
dto.setPatientName(patient.getName());
|
||||
dto.setGenderEnum(patient.getGenderEnum());
|
||||
dto.setBirthDate(patient.getBirthDate());
|
||||
if (patient.getBirthDate() != null) {
|
||||
dto.setAge(AgeCalculatorUtil.calculateAge(patient.getBirthDate()));
|
||||
}
|
||||
}
|
||||
|
||||
Encounter encounter = encounterMap.get(bill.getEncounterId());
|
||||
if (encounter != null) {
|
||||
dto.setEncounterNo(encounter.getBusNo());
|
||||
}
|
||||
|
||||
Practitioner practitioner = practitionerMap.get(bill.getEntererId());
|
||||
if (practitioner != null) {
|
||||
dto.setOperatorName(practitioner.getName());
|
||||
}
|
||||
|
||||
if (bill.getStatusEnum() != null) {
|
||||
PaymentStatus ps = PaymentStatus.getByValue(bill.getStatusEnum());
|
||||
dto.setPayStatus_dictText(ps != null ? ps.getInfo() : "");
|
||||
}
|
||||
|
||||
records.add(dto);
|
||||
}
|
||||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将List转为Map,keyExtractor为key提取函数
|
||||
*/
|
||||
private <T> Map<Long, T> listToMap(List<T> list, java.util.function.Function<T, Long> keyExtractor) {
|
||||
Map<Long, T> map = new HashMap<>();
|
||||
for (T item : list) {
|
||||
map.put(keyExtractor.apply(item), item);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建查询条件
|
||||
* @param searchPatientIds 预解析的患者ID列表(null表示无searchKey)
|
||||
* @param searchEncounterIds 预解析的就诊ID列表(null表示无searchKey)
|
||||
*/
|
||||
private LambdaQueryWrapper<PaymentReconciliation> buildBillQueryWrapper(
|
||||
String billType, String payStatus, String startTime, String endTime,
|
||||
List<Long> searchPatientIds, List<Long> searchEncounterIds) {
|
||||
LambdaQueryWrapper<PaymentReconciliation> wrapper = new LambdaQueryWrapper<>();
|
||||
wrapper.eq(PaymentReconciliation::getDeleteFlag, DelFlag.NO.getCode())
|
||||
.eq(PaymentReconciliation::getKindEnum, PaymentKind.OUTPATIENT_CLINIC.getValue());
|
||||
|
||||
if (StringUtils.isNotEmpty(payStatus)) {
|
||||
int ps = Integer.parseInt(payStatus);
|
||||
if (ps == 0) {
|
||||
wrapper.eq(PaymentReconciliation::getStatusEnum, PaymentStatus.DRAFT.getValue());
|
||||
} else if (ps == 1) {
|
||||
wrapper.eq(PaymentReconciliation::getStatusEnum, PaymentStatus.SUCCESS.getValue());
|
||||
} else if (ps == 2) {
|
||||
wrapper.in(PaymentReconciliation::getStatusEnum,
|
||||
PaymentStatus.REFUND_ALL.getValue(), PaymentStatus.REFUND_PART.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(startTime)) {
|
||||
wrapper.ge(PaymentReconciliation::getBillDate, startTime);
|
||||
}
|
||||
if (StringUtils.isNotEmpty(endTime)) {
|
||||
wrapper.le(PaymentReconciliation::getBillDate, endTime);
|
||||
}
|
||||
|
||||
// searchKey 过滤:使用预解析的ID列表
|
||||
if (searchPatientIds != null && searchEncounterIds != null) {
|
||||
boolean hasPatients = !searchPatientIds.isEmpty();
|
||||
boolean hasEncounters = !searchEncounterIds.isEmpty();
|
||||
if (hasPatients || hasEncounters) {
|
||||
wrapper.and(w -> {
|
||||
if (hasPatients) {
|
||||
w.or().in(PaymentReconciliation::getPatientId, searchPatientIds);
|
||||
}
|
||||
if (hasEncounters) {
|
||||
w.or().in(PaymentReconciliation::getEncounterId, searchEncounterIds);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wrapper.eq(PaymentReconciliation::getId, -1L);
|
||||
}
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询全部匹配记录的汇总数据(不受分页限制)
|
||||
*/
|
||||
private Map<String, Object> computeBillSummary(String billType, String payStatus, String startTime, String endTime,
|
||||
List<Long> searchPatientIds, List<Long> searchEncounterIds,
|
||||
long totalCount) {
|
||||
Map<String, Object> summary = new HashMap<>();
|
||||
LambdaQueryWrapper<PaymentReconciliation> wrapper = buildBillQueryWrapper(
|
||||
billType, payStatus, startTime, endTime, searchPatientIds, searchEncounterIds);
|
||||
wrapper.select(PaymentReconciliation::getStatusEnum, PaymentReconciliation::getTenderedAmount);
|
||||
List<PaymentReconciliation> allBills = paymentReconciliationService.list(wrapper);
|
||||
|
||||
BigDecimal totalAmount = BigDecimal.ZERO;
|
||||
BigDecimal refundAmount = BigDecimal.ZERO;
|
||||
for (PaymentReconciliation bill : allBills) {
|
||||
BigDecimal amount = bill.getTenderedAmount() != null ? bill.getTenderedAmount() : BigDecimal.ZERO;
|
||||
Integer status = bill.getStatusEnum();
|
||||
if (PaymentStatus.SUCCESS.getValue().equals(status)) {
|
||||
totalAmount = totalAmount.add(amount);
|
||||
} else if (PaymentStatus.REFUND_ALL.getValue().equals(status)
|
||||
|| PaymentStatus.REFUND_PART.getValue().equals(status)) {
|
||||
refundAmount = refundAmount.add(amount);
|
||||
}
|
||||
}
|
||||
|
||||
summary.put("totalAmount", totalAmount);
|
||||
summary.put("refundAmount", refundAmount);
|
||||
summary.put("actualAmount", totalAmount.subtract(refundAmount));
|
||||
summary.put("totalCount", totalCount);
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,4 +72,11 @@ public class IChargeBillServiceImpl implements IChargeBillService {
|
||||
public R<?> checkYbNo() {
|
||||
return chargeBillStatisticsService.checkYbNo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getBillPage(String searchKey, String billType, String payStatus,
|
||||
String startTime, String endTime, Integer pageNo, Integer pageSize) {
|
||||
return chargeBillQueryService.getBillPage(searchKey, billType, payStatus,
|
||||
startTime, endTime, pageNo, pageSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,4 +115,27 @@ public class ChargeBillController {
|
||||
return iChargeBillService.checkYbNo();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询收费账单列表
|
||||
*/
|
||||
@GetMapping("/page")
|
||||
public R<?> page(@RequestParam(value = "searchKey", required = false) String searchKey,
|
||||
@RequestParam(value = "billType", required = false) String billType,
|
||||
@RequestParam(value = "payStatus", required = false) String payStatus,
|
||||
@RequestParam(value = "startTime", required = false) String startTime,
|
||||
@RequestParam(value = "endTime", required = false) String endTime,
|
||||
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
|
||||
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
|
||||
return R.ok(iChargeBillService.getBillPage(searchKey, billType, payStatus,
|
||||
startTime, endTime, pageNo, pageSize));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取收费详情(按ID)
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public R<?> getById(@PathVariable Long id) {
|
||||
return R.ok(iChargeBillService.getDetail(id));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.healthlink.his.web.paymentmanage.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 收费账单列表DTO
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class BillListDto {
|
||||
|
||||
/** 账单ID */
|
||||
private Long id;
|
||||
|
||||
/** 账单号 */
|
||||
private String billNo;
|
||||
|
||||
/** 患者ID */
|
||||
private Long patientId;
|
||||
|
||||
/** 患者姓名 */
|
||||
private String patientName;
|
||||
|
||||
/** 性别枚举 */
|
||||
private Integer genderEnum;
|
||||
|
||||
/** 性别文本 */
|
||||
private String genderEnum_enumText;
|
||||
|
||||
/** 年龄 */
|
||||
private Integer age;
|
||||
|
||||
/** 出生日期 */
|
||||
private Date birthDate;
|
||||
|
||||
/** 就诊ID */
|
||||
private Long encounterId;
|
||||
|
||||
/** 门诊号 */
|
||||
private String encounterNo;
|
||||
|
||||
/** 收费类型枚举 */
|
||||
private Integer billType;
|
||||
|
||||
/** 收费类型文本 */
|
||||
private String billType_dictText;
|
||||
|
||||
/** 收费金额 */
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
/** 退费金额 */
|
||||
private BigDecimal refundAmount;
|
||||
|
||||
/** 收费状态枚举 */
|
||||
private Integer payStatus;
|
||||
|
||||
/** 收费状态文本 */
|
||||
private String payStatus_dictText;
|
||||
|
||||
/** 支付方式文本 */
|
||||
private String payMethod_dictText;
|
||||
|
||||
/** 收费员ID */
|
||||
private Long operatorId;
|
||||
|
||||
/** 收费员姓名 */
|
||||
private String operatorName;
|
||||
|
||||
/** 收费时间 */
|
||||
private Date payTime;
|
||||
|
||||
/** 合同编号 */
|
||||
private String contractNo;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
-- Bug #818: TPR变更体温单下拉框无数据 — 补充缺失的字典类型和字典数据
|
||||
-- 涉及的字典: temperature_select_type, breathe_unit, measurement_select_type,
|
||||
-- urination_frequency_unit, stoolfrequency_unit
|
||||
|
||||
-- ============================================================
|
||||
-- 1. 插入字典类型 (sys_dict_type)
|
||||
-- ============================================================
|
||||
INSERT INTO sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time, remark)
|
||||
VALUES
|
||||
(543, '体温测量类型', 'temperature_select_type', '0', 'admin', NOW(), 'TPR体温单-体温下拉选项'),
|
||||
(544, '呼吸类型', 'breathe_unit', '0', 'admin', NOW(), 'TPR体温单-呼吸下拉选项'),
|
||||
(545, '测量特殊状态', 'measurement_select_type', '0', 'admin', NOW(), 'TPR体温单-体重/腹围/身高特殊状态'),
|
||||
(546, '小便次数符号', 'urination_frequency_unit', '0', 'admin', NOW(), 'TPR体温单-小便次数特殊符号'),
|
||||
(547, '大便次数符号', 'stoolfrequency_unit', '0', 'admin', NOW(), 'TPR体温单-大便次数特殊符号')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 插入字典数据 (sys_dict_data)
|
||||
-- ============================================================
|
||||
|
||||
-- temperature_select_type: 腋温/口温/额温/耳温/肛温 + 拒测/外出/请假
|
||||
-- Codes 1-5 = measurement types (do NOT replace temperature value)
|
||||
-- Codes 6-8 = special statuses (replace temperature value with text)
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4142, 1, '腋温', '1', 'temperature_select_type', '', 'default', 'Y', '0', 'admin', NOW()),
|
||||
(4143, 2, '口温', '2', 'temperature_select_type', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4144, 3, '额温', '3', 'temperature_select_type', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4145, 4, '耳温', '4', 'temperature_select_type', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4146, 5, '肛温', '5', 'temperature_select_type', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4147, 6, '拒测', '6', 'temperature_select_type', '', 'danger', 'N', '0', 'admin', NOW()),
|
||||
(4148, 7, '外出', '7', 'temperature_select_type', '', 'warning', 'N', '0', 'admin', NOW()),
|
||||
(4149, 8, '请假', '8', 'temperature_select_type', '', 'info', 'N', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- breathe_unit: 平稳/急促/浅慢/叹息样呼吸/潮式呼吸/抑制呼吸/@
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4150, 1, '平稳', '1', 'breathe_unit', '', 'success', 'Y', '0', 'admin', NOW()),
|
||||
(4151, 2, '急促', '2', 'breathe_unit', '', 'danger', 'N', '0', 'admin', NOW()),
|
||||
(4152, 3, '浅慢', '3', 'breathe_unit', '', 'warning', 'N', '0', 'admin', NOW()),
|
||||
(4153, 4, '叹息样呼吸', '4', 'breathe_unit', '', 'info', 'N', '0', 'admin', NOW()),
|
||||
(4154, 5, '潮式呼吸', '5', 'breathe_unit', '', 'info', 'N', '0', 'admin', NOW()),
|
||||
(4155, 6, '抑制呼吸', '6', 'breathe_unit', '', 'danger', 'N', '0', 'admin', NOW()),
|
||||
(4156, 7, '@', '7', 'breathe_unit', '', 'default', 'N', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- measurement_select_type: 卧床/未测
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4157, 1, '卧床', '1', 'measurement_select_type', '', 'warning', 'N', '0', 'admin', NOW()),
|
||||
(4158, 2, '未测', '2', 'measurement_select_type', '', 'info', 'Y', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- urination_frequency_unit: ※/C
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4159, 1, '※', '1', 'urination_frequency_unit', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4160, 2, 'C', '2', 'urination_frequency_unit', '', 'default', 'N', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- stoolfrequency_unit: ※/☆/人工肛门
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4161, 1, '※', '1', 'stoolfrequency_unit', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4162, 2, '☆', '2', 'stoolfrequency_unit', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4163, 3, '人工肛门', '3', 'stoolfrequency_unit', '', 'default', 'N', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
@@ -0,0 +1,76 @@
|
||||
-- Bug #818: TPR变更体温单下拉框无数据 — 完整修复
|
||||
-- 原因: V20260626_2 使用的 dict_code 4142-4163 已被其他字典占用(rate_code/inpatient_diag_category/separate_decocting),
|
||||
-- dict_id 543-546 也被占用,导致 ON CONFLICT DO NOTHING 跳过所有插入。
|
||||
-- 本迁移使用全新未占用的 dict_id(548-552) 和 dict_code(4237-4258)。
|
||||
-- 同时恢复被 V20260626_2 误覆盖的两行原始数据(dict_code 4142→rate_code, 4153→inpatient_diag_category)。
|
||||
|
||||
-- ============================================================
|
||||
-- 1. 恢复被误覆盖的两行原始 dict_type
|
||||
-- ============================================================
|
||||
UPDATE sys_dict_data SET dict_type = 'rate_code' WHERE dict_code = 4142;
|
||||
UPDATE sys_dict_data SET dict_type = 'inpatient_diag_category' WHERE dict_code = 4153;
|
||||
|
||||
-- ============================================================
|
||||
-- 2. 插入字典类型 (sys_dict_type) — dict_id 548-552
|
||||
-- ============================================================
|
||||
INSERT INTO sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time, remark)
|
||||
VALUES
|
||||
(548, '体温测量类型', 'temperature_select_type', '0', 'admin', NOW(), 'TPR体温单-体温下拉选项'),
|
||||
(549, '呼吸类型', 'breathe_unit', '0', 'admin', NOW(), 'TPR体温单-呼吸下拉选项'),
|
||||
(550, '测量特殊状态', 'measurement_select_type', '0', 'admin', NOW(), 'TPR体温单-体重/腹围/身高特殊状态'),
|
||||
(551, '小便次数符号', 'urination_frequency_unit', '0', 'admin', NOW(), 'TPR体温单-小便次数特殊符号'),
|
||||
(552, '大便次数符号', 'stoolfrequency_unit', '0', 'admin', NOW(), 'TPR体温单-大便次数特殊符号')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- ============================================================
|
||||
-- 3. 插入字典数据 (sys_dict_data) — dict_code 4237-4258
|
||||
-- ============================================================
|
||||
|
||||
-- temperature_select_type: 腋温/口温/额温/耳温/肛温 + 拒测/外出/请假
|
||||
-- Codes 1-5 = measurement types (do NOT replace temperature value)
|
||||
-- Codes 6-8 = special statuses (replace temperature value with text)
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4237, 1, '腋温', '1', 'temperature_select_type', '', 'default', 'Y', '0', 'admin', NOW()),
|
||||
(4238, 2, '口温', '2', 'temperature_select_type', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4239, 3, '额温', '3', 'temperature_select_type', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4240, 4, '耳温', '4', 'temperature_select_type', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4241, 5, '肛温', '5', 'temperature_select_type', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4242, 6, '拒测', '6', 'temperature_select_type', '', 'danger', 'N', '0', 'admin', NOW()),
|
||||
(4243, 7, '外出', '7', 'temperature_select_type', '', 'warning', 'N', '0', 'admin', NOW()),
|
||||
(4244, 8, '请假', '8', 'temperature_select_type', '', 'info', 'N', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- breathe_unit: 平稳/急促/浅慢/叹息样呼吸/潮式呼吸/抑制呼吸/@
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4245, 1, '平稳', '1', 'breathe_unit', '', 'success', 'Y', '0', 'admin', NOW()),
|
||||
(4246, 2, '急促', '2', 'breathe_unit', '', 'danger', 'N', '0', 'admin', NOW()),
|
||||
(4247, 3, '浅慢', '3', 'breathe_unit', '', 'warning', 'N', '0', 'admin', NOW()),
|
||||
(4248, 4, '叹息样呼吸', '4', 'breathe_unit', '', 'info', 'N', '0', 'admin', NOW()),
|
||||
(4249, 5, '潮式呼吸', '5', 'breathe_unit', '', 'info', 'N', '0', 'admin', NOW()),
|
||||
(4250, 6, '抑制呼吸', '6', 'breathe_unit', '', 'danger', 'N', '0', 'admin', NOW()),
|
||||
(4251, 7, '@', '7', 'breathe_unit', '', 'default', 'N', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- measurement_select_type: 卧床/未测
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4252, 1, '卧床', '1', 'measurement_select_type', '', 'warning', 'N', '0', 'admin', NOW()),
|
||||
(4253, 2, '未测', '2', 'measurement_select_type', '', 'info', 'Y', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- urination_frequency_unit: ※/C
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4254, 1, '※', '1', 'urination_frequency_unit', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4255, 2, 'C', '2', 'urination_frequency_unit', '', 'default', 'N', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- stoolfrequency_unit: ※/☆/人工肛门
|
||||
INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time)
|
||||
VALUES
|
||||
(4256, 1, '※', '1', 'stoolfrequency_unit', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4257, 2, '☆', '2', 'stoolfrequency_unit', '', 'default', 'N', '0', 'admin', NOW()),
|
||||
(4258, 3, '人工肛门', '3', 'stoolfrequency_unit', '', 'default', 'N', '0', 'admin', NOW())
|
||||
ON CONFLICT DO NOTHING;
|
||||
@@ -0,0 +1,12 @@
|
||||
-- Bug #806: lab_apply 表增加 encounter_id 列,用于按就诊流水隔离检验申请单
|
||||
ALTER TABLE lab_apply ADD COLUMN IF NOT EXISTS encounter_id bigint;
|
||||
|
||||
-- 对已有数据:尝试通过 visit_no 关联 adm_encounter.bus_no 回填 encounter_id
|
||||
UPDATE lab_apply la
|
||||
SET encounter_id = ae.id
|
||||
FROM adm_encounter ae
|
||||
WHERE la.visit_no IS NOT NULL
|
||||
AND la.visit_no <> ''
|
||||
AND la.visit_no = ae.bus_no
|
||||
AND la.delete_flag = '0'
|
||||
AND ae.delete_flag = '0';
|
||||
@@ -173,13 +173,20 @@
|
||||
AND T9sr.delete_flag = '0'
|
||||
LEFT JOIN wor_service_request AS wsrp ON wsrp.id = wsr.parent_id AND wsrp.delete_flag = '0'
|
||||
WHERE T1.encounter_id = #{encounterId}
|
||||
AND T1.status_enum IN (0
|
||||
, #{planned}
|
||||
, #{billable}
|
||||
, #{billed}
|
||||
, #{refunding}
|
||||
, #{refunded}
|
||||
, #{partRefund})
|
||||
<choose>
|
||||
<when test="filterStatus != null">
|
||||
AND T1.status_enum = #{filterStatus}
|
||||
</when>
|
||||
<otherwise>
|
||||
AND T1.status_enum IN (0
|
||||
, #{planned}
|
||||
, #{billable}
|
||||
, #{billed}
|
||||
, #{refunding}
|
||||
, #{refunded}
|
||||
, #{partRefund})
|
||||
</otherwise>
|
||||
</choose>
|
||||
AND T1.context_enum != #{register}
|
||||
AND (
|
||||
-- 若能关联到请求表,则必须是“已签发”后才允许收费端展示
|
||||
|
||||
@@ -23,9 +23,8 @@
|
||||
t1.apply_status AS applyStatus,
|
||||
t1.apply_remark AS applyRemark
|
||||
FROM lab_apply AS t1
|
||||
INNER JOIN adm_encounter AS t3 ON t1.patient_id::bigint = t3.patient_id
|
||||
WHERE t1.delete_flag = '0'
|
||||
AND t3.id = #{encounterId}
|
||||
AND t1.encounter_id = #{encounterId}
|
||||
ORDER BY t1.apply_time DESC
|
||||
</select>
|
||||
|
||||
|
||||
@@ -187,6 +187,6 @@
|
||||
<if test="orgId != null">
|
||||
AND organization_id = #{orgId}
|
||||
</if>
|
||||
AND tenant_id = 1 <!-- 多租户ID(若为动态,可改为参数传入) -->
|
||||
<!-- 租户过滤由 MyBatis Plus TenantLineInnerInterceptor 自动注入 -->
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -323,7 +323,7 @@
|
||||
T1.performer_check_id,
|
||||
T1.reason_text AS reason_text,
|
||||
T1.check_time AS check_time,
|
||||
T2."name" AS advice_name,
|
||||
COALESCE(T2."name", T1.content_json::jsonb->>'adviceName') AS advice_name,
|
||||
T2.id AS item_id,
|
||||
NULL::varchar AS volume,
|
||||
NULL::varchar AS lot_number,
|
||||
|
||||
@@ -11,10 +11,7 @@
|
||||
SELECT
|
||||
a.total_price,
|
||||
COALESCE(b1.org_id, b2.org_id, b3.org_id, b4.offered_org_id, b5.org_id) AS org_id,
|
||||
--COALESCE(b1.yb_class_enum, b2.yb_class_enum, b3.yb_class_enum) AS yb_class_enum,
|
||||
b5.yb_type
|
||||
|
||||
-- 添加更多需要的字段
|
||||
FROM
|
||||
adm_charge_item a
|
||||
LEFT JOIN
|
||||
@@ -42,4 +39,5 @@
|
||||
</foreach>
|
||||
</if>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -124,6 +124,11 @@ public class InspectionLabApply extends HisBaseEntity {
|
||||
* 备注
|
||||
*/
|
||||
private String applyRemark;
|
||||
/**
|
||||
* 就诊ID(本次就诊流水,用于数据隔离)
|
||||
*/
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long encounterId;
|
||||
/**
|
||||
* 操作员工号
|
||||
*/
|
||||
|
||||
@@ -14,9 +14,13 @@ export function getList(queryParams) {
|
||||
/**
|
||||
* 患者处方列表
|
||||
*/
|
||||
export function getChargeList(encounterId, config = {}) {
|
||||
export function getChargeList(encounterId, statusEnum, config = {}) {
|
||||
let url = '/charge-manage/charge/patient-prescription?encounterId=' + encounterId
|
||||
if (statusEnum !== undefined && statusEnum !== null) {
|
||||
url += '&statusEnum=' + statusEnum
|
||||
}
|
||||
return request({
|
||||
url: '/charge-manage/charge/patient-prescription?encounterId=' + encounterId,
|
||||
url: url,
|
||||
method: 'get',
|
||||
...config
|
||||
})
|
||||
|
||||
@@ -468,9 +468,11 @@ function handleSelectionChange(selection) {
|
||||
}
|
||||
function handleTotalAmount() {
|
||||
if (selectedRows.value.length == 0) {
|
||||
totalAmounts.value = chargeList.value.reduce((accumulator, currentRow) => {
|
||||
return new Decimal(accumulator).add(currentRow.totalPrice.toFixed(2) || 0);
|
||||
}, new Decimal(0));
|
||||
totalAmounts.value = chargeList.value
|
||||
.filter((row) => row.statusEnum === 1)
|
||||
.reduce((accumulator, currentRow) => {
|
||||
return new Decimal(accumulator).add(currentRow.totalPrice.toFixed(2) || 0);
|
||||
}, new Decimal(0));
|
||||
} else {
|
||||
totalAmounts.value = selectedRows.value.reduce((accumulator, currentRow) => {
|
||||
return new Decimal(accumulator).add(currentRow.totalPrice.toFixed(2) || 0);
|
||||
@@ -532,7 +534,7 @@ function clickRow(params) {
|
||||
patientInfo.value = { ...row, encounterId: encId };
|
||||
chargeLoading.value = true;
|
||||
encounterId.value = encId;
|
||||
getChargeList(encId).then((res) => {
|
||||
getChargeList(encId, queryParams.value.statusEnum).then((res) => {
|
||||
chargeList.value = res.data;
|
||||
setTimeout(() => {
|
||||
chargeLoading.value = false;
|
||||
@@ -546,7 +548,7 @@ function handleClose(value, msg) {
|
||||
if (value == 'success') {
|
||||
proxy.$modal.msgSuccess(msg);
|
||||
chargeLoading.value = true;
|
||||
getChargeList(patientInfo.value.encounterId, { skipErrorMsg: true }).then((res) => {
|
||||
getChargeList(patientInfo.value.encounterId, queryParams.value.statusEnum, { skipErrorMsg: true }).then((res) => {
|
||||
chargeList.value = res.data;
|
||||
setTimeout(() => {
|
||||
chargeLoading.value = false;
|
||||
|
||||
@@ -2003,16 +2003,16 @@ const formatAmount = (amount) => {
|
||||
|
||||
// 单据状态标签文字
|
||||
const getStatusLabel = (applyStatus, row) => {
|
||||
// applyStatus: 0=待开立, 1=已开立(已签发)
|
||||
// applyStatus: 0=待签发, 1=已签发
|
||||
// 结合收费/执行标记推导更丰富的状态
|
||||
if (applyStatus === 1) {
|
||||
// 已收费后根据执行标记判断
|
||||
if (row.needExecute === true) {
|
||||
return '已执行'
|
||||
}
|
||||
return '已开立'
|
||||
return '已签发'
|
||||
}
|
||||
return '待开立'
|
||||
return '待签发'
|
||||
}
|
||||
|
||||
// 单据状态标签颜色
|
||||
|
||||
@@ -485,10 +485,8 @@ const handleEditSubmit = () => {
|
||||
const openAct = () => {
|
||||
console.log(props.patientInfo, 'patientRegister.vue');
|
||||
console.log(props.inHospitalInfo, 'inHospitalInfo.vue');
|
||||
/* 初始化数据 */
|
||||
advance.value = props.inHospitalInfo.balanceAmount || 0;
|
||||
advancePaymentVisible.value = false;
|
||||
RegisterFormRef.value.init();
|
||||
};
|
||||
const closedAct = () => {
|
||||
dialogVisible.value = false;
|
||||
|
||||
@@ -312,11 +312,12 @@ const props = defineProps({
|
||||
});
|
||||
|
||||
const organization = ref([]);
|
||||
const fullOrgTree = ref([]); // 未过滤的完整组织树(保留 children 层级)
|
||||
const wardListOptions = ref([]);
|
||||
const practitionerWardList = ref([]); // 当前用户有权限的病区(与护士站同源)
|
||||
const contractList = ref([]);
|
||||
const verificationStatusOptions = ref([]);
|
||||
const diagnosisDefinitionList = ref([]);
|
||||
const wardLoading = ref(false);
|
||||
const rules = reactive({
|
||||
inHospitalOrgId: [
|
||||
{
|
||||
@@ -451,17 +452,6 @@ watch(
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
watch(
|
||||
() => props.isRegistered,
|
||||
(newVal) => {
|
||||
if (newVal) {
|
||||
// 已登记状态可以做一些数据锁定操作
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
await getInitOptions();
|
||||
setValue();
|
||||
@@ -501,15 +491,21 @@ function handleWardClick(item) {
|
||||
function getInitOptions() {
|
||||
// 获取所有科室
|
||||
const orgPromise = getOrgList();
|
||||
// 获取所有病区
|
||||
// 获取当前用户有权限的病区(与护士站入出管理同款数据源)
|
||||
const wardPromise = getPractitionerWard();
|
||||
|
||||
const initPromise = Promise.all([orgPromise, wardPromise]).then(([orgRes, wardRes]) => {
|
||||
// 保存完整组织树(含 children 层级),用于 findOrgNode 递归查找
|
||||
fullOrgTree.value = orgRes.data.records || [];
|
||||
|
||||
// 入院科室:展示所有 typeEnum=2(科室) + classEnum含"2"(住院) 的科室
|
||||
organization.value = orgRes.data.records.filter(
|
||||
(record) => record.typeEnum === 2 && checkClassEnumValue(record.classEnum, 2)
|
||||
);
|
||||
|
||||
// 保存当前用户有权限的病区列表(与护士站使用相同数据源)
|
||||
practitionerWardList.value = wardRes.data || [];
|
||||
|
||||
// Bug #178 Fix: 如果已选科室不在列表中,手动添加以确保正确显示
|
||||
const selectedOrgId = props.inHospitalInfo?.inHospitalOrgId;
|
||||
const selectedOrgName = props.inHospitalInfo?.inHospitalOrgName;
|
||||
@@ -545,39 +541,43 @@ function getDiagnosisInfo(value) {
|
||||
}
|
||||
|
||||
function handleNodeClick(orgInfo) {
|
||||
const savedWardId = props.inHospitalInfo?.wardLocationId; // 保存原始病区ID,用于编辑模式恢复
|
||||
submitForm.wardLocationId = undefined; // 切换科室时,先清空原有病区
|
||||
const savedWardId = props.inHospitalInfo?.wardLocationId;
|
||||
submitForm.wardLocationId = undefined;
|
||||
submitForm.totalBedsNum = undefined;
|
||||
submitForm.idleBedsNum = undefined;
|
||||
wardListOptions.value = []; // 先清空列表,避免旧数据残留
|
||||
wardLoading.value = true;
|
||||
wardList({ orgId: orgInfo.id })
|
||||
.then((res) => {
|
||||
wardListOptions.value = res.data || [];
|
||||
if (wardListOptions.value.length > 0) {
|
||||
// 编辑模式:尝试恢复之前保存的病区
|
||||
if (savedWardId) {
|
||||
const savedWard = wardListOptions.value.find((item) => String(item.id) === String(savedWardId));
|
||||
if (savedWard) {
|
||||
submitForm.wardLocationId = savedWardId;
|
||||
handleWardClick(savedWard);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 新增模式 或 原病区不在新科室下:自动选中第一个病区
|
||||
if (!submitForm.wardLocationId) {
|
||||
submitForm.wardLocationId = wardListOptions.value[0].id;
|
||||
handleWardClick(wardListOptions.value[0]);
|
||||
}
|
||||
wardListOptions.value = [];
|
||||
|
||||
if (orgInfo.id) {
|
||||
// 后端查询:自动包含子孙科室的病区(通过 busNo 层级匹配)
|
||||
wardList({ orgId: orgInfo.id })
|
||||
.then((res) => {
|
||||
wardListOptions.value = res.data || [];
|
||||
selectSavedOrFirstWard(savedWardId);
|
||||
})
|
||||
.catch(() => {
|
||||
wardListOptions.value = [];
|
||||
});
|
||||
} else {
|
||||
wardListOptions.value = practitionerWardList.value || [];
|
||||
selectSavedOrFirstWard(savedWardId);
|
||||
}
|
||||
}
|
||||
|
||||
function selectSavedOrFirstWard(savedWardId) {
|
||||
if (wardListOptions.value.length > 0) {
|
||||
if (savedWardId) {
|
||||
const savedWard = wardListOptions.value.find((item) => String(item.id) === String(savedWardId));
|
||||
if (savedWard) {
|
||||
submitForm.wardLocationId = savedWardId;
|
||||
handleWardClick(savedWard);
|
||||
return;
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('加载病区失败:', err);
|
||||
wardListOptions.value = [];
|
||||
})
|
||||
.finally(() => {
|
||||
wardLoading.value = false;
|
||||
});
|
||||
}
|
||||
if (!submitForm.wardLocationId) {
|
||||
submitForm.wardLocationId = wardListOptions.value[0].id;
|
||||
handleWardClick(wardListOptions.value[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleChange(value) {
|
||||
@@ -586,7 +586,6 @@ function handleChange(value) {
|
||||
submitForm.wardLocationId = undefined;
|
||||
submitForm.totalBedsNum = undefined;
|
||||
submitForm.idleBedsNum = undefined;
|
||||
wardLoading.value = false; // 同步停止加载
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,14 +648,6 @@ const validateData = async (callback) => {
|
||||
});
|
||||
};
|
||||
|
||||
const init = () => {
|
||||
if (!props.isRegistered) {
|
||||
// 只有待登记状态才重置
|
||||
submitForm.inDocterWorkGroupCode = '';
|
||||
submitForm.wardLocationId = '';
|
||||
}
|
||||
};
|
||||
|
||||
// 检查classEnum值是否包含指定值(支持多选)
|
||||
function checkClassEnumValue(classEnum, targetValue) {
|
||||
if (!classEnum) return false;
|
||||
@@ -671,7 +662,7 @@ function checkClassEnumValue(classEnum, targetValue) {
|
||||
return classEnum == targetValue;
|
||||
}
|
||||
|
||||
defineExpose({ validateData, submitForm, init, medicalInsuranceTitle });
|
||||
defineExpose({ validateData, submitForm, medicalInsuranceTitle });
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.registerForm-container {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
:model-value="visible"
|
||||
:title="t('module.diagnosis.title.tcmDiagnosis')"
|
||||
title="中医诊断"
|
||||
:width="width"
|
||||
:z-index="20"
|
||||
teleported
|
||||
@@ -17,12 +17,12 @@
|
||||
label-width="100px"
|
||||
>
|
||||
<el-form-item
|
||||
:label="t('module.diagnosis.title.tcmDiagnosis')"
|
||||
label="中医诊断"
|
||||
prop="conditionCode"
|
||||
>
|
||||
<el-select
|
||||
v-model="formData.conditionCode"
|
||||
:placeholder="t('module.diagnosis.placeholder.selectTcmDiagnosis')"
|
||||
placeholder="请选择中医诊断"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 100%"
|
||||
@@ -37,21 +37,23 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="t('module.diagnosis.label.tcmSyndrome')"
|
||||
label="中医证候"
|
||||
prop="syndromeCode"
|
||||
>
|
||||
<el-cascader
|
||||
ref="cascaderRef"
|
||||
<el-select
|
||||
v-model="formData.syndromeCode"
|
||||
:options="getGroupedSyndromeOptions(syndromeOptions)"
|
||||
:props="{ emitPath: false, checkStrictly: true }"
|
||||
:show-all-levels="false"
|
||||
:placeholder="t('module.diagnosis.placeholder.selectTcmSyndrome')"
|
||||
placeholder="请选择中医证候"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 100%"
|
||||
@change="handleSyndromeCodeChange"
|
||||
/>
|
||||
>
|
||||
<el-option
|
||||
v-for="item in syndromeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@@ -76,14 +78,11 @@
|
||||
import {onMounted, reactive, ref} from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { getTcmCondition, getTcmSyndrome, saveTcmDiagnosis } from '../api'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const { proxy } = getCurrentInstance()
|
||||
const { t } = useI18n()
|
||||
|
||||
const conditionOptions = ref([])
|
||||
const syndromeOptions = ref([])
|
||||
const cascaderRef = ref(null)
|
||||
|
||||
const formData = ref({
|
||||
conditionCode: '',
|
||||
@@ -160,14 +159,14 @@ const handleSubmit = async () => {
|
||||
}]
|
||||
saveTcmDiagnosis(submitData).then((res) => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success(t('inpatientDoctor.diagnosis.tcmSaveSuccess'))
|
||||
ElMessage.success('中医诊断保存成功')
|
||||
emit('ok-act')
|
||||
cancelAct()
|
||||
} else {
|
||||
ElMessage.error(res.msg || t('inpatientDoctor.diagnosis.saveFailed'))
|
||||
ElMessage.error(res.msg || '保存失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
ElMessage.error(t('inpatientDoctor.diagnosis.saveFailedRetry'))
|
||||
ElMessage.error('保存失败,请重试')
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -178,154 +177,6 @@ const openAct = () => {
|
||||
loadConditionOptions()
|
||||
loadSyndromeOptions()
|
||||
}
|
||||
function getGroupedSyndromeOptions(options) {
|
||||
if (!options || !options.length) return []
|
||||
|
||||
const seen = new Set()
|
||||
const uniqueOptions = []
|
||||
options.forEach(item => {
|
||||
if (!seen.has(item.label)) {
|
||||
seen.add(item.label)
|
||||
uniqueOptions.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
const nameToItems = {}
|
||||
uniqueOptions.forEach(item => {
|
||||
const name = item.label
|
||||
if (!nameToItems[name]) {
|
||||
nameToItems[name] = []
|
||||
}
|
||||
nameToItems[name].push(item)
|
||||
})
|
||||
|
||||
// Level 3 Children of 阴证 (寒证, 虚证)
|
||||
const childrenOfYin = []
|
||||
;['寒证', '虚证'].forEach(name => {
|
||||
if (nameToItems[name]) {
|
||||
childrenOfYin.push(...nameToItems[name])
|
||||
}
|
||||
})
|
||||
|
||||
// Level 3 Children of 阳证 (热证, 实证)
|
||||
const childrenOfYang = []
|
||||
;['热证', '实证'].forEach(name => {
|
||||
if (nameToItems[name]) {
|
||||
childrenOfYang.push(...nameToItems[name])
|
||||
}
|
||||
})
|
||||
|
||||
// Level 2 under 八纲总纲 (阴证, 阳证)
|
||||
const level2OfBagang = []
|
||||
|
||||
if (nameToItems['阴证']) {
|
||||
nameToItems['阴证'].forEach(item => {
|
||||
level2OfBagang.push({
|
||||
value: item.value,
|
||||
label: item.label,
|
||||
id: item.id,
|
||||
children: childrenOfYin.length ? childrenOfYin : undefined
|
||||
})
|
||||
})
|
||||
} else if (childrenOfYin.length > 0) {
|
||||
level2OfBagang.push({
|
||||
value: 'virtual-yin',
|
||||
label: '阴证',
|
||||
children: childrenOfYin
|
||||
})
|
||||
}
|
||||
|
||||
if (nameToItems['阳证']) {
|
||||
nameToItems['阳证'].forEach(item => {
|
||||
level2OfBagang.push({
|
||||
value: item.value,
|
||||
label: item.label,
|
||||
id: item.id,
|
||||
children: childrenOfYang.length ? childrenOfYang : undefined
|
||||
})
|
||||
})
|
||||
} else if (childrenOfYang.length > 0) {
|
||||
level2OfBagang.push({
|
||||
value: 'virtual-yang',
|
||||
label: '阳证',
|
||||
children: childrenOfYang
|
||||
})
|
||||
}
|
||||
|
||||
// Level 2 under 危重急症 (闭证, 脱证)
|
||||
const level2OfWeizhong = []
|
||||
;['闭证', '脱证'].forEach(name => {
|
||||
if (nameToItems[name]) {
|
||||
level2OfWeizhong.push(...nameToItems[name])
|
||||
}
|
||||
})
|
||||
|
||||
// Level 2 under 其他证候 (all other syndromes)
|
||||
const level2OfOther = []
|
||||
const specialNames = new Set(['阴证', '阳证', '寒证', '热证', '虚证', '实证', '闭证', '脱证'])
|
||||
options.forEach(item => {
|
||||
if (!specialNames.has(item.label)) {
|
||||
level2OfOther.push(item)
|
||||
}
|
||||
})
|
||||
|
||||
const finalTree = []
|
||||
|
||||
if (level2OfBagang.length > 0) {
|
||||
finalTree.push({
|
||||
value: 'root-bagang',
|
||||
label: '八纲总纲',
|
||||
children: level2OfBagang
|
||||
})
|
||||
}
|
||||
|
||||
if (level2OfWeizhong.length > 0) {
|
||||
finalTree.push({
|
||||
value: 'root-weizhong',
|
||||
label: '危重急症',
|
||||
children: level2OfWeizhong
|
||||
})
|
||||
}
|
||||
|
||||
if (level2OfOther.length > 0) {
|
||||
finalTree.push({
|
||||
value: 'root-other',
|
||||
label: '其他证候',
|
||||
children: level2OfOther
|
||||
})
|
||||
}
|
||||
|
||||
return finalTree
|
||||
}
|
||||
|
||||
function handleSyndromeCodeChange(val) {
|
||||
console.log('handleSyndromeCodeChange called with:', val)
|
||||
if (val === 'root-bagang' || val === 'root-weizhong' || val === 'root-other' || (typeof val === 'string' && val.startsWith('virtual-'))) {
|
||||
formData.value.syndromeCode = ''
|
||||
} else if (val) {
|
||||
if (cascaderRef.value) {
|
||||
console.log('Cascader Ref component instance:', cascaderRef.value)
|
||||
if (typeof cascaderRef.value.togglePopperVisible === 'function') {
|
||||
cascaderRef.value.togglePopperVisible(false)
|
||||
}
|
||||
if (typeof cascaderRef.value.toggleDropDownVisible === 'function') {
|
||||
cascaderRef.value.toggleDropDownVisible(false)
|
||||
}
|
||||
cascaderRef.value.popperVisible = false
|
||||
if (typeof cascaderRef.value.blur === 'function') {
|
||||
cascaderRef.value.blur()
|
||||
}
|
||||
}
|
||||
if (document.activeElement && typeof document.activeElement.blur === 'function') {
|
||||
console.log('Blurring active element:', document.activeElement)
|
||||
document.activeElement.blur()
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.body.click()
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
|
||||
const closedAct = () => {
|
||||
emit('update:visible', false)
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
>
|
||||
<el-input
|
||||
v-model="diagnosis"
|
||||
:placeholder="t('module.diagnosis.placeholder.diagnosisName')"
|
||||
placeholder="诊断名称"
|
||||
clearable
|
||||
style="width: 100%; margin-bottom: 10px"
|
||||
@keyup.enter="queryDiagnosisUse"
|
||||
@@ -53,7 +53,7 @@
|
||||
"
|
||||
width="200"
|
||||
:hide-after="10"
|
||||
:title="t('module.diagnosis.title.confirmDeleteDiagnosis')"
|
||||
title="确认删除此常用诊断吗"
|
||||
placement="top-start"
|
||||
@confirm="deleteChild(data)"
|
||||
>
|
||||
@@ -123,7 +123,7 @@
|
||||
height="650"
|
||||
>
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.seqNo')"
|
||||
title="序号"
|
||||
width="50"
|
||||
>
|
||||
<template #default="scope">
|
||||
@@ -131,7 +131,7 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.diagnosisSort')"
|
||||
title="诊断排序"
|
||||
align="center"
|
||||
field="diagSrtNo"
|
||||
width="120"
|
||||
@@ -151,7 +151,7 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.diagnosisSystem')"
|
||||
title="诊断体系"
|
||||
align="center"
|
||||
field="diagnosisSystem"
|
||||
width="120"
|
||||
@@ -167,11 +167,11 @@
|
||||
@change="handleDiagnosisSystemChange(scope.row)"
|
||||
>
|
||||
<el-option
|
||||
:label="t('inpatientDoctor.diagnosis.western')"
|
||||
label="西医"
|
||||
value="西医"
|
||||
/>
|
||||
<el-option
|
||||
:label="t('inpatientDoctor.diagnosis.chinese')"
|
||||
label="中医"
|
||||
value="中医"
|
||||
/>
|
||||
</el-select>
|
||||
@@ -179,7 +179,7 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.diagnosisCategory')"
|
||||
title="诊断类别"
|
||||
align="center"
|
||||
field="medTypeCode"
|
||||
width="160"
|
||||
@@ -205,7 +205,7 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.diagnosisName')"
|
||||
title="诊断名称"
|
||||
align="center"
|
||||
field="name"
|
||||
min-width="180"
|
||||
@@ -231,7 +231,7 @@
|
||||
<template #reference>
|
||||
<el-input
|
||||
v-model="scope.row.name"
|
||||
:placeholder="t('module.diagnosis.placeholder.selectDiagnosis')"
|
||||
placeholder="请选择诊断"
|
||||
@input="handleChange"
|
||||
@focus="handleFocus(scope.row, scope.rowIndex)"
|
||||
@blur="handleBlur(scope.row)"
|
||||
@@ -243,7 +243,7 @@
|
||||
</vxe-column>
|
||||
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.diagnosisDoctor')"
|
||||
title="诊断医生"
|
||||
align="center"
|
||||
field="diagnosisDoctor"
|
||||
width="120"
|
||||
@@ -268,19 +268,22 @@
|
||||
:prop="`diagnosisList.${scope.rowIndex}.tcmSyndromeCode`"
|
||||
:rules="scope.row.diagnosisSystem === '中医' ? [{ required: true, message: '请选择中医证候', trigger: 'change' }] : []"
|
||||
>
|
||||
<el-cascader
|
||||
:ref="el => setCascaderRef(el, scope.rowIndex)"
|
||||
<el-select
|
||||
v-model="scope.row.tcmSyndromeCode"
|
||||
:options="getGroupedSyndromeOptions(scope.row.syndromeOptions)"
|
||||
:props="{ emitPath: false, checkStrictly: true }"
|
||||
:show-all-levels="false"
|
||||
:placeholder="t('module.diagnosis.placeholder.selectTcmSyndrome')"
|
||||
placeholder="请选择中医证候"
|
||||
filterable
|
||||
clearable
|
||||
style="width: 100%"
|
||||
@focus="loadSyndromeOptions(scope.row)"
|
||||
@change="(val) => handleSyndromeSelect(val, scope.row, scope.rowIndex)"
|
||||
/>
|
||||
@change="(val) => handleSyndromeSelect(val, scope.row)"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in scope.row.syndromeOptions"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</template>
|
||||
<el-form-item v-else>
|
||||
@@ -289,7 +292,7 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.diagnosisTime')"
|
||||
title="诊断时间"
|
||||
align="center"
|
||||
field="diagnosisTime"
|
||||
width="180"
|
||||
@@ -301,7 +304,7 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.diagnosisCode')"
|
||||
title="诊断代码"
|
||||
align="center"
|
||||
field="ybNo"
|
||||
width="160"
|
||||
@@ -313,7 +316,7 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
:title="t('inpatientDoctor.diagnosis.diagnosisType')"
|
||||
title="诊断类型"
|
||||
align="center"
|
||||
field="maindiseFlag"
|
||||
width="170"
|
||||
@@ -347,7 +350,7 @@
|
||||
</template>
|
||||
</vxe-column>
|
||||
<vxe-column
|
||||
:title="t('common.operation')"
|
||||
title="操作"
|
||||
align="center"
|
||||
width="130"
|
||||
>
|
||||
@@ -404,9 +407,6 @@ import AddDiagnosisDialog from './addDiagnosisDialog.vue';
|
||||
import diagnosislist from '../diagnosis/diagnosislist.vue';
|
||||
|
||||
import {ElMessage} from 'element-plus';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
const { t } = useI18n();
|
||||
// const diagnosisList = ref([]);
|
||||
const allowAdd = ref(false);
|
||||
const isSaving = ref(false);
|
||||
@@ -419,12 +419,6 @@ const rowIndex = ref();
|
||||
const diagnosis = ref();
|
||||
const orgOrUser = ref();
|
||||
const syndromeOptions = ref([]);
|
||||
const cascaderRefs = ref({});
|
||||
const setCascaderRef = (el, index) => {
|
||||
if (el) {
|
||||
cascaderRefs.value[index] = el;
|
||||
}
|
||||
};
|
||||
const form = ref({
|
||||
diagnosisList: [],
|
||||
});
|
||||
@@ -641,7 +635,7 @@ function handleImport() {
|
||||
|
||||
// 检查是否已填写病历
|
||||
if (!allowAdd.value) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.fillEmrFirst'));
|
||||
proxy.$modal.msgWarning('请先填写病历');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -650,7 +644,7 @@ function handleImport() {
|
||||
(item) => !item.conditionId && !item.encounterDiagnosisId
|
||||
);
|
||||
if (hasUnsaved) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.saveCurrentDiagnosis'));
|
||||
proxy.$modal.msgWarning('请保存当前诊断');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -694,7 +688,7 @@ function addChild(data) {
|
||||
function deleteChild(data) {
|
||||
deleteDiagnosisBind(data.id).then((res) => {
|
||||
if (res.code == 200) {
|
||||
proxy.$modal.msgSuccess(t('inpatientDoctor.diagnosis.deleteSuccess'));
|
||||
proxy.$modal.msgSuccess('删除成功');
|
||||
getTree();
|
||||
}
|
||||
});
|
||||
@@ -755,7 +749,7 @@ function handleAddDiagnosis() {
|
||||
|
||||
// 检查是否已填写病历(必须先于其他检查)
|
||||
if (!allowAdd.value) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.fillEmrFirst'));
|
||||
proxy.$modal.msgWarning('请先填写病历');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -764,7 +758,7 @@ function handleAddDiagnosis() {
|
||||
(item) => !item.conditionId && !item.encounterDiagnosisId
|
||||
);
|
||||
if (hasUnsaved) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.saveCurrentDiagnosis'));
|
||||
proxy.$modal.msgWarning('请保存当前诊断');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -784,7 +778,7 @@ function handleAddDiagnosis() {
|
||||
);
|
||||
if (!valid || hasUnsavedNow) {
|
||||
if (hasUnsavedNow) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.saveCurrentDiagnosis'));
|
||||
proxy.$modal.msgWarning('请保存当前诊断');
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -857,43 +851,11 @@ function loadSyndromeOptions(row) {
|
||||
}
|
||||
|
||||
// 中医证候选中赋值
|
||||
function handleSyndromeSelect(val, row, rowIndex) {
|
||||
console.log('handleSyndromeSelect called with:', val, 'rowIndex:', rowIndex);
|
||||
function handleSyndromeSelect(val, row) {
|
||||
if (val) {
|
||||
if (val === 'root-bagang' || val === 'root-weizhong' || val === 'root-other' || (typeof val === 'string' && val.startsWith('virtual-'))) {
|
||||
row.tcmSyndromeCode = '';
|
||||
row.tcmSyndromeName = '';
|
||||
row.syndromeDefinitionId = '';
|
||||
return;
|
||||
}
|
||||
const selected = (row.syndromeOptions || []).find((item) => item.value === val);
|
||||
row.tcmSyndromeName = selected ? selected.label : '';
|
||||
row.syndromeDefinitionId = selected ? selected.id : '';
|
||||
|
||||
// Close the cascader dropdown programmatically
|
||||
if (rowIndex !== undefined && cascaderRefs.value[rowIndex]) {
|
||||
const refEl = cascaderRefs.value[rowIndex];
|
||||
console.log('Cascader Ref component instance:', refEl);
|
||||
if (refEl) {
|
||||
if (typeof refEl.togglePopperVisible === 'function') {
|
||||
refEl.togglePopperVisible(false);
|
||||
}
|
||||
if (typeof refEl.toggleDropDownVisible === 'function') {
|
||||
refEl.toggleDropDownVisible(false);
|
||||
}
|
||||
refEl.popperVisible = false;
|
||||
if (typeof refEl.blur === 'function') {
|
||||
refEl.blur();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (document.activeElement && typeof document.activeElement.blur === 'function') {
|
||||
console.log('Blurring active element:', document.activeElement);
|
||||
document.activeElement.blur();
|
||||
}
|
||||
setTimeout(() => {
|
||||
document.body.click();
|
||||
}, 50);
|
||||
} else {
|
||||
row.tcmSyndromeName = '';
|
||||
row.syndromeDefinitionId = '';
|
||||
@@ -954,7 +916,7 @@ function handleMaindise(value, index) {
|
||||
});
|
||||
if (flag > 1) {
|
||||
form.value.diagnosisList[index].maindiseFlag = 0;
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.onlyOneMainDiagnosis'));
|
||||
proxy.$modal.msgWarning('只能有一条主诊断');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -990,10 +952,10 @@ function handleSaveDiagnosis() {
|
||||
proxy.$refs.formRef.validate((valid) => {
|
||||
if (valid) {
|
||||
if (form.value.diagnosisList.length === 0) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.diagnosisCannotBeEmpty'));
|
||||
proxy.$modal.msgWarning('诊断不能为空');
|
||||
return;
|
||||
} else if (!form.value.diagnosisList.some((diagnosis) => diagnosis.maindiseFlag === 1)) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.addAtLeastOneMain'));
|
||||
proxy.$modal.msgWarning('至少添加一条主诊断');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1001,11 +963,11 @@ function handleSaveDiagnosis() {
|
||||
for (let i = 0; i < form.value.diagnosisList.length; i++) {
|
||||
const item = form.value.diagnosisList[i];
|
||||
if (!item.name) {
|
||||
ElMessage.warning(t('inpatientDoctor.diagnosis.rowNameCannotBeEmpty', { row: i + 1 }));
|
||||
ElMessage.warning(`第${i + 1}行诊断名称不能为空`);
|
||||
return;
|
||||
}
|
||||
if (item.diagnosisSystem === '中医' && !item.tcmSyndromeCode) {
|
||||
ElMessage.error(t('inpatientDoctor.diagnosis.tcmDiagnosisIncomplete'));
|
||||
ElMessage.error('中医诊断不完整,请录入对应的证候!');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1116,7 +1078,7 @@ function handleSaveDiagnosis() {
|
||||
|
||||
// 所有保存完成后刷新
|
||||
emits('diagnosisSave', false);
|
||||
proxy.$modal.msgSuccess(t('inpatientDoctor.diagnosis.diagnosisSaved'));
|
||||
proxy.$modal.msgSuccess('诊断已保存');
|
||||
getList();
|
||||
|
||||
// 食源性疾病逻辑
|
||||
@@ -1127,7 +1089,7 @@ function handleSaveDiagnosis() {
|
||||
});
|
||||
} catch (e) {
|
||||
console.error('保存诊断失败', e);
|
||||
proxy.$modal.msgError(t('inpatientDoctor.diagnosis.saveDiagnosisFailed'));
|
||||
proxy.$modal.msgError('保存诊断失败');
|
||||
} finally {
|
||||
setTimeout(() => {
|
||||
isSaving.value = false;
|
||||
@@ -1142,7 +1104,7 @@ function handleSaveDiagnosis() {
|
||||
*/
|
||||
function closeDiagnosisDialog(str) {
|
||||
if (str === 'success') {
|
||||
proxy.$modal.msgSuccess(t('inpatientDoctor.order.msg.operationSuccess'));
|
||||
proxy.$modal.msgSuccess('操作成功');
|
||||
}
|
||||
|
||||
openAddDiagnosisDialog.value = false;
|
||||
@@ -1190,7 +1152,7 @@ function handleNodeClick(data) {
|
||||
|
||||
// 检查是否已填写病历
|
||||
if (!allowAdd.value) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.fillEmrFirst'));
|
||||
proxy.$modal.msgWarning('请先填写病历');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1199,7 +1161,7 @@ function handleNodeClick(data) {
|
||||
(item) => !item.conditionId && !item.encounterDiagnosisId
|
||||
);
|
||||
if (hasUnsaved) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.saveCurrentDiagnosis'));
|
||||
proxy.$modal.msgWarning('请保存当前诊断');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1207,7 +1169,7 @@ function handleNodeClick(data) {
|
||||
(diagnosis) => diagnosis.ybNo === data.ybNo || diagnosis.name === data.name
|
||||
);
|
||||
if (isDuplicate) {
|
||||
proxy.$modal.msgWarning(t('inpatientDoctor.diagnosis.diagnosisAlreadyExists'));
|
||||
proxy.$modal.msgWarning('该诊断项已存在');
|
||||
return;
|
||||
}
|
||||
form.value.diagnosisList.push({
|
||||
@@ -1235,126 +1197,6 @@ function handleNodeClick(data) {
|
||||
}
|
||||
}
|
||||
|
||||
function getGroupedSyndromeOptions(options) {
|
||||
if (!options || !options.length) return [];
|
||||
|
||||
const seen = new Set();
|
||||
const uniqueOptions = [];
|
||||
options.forEach(item => {
|
||||
if (!seen.has(item.label)) {
|
||||
seen.add(item.label);
|
||||
uniqueOptions.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
const nameToItems = {};
|
||||
uniqueOptions.forEach(item => {
|
||||
const name = item.label;
|
||||
if (!nameToItems[name]) {
|
||||
nameToItems[name] = [];
|
||||
}
|
||||
nameToItems[name].push(item);
|
||||
});
|
||||
|
||||
// Level 3 Children of 阴证 (寒证, 虚证)
|
||||
const childrenOfYin = [];
|
||||
['寒证', '虚证'].forEach(name => {
|
||||
if (nameToItems[name]) {
|
||||
childrenOfYin.push(...nameToItems[name]);
|
||||
}
|
||||
});
|
||||
|
||||
// Level 3 Children of 阳证 (热证, 实证)
|
||||
const childrenOfYang = [];
|
||||
['热证', '实证'].forEach(name => {
|
||||
if (nameToItems[name]) {
|
||||
childrenOfYang.push(...nameToItems[name]);
|
||||
}
|
||||
});
|
||||
|
||||
// Level 2 under 八纲总纲 (阴证, 阳证)
|
||||
const level2OfBagang = [];
|
||||
|
||||
if (nameToItems['阴证']) {
|
||||
nameToItems['阴证'].forEach(item => {
|
||||
level2OfBagang.push({
|
||||
value: item.value,
|
||||
label: item.label,
|
||||
id: item.id,
|
||||
children: childrenOfYin.length ? childrenOfYin : undefined
|
||||
});
|
||||
});
|
||||
} else if (childrenOfYin.length > 0) {
|
||||
level2OfBagang.push({
|
||||
value: 'virtual-yin',
|
||||
label: '阴证',
|
||||
children: childrenOfYin
|
||||
});
|
||||
}
|
||||
|
||||
if (nameToItems['阳证']) {
|
||||
nameToItems['阳证'].forEach(item => {
|
||||
level2OfBagang.push({
|
||||
value: item.value,
|
||||
label: item.label,
|
||||
id: item.id,
|
||||
children: childrenOfYang.length ? childrenOfYang : undefined
|
||||
});
|
||||
});
|
||||
} else if (childrenOfYang.length > 0) {
|
||||
level2OfBagang.push({
|
||||
value: 'virtual-yang',
|
||||
label: '阳证',
|
||||
children: childrenOfYang
|
||||
});
|
||||
}
|
||||
|
||||
// Level 2 under 危重急症 (闭证, 脱证)
|
||||
const level2OfWeizhong = [];
|
||||
['闭证', '脱证'].forEach(name => {
|
||||
if (nameToItems[name]) {
|
||||
level2OfWeizhong.push(...nameToItems[name]);
|
||||
}
|
||||
});
|
||||
|
||||
// Level 2 under 其他证候 (all other syndromes)
|
||||
const level2OfOther = [];
|
||||
const specialNames = new Set(['阴证', '阳证', '寒证', '热证', '虚证', '实证', '闭证', '脱证']);
|
||||
options.forEach(item => {
|
||||
if (!specialNames.has(item.label)) {
|
||||
level2OfOther.push(item);
|
||||
}
|
||||
});
|
||||
|
||||
const finalTree = [];
|
||||
|
||||
if (level2OfBagang.length > 0) {
|
||||
finalTree.push({
|
||||
value: 'root-bagang',
|
||||
label: '八纲总纲',
|
||||
children: level2OfBagang
|
||||
});
|
||||
}
|
||||
|
||||
if (level2OfWeizhong.length > 0) {
|
||||
finalTree.push({
|
||||
value: 'root-weizhong',
|
||||
label: '危重急症',
|
||||
children: level2OfWeizhong
|
||||
});
|
||||
}
|
||||
|
||||
if (level2OfOther.length > 0) {
|
||||
finalTree.push({
|
||||
value: 'root-other',
|
||||
label: '其他证候',
|
||||
children: level2OfOther
|
||||
});
|
||||
}
|
||||
|
||||
return finalTree;
|
||||
}
|
||||
|
||||
defineExpose({ getList, getDetail, handleSaveDiagnosis });
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1137,18 +1137,28 @@ const onActionEdit = async (type) => {
|
||||
getTemRequset();
|
||||
};
|
||||
// 根据code获取文字
|
||||
// 体温(type=1): code 1-5=测量类型(腋温~肛温,不替换值), code 6-8=特殊状态(拒测/外出/请假)
|
||||
// 呼吸(type=2): code 1-6=呼吸类型(平稳~抑制呼吸,不替换值), code 7=@
|
||||
// 血压(type=3): code 1-3=特殊状态(拒测/外出/请假)
|
||||
// 体重/腹围/身高(type=4/5/6): code 1-2=特殊状态(卧床/未测)
|
||||
// 小便(type=7): code 1-2=特殊符号(※/C)
|
||||
// 大便(type=8): code 1-3=特殊符号(※/☆/人工肛门)
|
||||
const selectContent = (code, type) => {
|
||||
let title = '';
|
||||
if (type == 1) {
|
||||
if (code == 1) {
|
||||
// 体温: code 1-5 为测量类型,不替换体温值
|
||||
if (code >= 1 && code <= 5) {
|
||||
title = '';
|
||||
} else if (code == 6) {
|
||||
title = '拒测';
|
||||
} else if (code == 2) {
|
||||
} else if (code == 7) {
|
||||
title = '外出';
|
||||
} else {
|
||||
} else if (code == 8) {
|
||||
title = '请假';
|
||||
}
|
||||
} else if (type == 2) {
|
||||
if (code == 1) {
|
||||
// 呼吸: code 1-6 为呼吸类型,不替换呼吸值; code 7=@
|
||||
if (code == 7) {
|
||||
title = '@';
|
||||
}
|
||||
} else if (type == 3) {
|
||||
@@ -1183,25 +1193,30 @@ const selectContent = (code, type) => {
|
||||
return title;
|
||||
};
|
||||
const temperChange = (row, type = 0) => {
|
||||
// 只有特殊状态码才替换输入值,测量类型选择不替换
|
||||
const replaceValue = (field, content) => {
|
||||
if (content) row[field] = content;
|
||||
};
|
||||
if (type == 1) {
|
||||
row.temperature = selectContent(row.temperatureUnit, type);
|
||||
replaceValue('temperature', selectContent(row.temperatureUnit, type));
|
||||
} else if (type == 2) {
|
||||
row.breathe = selectContent(row.breatheUnit, type);
|
||||
replaceValue('breathe', selectContent(row.breatheUnit, type));
|
||||
} else if (type == 3) {
|
||||
row.systolicPressure = selectContent(row.pressureUnit, type);
|
||||
row.diastolicPressure = selectContent(row.pressureUnit, type);
|
||||
row.bloodPressure = selectContent(row.pressureUnit, type);
|
||||
const content = selectContent(row.pressureUnit, type);
|
||||
replaceValue('systolicPressure', content);
|
||||
replaceValue('diastolicPressure', content);
|
||||
replaceValue('bloodPressure', content);
|
||||
} else if (type == 4) {
|
||||
row.weight = selectContent(row.weightUnit, type);
|
||||
replaceValue('weight', selectContent(row.weightUnit, type));
|
||||
} else if (type == 5) {
|
||||
row.waistCircumference = selectContent(row.waistCircumferenceUnit, type);
|
||||
replaceValue('waistCircumference', selectContent(row.waistCircumferenceUnit, type));
|
||||
} else if (type == 6) {
|
||||
row.height = selectContent(row.heightUnit, type);
|
||||
replaceValue('height', selectContent(row.heightUnit, type));
|
||||
} else if (type == 7) {
|
||||
row.urinationFrequency = selectContent(row.urinationFrequencyUnit, type);
|
||||
replaceValue('urinationFrequency', selectContent(row.urinationFrequencyUnit, type));
|
||||
} else if (type == 8) {
|
||||
console.log('uuuuuu=========>', row.stoolFrequencyUnit);
|
||||
row.stoolFrequency = selectContent(row.stoolFrequencyUnit, type);
|
||||
replaceValue('stoolFrequency', selectContent(row.stoolFrequencyUnit, type));
|
||||
}
|
||||
};
|
||||
// 正则只能输入数字(包含小数)
|
||||
|
||||
Reference in New Issue
Block a user