Compare commits
35 Commits
8a863b4ecb
...
bug/334
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0c5353cf8b | ||
|
|
8a84b40ee5 | ||
| f6b39a4815 | |||
|
|
1b3d4e3dc0 | ||
|
|
cb46461ede | ||
| 3b0a359412 | |||
| 6fa26e895d | |||
| 8ab8691c17 | |||
|
|
35b8a7d10a | ||
| 22de02f132 | |||
| 11244aa48f | |||
| 0a5f26e9c0 | |||
| 4a8e9b5a22 | |||
| bfb2491842 | |||
|
|
b747f80507 | ||
| ced931a280 | |||
| b497eb853c | |||
| 7a2342ea2e | |||
|
|
09fdfa294a | ||
|
|
4ef9aa07d2 | ||
| 08085403b3 | |||
| 2d7dcb4aeb | |||
| ad29502488 | |||
| 5b0acede89 | |||
| ac1cd3afc8 | |||
| 6694ae52ba | |||
| 9491ceaa5d | |||
| db9a70a99d | |||
| b1d6c6008e | |||
| 6b9f9a107e | |||
| 11a7f49162 | |||
| b4e5061b73 | |||
| f5a1ad7f3f | |||
| eeac88b1d1 | |||
| 9f619ccdd4 |
@@ -1,11 +1,15 @@
|
|||||||
package com.core.framework.config;
|
package com.core.framework.config;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||||
import org.mybatis.spring.annotation.MapperScan;
|
import org.mybatis.spring.annotation.MapperScan;
|
||||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,6 +28,14 @@ public class ApplicationConfig {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
|
||||||
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
|
return builder -> {
|
||||||
|
// 设置默认时区
|
||||||
|
builder.timeZone(TimeZone.getDefault());
|
||||||
|
// 设置日期格式为 yyyy/M/d HH:mm:ss,支持多种格式反序列化
|
||||||
|
builder.simpleDateFormat("yyyy/M/d HH:mm:ss");
|
||||||
|
// 添加JavaTimeModule支持,用于LocalDateTime
|
||||||
|
builder.modules(new JavaTimeModule());
|
||||||
|
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss")));
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
@@ -123,6 +124,7 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
if (query == null) {
|
if (query == null) {
|
||||||
query = new com.openhis.appointmentmanage.dto.TicketQueryDTO();
|
query = new com.openhis.appointmentmanage.dto.TicketQueryDTO();
|
||||||
}
|
}
|
||||||
|
normalizeQueryStatus(query);
|
||||||
|
|
||||||
// 2. 构造 MyBatis 的分页对象 (传入前端给的当前页和每页条数)
|
// 2. 构造 MyBatis 的分页对象 (传入前端给的当前页和每页条数)
|
||||||
com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.openhis.appointmentmanage.domain.TicketSlotDTO> pageParam = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
|
com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.openhis.appointmentmanage.domain.TicketSlotDTO> pageParam = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
|
||||||
@@ -140,42 +142,67 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
|
|
||||||
// 基础字段映射
|
// 基础字段映射
|
||||||
dto.setSlot_id(raw.getSlotId());
|
dto.setSlot_id(raw.getSlotId());
|
||||||
|
dto.setSeqNo(raw.getSeqNo());
|
||||||
dto.setBusNo(String.valueOf(raw.getSlotId()));
|
dto.setBusNo(String.valueOf(raw.getSlotId()));
|
||||||
dto.setDoctor(raw.getDoctor());
|
dto.setDoctor(raw.getDoctor());
|
||||||
dto.setDepartment(raw.getDepartmentName()); // 注意:以前这里传成了ID,导致前端出Bug,现在修复成了真正的科室名
|
dto.setDepartment(raw.getDepartmentName()); // 注意:以前这里传成了ID,导致前端出Bug,现在修复成了真正的科室名
|
||||||
dto.setFee(raw.getFee());
|
dto.setFee(raw.getFee());
|
||||||
dto.setPatientName(raw.getPatientName());
|
dto.setPatientName(raw.getPatientName());
|
||||||
dto.setPatientId(raw.getPatientId() != null ? String.valueOf(raw.getPatientId()) : null);
|
dto.setPatientId(raw.getMedicalCard());
|
||||||
dto.setPhone(raw.getPhone());
|
dto.setPhone(raw.getPhone());
|
||||||
|
dto.setIdCard(raw.getIdCard());
|
||||||
|
dto.setDoctorId(raw.getDoctorId());
|
||||||
|
dto.setDepartmentId(raw.getDepartmentId());
|
||||||
|
dto.setRealPatientId(raw.getPatientId());
|
||||||
|
|
||||||
|
// 性别处理:直接读取优先级最高的订单性别字段 (SQL 已处理优先级)
|
||||||
|
if (raw.getPatientGender() != null) {
|
||||||
|
String pg = raw.getPatientGender().trim();
|
||||||
|
dto.setGender("1".equals(pg) ? "男" : ("2".equals(pg) ? "女" : "未知"));
|
||||||
|
} else {
|
||||||
|
dto.setGender("未知");
|
||||||
|
}
|
||||||
|
|
||||||
// 号源类型处理 (底层是1,前端要的是expert)
|
|
||||||
if (raw.getRegType() != null && raw.getRegType() == 1) {
|
if (raw.getRegType() != null && raw.getRegType() == 1) {
|
||||||
dto.setTicketType("expert");
|
dto.setTicketType("expert");
|
||||||
} else {
|
} else {
|
||||||
dto.setTicketType("general");
|
dto.setTicketType("general");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拼接就诊时间
|
|
||||||
if (raw.getScheduleDate() != null && raw.getExpectTime() != null) {
|
if (raw.getScheduleDate() != null && raw.getExpectTime() != null) {
|
||||||
dto.setDateTime(raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
|
dto.setDateTime(raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
|
||||||
try {
|
try {
|
||||||
dto.setAppointmentDate(
|
String timeStr = raw.getAppointmentTime() != null ? raw.getAppointmentTime() : (raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
|
||||||
new java.text.SimpleDateFormat("yyyy-MM-dd").parse(raw.getScheduleDate().toString()));
|
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(timeStr.length() > 10 ? "yyyy-MM-dd HH:mm" : "yyyy-MM-dd");
|
||||||
|
java.util.Date date = sdf.parse(timeStr);
|
||||||
|
dto.setAppointmentDate(date);
|
||||||
|
dto.setAppointmentTime(date);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
dto.setAppointmentDate(new java.util.Date());
|
dto.setAppointmentDate(new java.util.Date());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 精准状态翻译!把底层的1和2,翻译回前端能懂的中文
|
|
||||||
if (Boolean.TRUE.equals(raw.getIsStopped())) {
|
if (Boolean.TRUE.equals(raw.getIsStopped())) {
|
||||||
dto.setStatus("已停诊");
|
dto.setStatus("已停诊");
|
||||||
} else {
|
} else {
|
||||||
Integer slotStatus = raw.getSlotStatus();
|
Integer slotStatus = raw.getSlotStatus();
|
||||||
if (slotStatus != null) {
|
if (slotStatus != null) {
|
||||||
if (SlotStatus.BOOKED.equals(slotStatus)) {
|
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
|
||||||
dto.setStatus(AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus()) ? "已取号" : "已预约");
|
dto.setStatus("已取号");
|
||||||
} else if (SlotStatus.STOPPED.equals(slotStatus)) {
|
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
|
||||||
|
if (AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus())) {
|
||||||
|
dto.setStatus("已取号");
|
||||||
|
} else if (AppointmentOrderStatus.RETURNED.equals(raw.getOrderStatus())) {
|
||||||
|
dto.setStatus("已退号");
|
||||||
|
} else {
|
||||||
|
dto.setStatus("已预约");
|
||||||
|
}
|
||||||
|
} else if (SlotStatus.RETURNED.equals(slotStatus)) {
|
||||||
|
dto.setStatus("已退号");
|
||||||
|
} else if (SlotStatus.CANCELLED.equals(slotStatus)) {
|
||||||
dto.setStatus("已停诊");
|
dto.setStatus("已停诊");
|
||||||
|
} else if (SlotStatus.LOCKED.equals(slotStatus)) {
|
||||||
|
dto.setStatus("已锁定");
|
||||||
} else {
|
} else {
|
||||||
dto.setStatus("未预约");
|
dto.setStatus("未预约");
|
||||||
}
|
}
|
||||||
@@ -198,6 +225,62 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
return R.ok(result);
|
return R.ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 统一状态入参,避免前端状态值大小写/中文/数字差异导致 SQL 条件失效后回全量数据
|
||||||
|
*/
|
||||||
|
private void normalizeQueryStatus(com.openhis.appointmentmanage.dto.TicketQueryDTO query) {
|
||||||
|
String rawStatus = query.getStatus();
|
||||||
|
if (rawStatus == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String normalized = rawStatus.trim();
|
||||||
|
if (normalized.isEmpty()) {
|
||||||
|
query.setStatus(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String lower = normalized.toLowerCase(Locale.ROOT);
|
||||||
|
switch (lower) {
|
||||||
|
case "all":
|
||||||
|
case "全部":
|
||||||
|
query.setStatus("all");
|
||||||
|
break;
|
||||||
|
case "unbooked":
|
||||||
|
case "0":
|
||||||
|
case "未预约":
|
||||||
|
query.setStatus("unbooked");
|
||||||
|
break;
|
||||||
|
case "booked":
|
||||||
|
case "1":
|
||||||
|
case "已预约":
|
||||||
|
query.setStatus("booked");
|
||||||
|
break;
|
||||||
|
case "checked":
|
||||||
|
case "checkin":
|
||||||
|
case "checkedin":
|
||||||
|
case "2":
|
||||||
|
case "已取号":
|
||||||
|
query.setStatus("checked");
|
||||||
|
break;
|
||||||
|
case "cancelled":
|
||||||
|
case "canceled":
|
||||||
|
case "3":
|
||||||
|
case "已停诊":
|
||||||
|
case "已取消":
|
||||||
|
query.setStatus("cancelled");
|
||||||
|
break;
|
||||||
|
case "returned":
|
||||||
|
case "4":
|
||||||
|
case "5":
|
||||||
|
case "已退号":
|
||||||
|
query.setStatus("returned");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// 设置为 impossible 值,配合 mapper 的 otherwise 分支直接返回空
|
||||||
|
query.setStatus("__invalid__");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R<?> listDoctorAvailability(com.openhis.appointmentmanage.dto.TicketQueryDTO query) {
|
public R<?> listDoctorAvailability(com.openhis.appointmentmanage.dto.TicketQueryDTO query) {
|
||||||
if (query == null) {
|
if (query == null) {
|
||||||
@@ -237,12 +320,13 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
// --- 基础字段处理 ---
|
// --- 基础字段处理 ---
|
||||||
// 注意:这里已经变成了极其舒服的 .getSlotId() 方法调用,告别魔鬼字符串!
|
// 注意:这里已经变成了极其舒服的 .getSlotId() 方法调用,告别魔鬼字符串!
|
||||||
dto.setSlot_id(raw.getSlotId());
|
dto.setSlot_id(raw.getSlotId());
|
||||||
|
dto.setSeqNo(raw.getSeqNo());
|
||||||
dto.setBusNo(String.valueOf(raw.getSlotId())); // 暂时借用真实槽位ID做唯一流水号
|
dto.setBusNo(String.valueOf(raw.getSlotId())); // 暂时借用真实槽位ID做唯一流水号
|
||||||
dto.setDoctor(raw.getDoctor());
|
dto.setDoctor(raw.getDoctor());
|
||||||
dto.setDepartment(raw.getDepartmentName());
|
dto.setDepartment(raw.getDepartmentName());
|
||||||
dto.setFee(raw.getFee());
|
dto.setFee(raw.getFee());
|
||||||
dto.setPatientName(raw.getPatientName());
|
dto.setPatientName(raw.getPatientName());
|
||||||
dto.setPatientId(raw.getPatientId() != null ? String.valueOf(raw.getPatientId()) : null);
|
dto.setPatientId(raw.getMedicalCard());
|
||||||
dto.setPhone(raw.getPhone());
|
dto.setPhone(raw.getPhone());
|
||||||
|
|
||||||
// --- 号源类型处理 (普通/专家) ---
|
// --- 号源类型处理 (普通/专家) ---
|
||||||
@@ -258,9 +342,13 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
if (raw.getScheduleDate() != null && raw.getExpectTime() != null) {
|
if (raw.getScheduleDate() != null && raw.getExpectTime() != null) {
|
||||||
dto.setDateTime(raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
|
dto.setDateTime(raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
|
||||||
try {
|
try {
|
||||||
dto.setAppointmentDate(
|
String timeStr = raw.getAppointmentTime() != null ? raw.getAppointmentTime() : (raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
|
||||||
new java.text.SimpleDateFormat("yyyy-MM-dd").parse(raw.getScheduleDate().toString()));
|
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(timeStr.length() > 10 ? "yyyy-MM-dd HH:mm" : "yyyy-MM-dd");
|
||||||
|
java.util.Date date = sdf.parse(timeStr);
|
||||||
|
dto.setAppointmentDate(date);
|
||||||
|
dto.setAppointmentTime(date);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
log.error("时间解析失败", e);
|
||||||
dto.setAppointmentDate(new java.util.Date());
|
dto.setAppointmentDate(new java.util.Date());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -273,10 +361,22 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
// 第二关:看独立的细分槽位状态 (0: 可用, 1: 已预约, 2: 已取消...)
|
// 第二关:看独立的细分槽位状态 (0: 可用, 1: 已预约, 2: 已取消...)
|
||||||
Integer slotStatus = raw.getSlotStatus();
|
Integer slotStatus = raw.getSlotStatus();
|
||||||
if (slotStatus != null) {
|
if (slotStatus != null) {
|
||||||
if (SlotStatus.BOOKED.equals(slotStatus)) {
|
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
|
||||||
dto.setStatus(AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus()) ? "已取号" : "已预约");
|
dto.setStatus("已取号");
|
||||||
} else if (SlotStatus.STOPPED.equals(slotStatus)) {
|
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
|
||||||
dto.setStatus("已停诊"); // 视业务可改回已取消
|
if (AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus())) {
|
||||||
|
dto.setStatus("已取号");
|
||||||
|
} else if (AppointmentOrderStatus.RETURNED.equals(raw.getOrderStatus())) {
|
||||||
|
dto.setStatus("已退号");
|
||||||
|
} else {
|
||||||
|
dto.setStatus("已预约");
|
||||||
|
}
|
||||||
|
} else if (SlotStatus.RETURNED.equals(slotStatus)) {
|
||||||
|
dto.setStatus("已退号");
|
||||||
|
} else if (SlotStatus.CANCELLED.equals(slotStatus)) {
|
||||||
|
dto.setStatus("已停诊");
|
||||||
|
} else if (SlotStatus.LOCKED.equals(slotStatus)) {
|
||||||
|
dto.setStatus("已锁定");
|
||||||
} else {
|
} else {
|
||||||
dto.setStatus("未预约");
|
dto.setStatus("未预约");
|
||||||
}
|
}
|
||||||
@@ -355,15 +455,12 @@ public class TicketAppServiceImpl implements ITicketAppService {
|
|||||||
if (patient != null) {
|
if (patient != null) {
|
||||||
Integer genderEnum = patient.getGenderEnum();
|
Integer genderEnum = patient.getGenderEnum();
|
||||||
if (genderEnum != null) {
|
if (genderEnum != null) {
|
||||||
switch (genderEnum) {
|
if (Integer.valueOf(1).equals(genderEnum)) {
|
||||||
case 1:
|
dto.setGender("男");
|
||||||
dto.setGender("男");
|
} else if (Integer.valueOf(2).equals(genderEnum)) {
|
||||||
break;
|
dto.setGender("女");
|
||||||
case 2:
|
} else {
|
||||||
dto.setGender("女");
|
dto.setGender("未知");
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dto.setGender("未知");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,11 @@ public class TicketDto {
|
|||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long slot_id;
|
private Long slot_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 号源序号(对应 adm_schedule_slot.seq_no)
|
||||||
|
*/
|
||||||
|
private Integer seqNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 号源编码
|
* 号源编码
|
||||||
*/
|
*/
|
||||||
@@ -99,4 +104,15 @@ public class TicketDto {
|
|||||||
*/
|
*/
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long doctorId;
|
private Long doctorId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 真实患者ID(数据库主键,区别于 patientId 存的就诊卡号)
|
||||||
|
*/
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long realPatientId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 身份证号
|
||||||
|
*/
|
||||||
|
private String idCard;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,11 +73,10 @@ public class OutpatientPricingAppServiceImpl implements IOutpatientPricingAppSer
|
|||||||
} else {
|
} else {
|
||||||
adviceTypes = List.of(1, 2, 3);
|
adviceTypes = List.of(1, 2, 3);
|
||||||
}
|
}
|
||||||
// 门诊划价:不要强制 pricingFlag=1 参与过滤(wor_activity_definition.pricing_flag 可能为 0),
|
|
||||||
// 否则会导致诊疗项目(adviceType=3)查询结果为空 records=[]
|
|
||||||
String categoryCode = adviceBaseDto != null ? adviceBaseDto.getCategoryCode() : null;
|
String categoryCode = adviceBaseDto != null ? adviceBaseDto.getCategoryCode() : null;
|
||||||
|
// 门诊划价:仅返回划价标记为“是”的项目
|
||||||
return iDoctorStationAdviceAppService.getAdviceBaseInfo(adviceBaseDto, searchKey, locationId, null,
|
return iDoctorStationAdviceAppService.getAdviceBaseInfo(adviceBaseDto, searchKey, locationId, null,
|
||||||
organizationId, pageNo, pageSize, null, adviceTypes, null, categoryCode);
|
organizationId, pageNo, pageSize, Whether.YES.getValue(), adviceTypes, null, categoryCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ import com.openhis.common.enums.ybenums.YbPayment;
|
|||||||
import com.openhis.common.utils.EnumUtils;
|
import com.openhis.common.utils.EnumUtils;
|
||||||
import com.openhis.common.utils.HisPageUtils;
|
import com.openhis.common.utils.HisPageUtils;
|
||||||
import com.openhis.common.utils.HisQueryUtils;
|
import com.openhis.common.utils.HisQueryUtils;
|
||||||
|
import com.openhis.appointmentmanage.mapper.SchedulePoolMapper;
|
||||||
|
import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper;
|
||||||
|
import com.openhis.clinical.domain.Order;
|
||||||
|
import com.openhis.clinical.service.IOrderService;
|
||||||
import com.openhis.financial.domain.PaymentReconciliation;
|
import com.openhis.financial.domain.PaymentReconciliation;
|
||||||
import com.openhis.financial.domain.RefundLog;
|
import com.openhis.financial.domain.RefundLog;
|
||||||
import com.openhis.financial.service.IRefundLogService;
|
import com.openhis.financial.service.IRefundLogService;
|
||||||
@@ -48,6 +52,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -97,6 +102,15 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
@Resource
|
@Resource
|
||||||
IRefundLogService iRefundLogService;
|
IRefundLogService iRefundLogService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
IOrderService orderService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
ScheduleSlotMapper scheduleSlotMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
SchedulePoolMapper schedulePoolMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 门诊挂号 - 查询患者信息
|
* 门诊挂号 - 查询患者信息
|
||||||
*
|
*
|
||||||
@@ -291,6 +305,11 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果本次门诊挂号来自预约签到,同步把预约订单与号源槽位状态改为已退号
|
||||||
|
if (result != null && result.getCode() == 200) {
|
||||||
|
syncAppointmentReturnStatus(byId, cancelRegPaymentDto.getReason());
|
||||||
|
}
|
||||||
|
|
||||||
// 记录退号日志
|
// 记录退号日志
|
||||||
recordRefundLog(cancelRegPaymentDto, byId, result, paymentRecon);
|
recordRefundLog(cancelRegPaymentDto, byId, result, paymentRecon);
|
||||||
|
|
||||||
@@ -399,6 +418,74 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
|
|||||||
return R.ok("已取消挂号");
|
return R.ok("已取消挂号");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 同步预约号源状态为已退号。
|
||||||
|
* 说明:
|
||||||
|
* 1) 门诊退号主流程不依赖该步骤成功与否,因此此方法内部异常仅记录日志,不向上抛出。
|
||||||
|
* 2) 通过患者、科室、日期以及状态筛选最近一条预约订单,尽量避免误匹配。
|
||||||
|
*/
|
||||||
|
private void syncAppointmentReturnStatus(Encounter encounter, String reason) {
|
||||||
|
if (encounter == null || encounter.getPatientId() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
|
||||||
|
.eq(Order::getPatientId, encounter.getPatientId())
|
||||||
|
.in(Order::getStatus, CommonConstants.AppointmentOrderStatus.BOOKED,
|
||||||
|
CommonConstants.AppointmentOrderStatus.CHECKED_IN)
|
||||||
|
.orderByDesc(Order::getUpdateTime)
|
||||||
|
.orderByDesc(Order::getCreateTime)
|
||||||
|
.last("LIMIT 1");
|
||||||
|
|
||||||
|
if (encounter.getOrganizationId() != null) {
|
||||||
|
queryWrapper.eq(Order::getDepartmentId, encounter.getOrganizationId());
|
||||||
|
}
|
||||||
|
if (encounter.getTenantId() != null) {
|
||||||
|
queryWrapper.eq(Order::getTenantId, encounter.getTenantId());
|
||||||
|
}
|
||||||
|
if (encounter.getCreateTime() != null) {
|
||||||
|
LocalDate encounterDate = encounter.getCreateTime().toInstant()
|
||||||
|
.atZone(ZoneId.systemDefault()).toLocalDate();
|
||||||
|
Date startOfDay = Date.from(encounterDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||||
|
Date nextDayStart = Date.from(encounterDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
|
||||||
|
queryWrapper.ge(Order::getAppointmentDate, startOfDay)
|
||||||
|
.lt(Order::getAppointmentDate, nextDayStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
Order appointmentOrder = orderService.getOne(queryWrapper, false);
|
||||||
|
if (appointmentOrder == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Date now = new Date();
|
||||||
|
if (!CommonConstants.AppointmentOrderStatus.RETURNED.equals(appointmentOrder.getStatus())) {
|
||||||
|
Order updateOrder = new Order();
|
||||||
|
updateOrder.setId(appointmentOrder.getId());
|
||||||
|
updateOrder.setStatus(CommonConstants.AppointmentOrderStatus.RETURNED);
|
||||||
|
updateOrder.setCancelTime(now);
|
||||||
|
updateOrder.setCancelReason(
|
||||||
|
StringUtils.isNotEmpty(reason) ? reason : "门诊退号");
|
||||||
|
updateOrder.setUpdateTime(now);
|
||||||
|
orderService.updateById(updateOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
Long slotId = appointmentOrder.getSlotId();
|
||||||
|
if (slotId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slotRows = scheduleSlotMapper.updateSlotStatus(slotId, CommonConstants.SlotStatus.RETURNED);
|
||||||
|
if (slotRows > 0) {
|
||||||
|
Long poolId = scheduleSlotMapper.selectPoolIdBySlotId(slotId);
|
||||||
|
if (poolId != null) {
|
||||||
|
schedulePoolMapper.refreshPoolStats(poolId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.warn("同步预约号源已退号状态失败, encounterId={}", encounter.getId(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 补打挂号
|
* 补打挂号
|
||||||
* 补打挂号不需要修改数据库,只需要返回成功即可,前端已有所有需要的数据用于打印
|
* 补打挂号不需要修改数据库,只需要返回成功即可,前端已有所有需要的数据用于打印
|
||||||
|
|||||||
@@ -343,7 +343,24 @@ public class SurgeryAppServiceImpl implements ISurgeryAppService {
|
|||||||
serviceRequest.setEncounterId(surgeryDto.getEncounterId()); // 就诊id
|
serviceRequest.setEncounterId(surgeryDto.getEncounterId()); // 就诊id
|
||||||
serviceRequest.setAuthoredTime(curDate); // 请求签发时间
|
serviceRequest.setAuthoredTime(curDate); // 请求签发时间
|
||||||
serviceRequest.setOrgId(orgId); // 执行科室
|
serviceRequest.setOrgId(orgId); // 执行科室
|
||||||
|
// 🔧 BugFix#318: 设置 contentJson,包含手术名称
|
||||||
|
Map<String, String> serviceContentMap = new HashMap<>();
|
||||||
|
String surgeryNameFromDto = surgeryDto.getSurgeryName();
|
||||||
|
String surgeryCodeFromDto = surgeryDto.getSurgeryCode();
|
||||||
|
log.info("【DEBUG】surgeryName from DTO: {}", surgeryNameFromDto);
|
||||||
|
log.info("【DEBUG】surgeryCode from DTO: {}", surgeryCodeFromDto);
|
||||||
|
serviceContentMap.put("surgeryName", surgeryNameFromDto != null ? surgeryNameFromDto : "");
|
||||||
|
serviceContentMap.put("surgeryCode", surgeryCodeFromDto != null ? surgeryCodeFromDto : "");
|
||||||
|
try {
|
||||||
|
String contentJson = new ObjectMapper().writeValueAsString(serviceContentMap);
|
||||||
|
log.info("【DEBUG】Setting contentJson: {}", contentJson);
|
||||||
|
serviceRequest.setContentJson(contentJson);
|
||||||
|
} catch (JsonProcessingException e) {
|
||||||
|
log.error("【DEBUG】设置手术医嘱 contentJson 失败", e);
|
||||||
|
}
|
||||||
serviceRequestService.save(serviceRequest);
|
serviceRequestService.save(serviceRequest);
|
||||||
|
log.info("【DEBUG】Saved serviceRequest with ID: {}, contentJson: {}",
|
||||||
|
serviceRequest.getId(), serviceRequest.getContentJson());
|
||||||
|
|
||||||
// 生成收费项目
|
// 生成收费项目
|
||||||
ChargeItem chargeItem = new ChargeItem();
|
ChargeItem chargeItem = new ChargeItem();
|
||||||
|
|||||||
@@ -371,7 +371,7 @@ public class SurgicalScheduleAppServiceImpl implements ISurgicalScheduleAppServi
|
|||||||
index, // 序号从1开始
|
index, // 序号从1开始
|
||||||
schedule.getOrgName() != null ? schedule.getOrgName() : "",
|
schedule.getOrgName() != null ? schedule.getOrgName() : "",
|
||||||
schedule.getPatientName() != null ? schedule.getPatientName() : "",
|
schedule.getPatientName() != null ? schedule.getPatientName() : "",
|
||||||
schedule.getVisitId() != null ? schedule.getVisitId().toString() : "",
|
schedule.getIdentifierNo() != null ? schedule.getIdentifierNo() : "",
|
||||||
schedule.getOperCode() != null ? schedule.getOperCode() : "",
|
schedule.getOperCode() != null ? schedule.getOperCode() : "",
|
||||||
schedule.getOperName() != null ? schedule.getOperName() : "",
|
schedule.getOperName() != null ? schedule.getOperName() : "",
|
||||||
schedule.getApplyDeptName() != null ? schedule.getApplyDeptName() : "",
|
schedule.getApplyDeptName() != null ? schedule.getApplyDeptName() : "",
|
||||||
|
|||||||
@@ -24,6 +24,11 @@ public class OpCreateScheduleDto {
|
|||||||
*/
|
*/
|
||||||
private Long visitId;
|
private Long visitId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 就诊卡号
|
||||||
|
*/
|
||||||
|
private String identifierNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 手术编码
|
* 手术编码
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,6 +43,11 @@ public class OpScheduleDto extends OpSchedule {
|
|||||||
*/
|
*/
|
||||||
private Long encounterId;
|
private Long encounterId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 就诊卡号
|
||||||
|
*/
|
||||||
|
private String patientCardNo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 性别
|
* 性别
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ public class SurgeryDto {
|
|||||||
/** 就诊流水号 */
|
/** 就诊流水号 */
|
||||||
private String encounterNo;
|
private String encounterNo;
|
||||||
|
|
||||||
|
/** 就诊卡号 */
|
||||||
|
private String patientCardNo;
|
||||||
|
|
||||||
/** 申请医生ID */
|
/** 申请医生ID */
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long applyDoctorId;
|
private Long applyDoctorId;
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
|
|||||||
private IOperationRecordService operationRecordService;
|
private IOperationRecordService operationRecordService;
|
||||||
@Resource
|
@Resource
|
||||||
private IServiceRequestService serviceRequestService;
|
private IServiceRequestService serviceRequestService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 诊疗目录初期查询
|
* 诊疗目录初期查询
|
||||||
*
|
*
|
||||||
@@ -240,9 +239,8 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
|
|||||||
DiagnosisTreatmentSelParam.setPricingFlag(pricingFlagValue);
|
DiagnosisTreatmentSelParam.setPricingFlag(pricingFlagValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分页查询
|
|
||||||
IPage<DiagnosisTreatmentDto> diseaseTreatmentPage
|
IPage<DiagnosisTreatmentDto> diseaseTreatmentPage
|
||||||
= activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page<DiagnosisTreatmentDto>(pageNo, pageSize), queryWrapper);
|
= activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page<>(pageNo, pageSize), queryWrapper);
|
||||||
|
|
||||||
diseaseTreatmentPage.getRecords().forEach(e -> {
|
diseaseTreatmentPage.getRecords().forEach(e -> {
|
||||||
// 医保标记枚举类回显赋值
|
// 医保标记枚举类回显赋值
|
||||||
@@ -447,24 +445,17 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public R<?> editDiseaseTreatmentStop(List<Long> ids) {
|
public R<?> editDiseaseTreatmentStop(List<Long> ids) {
|
||||||
|
List<ActivityDefinition> actList = new CopyOnWriteArrayList<>();
|
||||||
List<ActivityDefinition> ActivityDefinitionList = new CopyOnWriteArrayList<>();
|
for (Long id : ids) {
|
||||||
|
ActivityDefinition act = new ActivityDefinition();
|
||||||
// 取得更新值
|
act.setId(id);
|
||||||
for (Long detail : ids) {
|
act.setStatusEnum(PublicationStatus.RETIRED.getValue());
|
||||||
ActivityDefinition ActivityDefinition = new ActivityDefinition();
|
actList.add(act);
|
||||||
ActivityDefinition.setId(detail);
|
|
||||||
ActivityDefinition.setStatusEnum(PublicationStatus.RETIRED.getValue());
|
|
||||||
ActivityDefinitionList.add(ActivityDefinition);
|
|
||||||
}
|
}
|
||||||
// 插入操作记录
|
|
||||||
operationRecordService.addIdsOperationRecord(DbOpType.STOP.getCode(),
|
operationRecordService.addIdsOperationRecord(DbOpType.STOP.getCode(),
|
||||||
CommonConstants.TableName.WOR_ACTIVITY_DEFINITION, ids);
|
CommonConstants.TableName.WOR_ACTIVITY_DEFINITION, ids);
|
||||||
// 更新诊疗信息
|
activityDefinitionService.updateBatchById(actList);
|
||||||
return activityDefinitionService.updateBatchById(ActivityDefinitionList)
|
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"\u8bca\u7597\u76ee\u5f55"}));
|
||||||
? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"诊疗目录"}))
|
|
||||||
: R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -475,24 +466,17 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public R<?> editDiseaseTreatmentStart(List<Long> ids) {
|
public R<?> editDiseaseTreatmentStart(List<Long> ids) {
|
||||||
|
List<ActivityDefinition> actList = new CopyOnWriteArrayList<>();
|
||||||
List<ActivityDefinition> ActivityDefinitionList = new CopyOnWriteArrayList<>();
|
for (Long id : ids) {
|
||||||
|
ActivityDefinition act = new ActivityDefinition();
|
||||||
// 取得更新值
|
act.setId(id);
|
||||||
for (Long detail : ids) {
|
act.setStatusEnum(PublicationStatus.ACTIVE.getValue());
|
||||||
ActivityDefinition ActivityDefinition = new ActivityDefinition();
|
actList.add(act);
|
||||||
ActivityDefinition.setId(detail);
|
|
||||||
ActivityDefinition.setStatusEnum(PublicationStatus.ACTIVE.getValue());
|
|
||||||
ActivityDefinitionList.add(ActivityDefinition);
|
|
||||||
}
|
}
|
||||||
// 插入操作记录
|
|
||||||
operationRecordService.addIdsOperationRecord(DbOpType.START.getCode(),
|
operationRecordService.addIdsOperationRecord(DbOpType.START.getCode(),
|
||||||
CommonConstants.TableName.WOR_ACTIVITY_DEFINITION, ids);
|
CommonConstants.TableName.WOR_ACTIVITY_DEFINITION, ids);
|
||||||
// 更新诊疗信息
|
activityDefinitionService.updateBatchById(actList);
|
||||||
return activityDefinitionService.updateBatchById(ActivityDefinitionList)
|
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"诊疗目录"}));
|
||||||
? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"诊疗目录"}))
|
|
||||||
: R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package com.openhis.web.datadictionary.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
|
import com.baomidou.mybatisplus.core.toolkit.Constants;
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
|
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目定义管理 Mapper(操作 lab_activity_definition 表)
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface LabActivityDefinitionManageMapper {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目分页查询
|
||||||
|
*
|
||||||
|
* @param page 分页参数
|
||||||
|
* @param queryWrapper 查询条件
|
||||||
|
* @return 分页结果
|
||||||
|
*/
|
||||||
|
IPage<DiagnosisTreatmentDto> getLabActivityDefinitionPage(
|
||||||
|
@Param("page") Page<DiagnosisTreatmentDto> page,
|
||||||
|
@Param(Constants.WRAPPER) QueryWrapper<DiagnosisTreatmentDto> queryWrapper);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目详情
|
||||||
|
*
|
||||||
|
* @param id 项目ID
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @return 详情
|
||||||
|
*/
|
||||||
|
DiagnosisTreatmentDto getLabActivityDefinitionOne(@Param("id") Long id, @Param("tenantId") Integer tenantId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目下拉列表(轻量级)
|
||||||
|
*
|
||||||
|
* @param statusEnum 状态
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @param searchKey 搜索关键词(可选)
|
||||||
|
* @return 列表
|
||||||
|
*/
|
||||||
|
List<DiagnosisTreatmentDto> getLabActivityDefinitionSimpleList(
|
||||||
|
@Param("statusEnum") Integer statusEnum,
|
||||||
|
@Param("tenantId") Integer tenantId,
|
||||||
|
@Param("searchKey") String searchKey);
|
||||||
|
}
|
||||||
@@ -570,13 +570,15 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
// 耗材(前端adviceType=4,后端ItemType.DEVICE=2)
|
// 耗材(前端adviceType=4,后端ItemType.DEVICE=2)
|
||||||
List<AdviceSaveDto> deviceList = adviceSaveList.stream()
|
List<AdviceSaveDto> deviceList = adviceSaveList.stream()
|
||||||
.filter(e -> ItemType.DEVICE.getValue().equals(e.getAdviceType())
|
.filter(e -> ItemType.DEVICE.getValue().equals(e.getAdviceType())
|
||||||
|| e.getAdviceType() == 4) // 🔧 BugFix: 前端耗材类型值为4
|
|| e.getAdviceType() == 4) // 前端耗材类型值为4
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
// 诊疗活动(包括普通诊疗:前端adviceType=3,会诊:前端adviceType=5)
|
|
||||||
|
// 诊疗活动(前端adviceType=3诊疗、adviceType=5会诊、adviceType=6手术)
|
||||||
List<AdviceSaveDto> activityList = adviceSaveList.stream()
|
List<AdviceSaveDto> activityList = adviceSaveList.stream()
|
||||||
.filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
|
.filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
|
||||||
|| e.getAdviceType() == 3 // 🔧 BugFix: 前端诊疗类型值为3
|
|| e.getAdviceType() == 3 // 前端诊疗类型值为3
|
||||||
|| e.getAdviceType() == 5) // 🔧 BugFix: 前端会诊类型值为5
|
|| e.getAdviceType() == 5 // 前端会诊类型值为5
|
||||||
|
|| ItemType.SURGERY.getValue().equals(e.getAdviceType())) // 🔧 BugFix#318: 手术类型值为6
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
// 🔍 Debug日志: 记录分类结果
|
// 🔍 Debug日志: 记录分类结果
|
||||||
@@ -605,11 +607,12 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
iDeviceDispenseService.deleteDeviceDispense(adviceSaveDto.getRequestId());
|
iDeviceDispenseService.deleteDeviceDispense(adviceSaveDto.getRequestId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 🔧 Bug Fix: 跳过耗材的库存校验(耗材的库存校验逻辑不同)
|
// 🔧 Bug Fix: 跳过耗材、诊疗、手术的库存校验
|
||||||
List<AdviceSaveDto> needCheckList = adviceSaveList.stream()
|
List<AdviceSaveDto> needCheckList = adviceSaveList.stream()
|
||||||
.filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType())
|
.filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType())
|
||||||
&& !ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
|
&& !ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
|
||||||
&& !ItemType.DEVICE.getValue().equals(e.getAdviceType())) // 排除耗材
|
&& !ItemType.DEVICE.getValue().equals(e.getAdviceType())
|
||||||
|
&& !ItemType.SURGERY.getValue().equals(e.getAdviceType())) // 🔧 BugFix#318: 排除手术类型
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
// 校验库存
|
// 校验库存
|
||||||
String tipRes = adviceUtils.checkInventory(needCheckList);
|
String tipRes = adviceUtils.checkInventory(needCheckList);
|
||||||
@@ -1198,6 +1201,47 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
|
|||||||
chargeItem.setServiceId(deviceRequest.getId()); // 医疗服务ID
|
chargeItem.setServiceId(deviceRequest.getId()); // 医疗服务ID
|
||||||
chargeItem.setProductTable(adviceSaveDto.getAdviceTableName());// 产品所在表
|
chargeItem.setProductTable(adviceSaveDto.getAdviceTableName());// 产品所在表
|
||||||
chargeItem.setProductId(adviceSaveDto.getAdviceDefinitionId());// 收费项id
|
chargeItem.setProductId(adviceSaveDto.getAdviceDefinitionId());// 收费项id
|
||||||
|
|
||||||
|
// 🔧 Bug Fix: 如果 definitionId 或 definitionDetailId 为 null,从定价信息中获取
|
||||||
|
if (chargeItem.getDefinitionId() == null || chargeItem.getDefDetailId() == null) {
|
||||||
|
log.warn("耗材的 definitionId 或 definitionDetailId 为 null,尝试从定价信息中获取: deviceDefId={}",
|
||||||
|
adviceSaveDto.getAdviceDefinitionId());
|
||||||
|
// 查询耗材定价信息
|
||||||
|
IPage<AdviceBaseDto> devicePage = doctorStationAdviceAppMapper.getAdviceBaseInfo(
|
||||||
|
new Page<>(1, 1),
|
||||||
|
PublicationStatus.ACTIVE.getValue(),
|
||||||
|
orgId,
|
||||||
|
CommonConstants.TableName.ADM_DEVICE_DEFINITION,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
Arrays.asList(adviceSaveDto.getAdviceDefinitionId()),
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
if (devicePage != null && !devicePage.getRecords().isEmpty()) {
|
||||||
|
AdviceBaseDto deviceBaseInfo = devicePage.getRecords().get(0);
|
||||||
|
if (deviceBaseInfo.getPriceList() != null && !deviceBaseInfo.getPriceList().isEmpty()) {
|
||||||
|
AdvicePriceDto devicePrice = deviceBaseInfo.getPriceList().get(0);
|
||||||
|
if (chargeItem.getDefinitionId() == null) {
|
||||||
|
chargeItem.setDefinitionId(devicePrice.getDefinitionId());
|
||||||
|
log.info("从定价信息中获取 definitionId: {}", devicePrice.getDefinitionId());
|
||||||
|
}
|
||||||
|
if (chargeItem.getDefDetailId() == null) {
|
||||||
|
chargeItem.setDefDetailId(devicePrice.getDefinitionDetailId());
|
||||||
|
log.info("从定价信息中获取 definitionDetailId: {}", devicePrice.getDefinitionDetailId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 🔧 Bug Fix: 确保定义ID不为null
|
||||||
|
if (chargeItem.getDefinitionId() == null) {
|
||||||
|
log.error("无法获取耗材的 definitionId: deviceDefId={}", adviceSaveDto.getAdviceDefinitionId());
|
||||||
|
throw new ServiceException("无法获取耗材的定价信息,请联系管理员");
|
||||||
|
}
|
||||||
|
|
||||||
// 🔧 Bug Fix: 如果accountId为null,从就诊中获取账户ID,如果没有则自动创建
|
// 🔧 Bug Fix: 如果accountId为null,从就诊中获取账户ID,如果没有则自动创建
|
||||||
Long accountId = adviceSaveDto.getAccountId();
|
Long accountId = adviceSaveDto.getAccountId();
|
||||||
if (accountId == null) {
|
if (accountId == null) {
|
||||||
|
|||||||
@@ -273,12 +273,28 @@ public class DoctorStationDiagnosisAppServiceImpl implements IDoctorStationDiagn
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public R<?> saveDoctorDiagnosisNew(SaveDiagnosisParam saveDiagnosisParam) {
|
public R<?> saveDoctorDiagnosisNew(SaveDiagnosisParam saveDiagnosisParam) {
|
||||||
|
// 参数校验:确保诊断列表不为空
|
||||||
|
if (saveDiagnosisParam == null) {
|
||||||
|
return R.fail(MessageUtils.message(PromptMsgConstant.Common.M00009, new Object[] { "保存诊断参数" }));
|
||||||
|
}
|
||||||
|
|
||||||
// 患者id
|
// 患者id
|
||||||
Long patientId = saveDiagnosisParam.getPatientId();
|
Long patientId = saveDiagnosisParam.getPatientId();
|
||||||
// 就诊ID
|
// 就诊ID
|
||||||
Long encounterId = saveDiagnosisParam.getEncounterId();
|
Long encounterId = saveDiagnosisParam.getEncounterId();
|
||||||
// 诊断定义集合
|
// 诊断定义集合
|
||||||
List<SaveDiagnosisChildParam> diagnosisChildList = saveDiagnosisParam.getDiagnosisChildList();
|
List<SaveDiagnosisChildParam> diagnosisChildList = saveDiagnosisParam.getDiagnosisChildList();
|
||||||
|
|
||||||
|
// 校验患者ID和就诊ID
|
||||||
|
if (patientId == null || encounterId == null) {
|
||||||
|
return R.fail(MessageUtils.message(PromptMsgConstant.Common.M00009, new Object[] { "患者ID或就诊ID" }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验诊断列表不为空
|
||||||
|
if (diagnosisChildList == null || diagnosisChildList.isEmpty()) {
|
||||||
|
return R.fail(MessageUtils.message(PromptMsgConstant.Common.M00009, new Object[] { "诊断列表" }));
|
||||||
|
}
|
||||||
|
|
||||||
// 先删除再保存
|
// 先删除再保存
|
||||||
// iEncounterDiagnosisService.deleteEncounterDiagnosisInfos(encounterId);
|
// iEncounterDiagnosisService.deleteEncounterDiagnosisInfos(encounterId);
|
||||||
|
|
||||||
|
|||||||
@@ -374,11 +374,11 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
|
|||||||
|
|
||||||
// 查询检验申请单列表
|
// 查询检验申请单列表
|
||||||
log.debug("查询申请单数据前");
|
log.debug("查询申请单数据前");
|
||||||
List<InspectionLabApply> list = doctorStationLabApplyMapper.getInspectionApplyListPage(encounterId);
|
List<DoctorStationLabApplyDto> list = doctorStationLabApplyMapper.getInspectionApplyListPage(encounterId);
|
||||||
log.debug("查询申请单数据后");
|
log.debug("查询申请单数据后");
|
||||||
|
|
||||||
// 使用 PageInfo 包装查询结果
|
// 使用 PageInfo 包装查询结果
|
||||||
PageInfo<InspectionLabApply> pageInfo = new PageInfo<>(list);
|
PageInfo<DoctorStationLabApplyDto> pageInfo = new PageInfo<>(list);
|
||||||
|
|
||||||
// 构建返回结果
|
// 构建返回结果
|
||||||
Map<String, Object> result = new HashMap<>();
|
Map<String, Object> result = new HashMap<>();
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.openhis.web.doctorstation.appservice.impl;
|
package com.openhis.web.doctorstation.appservice.impl;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
@@ -16,21 +17,23 @@ import com.openhis.common.constant.CommonConstants;
|
|||||||
import com.openhis.common.enums.*;
|
import com.openhis.common.enums.*;
|
||||||
import com.openhis.common.utils.EnumUtils;
|
import com.openhis.common.utils.EnumUtils;
|
||||||
import com.openhis.common.utils.HisQueryUtils;
|
import com.openhis.common.utils.HisQueryUtils;
|
||||||
|
import com.openhis.triageandqueuemanage.domain.TriageQueueItem;
|
||||||
|
import com.openhis.triageandqueuemanage.service.TriageQueueItemService;
|
||||||
import com.openhis.web.doctorstation.appservice.*;
|
import com.openhis.web.doctorstation.appservice.*;
|
||||||
import com.openhis.web.doctorstation.dto.PatientInfoDto;
|
import com.openhis.web.doctorstation.dto.PatientInfoDto;
|
||||||
import com.openhis.web.doctorstation.dto.PrescriptionInfoBaseDto;
|
import com.openhis.web.doctorstation.dto.PrescriptionInfoBaseDto;
|
||||||
import com.openhis.web.doctorstation.dto.PrescriptionInfoDetailDto;
|
import com.openhis.web.doctorstation.dto.PrescriptionInfoDetailDto;
|
||||||
import com.openhis.web.doctorstation.dto.ReceptionStatisticsDto;
|
import com.openhis.web.doctorstation.dto.ReceptionStatisticsDto;
|
||||||
import com.openhis.web.doctorstation.mapper.DoctorStationMainAppMapper;
|
import com.openhis.web.doctorstation.mapper.DoctorStationMainAppMapper;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.jdbc.core.JdbcTemplate;
|
import org.springframework.jdbc.core.JdbcTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -64,6 +67,9 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private JdbcTemplate jdbcTemplate;
|
private JdbcTemplate jdbcTemplate;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TriageQueueItemService triageQueueItemService;
|
||||||
/**
|
/**
|
||||||
* 查询就诊患者信息
|
* 查询就诊患者信息
|
||||||
*
|
*
|
||||||
@@ -124,14 +130,40 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public R<?> receiveEncounter(Long encounterId) {
|
public R<?> receiveEncounter(Long encounterId) {
|
||||||
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||||
String currentUsername = SecurityUtils.getUsername();
|
String currentUsername = SecurityUtils.getUsername();
|
||||||
|
|
||||||
|
// 检查就诊记录是否存在
|
||||||
|
Encounter encounter = encounterMapper.selectById(encounterId);
|
||||||
|
if (encounter == null) {
|
||||||
|
return R.fail("就诊记录不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查患者状态,防止重复接诊
|
||||||
|
Integer currentStatus = encounter.getStatusEnum();
|
||||||
|
if (EncounterStatus.IN_PROGRESS.getValue().equals(currentStatus)) {
|
||||||
|
return R.fail("已接诊,请勿重复点击,已为您刷新");
|
||||||
|
}
|
||||||
|
|
||||||
int update = encounterMapper.update(null,
|
int update = encounterMapper.update(null,
|
||||||
new LambdaUpdateWrapper<Encounter>().eq(Encounter::getId, encounterId)
|
new LambdaUpdateWrapper<Encounter>().eq(Encounter::getId, encounterId)
|
||||||
|
.eq(Encounter::getStatusEnum, EncounterStatus.PLANNED.getValue()) // 只更新待诊状态的患者
|
||||||
.set(Encounter::getReceptionTime, new Date())
|
.set(Encounter::getReceptionTime, new Date())
|
||||||
.set(Encounter::getStatusEnum, EncounterStatus.IN_PROGRESS.getValue())
|
.set(Encounter::getStatusEnum, EncounterStatus.IN_PROGRESS.getValue())
|
||||||
.set(Encounter::getSubjectStatusEnum, EncounterSubjectStatus.RECEIVING_CARE.getValue()));
|
.set(Encounter::getSubjectStatusEnum, EncounterSubjectStatus.RECEIVING_CARE.getValue()));
|
||||||
|
|
||||||
|
// 如果更新失败,说明状态已被其他医生修改
|
||||||
|
if (update <= 0) {
|
||||||
|
// 重新查询当前状态
|
||||||
|
encounter = encounterMapper.selectById(encounterId);
|
||||||
|
if (EncounterStatus.IN_PROGRESS.getValue().equals(encounter.getStatusEnum())) {
|
||||||
|
return R.fail("已接诊,请勿重复接诊");
|
||||||
|
}
|
||||||
|
return R.fail("接诊失败,请刷新后重试");
|
||||||
|
}
|
||||||
|
|
||||||
// 先把之前的接诊记录更新为已完成
|
// 先把之前的接诊记录更新为已完成
|
||||||
iEncounterParticipantService.update(new LambdaUpdateWrapper<EncounterParticipant>()
|
iEncounterParticipantService.update(new LambdaUpdateWrapper<EncounterParticipant>()
|
||||||
.eq(EncounterParticipant::getTypeCode, ParticipantType.ADMITTER.getCode())
|
.eq(EncounterParticipant::getTypeCode, ParticipantType.ADMITTER.getCode())
|
||||||
@@ -148,7 +180,28 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
|
|||||||
encounterParticipant.setCreateBy(currentUsername);
|
encounterParticipant.setCreateBy(currentUsername);
|
||||||
encounterParticipant.setCreateTime(new Date());
|
encounterParticipant.setCreateTime(new Date());
|
||||||
iEncounterParticipantService.save(encounterParticipant);
|
iEncounterParticipantService.save(encounterParticipant);
|
||||||
return update > 0 ? R.ok() : R.fail();
|
|
||||||
|
// 更新 triage_queue_item 队列记录状态为 CALLING
|
||||||
|
try {
|
||||||
|
TriageQueueItem queueItem = triageQueueItemService.getOne(
|
||||||
|
new LambdaQueryWrapper<TriageQueueItem>()
|
||||||
|
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||||
|
.eq(TriageQueueItem::getEncounterId, encounterId)
|
||||||
|
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||||
|
);
|
||||||
|
if (queueItem != null) {
|
||||||
|
queueItem.setStatus("CALLING");
|
||||||
|
queueItem.setUpdateTime(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
|
||||||
|
triageQueueItemService.updateById(queueItem);
|
||||||
|
log.info("接诊时更新队列状态为CALLING,encounterId={}, queueItemId={}", encounterId, queueItem.getId());
|
||||||
|
} else {
|
||||||
|
log.warn("接诊时未找到队列记录,encounterId={}", encounterId);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("接诊时更新队列状态失败,encounterId={}", encounterId, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return R.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,11 +234,54 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
|
|||||||
return R.fail("就诊记录不存在");
|
return R.fail("就诊记录不存在");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EncounterStatus.IN_PROGRESS.getValue().equals(encounter.getStatusEnum())) {
|
// 检查患者状态,防止重复完诊
|
||||||
return R.fail("当前患者不在就诊中状态");
|
Integer currentStatus = encounter.getStatusEnum();
|
||||||
|
if (EncounterStatus.DISCHARGED.getValue().equals(currentStatus) ||
|
||||||
|
EncounterStatus.COMPLETED.getValue().equals(currentStatus)) {
|
||||||
|
// 患者已完成就诊,返回特定提示
|
||||||
|
return R.fail("患者已完成就诊,已为您自动刷新患者列表");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. 更新状态、完成时间以及初复诊标识
|
if (!EncounterStatus.IN_PROGRESS.getValue().equals(currentStatus)) {
|
||||||
|
return R.fail("非就诊中患者不能完诊");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 查找队列项
|
||||||
|
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||||
|
TriageQueueItem queueItem = triageQueueItemService.getOne(
|
||||||
|
new LambdaQueryWrapper<TriageQueueItem>()
|
||||||
|
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||||
|
.eq(TriageQueueItem::getEncounterId, encounterId)
|
||||||
|
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||||
|
);
|
||||||
|
|
||||||
|
// 如果队列项存在,检查状态并更新
|
||||||
|
if (queueItem != null && "CALLING".equals(queueItem.getStatus())) {
|
||||||
|
// 更新队列状态为已完成
|
||||||
|
java.time.LocalDateTime nowLocal = java.time.LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS);
|
||||||
|
queueItem.setStatus("COMPLETED");
|
||||||
|
queueItem.setUpdateTime(nowLocal);
|
||||||
|
triageQueueItemService.updateById(queueItem);
|
||||||
|
|
||||||
|
// 写入 div_log 审计日志
|
||||||
|
try {
|
||||||
|
Long userId = SecurityUtils.getLoginUser().getUserId();
|
||||||
|
String divLogSql = "INSERT INTO hisdev.div_log "
|
||||||
|
+ "(pool_id, slot_id, queue_no, op_user_id, action, create_time) "
|
||||||
|
+ "VALUES (?, ?, ?, ?, 'COMPLETE', NOW()::timestamp(0))";
|
||||||
|
|
||||||
|
jdbcTemplate.update(divLogSql,
|
||||||
|
queueItem.getOrganizationId(), // pool_id: 候选池ID(科室)
|
||||||
|
queueItem.getPractitionerId(), // slot_id: 槽位ID(医生)
|
||||||
|
queueItem.getQueueOrder(), // queue_no: 队列号
|
||||||
|
userId); // op_user_id: 操作用户ID
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("写入div_log审计日志失败", e);
|
||||||
|
// 审计日志失败不影响主流程
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 更新状态、完成时间以及初复诊标识
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
int update = encounterMapper.update(null,
|
int update = encounterMapper.update(null,
|
||||||
new LambdaUpdateWrapper<Encounter>()
|
new LambdaUpdateWrapper<Encounter>()
|
||||||
@@ -198,7 +294,7 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
|
|||||||
|
|
||||||
if (update <= 0) return R.fail("完诊失败");
|
if (update <= 0) return R.fail("完诊失败");
|
||||||
|
|
||||||
// 3. 审计日志
|
// 4. 审计日志(sys_oper_log)
|
||||||
try {
|
try {
|
||||||
String username = SecurityUtils.getUsernameSafe();
|
String username = SecurityUtils.getUsernameSafe();
|
||||||
String sql = "INSERT INTO sys_oper_log "
|
String sql = "INSERT INTO sys_oper_log "
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
public class DoctorStationLabApplyDto {
|
public class DoctorStationLabApplyDto {
|
||||||
|
/**
|
||||||
|
* 申请单ID(数据库自增主键)
|
||||||
|
*/
|
||||||
|
private Long applicationId;
|
||||||
/**
|
/**
|
||||||
* 申请单编号
|
* 申请单编号
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -161,6 +161,11 @@ public class RequestBaseDto {
|
|||||||
private String doseUnitCode;
|
private String doseUnitCode;
|
||||||
private String doseUnitCode_dictText;
|
private String doseUnitCode_dictText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单价
|
||||||
|
*/
|
||||||
|
private BigDecimal unitPrice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 总价
|
* 总价
|
||||||
*/
|
*/
|
||||||
@@ -215,4 +220,16 @@ public class RequestBaseDto {
|
|||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long basedOnId;
|
private Long basedOnId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 就诊id
|
||||||
|
*/
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long encounterId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 患者id
|
||||||
|
*/
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long patientId;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.openhis.web.doctorstation.dto;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
@@ -73,12 +74,16 @@ public class SaveDiagnosisChildParam {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 诊断时间
|
* 诊断时间
|
||||||
|
* 添加 pattern 以支持前端传来的 "yyyy/M/d HH:mm:ss" 格式
|
||||||
*/
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy/M/d HH:mm:ss", timezone = "GMT+8")
|
||||||
private Date diagnosisTime;
|
private Date diagnosisTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发病时间
|
* 发病时间
|
||||||
|
* 同样添加 pattern 以防前端传来相同格式的发病时间
|
||||||
*/
|
*/
|
||||||
|
@JsonFormat(pattern = "yyyy/M/d HH:mm:ss", timezone = "GMT+8")
|
||||||
private Date onsetDate;
|
private Date onsetDate;
|
||||||
|
|
||||||
/** 患者疾病诊断类型代码 */
|
/** 患者疾病诊断类型代码 */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package com.openhis.web.doctorstation.mapper;
|
package com.openhis.web.doctorstation.mapper;
|
||||||
|
|
||||||
import com.openhis.lab.domain.InspectionLabApply;
|
import com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@@ -23,5 +23,5 @@ public interface DoctorStationLabApplyMapper {
|
|||||||
* @param encounterId 就诊 ID
|
* @param encounterId 就诊 ID
|
||||||
* @return 检验申请单列表
|
* @return 检验申请单列表
|
||||||
*/
|
*/
|
||||||
List<InspectionLabApply> getInspectionApplyListPage(@Param("encounterId") Long encounterId);
|
List<DoctorStationLabApplyDto> getInspectionApplyListPage(@Param("encounterId") Long encounterId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,15 @@ public class AdviceUtils {
|
|||||||
matched = true;
|
matched = true;
|
||||||
// 检查库存是否充足
|
// 检查库存是否充足
|
||||||
BigDecimal minUnitQuantity = saveDto.getMinUnitQuantity();
|
BigDecimal minUnitQuantity = saveDto.getMinUnitQuantity();
|
||||||
|
// 🔧 Bug Fix: 对于耗材类型,如果没有设置minUnitQuantity,则使用quantity作为默认值
|
||||||
|
if (minUnitQuantity == null) {
|
||||||
|
if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(inventoryDto.getItemTable())) {
|
||||||
|
// 耗材只有一个单位,minUnitQuantity等于quantity
|
||||||
|
minUnitQuantity = saveDto.getQuantity();
|
||||||
|
} else {
|
||||||
|
return saveDto.getAdviceName() + "的小单位数量不能为空";
|
||||||
|
}
|
||||||
|
}
|
||||||
BigDecimal chineseHerbsDoseQuantity = saveDto.getChineseHerbsDoseQuantity(); // 中药付数
|
BigDecimal chineseHerbsDoseQuantity = saveDto.getChineseHerbsDoseQuantity(); // 中药付数
|
||||||
// 中草药医嘱的情况
|
// 中草药医嘱的情况
|
||||||
if (chineseHerbsDoseQuantity != null && chineseHerbsDoseQuantity.compareTo(BigDecimal.ZERO) > 0) {
|
if (chineseHerbsDoseQuantity != null && chineseHerbsDoseQuantity.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.openhis.web.lab.appservice;
|
||||||
|
|
||||||
|
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentSelParam;
|
||||||
|
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentUpDto;
|
||||||
|
import com.core.common.core.domain.R;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目 AppService 接口(独立操作 lab_activity_definition 表)
|
||||||
|
*/
|
||||||
|
public interface ILabActivityDefinitionAppService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询检验项目列表
|
||||||
|
*/
|
||||||
|
R<?> getLabActivityDefinitionPage(DiagnosisTreatmentSelParam selParam, String searchKey,
|
||||||
|
Integer pageNo, Integer pageSize, HttpServletRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询检验项目详情
|
||||||
|
*/
|
||||||
|
R<?> getLabActivityDefinitionOne(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增检验项目
|
||||||
|
*/
|
||||||
|
R<?> addLabActivityDefinition(DiagnosisTreatmentUpDto dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑检验项目
|
||||||
|
*/
|
||||||
|
R<?> editLabActivityDefinition(DiagnosisTreatmentUpDto dto);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停用检验项目
|
||||||
|
*/
|
||||||
|
R<?> stopLabActivityDefinition(List<Long> ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用检验项目
|
||||||
|
*/
|
||||||
|
R<?> startLabActivityDefinition(List<Long> ids);
|
||||||
|
}
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
package com.openhis.web.lab.appservice.impl;
|
||||||
|
|
||||||
|
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.core.domain.model.LoginUser;
|
||||||
|
import com.core.common.utils.*;
|
||||||
|
import com.core.common.utils.bean.BeanUtils;
|
||||||
|
import com.openhis.common.constant.PromptMsgConstant;
|
||||||
|
import com.openhis.common.enums.ActivityType;
|
||||||
|
import com.openhis.common.enums.PublicationStatus;
|
||||||
|
import com.openhis.common.enums.Whether;
|
||||||
|
import com.core.common.utils.ChineseConvertUtils;
|
||||||
|
import com.openhis.common.utils.EnumUtils;
|
||||||
|
import com.openhis.common.utils.HisQueryUtils;
|
||||||
|
import com.openhis.common.enums.AssignSeqEnum;
|
||||||
|
import com.openhis.lab.domain.LabActivityDefinition;
|
||||||
|
import com.openhis.lab.service.ILabActivityDefinitionService;
|
||||||
|
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto;
|
||||||
|
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentSelParam;
|
||||||
|
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentUpDto;
|
||||||
|
import com.openhis.web.lab.appservice.ILabActivityDefinitionAppService;
|
||||||
|
import com.openhis.web.datadictionary.mapper.LabActivityDefinitionManageMapper;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目 AppService 实现(独立操作 lab_activity_definition 表)
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class LabActivityDefinitionAppServiceImpl implements ILabActivityDefinitionAppService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ILabActivityDefinitionService labActivityDefinitionService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private LabActivityDefinitionManageMapper labActivityDefinitionManageMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AssignSeqUtil assignSeqUtil;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<?> getLabActivityDefinitionPage(DiagnosisTreatmentSelParam selParam, String searchKey,
|
||||||
|
Integer pageNo, Integer pageSize, HttpServletRequest request) {
|
||||||
|
if (selParam == null) {
|
||||||
|
selParam = new DiagnosisTreatmentSelParam();
|
||||||
|
}
|
||||||
|
if (selParam.getStatusEnum() == null) {
|
||||||
|
selParam.setStatusEnum(PublicationStatus.ACTIVE.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 临时移除需要手动拼别名条件的字段
|
||||||
|
Long inspectionTypeIdValue = null;
|
||||||
|
if (selParam.getInspectionTypeId() != null) {
|
||||||
|
inspectionTypeIdValue = selParam.getInspectionTypeId();
|
||||||
|
selParam.setInspectionTypeId(null);
|
||||||
|
}
|
||||||
|
Integer pricingFlagValue = null;
|
||||||
|
if (selParam.getPricingFlag() != null) {
|
||||||
|
pricingFlagValue = selParam.getPricingFlag();
|
||||||
|
selParam.setPricingFlag(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryWrapper<DiagnosisTreatmentDto> queryWrapper = HisQueryUtils.buildQueryWrapper(selParam,
|
||||||
|
searchKey, new HashSet<>(Arrays.asList("T1.bus_no", "T1.name", "T1.py_str", "T1.wb_str")), request);
|
||||||
|
|
||||||
|
if (inspectionTypeIdValue != null) {
|
||||||
|
queryWrapper.eq("T1.inspection_type_id", inspectionTypeIdValue);
|
||||||
|
selParam.setInspectionTypeId(inspectionTypeIdValue);
|
||||||
|
}
|
||||||
|
if (pricingFlagValue != null) {
|
||||||
|
queryWrapper.eq("T1.pricing_flag", pricingFlagValue);
|
||||||
|
selParam.setPricingFlag(pricingFlagValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
IPage<DiagnosisTreatmentDto> page = labActivityDefinitionManageMapper
|
||||||
|
.getLabActivityDefinitionPage(new Page<>(pageNo, pageSize), queryWrapper);
|
||||||
|
|
||||||
|
page.getRecords().forEach(e -> {
|
||||||
|
e.setYbFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getYbFlag()));
|
||||||
|
e.setYbMatchFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getYbMatchFlag()));
|
||||||
|
e.setTypeEnum_enumText(EnumUtils.getInfoByValue(ActivityType.class, e.getTypeEnum()));
|
||||||
|
e.setStatusEnum_enumText(EnumUtils.getInfoByValue(PublicationStatus.class, e.getStatusEnum()));
|
||||||
|
e.setPricingFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getPricingFlag()));
|
||||||
|
});
|
||||||
|
|
||||||
|
return R.ok(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<?> getLabActivityDefinitionOne(Long id) {
|
||||||
|
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
|
||||||
|
DiagnosisTreatmentDto dto = labActivityDefinitionManageMapper.getLabActivityDefinitionOne(id, tenantId);
|
||||||
|
return R.ok(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<?> addLabActivityDefinition(DiagnosisTreatmentUpDto dto) {
|
||||||
|
if (dto.getOrgId() == null) {
|
||||||
|
dto.setOrgId(SecurityUtils.getLoginUser().getHospitalId());
|
||||||
|
}
|
||||||
|
|
||||||
|
LabActivityDefinition lab = new LabActivityDefinition();
|
||||||
|
BeanUtils.copyProperties(dto, lab);
|
||||||
|
lab.setSortOrder(dto.getSortOrder())
|
||||||
|
.setServiceRange(dto.getServiceRange())
|
||||||
|
.setInspectionTypeId(dto.getInspectionTypeId())
|
||||||
|
.setFeePackageId(dto.getFeePackageId())
|
||||||
|
.setSubItemId(dto.getSubItemId());
|
||||||
|
|
||||||
|
if (StringUtils.isEmpty(lab.getBusNo())) {
|
||||||
|
lab.setBusNo(assignSeqUtil.getSeq(AssignSeqEnum.ACTIVITY_DEFINITION_NUM.getPrefix(), 10));
|
||||||
|
}
|
||||||
|
lab.setPyStr(ChineseConvertUtils.toPinyinFirstLetter(lab.getName()));
|
||||||
|
lab.setWbStr(ChineseConvertUtils.toWBFirstLetter(lab.getName()));
|
||||||
|
lab.setStatusEnum(PublicationStatus.ACTIVE.getValue());
|
||||||
|
|
||||||
|
// 设置创建者和租户ID
|
||||||
|
String createBy = "system";
|
||||||
|
Integer tenantId = null;
|
||||||
|
try {
|
||||||
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
|
if (loginUser != null) {
|
||||||
|
createBy = loginUser.getUsername();
|
||||||
|
tenantId = loginUser.getTenantId();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
// 使用默认值
|
||||||
|
}
|
||||||
|
lab.setCreateBy(createBy);
|
||||||
|
lab.setTenantId(tenantId != null ? tenantId : 1);
|
||||||
|
if (lab.getCreateTime() == null) {
|
||||||
|
lab.setCreateTime(new java.util.Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
return labActivityDefinitionService.addLabActivityDefinition(lab)
|
||||||
|
? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"检验项目"}))
|
||||||
|
: R.fail(null, "检验编码已存在:" + lab.getBusNo());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<?> editLabActivityDefinition(DiagnosisTreatmentUpDto dto) {
|
||||||
|
LabActivityDefinition lab = new LabActivityDefinition();
|
||||||
|
BeanUtils.copyProperties(dto, lab);
|
||||||
|
lab.setSortOrder(dto.getSortOrder())
|
||||||
|
.setServiceRange(dto.getServiceRange())
|
||||||
|
.setInspectionTypeId(dto.getInspectionTypeId())
|
||||||
|
.setFeePackageId(dto.getFeePackageId())
|
||||||
|
.setSubItemId(dto.getSubItemId())
|
||||||
|
.setPricingFlag(dto.getPricingFlag());
|
||||||
|
lab.setPyStr(ChineseConvertUtils.toPinyinFirstLetter(lab.getName()));
|
||||||
|
lab.setWbStr(ChineseConvertUtils.toWBFirstLetter(lab.getName()));
|
||||||
|
|
||||||
|
return labActivityDefinitionService.updateById(lab)
|
||||||
|
? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"检验项目"}))
|
||||||
|
: R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<?> stopLabActivityDefinition(List<Long> ids) {
|
||||||
|
List<LabActivityDefinition> labList = new CopyOnWriteArrayList<>();
|
||||||
|
for (Long id : ids) {
|
||||||
|
LabActivityDefinition lab = new LabActivityDefinition();
|
||||||
|
lab.setId(id).setStatusEnum(PublicationStatus.RETIRED.getValue());
|
||||||
|
labList.add(lab);
|
||||||
|
}
|
||||||
|
labActivityDefinitionService.updateBatchById(labList);
|
||||||
|
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"检验项目"}));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public R<?> startLabActivityDefinition(List<Long> ids) {
|
||||||
|
List<LabActivityDefinition> labList = new CopyOnWriteArrayList<>();
|
||||||
|
for (Long id : ids) {
|
||||||
|
LabActivityDefinition lab = new LabActivityDefinition();
|
||||||
|
lab.setId(id).setStatusEnum(PublicationStatus.ACTIVE.getValue());
|
||||||
|
labList.add(lab);
|
||||||
|
}
|
||||||
|
labActivityDefinitionService.updateBatchById(labList);
|
||||||
|
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"检验项目"}));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,7 +94,6 @@ public class InspectionTypeController extends BaseController {
|
|||||||
|
|
||||||
// 查询是否存在相同编码的记录
|
// 查询是否存在相同编码的记录
|
||||||
List<InspectionType> existingRecords = inspectionTypeService.list(queryWrapper);
|
List<InspectionType> existingRecords = inspectionTypeService.list(queryWrapper);
|
||||||
log.debug("检查编码唯一性:code={}, 数据库中存在记录数={}", inspectionType.getCode(), existingRecords.size());
|
|
||||||
|
|
||||||
if (!existingRecords.isEmpty()) {
|
if (!existingRecords.isEmpty()) {
|
||||||
return AjaxResult.error("检验类型编码已存在");
|
return AjaxResult.error("检验类型编码已存在");
|
||||||
@@ -119,8 +118,6 @@ public class InspectionTypeController extends BaseController {
|
|||||||
return toAjax(result);
|
return toAjax(result);
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("新增检验类型失败:code={}, 错误信息:{}", inspectionType.getCode(), e.getMessage(), e);
|
|
||||||
|
|
||||||
// 捕获唯一性约束冲突异常
|
// 捕获唯一性约束冲突异常
|
||||||
if (e.getMessage().contains("uk_inspection_type_code") ||
|
if (e.getMessage().contains("uk_inspection_type_code") ||
|
||||||
e.getMessage().contains("duplicate key value") ||
|
e.getMessage().contains("duplicate key value") ||
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package com.openhis.web.lab.controller;
|
||||||
|
|
||||||
|
import com.core.common.core.domain.R;
|
||||||
|
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentSelParam;
|
||||||
|
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentUpDto;
|
||||||
|
import com.openhis.web.lab.appservice.ILabActivityDefinitionAppService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目维护 Controller(独立操作 lab_activity_definition 表)
|
||||||
|
* 路径前缀:/lab/activity-definition
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/lab/activity-definition")
|
||||||
|
@Slf4j
|
||||||
|
public class LabActivityDefinitionController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ILabActivityDefinitionAppService labActivityDefinitionAppService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询检验项目列表
|
||||||
|
*/
|
||||||
|
@GetMapping("/page")
|
||||||
|
public R<?> getPage(DiagnosisTreatmentSelParam selParam,
|
||||||
|
@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
|
||||||
|
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
|
||||||
|
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
return labActivityDefinitionAppService.getLabActivityDefinitionPage(selParam, searchKey, pageNo, pageSize, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据id查询检验项目详情
|
||||||
|
*/
|
||||||
|
@GetMapping("/one")
|
||||||
|
public R<?> getOne(@RequestParam Long id) {
|
||||||
|
return labActivityDefinitionAppService.getLabActivityDefinitionOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增检验项目
|
||||||
|
*/
|
||||||
|
@PostMapping("/add")
|
||||||
|
public R<?> add(@Validated @RequestBody DiagnosisTreatmentUpDto dto) {
|
||||||
|
return labActivityDefinitionAppService.addLabActivityDefinition(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑检验项目
|
||||||
|
*/
|
||||||
|
@PutMapping("/edit")
|
||||||
|
public R<?> edit(@RequestBody DiagnosisTreatmentUpDto dto) {
|
||||||
|
return labActivityDefinitionAppService.editLabActivityDefinition(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 停用检验项目
|
||||||
|
*/
|
||||||
|
@PutMapping("/stop")
|
||||||
|
public R<?> stop(@RequestBody List<Long> ids) {
|
||||||
|
return labActivityDefinitionAppService.stopLabActivityDefinition(ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启用检验项目
|
||||||
|
*/
|
||||||
|
@PutMapping("/start")
|
||||||
|
public R<?> start(@RequestBody List<Long> ids) {
|
||||||
|
return labActivityDefinitionAppService.startLabActivityDefinition(ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,6 +55,8 @@ import com.openhis.web.paymentmanage.dto.CancelPaymentDto;
|
|||||||
import com.openhis.web.paymentmanage.dto.Clinic2207OrderResultDto;
|
import com.openhis.web.paymentmanage.dto.Clinic2207OrderResultDto;
|
||||||
import com.openhis.web.paymentmanage.mapper.PaymentMapper;
|
import com.openhis.web.paymentmanage.mapper.PaymentMapper;
|
||||||
import com.openhis.web.personalization.dto.ActivityDeviceDto;
|
import com.openhis.web.personalization.dto.ActivityDeviceDto;
|
||||||
|
import com.openhis.triageandqueuemanage.domain.TriageQueueItem;
|
||||||
|
import com.openhis.triageandqueuemanage.service.TriageQueueItemService;
|
||||||
import com.openhis.workflow.domain.ServiceRequest;
|
import com.openhis.workflow.domain.ServiceRequest;
|
||||||
import com.openhis.workflow.service.IDeviceDispenseService;
|
import com.openhis.workflow.service.IDeviceDispenseService;
|
||||||
import com.openhis.workflow.service.IDeviceRequestService;
|
import com.openhis.workflow.service.IDeviceRequestService;
|
||||||
@@ -81,9 +83,11 @@ import javax.annotation.Resource;
|
|||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -149,6 +153,8 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
@Resource
|
@Resource
|
||||||
private OutpatientRegistrationAppMapper outpatientRegistrationAppMapper;
|
private OutpatientRegistrationAppMapper outpatientRegistrationAppMapper;
|
||||||
@Resource
|
@Resource
|
||||||
|
private TriageQueueItemService triageQueueItemService;
|
||||||
|
@Resource
|
||||||
private IRegService iRegService;
|
private IRegService iRegService;
|
||||||
@Resource
|
@Resource
|
||||||
private IPatientService iPatientService;
|
private IPatientService iPatientService;
|
||||||
@@ -255,7 +261,9 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
|
|
||||||
// 账户id,对应的账单列表
|
// 账户id,对应的账单列表
|
||||||
Map<Long, List<ChargeItem>> chargeItemMapByAccountId
|
Map<Long, List<ChargeItem>> chargeItemMapByAccountId
|
||||||
= chargeItemList.stream().collect(Collectors.groupingBy(ChargeItem::getAccountId));
|
= chargeItemList.stream()
|
||||||
|
.filter(item -> item.getAccountId() != null)
|
||||||
|
.collect(Collectors.groupingBy(ChargeItem::getAccountId));
|
||||||
// 查询合同信息
|
// 查询合同信息
|
||||||
List<Contract> contractList = contractService.list();
|
List<Contract> contractList = contractService.list();
|
||||||
|
|
||||||
@@ -1928,6 +1936,80 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
|
|
||||||
// 就诊ID
|
// 就诊ID
|
||||||
Long encounterId = iEncounterService.saveEncounterByRegister(encounter);
|
Long encounterId = iEncounterService.saveEncounterByRegister(encounter);
|
||||||
|
|
||||||
|
// 创建 triage_queue_item 队列记录
|
||||||
|
try {
|
||||||
|
Integer tenantId = encounter.getTenantId() != null ? encounter.getTenantId() : SecurityUtils.getLoginUser().getTenantId();
|
||||||
|
LocalDate queueDate = LocalDate.now();
|
||||||
|
|
||||||
|
// 查询当前科室当天的最大排队序号
|
||||||
|
Integer maxOrder = triageQueueItemService.list(
|
||||||
|
new LambdaQueryWrapper<TriageQueueItem>()
|
||||||
|
.eq(TriageQueueItem::getTenantId, tenantId)
|
||||||
|
.eq(TriageQueueItem::getOrganizationId, encounter.getOrganizationId())
|
||||||
|
.eq(TriageQueueItem::getQueueDate, queueDate)
|
||||||
|
.eq(TriageQueueItem::getDeleteFlag, "0")
|
||||||
|
.ne(TriageQueueItem::getStatus, "COMPLETED")
|
||||||
|
).stream()
|
||||||
|
.map(TriageQueueItem::getQueueOrder)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.max(Integer::compareTo)
|
||||||
|
.orElse(0);
|
||||||
|
|
||||||
|
// 获取患者信息
|
||||||
|
Patient patient = iPatientService.getById(encounter.getPatientId());
|
||||||
|
String patientName = patient != null ? patient.getName() : null;
|
||||||
|
|
||||||
|
// 获取挂号医生信息
|
||||||
|
String practitionerName = null;
|
||||||
|
Long queuePractitionerId = null;
|
||||||
|
if (encounterParticipantFormData.getPractitionerId() != null) {
|
||||||
|
Practitioner practitioner = iPractitionerService.getById(encounterParticipantFormData.getPractitionerId());
|
||||||
|
if (practitioner != null) {
|
||||||
|
practitionerName = practitioner.getName();
|
||||||
|
queuePractitionerId = practitioner.getId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取科室信息
|
||||||
|
Organization organization = iOrganizationService.getById(encounter.getOrganizationId());
|
||||||
|
String organizationName = organization != null ? organization.getName() : null;
|
||||||
|
|
||||||
|
// 获取服务项目信息(挂号类型)
|
||||||
|
String healthcareName = null;
|
||||||
|
if (encounter.getServiceTypeId() != null) {
|
||||||
|
HealthcareService healthcareService = healthcareServiceService.getById(encounter.getServiceTypeId());
|
||||||
|
if (healthcareService != null) {
|
||||||
|
healthcareName = healthcareService.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建队列项
|
||||||
|
TriageQueueItem queueItem = new TriageQueueItem()
|
||||||
|
.setTenantId(tenantId)
|
||||||
|
.setQueueDate(queueDate)
|
||||||
|
.setOrganizationId(encounter.getOrganizationId())
|
||||||
|
.setOrganizationName(organizationName)
|
||||||
|
.setEncounterId(encounterId)
|
||||||
|
.setPatientId(encounter.getPatientId())
|
||||||
|
.setPatientName(patientName)
|
||||||
|
.setHealthcareName(healthcareName)
|
||||||
|
.setPractitionerId(queuePractitionerId)
|
||||||
|
.setPractitionerName(practitionerName)
|
||||||
|
.setRoomNo(null)
|
||||||
|
.setStatus("WAITING")
|
||||||
|
.setQueueOrder(maxOrder + 1)
|
||||||
|
.setDeleteFlag("0")
|
||||||
|
.setCreateTime(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS))
|
||||||
|
.setUpdateTime(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
|
||||||
|
|
||||||
|
triageQueueItemService.save(queueItem);
|
||||||
|
logger.info("挂号时创建队列记录成功,encounterId={}, queueItemId={}", encounterId, queueItem.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("挂号时创建队列记录失败,encounterId={}", encounterId, e);
|
||||||
|
// 队列记录创建失败不影响挂号流程
|
||||||
|
}
|
||||||
|
|
||||||
// 保存就诊位置信息
|
// 保存就诊位置信息
|
||||||
// 挂号时不选Location了
|
// 挂号时不选Location了
|
||||||
// encounterLocationFormData.setEncounterId(encounterId);
|
// encounterLocationFormData.setEncounterId(encounterId);
|
||||||
@@ -2251,7 +2333,9 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
= iChargeItemService.getChargeItemBaseInfoByIds(prePaymentDto.getChargeItemIds());
|
= iChargeItemService.getChargeItemBaseInfoByIds(prePaymentDto.getChargeItemIds());
|
||||||
|
|
||||||
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
|
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
|
||||||
= chargeItemBaseInfoByIds.stream().collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
|
= chargeItemBaseInfoByIds.stream()
|
||||||
|
.filter(dto -> dto.getContractNo() != null && !dto.getContractNo().isEmpty())
|
||||||
|
.collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
|
||||||
|
|
||||||
List<InpatientPreSettleDto> yb2303OutputSetInfos = new ArrayList<>();
|
List<InpatientPreSettleDto> yb2303OutputSetInfos = new ArrayList<>();
|
||||||
Yb2303OutputSetInfo yb2303OutputSetInfo;
|
Yb2303OutputSetInfo yb2303OutputSetInfo;
|
||||||
@@ -2379,13 +2463,17 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
List<ChargeItemBaseInfoDto> chargeItemBaseInfoByIds
|
List<ChargeItemBaseInfoDto> chargeItemBaseInfoByIds
|
||||||
= iChargeItemService.getChargeItemBaseInfoByIds(paymentDto.getChargeItemIds());
|
= iChargeItemService.getChargeItemBaseInfoByIds(paymentDto.getChargeItemIds());
|
||||||
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
|
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
|
||||||
= chargeItemBaseInfoByIds.stream().collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
|
= chargeItemBaseInfoByIds.stream()
|
||||||
|
.filter(dto -> dto.getContractNo() != null && !dto.getContractNo().isEmpty())
|
||||||
|
.collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
|
||||||
|
|
||||||
List<Account> accountList = iAccountService.getAccountListByEncounter(paymentDto.getEncounterId());
|
List<Account> accountList = iAccountService.getAccountListByEncounter(paymentDto.getEncounterId());
|
||||||
if (accountList.isEmpty()) {
|
if (accountList.isEmpty()) {
|
||||||
throw new ServiceException("未查询到账户信息");
|
throw new ServiceException("未查询到账户信息");
|
||||||
}
|
}
|
||||||
Map<Long, List<Account>> accountKVById = accountList.stream().collect(Collectors.groupingBy(Account::getId));
|
Map<Long, List<Account>> accountKVById = accountList.stream()
|
||||||
|
.filter(acc -> acc.getId() != null)
|
||||||
|
.collect(Collectors.groupingBy(Account::getId));
|
||||||
|
|
||||||
com.openhis.financial.model.PaymentResult paymentResult;
|
com.openhis.financial.model.PaymentResult paymentResult;
|
||||||
List<com.openhis.financial.model.PaymentResult> paymentResultList = new ArrayList<>();
|
List<com.openhis.financial.model.PaymentResult> paymentResultList = new ArrayList<>();
|
||||||
@@ -2395,7 +2483,9 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
|
|||||||
|
|
||||||
// <3>收费详情按照收费批次进行分组后结算
|
// <3>收费详情按照收费批次进行分组后结算
|
||||||
Map<Long, List<PaymentRecDetail>> payTransNoMap
|
Map<Long, List<PaymentRecDetail>> payTransNoMap
|
||||||
= paymentRecDetails.stream().collect(Collectors.groupingBy(PaymentRecDetail::getAccountId));
|
= paymentRecDetails.stream()
|
||||||
|
.filter(detail -> detail.getAccountId() != null)
|
||||||
|
.collect(Collectors.groupingBy(PaymentRecDetail::getAccountId));
|
||||||
|
|
||||||
for (Map.Entry<Long, List<PaymentRecDetail>> stringListEntry : payTransNoMap.entrySet()) {
|
for (Map.Entry<Long, List<PaymentRecDetail>> stringListEntry : payTransNoMap.entrySet()) {
|
||||||
// paymentResult = new PaymentResult();
|
// paymentResult = new PaymentResult();
|
||||||
|
|||||||
@@ -216,136 +216,186 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 如果是手术申请单,需要额外生成手术医嘱
|
// 如果是手术申请单,需要额外生成手术医嘱
|
||||||
if (ActivityDefCategory.PROCEDURE.getCode().equals(typeCode)) {
|
log.info("【调试】判断手术医嘱生成条件: typeCode={}, PROCEDURE.code={}, typeCode类型={}, PROCEDURE.code类型={}",
|
||||||
log.info("开始生成手术医嘱,encounterId={}, patientId={}, typeCode={}", encounterId, patientId, typeCode);
|
typeCode, ActivityDefCategory.PROCEDURE.getCode(),
|
||||||
// 从 descJson 中解析手术信息
|
typeCode != null ? typeCode.getClass().getName() : "null",
|
||||||
String descJson = requestFormSaveDto.getDescJson();
|
ActivityDefCategory.PROCEDURE.getCode().getClass().getName());
|
||||||
Map<String, Object> descMap = null;
|
boolean isProcedure = ActivityDefCategory.PROCEDURE.getCode().equals(typeCode);
|
||||||
if (descJson != null && !descJson.isEmpty()) {
|
log.info("【调试】判断结果: isProcedure={}, typeCode字符串={}, PROCEDURE.code字符串={}",
|
||||||
try {
|
isProcedure,
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
typeCode != null ? "'" + typeCode + "'" : "null",
|
||||||
descMap = objectMapper.readValue(descJson, Map.class);
|
"'" + ActivityDefCategory.PROCEDURE.getCode() + "'");
|
||||||
} catch (Exception e) {
|
if (isProcedure) {
|
||||||
log.error("解析手术申请单 descJson 失败", e);
|
log.info("开始生成手术医嘱,encounterId={}, patientId={}, typeCode={}, activityListSize={}",
|
||||||
}
|
encounterId, patientId, typeCode, activityList != null ? activityList.size() : 0);
|
||||||
}
|
try {
|
||||||
|
// 从 descJson 中解析手术信息
|
||||||
// 获取手术信息
|
String descJson = requestFormSaveDto.getDescJson();
|
||||||
String surgeryName = descMap != null ? (String) descMap.get("surgeryName") : null;
|
Map<String, Object> descMap = null;
|
||||||
String surgeryCode = descMap != null ? (String) descMap.get("surgeryCode") : null;
|
if (descJson != null && !descJson.isEmpty()) {
|
||||||
String surgeryFee = descMap != null ? (String) descMap.get("surgeryFee") : null;
|
try {
|
||||||
String anesthesiaFee = descMap != null ? (String) descMap.get("anesthesiaFee") : null;
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
String plannedTime = descMap != null ? (String) descMap.get("plannedTime") : null;
|
descMap = objectMapper.readValue(descJson, Map.class);
|
||||||
String surgeryIndication = descMap != null ? (String) descMap.get("surgeryIndication") : null;
|
log.info("解析手术申请单 descJson 成功: {}", descMap);
|
||||||
String preoperativeDiagnosis = descMap != null ? (String) descMap.get("preoperativeDiagnosis") : null;
|
} catch (Exception e) {
|
||||||
|
log.error("解析手术申请单 descJson 失败: {}", descJson, e);
|
||||||
// 生成手术医嘱
|
|
||||||
ServiceRequest surgeryServiceRequest = new ServiceRequest();
|
|
||||||
surgeryServiceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());
|
|
||||||
surgeryServiceRequest.setBusNo(String.format("%04d", (int) (Math.random() * 10000)));
|
|
||||||
surgeryServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
|
|
||||||
surgeryServiceRequest.setPrescriptionNo(prescriptionNo);
|
|
||||||
surgeryServiceRequest.setTherapyEnum(TherapyTimeType.TEMPORARY.getValue());
|
|
||||||
surgeryServiceRequest.setQuantity(BigDecimal.valueOf(1));
|
|
||||||
surgeryServiceRequest.setUnitCode("次");
|
|
||||||
surgeryServiceRequest.setCategoryEnum(4); // 4-手术
|
|
||||||
// 优先从 activityList 获取手术 ID,如果为空则从 descJson 获取
|
|
||||||
if (!activityList.isEmpty()) {
|
|
||||||
surgeryServiceRequest.setActivityId(activityList.get(0).getAdviceDefinitionId());
|
|
||||||
}
|
|
||||||
surgeryServiceRequest.setPatientId(patientId);
|
|
||||||
surgeryServiceRequest.setRequesterId(practitionerId);
|
|
||||||
surgeryServiceRequest.setEncounterId(encounterId);
|
|
||||||
surgeryServiceRequest.setAuthoredTime(curDate);
|
|
||||||
surgeryServiceRequest.setOrgId(orgId);
|
|
||||||
// 设置手术相关信息到 contentJson 字段
|
|
||||||
Map<String, String> contentMap = new java.util.HashMap<>();
|
|
||||||
if (surgeryName != null && !surgeryName.isEmpty()) {
|
|
||||||
contentMap.put("surgeryName", surgeryName);
|
|
||||||
}
|
|
||||||
if (surgeryCode != null && !surgeryCode.isEmpty()) {
|
|
||||||
contentMap.put("surgeryCode", surgeryCode);
|
|
||||||
}
|
|
||||||
if (plannedTime != null && !plannedTime.isEmpty()) {
|
|
||||||
contentMap.put("plannedTime", plannedTime);
|
|
||||||
}
|
|
||||||
if (surgeryIndication != null && !surgeryIndication.isEmpty()) {
|
|
||||||
contentMap.put("surgeryIndication", surgeryIndication);
|
|
||||||
}
|
|
||||||
if (preoperativeDiagnosis != null && !preoperativeDiagnosis.isEmpty()) {
|
|
||||||
contentMap.put("preoperativeDiagnosis", preoperativeDiagnosis);
|
|
||||||
}
|
|
||||||
if (!contentMap.isEmpty()) {
|
|
||||||
try {
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
surgeryServiceRequest.setContentJson(objectMapper.writeValueAsString(contentMap));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("序列化手术信息失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iServiceRequestService.save(surgeryServiceRequest);
|
|
||||||
log.info("手术医嘱生成成功,serviceRequestId={}, prescriptionNo={}", surgeryServiceRequest.getId(), prescriptionNo);
|
|
||||||
|
|
||||||
// 生成手术收费项目
|
|
||||||
ChargeItem surgeryChargeItem = new ChargeItem();
|
|
||||||
surgeryChargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
|
|
||||||
surgeryChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
|
|
||||||
surgeryChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
|
|
||||||
surgeryChargeItem.setPatientId(patientId);
|
|
||||||
surgeryChargeItem.setContextEnum(3); // 3-诊疗
|
|
||||||
surgeryChargeItem.setEncounterId(encounterId);
|
|
||||||
surgeryChargeItem.setEntererId(practitionerId);
|
|
||||||
surgeryChargeItem.setEnteredDate(curDate);
|
|
||||||
surgeryChargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
|
|
||||||
surgeryChargeItem.setServiceId(surgeryServiceRequest.getId());
|
|
||||||
surgeryChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
|
|
||||||
// 优先从 activityList 获取 productId,如果为空则不设置
|
|
||||||
if (!activityList.isEmpty()) {
|
|
||||||
surgeryChargeItem.setProductId(activityList.get(0).getAdviceDefinitionId());
|
|
||||||
}
|
|
||||||
surgeryChargeItem.setAccountId(activityList.isEmpty() ? null : activityList.get(0).getAccountId());
|
|
||||||
surgeryChargeItem.setRequestingOrgId(orgId);
|
|
||||||
surgeryChargeItem.setQuantityValue(BigDecimal.valueOf(1));
|
|
||||||
surgeryChargeItem.setQuantityUnit("次");
|
|
||||||
// 设置手术费用
|
|
||||||
if (surgeryFee != null && !surgeryFee.isEmpty()) {
|
|
||||||
try {
|
|
||||||
surgeryChargeItem.setUnitPrice(new BigDecimal(surgeryFee));
|
|
||||||
surgeryChargeItem.setTotalPrice(new BigDecimal(surgeryFee));
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
log.warn("手术费用格式不正确:{}", surgeryFee);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
iChargeItemService.save(surgeryChargeItem);
|
|
||||||
|
|
||||||
// 如果存在麻醉费用,生成麻醉收费项目
|
|
||||||
if (anesthesiaFee != null && !anesthesiaFee.isEmpty()) {
|
|
||||||
try {
|
|
||||||
BigDecimal anesthesiaFeeAmount = new BigDecimal(anesthesiaFee);
|
|
||||||
if (anesthesiaFeeAmount.compareTo(BigDecimal.ZERO) > 0) {
|
|
||||||
ChargeItem anesthesiaChargeItem = new ChargeItem();
|
|
||||||
anesthesiaChargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
|
|
||||||
anesthesiaChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
|
|
||||||
anesthesiaChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
|
|
||||||
anesthesiaChargeItem.setPatientId(patientId);
|
|
||||||
anesthesiaChargeItem.setContextEnum(3); // 3-诊疗
|
|
||||||
anesthesiaChargeItem.setEncounterId(encounterId);
|
|
||||||
anesthesiaChargeItem.setEntererId(practitionerId);
|
|
||||||
anesthesiaChargeItem.setEnteredDate(curDate);
|
|
||||||
anesthesiaChargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
|
|
||||||
anesthesiaChargeItem.setServiceId(surgeryServiceRequest.getId());
|
|
||||||
anesthesiaChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
|
|
||||||
anesthesiaChargeItem.setRequestingOrgId(orgId);
|
|
||||||
anesthesiaChargeItem.setQuantityValue(BigDecimal.valueOf(1));
|
|
||||||
anesthesiaChargeItem.setQuantityUnit("次");
|
|
||||||
anesthesiaChargeItem.setUnitPrice(anesthesiaFeeAmount);
|
|
||||||
anesthesiaChargeItem.setTotalPrice(anesthesiaFeeAmount);
|
|
||||||
iChargeItemService.save(anesthesiaChargeItem);
|
|
||||||
}
|
}
|
||||||
} catch (NumberFormatException e) {
|
} else {
|
||||||
log.warn("麻醉费用格式不正确:{}", anesthesiaFee);
|
log.warn("手术申请单 descJson 为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取手术信息
|
||||||
|
String surgeryName = descMap != null ? (String) descMap.get("surgeryName") : null;
|
||||||
|
String surgeryCode = descMap != null ? (String) descMap.get("surgeryCode") : null;
|
||||||
|
String surgeryFee = descMap != null ? (String) descMap.get("surgeryFee") : null;
|
||||||
|
String anesthesiaFee = descMap != null ? (String) descMap.get("anesthesiaFee") : null;
|
||||||
|
String plannedTime = descMap != null ? (String) descMap.get("plannedTime") : null;
|
||||||
|
String surgeryIndication = descMap != null ? (String) descMap.get("surgeryIndication") : null;
|
||||||
|
String preoperativeDiagnosis = descMap != null ? (String) descMap.get("preoperativeDiagnosis") : null;
|
||||||
|
|
||||||
|
// 🔧 BugFix#318: 从 activityList 获取手术项目名称
|
||||||
|
String adviceDefinitionName = null;
|
||||||
|
if (activityList != null && !activityList.isEmpty()) {
|
||||||
|
adviceDefinitionName = activityList.get(0).getAdviceDefinitionName();
|
||||||
|
log.info("从 activityList 获取手术项目名称: {}", adviceDefinitionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("手术信息: surgeryName={}, surgeryCode={}, surgeryFee={}, anesthesiaFee={}, adviceDefinitionName={}",
|
||||||
|
surgeryName, surgeryCode, surgeryFee, anesthesiaFee, adviceDefinitionName);
|
||||||
|
|
||||||
|
// 生成手术医嘱
|
||||||
|
ServiceRequest surgeryServiceRequest = new ServiceRequest();
|
||||||
|
surgeryServiceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());
|
||||||
|
surgeryServiceRequest.setBusNo(String.format("%04d", (int) (Math.random() * 10000)));
|
||||||
|
surgeryServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
|
||||||
|
surgeryServiceRequest.setPrescriptionNo(prescriptionNo);
|
||||||
|
surgeryServiceRequest.setTherapyEnum(TherapyTimeType.TEMPORARY.getValue());
|
||||||
|
surgeryServiceRequest.setQuantity(BigDecimal.valueOf(1));
|
||||||
|
surgeryServiceRequest.setUnitCode("次");
|
||||||
|
surgeryServiceRequest.setCategoryEnum(4); // 4-手术
|
||||||
|
// 优先从 activityList 获取手术 ID
|
||||||
|
if (activityList != null && !activityList.isEmpty()) {
|
||||||
|
Long activityId = activityList.get(0).getAdviceDefinitionId();
|
||||||
|
surgeryServiceRequest.setActivityId(activityId);
|
||||||
|
log.info("从 activityList 获取手术ID: {}", activityId);
|
||||||
|
} else {
|
||||||
|
log.warn("activityList 为空,无法获取手术ID");
|
||||||
|
}
|
||||||
|
surgeryServiceRequest.setPatientId(patientId);
|
||||||
|
surgeryServiceRequest.setRequesterId(practitionerId);
|
||||||
|
surgeryServiceRequest.setEncounterId(encounterId);
|
||||||
|
surgeryServiceRequest.setAuthoredTime(curDate);
|
||||||
|
surgeryServiceRequest.setOrgId(orgId);
|
||||||
|
|
||||||
|
// 设置手术相关信息到 contentJson 字段
|
||||||
|
Map<String, String> contentMap = new java.util.HashMap<>();
|
||||||
|
// 🔧 BugFix#318: 优先使用 activityList 中的手术项目名称
|
||||||
|
if (adviceDefinitionName != null && !adviceDefinitionName.isEmpty()) {
|
||||||
|
contentMap.put("surgeryName", adviceDefinitionName);
|
||||||
|
} else if (surgeryName != null && !surgeryName.isEmpty()) {
|
||||||
|
contentMap.put("surgeryName", surgeryName);
|
||||||
|
}
|
||||||
|
if (surgeryCode != null && !surgeryCode.isEmpty()) {
|
||||||
|
contentMap.put("surgeryCode", surgeryCode);
|
||||||
|
}
|
||||||
|
if (plannedTime != null && !plannedTime.isEmpty()) {
|
||||||
|
contentMap.put("plannedTime", plannedTime);
|
||||||
|
}
|
||||||
|
if (surgeryIndication != null && !surgeryIndication.isEmpty()) {
|
||||||
|
contentMap.put("surgeryIndication", surgeryIndication);
|
||||||
|
}
|
||||||
|
if (preoperativeDiagnosis != null && !preoperativeDiagnosis.isEmpty()) {
|
||||||
|
contentMap.put("preoperativeDiagnosis", preoperativeDiagnosis);
|
||||||
|
}
|
||||||
|
if (!contentMap.isEmpty()) {
|
||||||
|
try {
|
||||||
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
surgeryServiceRequest.setContentJson(objectMapper.writeValueAsString(contentMap));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("序列化手术信息失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
iServiceRequestService.save(surgeryServiceRequest);
|
||||||
|
log.info("手术医嘱生成成功,serviceRequestId={}, prescriptionNo={}", surgeryServiceRequest.getId(), prescriptionNo);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("保存手术医嘱失败", e);
|
||||||
|
throw new ServiceException("保存手术医嘱失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成手术收费项目
|
||||||
|
try {
|
||||||
|
ChargeItem surgeryChargeItem = new ChargeItem();
|
||||||
|
surgeryChargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
|
||||||
|
surgeryChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
|
||||||
|
surgeryChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
|
||||||
|
surgeryChargeItem.setPatientId(patientId);
|
||||||
|
surgeryChargeItem.setContextEnum(6); // 6-手术
|
||||||
|
surgeryChargeItem.setEncounterId(encounterId);
|
||||||
|
surgeryChargeItem.setEntererId(practitionerId);
|
||||||
|
surgeryChargeItem.setEnteredDate(curDate);
|
||||||
|
surgeryChargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
|
||||||
|
surgeryChargeItem.setServiceId(surgeryServiceRequest.getId());
|
||||||
|
surgeryChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
|
||||||
|
// 优先从 activityList 获取 productId
|
||||||
|
if (activityList != null && !activityList.isEmpty()) {
|
||||||
|
surgeryChargeItem.setProductId(activityList.get(0).getAdviceDefinitionId());
|
||||||
|
surgeryChargeItem.setAccountId(activityList.get(0).getAccountId());
|
||||||
|
}
|
||||||
|
surgeryChargeItem.setRequestingOrgId(orgId);
|
||||||
|
surgeryChargeItem.setQuantityValue(BigDecimal.valueOf(1));
|
||||||
|
surgeryChargeItem.setQuantityUnit("次");
|
||||||
|
// 设置手术费用
|
||||||
|
if (surgeryFee != null && !surgeryFee.isEmpty()) {
|
||||||
|
try {
|
||||||
|
surgeryChargeItem.setUnitPrice(new BigDecimal(surgeryFee));
|
||||||
|
surgeryChargeItem.setTotalPrice(new BigDecimal(surgeryFee));
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("手术费用格式不正确:{}", surgeryFee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iChargeItemService.save(surgeryChargeItem);
|
||||||
|
log.info("手术收费项目生成成功,chargeItemId={}", surgeryChargeItem.getId());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("生成手术收费项目失败", e);
|
||||||
|
throw new ServiceException("生成手术收费项目失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果存在麻醉费用,生成麻醉收费项目
|
||||||
|
if (anesthesiaFee != null && !anesthesiaFee.isEmpty()) {
|
||||||
|
try {
|
||||||
|
BigDecimal anesthesiaFeeAmount = new BigDecimal(anesthesiaFee);
|
||||||
|
if (anesthesiaFeeAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
ChargeItem anesthesiaChargeItem = new ChargeItem();
|
||||||
|
anesthesiaChargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
|
||||||
|
anesthesiaChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
|
||||||
|
anesthesiaChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
|
||||||
|
anesthesiaChargeItem.setPatientId(patientId);
|
||||||
|
anesthesiaChargeItem.setContextEnum(3); // 3-诊疗
|
||||||
|
anesthesiaChargeItem.setEncounterId(encounterId);
|
||||||
|
anesthesiaChargeItem.setEntererId(practitionerId);
|
||||||
|
anesthesiaChargeItem.setEnteredDate(curDate);
|
||||||
|
anesthesiaChargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
|
||||||
|
anesthesiaChargeItem.setServiceId(surgeryServiceRequest.getId());
|
||||||
|
anesthesiaChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
|
||||||
|
anesthesiaChargeItem.setRequestingOrgId(orgId);
|
||||||
|
anesthesiaChargeItem.setQuantityValue(BigDecimal.valueOf(1));
|
||||||
|
anesthesiaChargeItem.setQuantityUnit("次");
|
||||||
|
anesthesiaChargeItem.setUnitPrice(anesthesiaFeeAmount);
|
||||||
|
anesthesiaChargeItem.setTotalPrice(anesthesiaFeeAmount);
|
||||||
|
iChargeItemService.save(anesthesiaChargeItem);
|
||||||
|
log.info("麻醉收费项目生成成功");
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
log.warn("麻醉费用格式不正确:{}", anesthesiaFee);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("生成手术医嘱过程中发生异常", e);
|
||||||
|
throw e;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
log.info("不是手术申请单,跳过手术医嘱生成,typeCode={}", typeCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[] {"申请单"}));
|
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[] {"申请单"}));
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ public class RequestFormManageController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping(value = "/save-surgery")
|
@PostMapping(value = "/save-surgery")
|
||||||
public R<?> saveSurgeryRequestForm(@RequestBody RequestFormSaveDto requestFormSaveDto) {
|
public R<?> saveSurgeryRequestForm(@RequestBody RequestFormSaveDto requestFormSaveDto) {
|
||||||
|
log.info("【Controller】保存手术申请单,typeCode={}", ActivityDefCategory.PROCEDURE.getCode());
|
||||||
return iRequestFormManageAppService.saveRequestForm(requestFormSaveDto,
|
return iRequestFormManageAppService.saveRequestForm(requestFormSaveDto,
|
||||||
ActivityDefCategory.PROCEDURE.getCode());
|
ActivityDefCategory.PROCEDURE.getCode());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,4 +93,9 @@ public class RequestFormPageDto {
|
|||||||
* 手术等级
|
* 手术等级
|
||||||
*/
|
*/
|
||||||
private Integer surgeryLevel;
|
private Integer surgeryLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 就诊卡号
|
||||||
|
*/
|
||||||
|
private String identifierNo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="patientAge" column="patient_age" />
|
<result property="patientAge" column="patient_age" />
|
||||||
<result property="encounterId" column="encounter_id" />
|
<result property="encounterId" column="encounter_id" />
|
||||||
<result property="encounterNo" column="encounter_no" />
|
<result property="encounterNo" column="encounter_no" />
|
||||||
|
<result property="patientCardNo" column="patient_card_no" />
|
||||||
<result property="applyDoctorId" column="apply_doctor_id" />
|
<result property="applyDoctorId" column="apply_doctor_id" />
|
||||||
<result property="applyDoctorName" column="apply_doctor_name" />
|
<result property="applyDoctorName" column="apply_doctor_name" />
|
||||||
<result property="applyDeptId" column="apply_dept_id" />
|
<result property="applyDeptId" column="apply_dept_id" />
|
||||||
@@ -79,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
EXTRACT(YEAR FROM AGE(p.birth_date)) as patient_age,
|
EXTRACT(YEAR FROM AGE(p.birth_date)) as patient_age,
|
||||||
s.encounter_id,
|
s.encounter_id,
|
||||||
e.bus_no as encounter_no,
|
e.bus_no as encounter_no,
|
||||||
|
pi.identifier_no as patient_card_no,
|
||||||
s.apply_doctor_id,
|
s.apply_doctor_id,
|
||||||
COALESCE(s.apply_doctor_name, apply_doc.name) as apply_doctor_name,
|
COALESCE(s.apply_doctor_name, apply_doc.name) as apply_doctor_name,
|
||||||
s.apply_dept_id,
|
s.apply_dept_id,
|
||||||
@@ -177,6 +179,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
FROM cli_surgery s
|
FROM cli_surgery s
|
||||||
LEFT JOIN adm_patient p ON s.patient_id = p.id
|
LEFT JOIN adm_patient p ON s.patient_id = p.id
|
||||||
LEFT JOIN adm_encounter e ON s.encounter_id = e.id
|
LEFT JOIN adm_encounter e ON s.encounter_id = e.id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT patient_id, identifier_no
|
||||||
|
FROM (
|
||||||
|
SELECT patient_id, identifier_no,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
|
||||||
|
FROM adm_patient_identifier
|
||||||
|
WHERE delete_flag = '0'
|
||||||
|
AND identifier_no IS NOT NULL
|
||||||
|
AND identifier_no != ''
|
||||||
|
) t
|
||||||
|
WHERE rn = 1
|
||||||
|
) pi ON s.patient_id = pi.patient_id
|
||||||
LEFT JOIN adm_operating_room r ON s.operating_room_id = r.id
|
LEFT JOIN adm_operating_room r ON s.operating_room_id = r.id
|
||||||
LEFT JOIN adm_organization ro ON r.organization_id = ro.id
|
LEFT JOIN adm_organization ro ON r.organization_id = ro.id
|
||||||
LEFT JOIN adm_organization o ON s.org_id = o.id
|
LEFT JOIN adm_organization o ON s.org_id = o.id
|
||||||
@@ -248,6 +262,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
p.birth_date,
|
p.birth_date,
|
||||||
<!-- 就诊编号 -->
|
<!-- 就诊编号 -->
|
||||||
e.bus_no as encounter_no,
|
e.bus_no as encounter_no,
|
||||||
|
<!-- 就诊卡号 -->
|
||||||
|
pi.identifier_no as patient_card_no,
|
||||||
<!-- 字典文本:使用CASE WHEN避免额外JOIN -->
|
<!-- 字典文本:使用CASE WHEN避免额外JOIN -->
|
||||||
CASE s.surgery_type_enum
|
CASE s.surgery_type_enum
|
||||||
WHEN 1 THEN '门诊手术'
|
WHEN 1 THEN '门诊手术'
|
||||||
@@ -302,6 +318,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<!-- 只JOIN必要的表:患者和就诊 -->
|
<!-- 只JOIN必要的表:患者和就诊 -->
|
||||||
LEFT JOIN adm_patient p ON s.patient_id = p.id
|
LEFT JOIN adm_patient p ON s.patient_id = p.id
|
||||||
LEFT JOIN adm_encounter e ON s.encounter_id = e.id
|
LEFT JOIN adm_encounter e ON s.encounter_id = e.id
|
||||||
|
<!-- 关联患者标识表获取就诊卡号 -->
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT patient_id, identifier_no
|
||||||
|
FROM (
|
||||||
|
SELECT patient_id, identifier_no,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
|
||||||
|
FROM adm_patient_identifier
|
||||||
|
WHERE delete_flag = '0'
|
||||||
|
AND identifier_no IS NOT NULL
|
||||||
|
AND identifier_no != ''
|
||||||
|
) t
|
||||||
|
WHERE rn = 1
|
||||||
|
) pi ON s.patient_id = pi.patient_id
|
||||||
<where>
|
<where>
|
||||||
s.delete_flag = '0'
|
s.delete_flag = '0'
|
||||||
<if test="ew.sqlSegment != null and ew.sqlSegment != ''">
|
<if test="ew.sqlSegment != null and ew.sqlSegment != ''">
|
||||||
|
|||||||
@@ -30,13 +30,26 @@
|
|||||||
cs.apply_dept_name,
|
cs.apply_dept_name,
|
||||||
cs.org_id,
|
cs.org_id,
|
||||||
o.name AS org_name,
|
o.name AS org_name,
|
||||||
cs.main_surgeon_name AS surgeon_name
|
cs.main_surgeon_name AS surgeon_name,
|
||||||
|
COALESCE(pi.identifier_no, ap.bus_no, '') AS identifierNo
|
||||||
FROM op_schedule os
|
FROM op_schedule os
|
||||||
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
|
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
|
||||||
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
|
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
|
||||||
LEFT JOIN adm_organization o ON cs.org_id = o.id
|
LEFT JOIN adm_organization o ON cs.org_id = o.id
|
||||||
LEFT JOIN sys_tenant st ON st.id = os.tenant_id
|
LEFT JOIN sys_tenant st ON st.id = os.tenant_id
|
||||||
LEFT JOIN sys_user su ON su.user_id = os.creator_id
|
LEFT JOIN sys_user su ON su.user_id = os.creator_id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT patient_id, identifier_no
|
||||||
|
FROM (
|
||||||
|
SELECT patient_id, identifier_no,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
|
||||||
|
FROM adm_patient_identifier
|
||||||
|
WHERE delete_flag = '0'
|
||||||
|
AND identifier_no IS NOT NULL
|
||||||
|
AND identifier_no != ''
|
||||||
|
) t
|
||||||
|
WHERE rn = 1
|
||||||
|
) pi ON os.patient_id = pi.patient_id
|
||||||
<where>
|
<where>
|
||||||
<if test="dto.tenantId != null">
|
<if test="dto.tenantId != null">
|
||||||
AND os.tenant_id = #{dto.tenantId}
|
AND os.tenant_id = #{dto.tenantId}
|
||||||
@@ -75,12 +88,25 @@
|
|||||||
cs.main_surgeon_name AS surgeon_name,
|
cs.main_surgeon_name AS surgeon_name,
|
||||||
cs.apply_doctor_name AS apply_doctor_name,
|
cs.apply_doctor_name AS apply_doctor_name,
|
||||||
drf.create_time AS apply_time,
|
drf.create_time AS apply_time,
|
||||||
os.surgery_nature AS surgeryType
|
os.surgery_nature AS surgeryType,
|
||||||
|
COALESCE(pi.identifier_no, ap.bus_no, '') AS identifierNo
|
||||||
FROM op_schedule os
|
FROM op_schedule os
|
||||||
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
|
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
|
||||||
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
|
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
|
||||||
LEFT JOIN adm_organization o ON cs.org_id = o.id
|
LEFT JOIN adm_organization o ON cs.org_id = o.id
|
||||||
LEFT JOIN doc_request_form drf ON drf.prescription_no=cs.surgery_no
|
LEFT JOIN doc_request_form drf ON drf.prescription_no=cs.surgery_no
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT patient_id, identifier_no
|
||||||
|
FROM (
|
||||||
|
SELECT patient_id, identifier_no,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
|
||||||
|
FROM adm_patient_identifier
|
||||||
|
WHERE delete_flag = '0'
|
||||||
|
AND identifier_no IS NOT NULL
|
||||||
|
AND identifier_no != ''
|
||||||
|
) t
|
||||||
|
WHERE rn = 1
|
||||||
|
) pi ON os.patient_id = pi.patient_id
|
||||||
WHERE os.schedule_id = #{scheduleId}
|
WHERE os.schedule_id = #{scheduleId}
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
</select>
|
</select>
|
||||||
@@ -123,13 +149,26 @@
|
|||||||
cs.apply_dept_name,
|
cs.apply_dept_name,
|
||||||
cs.org_id,
|
cs.org_id,
|
||||||
o.name AS org_name,
|
o.name AS org_name,
|
||||||
cs.main_surgeon_name AS surgeon_name
|
cs.main_surgeon_name AS surgeon_name,
|
||||||
|
COALESCE(pi.identifier_no, ap.bus_no, '') AS identifierNo
|
||||||
FROM op_schedule os
|
FROM op_schedule os
|
||||||
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
|
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
|
||||||
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
|
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
|
||||||
LEFT JOIN adm_organization o ON cs.org_id = o.id
|
LEFT JOIN adm_organization o ON cs.org_id = o.id
|
||||||
LEFT JOIN sys_tenant st ON st.id = os.tenant_id
|
LEFT JOIN sys_tenant st ON st.id = os.tenant_id
|
||||||
LEFT JOIN sys_user su ON su.user_id = os.creator_id
|
LEFT JOIN sys_user su ON su.user_id = os.creator_id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT patient_id, identifier_no
|
||||||
|
FROM (
|
||||||
|
SELECT patient_id, identifier_no,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
|
||||||
|
FROM adm_patient_identifier
|
||||||
|
WHERE delete_flag = '0'
|
||||||
|
AND identifier_no IS NOT NULL
|
||||||
|
AND identifier_no != ''
|
||||||
|
) t
|
||||||
|
WHERE rn = 1
|
||||||
|
) pi ON os.patient_id = pi.patient_id
|
||||||
<where>
|
<where>
|
||||||
AND os.delete_flag = '0'
|
AND os.delete_flag = '0'
|
||||||
<if test="dto.patientId != null"> AND os.patient_id = #{dto.patientId}</if>
|
<if test="dto.patientId != null"> AND os.patient_id = #{dto.patientId}</if>
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.openhis.web.datadictionary.mapper.LabActivityDefinitionManageMapper">
|
||||||
|
|
||||||
|
<!-- 检验项目分页查询(操作 lab_activity_definition 表,无物理外键) -->
|
||||||
|
<select id="getLabActivityDefinitionPage" parameterType="java.util.Map"
|
||||||
|
resultType="com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto">
|
||||||
|
SELECT
|
||||||
|
T1.id,
|
||||||
|
T1.category_code,
|
||||||
|
T1.bus_no,
|
||||||
|
T1.name,
|
||||||
|
T1.py_str,
|
||||||
|
T1.wb_str,
|
||||||
|
T1.type_enum,
|
||||||
|
T1.permitted_unit_code,
|
||||||
|
T1.org_id,
|
||||||
|
T1.location_id,
|
||||||
|
T1.yb_flag,
|
||||||
|
T1.yb_no,
|
||||||
|
T1.yb_match_flag,
|
||||||
|
T1.status_enum,
|
||||||
|
T1.body_site_code,
|
||||||
|
T1.specimen_code,
|
||||||
|
T1.description_text,
|
||||||
|
T1.rule_id,
|
||||||
|
T1.tenant_id,
|
||||||
|
T1.chrgitm_lv,
|
||||||
|
T1.children_json,
|
||||||
|
T1.pricing_flag,
|
||||||
|
T1.sort_order,
|
||||||
|
T1.service_range,
|
||||||
|
T1.inspection_type_id,
|
||||||
|
T1.fee_package_id,
|
||||||
|
T1.sub_item_id,
|
||||||
|
T3.name AS test_type,
|
||||||
|
T5.package_name,
|
||||||
|
T6.name AS sub_item_name
|
||||||
|
FROM lab_activity_definition T1
|
||||||
|
/* 检验类型关联(逻辑关联,无外键) */
|
||||||
|
LEFT JOIN inspection_type T3
|
||||||
|
ON T1.inspection_type_id = T3.id
|
||||||
|
AND T3.valid_flag = 1
|
||||||
|
/* 费用套餐关联(逻辑关联,无外键) */
|
||||||
|
LEFT JOIN inspection_basic_information T5
|
||||||
|
ON T1.fee_package_id = T5.basic_information_id
|
||||||
|
AND T5.del_flag = false
|
||||||
|
/* 下级医技类型关联(逻辑关联,无外键) */
|
||||||
|
LEFT JOIN inspection_type T6
|
||||||
|
ON T1.sub_item_id = T6.id
|
||||||
|
AND T6.valid_flag = 1
|
||||||
|
<where>
|
||||||
|
T1.delete_flag = '0'
|
||||||
|
<if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
|
||||||
|
<choose>
|
||||||
|
<when test="ew.customSqlSegment.contains('tenant_id')">
|
||||||
|
${ew.customSqlSegment.replaceFirst('tenant_id', 'T1.tenant_id').replaceFirst('status_enum', 'T1.status_enum').replaceFirst('WHERE', 'AND')}
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
${ew.customSqlSegment.replaceFirst('status_enum', 'T1.status_enum').replaceFirst('WHERE', 'AND')}
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
ORDER BY T1.id DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 检验项目详情 -->
|
||||||
|
<select id="getLabActivityDefinitionOne" resultType="com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto">
|
||||||
|
SELECT
|
||||||
|
T1.id,
|
||||||
|
T1.category_code,
|
||||||
|
T1.bus_no,
|
||||||
|
T1.name,
|
||||||
|
T1.py_str,
|
||||||
|
T1.wb_str,
|
||||||
|
T1.type_enum,
|
||||||
|
T1.permitted_unit_code,
|
||||||
|
T1.org_id,
|
||||||
|
T1.location_id,
|
||||||
|
T1.yb_flag,
|
||||||
|
T1.yb_no,
|
||||||
|
T1.yb_match_flag,
|
||||||
|
T1.status_enum,
|
||||||
|
T1.body_site_code,
|
||||||
|
T1.specimen_code,
|
||||||
|
T1.description_text,
|
||||||
|
T1.rule_id,
|
||||||
|
T1.tenant_id,
|
||||||
|
T1.chrgitm_lv,
|
||||||
|
T1.children_json,
|
||||||
|
T1.pricing_flag,
|
||||||
|
T1.sort_order,
|
||||||
|
T1.service_range,
|
||||||
|
T1.inspection_type_id,
|
||||||
|
T1.fee_package_id,
|
||||||
|
T1.sub_item_id,
|
||||||
|
T3.name AS test_type,
|
||||||
|
T5.package_name,
|
||||||
|
T6.name AS sub_item_name
|
||||||
|
FROM lab_activity_definition T1
|
||||||
|
LEFT JOIN inspection_type T3
|
||||||
|
ON T1.inspection_type_id = T3.id
|
||||||
|
AND T3.valid_flag = 1
|
||||||
|
LEFT JOIN inspection_basic_information T5
|
||||||
|
ON T1.fee_package_id = T5.basic_information_id
|
||||||
|
AND T5.del_flag = false
|
||||||
|
LEFT JOIN inspection_type T6
|
||||||
|
ON T1.sub_item_id = T6.id
|
||||||
|
AND T6.valid_flag = 1
|
||||||
|
<where>
|
||||||
|
T1.delete_flag = '0'
|
||||||
|
<if test="id != null">
|
||||||
|
AND T1.id = #{id}
|
||||||
|
</if>
|
||||||
|
<if test="tenantId != null">
|
||||||
|
AND T1.tenant_id = #{tenantId}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<!-- 检验项目下拉列表(轻量级) -->
|
||||||
|
<select id="getLabActivityDefinitionSimpleList" resultType="com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto">
|
||||||
|
SELECT
|
||||||
|
T1.id,
|
||||||
|
T1.bus_no,
|
||||||
|
T1.name,
|
||||||
|
T1.permitted_unit_code
|
||||||
|
FROM lab_activity_definition T1
|
||||||
|
WHERE T1.delete_flag = '0'
|
||||||
|
AND T1.status_enum = #{statusEnum}
|
||||||
|
AND T1.tenant_id = #{tenantId}
|
||||||
|
<if test="searchKey != null and searchKey != ''">
|
||||||
|
AND (
|
||||||
|
T1.name LIKE CONCAT('%', #{searchKey}, '%')
|
||||||
|
OR T1.bus_no LIKE CONCAT('%', #{searchKey}, '%')
|
||||||
|
OR T1.py_str LIKE CONCAT('%', #{searchKey}, '%')
|
||||||
|
)
|
||||||
|
</if>
|
||||||
|
ORDER BY T1.id DESC
|
||||||
|
<if test="searchKey != null and searchKey != ''">
|
||||||
|
LIMIT 1500
|
||||||
|
</if>
|
||||||
|
<if test="searchKey == null or searchKey == ''">
|
||||||
|
LIMIT 500
|
||||||
|
</if>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
@@ -471,6 +471,7 @@
|
|||||||
T1.dose AS dose,
|
T1.dose AS dose,
|
||||||
T1.dose_unit_code AS dose_unit_code,
|
T1.dose_unit_code AS dose_unit_code,
|
||||||
T4.id AS charge_item_id,
|
T4.id AS charge_item_id,
|
||||||
|
T4.unit_price AS unit_price,
|
||||||
T4.total_price AS total_price,
|
T4.total_price AS total_price,
|
||||||
T4.status_enum AS charge_status,
|
T4.status_enum AS charge_status,
|
||||||
al.id AS position_id,
|
al.id AS position_id,
|
||||||
@@ -480,7 +481,9 @@
|
|||||||
ccd.name AS condition_definition_name,
|
ccd.name AS condition_definition_name,
|
||||||
T1.sort_number AS sort_number,
|
T1.sort_number AS sort_number,
|
||||||
T1.based_on_id AS based_on_id,
|
T1.based_on_id AS based_on_id,
|
||||||
T1.category_enum AS category_enum
|
T1.category_enum AS category_enum,
|
||||||
|
T1.encounter_id AS encounter_id,
|
||||||
|
T1.patient_id AS patient_id
|
||||||
FROM med_medication_request AS T1
|
FROM med_medication_request AS T1
|
||||||
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
|
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
|
||||||
AND T2.delete_flag = '0'
|
AND T2.delete_flag = '0'
|
||||||
@@ -523,6 +526,7 @@
|
|||||||
NULL AS dose,
|
NULL AS dose,
|
||||||
'' AS dose_unit_code,
|
'' AS dose_unit_code,
|
||||||
T3.id AS charge_item_id,
|
T3.id AS charge_item_id,
|
||||||
|
T3.unit_price AS unit_price,
|
||||||
T3.total_price AS total_price,
|
T3.total_price AS total_price,
|
||||||
T3.status_enum AS charge_status,
|
T3.status_enum AS charge_status,
|
||||||
al.id AS position_id,
|
al.id AS position_id,
|
||||||
@@ -532,7 +536,9 @@
|
|||||||
'' AS condition_definition_name,
|
'' AS condition_definition_name,
|
||||||
99 AS sort_number,
|
99 AS sort_number,
|
||||||
T1.based_on_id AS based_on_id,
|
T1.based_on_id AS based_on_id,
|
||||||
T1.category_enum AS category_enum
|
T1.category_enum AS category_enum,
|
||||||
|
T1.encounter_id AS encounter_id,
|
||||||
|
T1.patient_id AS patient_id
|
||||||
FROM wor_device_request AS T1
|
FROM wor_device_request AS T1
|
||||||
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
|
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
|
||||||
AND T2.delete_flag = '0'
|
AND T2.delete_flag = '0'
|
||||||
@@ -550,7 +556,7 @@
|
|||||||
AND T1.refund_device_id IS NULL
|
AND T1.refund_device_id IS NULL
|
||||||
ORDER BY T1.status_enum)
|
ORDER BY T1.status_enum)
|
||||||
UNION ALL
|
UNION ALL
|
||||||
(SELECT 3 AS advice_type,
|
(SELECT CASE WHEN T1.category_enum = 4 THEN 6 ELSE COALESCE(T1.category_enum, 3) END AS advice_type,
|
||||||
T1.id AS request_id,
|
T1.id AS request_id,
|
||||||
T1.id || '-3' AS unique_key,
|
T1.id || '-3' AS unique_key,
|
||||||
'' AS prescription_no,
|
'' AS prescription_no,
|
||||||
@@ -561,18 +567,19 @@
|
|||||||
null AS skin_test_flag,
|
null AS skin_test_flag,
|
||||||
null AS inject_flag,
|
null AS inject_flag,
|
||||||
null AS group_id,
|
null AS group_id,
|
||||||
COALESCE(T2.NAME, CASE WHEN T1.content_json IS NOT NULL AND T1.content_json != '' THEN T1.content_json::json->>'adviceName' ELSE NULL END) AS advice_name,
|
COALESCE(T2.NAME, T1.content_json::jsonb->>'surgeryName', T1.content_json::jsonb->>'adviceName') AS advice_name,
|
||||||
'' AS volume,
|
'' AS volume,
|
||||||
'' AS lot_number,
|
'' AS lot_number,
|
||||||
T1.quantity AS quantity,
|
T1.quantity AS quantity,
|
||||||
T1.unit_code AS unit_code,
|
T1.unit_code AS unit_code,
|
||||||
T1.status_enum AS status_enum,
|
T1.status_enum AS status_enum,
|
||||||
'' AS method_code,
|
'' AS method_code,
|
||||||
'' AS rate_code,
|
'' AS rate_code,
|
||||||
NULL AS dose,
|
NULL AS dose,
|
||||||
'' AS dose_unit_code,
|
'' AS dose_unit_code,
|
||||||
T3.id AS charge_item_id,
|
T3.id AS charge_item_id,
|
||||||
T3.total_price AS total_price,
|
T3.unit_price AS unit_price,
|
||||||
|
T3.total_price AS total_price,
|
||||||
T3.status_enum AS charge_status,
|
T3.status_enum AS charge_status,
|
||||||
ao.id AS position_id,
|
ao.id AS position_id,
|
||||||
ao.name AS position_name,
|
ao.name AS position_name,
|
||||||
@@ -580,9 +587,11 @@
|
|||||||
1 AS part_percent,
|
1 AS part_percent,
|
||||||
'' AS condition_definition_name,
|
'' AS condition_definition_name,
|
||||||
99 AS sort_number,
|
99 AS sort_number,
|
||||||
T1.based_on_id AS based_on_id,
|
T1.based_on_id AS based_on_id,
|
||||||
T1.category_enum AS category_enum
|
T1.category_enum AS category_enum,
|
||||||
FROM wor_service_request AS T1
|
T1.encounter_id AS encounter_id,
|
||||||
|
T1.patient_id AS patient_id
|
||||||
|
FROM wor_service_request AS T1
|
||||||
LEFT JOIN wor_activity_definition AS T2
|
LEFT JOIN wor_activity_definition AS T2
|
||||||
ON T2.ID = T1.activity_id
|
ON T2.ID = T1.activity_id
|
||||||
AND T2.delete_flag = '0'
|
AND T2.delete_flag = '0'
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<!-- 根据申请单号查询检验申请单(返回完整字段) -->
|
<!-- 根据申请单号查询检验申请单(返回完整字段) -->
|
||||||
<select id="getInspectionApplyByApplyNo" resultType="com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto">
|
<select id="getInspectionApplyByApplyNo" resultType="com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto">
|
||||||
SELECT
|
SELECT
|
||||||
|
id AS applicationId,
|
||||||
apply_no AS applyNo,
|
apply_no AS applyNo,
|
||||||
patient_id AS patientId,
|
patient_id AS patientId,
|
||||||
patient_name AS patientName,
|
patient_name AS patientName,
|
||||||
@@ -40,20 +41,17 @@
|
|||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 分页查询检验申请单列表(根据就诊ID查询,按申请时间降序)
|
<!-- 分页查询检验申请单列表(根据就诊ID查询,按申请时间降序)
|
||||||
encounterId: 就诊ID作为查询条件查出患者id(patient_id)再以患者id对申请单进行查询
|
直接查询申请单表,不关联明细表,避免重复记录-->
|
||||||
对申请单表(lab_apply)、申请单明细表(lab_apply_item)和就诊表(adm_encounter)进行联合查询(申请单号,检验项目,申请医生,申请单优先级码,申请单状态,金额)-->
|
|
||||||
<select id="getInspectionApplyListPage" resultType="com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto">
|
<select id="getInspectionApplyListPage" resultType="com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto">
|
||||||
SELECT t1.apply_no AS applyNo,
|
SELECT t1.id AS applicationId,
|
||||||
t1.inspection_item AS inspectionItem,
|
t1.apply_no AS applyNo,
|
||||||
|
t1.inspection_item AS itemName,
|
||||||
t1.apply_doc_name AS applyDocName,
|
t1.apply_doc_name AS applyDocName,
|
||||||
t1.priority_code AS priorityCode,
|
t1.priority_code AS priorityCode,
|
||||||
t2.item_name AS itemName,
|
|
||||||
t1.apply_status AS applyStatus,
|
t1.apply_status AS applyStatus,
|
||||||
t2.item_amount AS itemAmount
|
t1.apply_remark AS applyRemark
|
||||||
FROM lab_apply AS t1
|
FROM lab_apply AS t1
|
||||||
INNER JOIN adm_encounter AS t3 ON t1.patient_id::bigint = t3.patient_id
|
INNER JOIN adm_encounter AS t3 ON t1.patient_id::bigint = t3.patient_id
|
||||||
LEFT JOIN lab_apply_item AS t2
|
|
||||||
ON t1.apply_no = t2.apply_no
|
|
||||||
WHERE t1.delete_flag = '0'
|
WHERE t1.delete_flag = '0'
|
||||||
AND t3.id = #{encounterId}
|
AND t3.id = #{encounterId}
|
||||||
ORDER BY t1.apply_time DESC
|
ORDER BY t1.apply_time DESC
|
||||||
|
|||||||
@@ -203,6 +203,7 @@
|
|||||||
T1.dose AS dose,
|
T1.dose AS dose,
|
||||||
T1.dose_unit_code AS dose_unit_code,
|
T1.dose_unit_code AS dose_unit_code,
|
||||||
T4.id AS charge_item_id,
|
T4.id AS charge_item_id,
|
||||||
|
T4.unit_price AS unit_price,
|
||||||
T4.total_price AS total_price,
|
T4.total_price AS total_price,
|
||||||
T4.status_enum AS charge_status,
|
T4.status_enum AS charge_status,
|
||||||
al.id AS position_id,
|
al.id AS position_id,
|
||||||
@@ -254,6 +255,7 @@
|
|||||||
NULL AS dose,
|
NULL AS dose,
|
||||||
'' AS dose_unit_code,
|
'' AS dose_unit_code,
|
||||||
T3.id AS charge_item_id,
|
T3.id AS charge_item_id,
|
||||||
|
T3.unit_price AS unit_price,
|
||||||
T3.total_price AS total_price,
|
T3.total_price AS total_price,
|
||||||
T3.status_enum AS charge_status,
|
T3.status_enum AS charge_status,
|
||||||
al.id AS position_id,
|
al.id AS position_id,
|
||||||
@@ -281,7 +283,7 @@
|
|||||||
AND T1.refund_device_id IS NULL
|
AND T1.refund_device_id IS NULL
|
||||||
ORDER BY T1.status_enum)
|
ORDER BY T1.status_enum)
|
||||||
UNION ALL
|
UNION ALL
|
||||||
(SELECT 3 AS advice_type,
|
(SELECT CASE WHEN T1.category_enum = 4 THEN 6 ELSE COALESCE(T1.category_enum, 3) END AS advice_type,
|
||||||
T1.id AS request_id,
|
T1.id AS request_id,
|
||||||
T1.id || '-3' AS unique_key,
|
T1.id || '-3' AS unique_key,
|
||||||
T1.requester_id AS requester_id,
|
T1.requester_id AS requester_id,
|
||||||
@@ -291,7 +293,7 @@
|
|||||||
null AS skin_test_flag,
|
null AS skin_test_flag,
|
||||||
null AS inject_flag,
|
null AS inject_flag,
|
||||||
null AS group_id,
|
null AS group_id,
|
||||||
T2.NAME AS advice_name,
|
COALESCE(T2.NAME, T1.content_json::jsonb->>'surgeryName') AS advice_name,
|
||||||
'' AS volume,
|
'' AS volume,
|
||||||
'' AS lot_number,
|
'' AS lot_number,
|
||||||
T1.quantity AS quantity,
|
T1.quantity AS quantity,
|
||||||
@@ -302,6 +304,7 @@
|
|||||||
NULL AS dose,
|
NULL AS dose,
|
||||||
'' AS dose_unit_code,
|
'' AS dose_unit_code,
|
||||||
T3.id AS charge_item_id,
|
T3.id AS charge_item_id,
|
||||||
|
T3.unit_price AS unit_price,
|
||||||
T3.total_price AS total_price,
|
T3.total_price AS total_price,
|
||||||
T3.status_enum AS charge_status,
|
T3.status_enum AS charge_status,
|
||||||
ao.id AS position_id,
|
ao.id AS position_id,
|
||||||
@@ -309,7 +312,7 @@
|
|||||||
null AS dispense_per_duration,
|
null AS dispense_per_duration,
|
||||||
1 AS part_percent,
|
1 AS part_percent,
|
||||||
'' AS condition_definition_name,
|
'' AS condition_definition_name,
|
||||||
T1.therapy_enum AS therapyEnum,
|
COALESCE(T1.therapy_enum, 2) AS therapyEnum,
|
||||||
99 AS sort_number,
|
99 AS sort_number,
|
||||||
T1.based_on_id AS based_on_id
|
T1.based_on_id AS based_on_id
|
||||||
FROM wor_service_request AS T1
|
FROM wor_service_request AS T1
|
||||||
|
|||||||
@@ -26,12 +26,13 @@
|
|||||||
<select id="getRequestFormDetail" resultType="com.openhis.web.regdoctorstation.dto.RequestFormDetailQueryDto">
|
<select id="getRequestFormDetail" resultType="com.openhis.web.regdoctorstation.dto.RequestFormDetailQueryDto">
|
||||||
SELECT wsr.quantity,
|
SELECT wsr.quantity,
|
||||||
wsr.unit_code,
|
wsr.unit_code,
|
||||||
wad.NAME AS advice_name,
|
COALESCE(wad.NAME, wsr.content_json::jsonb->>'surgeryName') AS advice_name,
|
||||||
aci.total_price
|
aci.total_price
|
||||||
FROM wor_service_request AS wsr
|
FROM wor_service_request AS wsr
|
||||||
LEFT JOIN wor_activity_definition AS wad ON wad.ID = wsr.activity_id
|
LEFT JOIN wor_activity_definition AS wad ON wad.ID = wsr.activity_id
|
||||||
AND wad.delete_flag = '0'
|
AND wad.delete_flag = '0'
|
||||||
LEFT JOIN adm_charge_item AS aci ON aci.service_id = wsr.ID
|
LEFT JOIN adm_charge_item AS aci ON aci.service_id = wsr.ID
|
||||||
|
AND aci.service_table = 'wor_service_request'
|
||||||
AND aci.delete_flag = '0'
|
AND aci.delete_flag = '0'
|
||||||
WHERE wsr.delete_flag = '0'
|
WHERE wsr.delete_flag = '0'
|
||||||
AND wsr.prescription_no = #{prescriptionNo}
|
AND wsr.prescription_no = #{prescriptionNo}
|
||||||
@@ -67,6 +68,7 @@
|
|||||||
<result column="anesthesia_type_enum" property="anesthesiaTypeEnum"/>
|
<result column="anesthesia_type_enum" property="anesthesiaTypeEnum"/>
|
||||||
<result column="incision_level" property="incisionLevel"/>
|
<result column="incision_level" property="incisionLevel"/>
|
||||||
<result column="surgery_level" property="surgeryLevel"/>
|
<result column="surgery_level" property="surgeryLevel"/>
|
||||||
|
<result column="identifier_no" property="identifierNo"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<!-- 分页查询申请单 -->
|
<!-- 分页查询申请单 -->
|
||||||
@@ -91,7 +93,8 @@
|
|||||||
cs.anesthesia_type_enum,
|
cs.anesthesia_type_enum,
|
||||||
cs.incision_level,
|
cs.incision_level,
|
||||||
cs.surgery_level,
|
cs.surgery_level,
|
||||||
fc.contract_name AS fee_type
|
fc.contract_name AS fee_type,
|
||||||
|
COALESCE(pi.identifier_no, ap.bus_no, '') AS identifier_no
|
||||||
FROM doc_request_form drf
|
FROM doc_request_form drf
|
||||||
LEFT JOIN cli_surgery cs ON cs.surgery_no = drf.prescription_no
|
LEFT JOIN cli_surgery cs ON cs.surgery_no = drf.prescription_no
|
||||||
LEFT JOIN adm_patient ap ON ap.id = cs.patient_id
|
LEFT JOIN adm_patient ap ON ap.id = cs.patient_id
|
||||||
@@ -99,6 +102,16 @@
|
|||||||
LEFT JOIN adm_account aa ON aa.encounter_id = ae.id AND aa.delete_flag = '0'
|
LEFT JOIN adm_account aa ON aa.encounter_id = ae.id AND aa.delete_flag = '0'
|
||||||
LEFT JOIN fin_contract fc ON fc.bus_no = aa.contract_no AND fc.delete_flag = '0'
|
LEFT JOIN fin_contract fc ON fc.bus_no = aa.contract_no AND fc.delete_flag = '0'
|
||||||
LEFT JOIN op_schedule os ON os.apply_id = drf.id AND os.delete_flag = '0'
|
LEFT JOIN op_schedule os ON os.apply_id = drf.id AND os.delete_flag = '0'
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT patient_id, identifier_no
|
||||||
|
FROM (
|
||||||
|
SELECT patient_id, identifier_no,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
|
||||||
|
FROM adm_patient_identifier
|
||||||
|
WHERE delete_flag = '0' AND identifier_no IS NOT NULL AND identifier_no != ''
|
||||||
|
) t
|
||||||
|
WHERE rn = 1
|
||||||
|
) pi ON ap.id = pi.patient_id
|
||||||
<where>
|
<where>
|
||||||
<if test="requestFormDto.surgeryNo != null and requestFormDto.surgeryNo != ''">
|
<if test="requestFormDto.surgeryNo != null and requestFormDto.surgeryNo != ''">
|
||||||
AND drf.prescription_no LIKE CONCAT('%', #{requestFormDto.surgeryNo}, '%')
|
AND drf.prescription_no LIKE CONCAT('%', #{requestFormDto.surgeryNo}, '%')
|
||||||
|
|||||||
@@ -769,15 +769,21 @@ public class CommonConstants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 号源槽位状态 (adm_schedule_slot.slot_status)
|
* 号源槽位状态 (adm_schedule_slot.status)
|
||||||
*/
|
*/
|
||||||
public interface SlotStatus {
|
public interface SlotStatus {
|
||||||
/** 可用 / 待预约 */
|
/** 可用 / 待预约 */
|
||||||
Integer AVAILABLE = 0;
|
Integer AVAILABLE = 0;
|
||||||
/** 已预约 */
|
/** 已预约 */
|
||||||
Integer BOOKED = 1;
|
Integer BOOKED = 1;
|
||||||
/** 已停诊 / 已失效 */
|
/** 已取消 / 已停诊 */
|
||||||
Integer STOPPED = 2;
|
Integer CANCELLED = 2;
|
||||||
|
/** 已锁定 */
|
||||||
|
Integer LOCKED = 3;
|
||||||
|
/** 已签到 / 已取号 */
|
||||||
|
Integer CHECKED_IN = 4;
|
||||||
|
/** 已退号 */
|
||||||
|
Integer RETURNED = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -790,6 +796,8 @@ public class CommonConstants {
|
|||||||
Integer CHECKED_IN = 2;
|
Integer CHECKED_IN = 2;
|
||||||
/** 已取消 */
|
/** 已取消 */
|
||||||
Integer CANCELLED = 3;
|
Integer CANCELLED = 3;
|
||||||
|
/** 已退号 */
|
||||||
|
Integer RETURNED = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,14 +23,19 @@ public enum ItemType implements HisEnumInterface {
|
|||||||
MEDICINE(1, "1", "药品"),
|
MEDICINE(1, "1", "药品"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 耗材
|
* 医疗活动
|
||||||
|
*/
|
||||||
|
ACTIVITY(3, "3", "医疗活动"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 耗材(前端使用值2)
|
||||||
*/
|
*/
|
||||||
DEVICE(2, "2", "耗材"),
|
DEVICE(2, "2", "耗材"),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 医疗活动
|
* 手术(前端使用值6,避免与耗材冲突)
|
||||||
*/
|
*/
|
||||||
ACTIVITY(3, "3", "医疗活动");
|
SURGERY(6, "6", "手术");
|
||||||
|
|
||||||
@EnumValue
|
@EnumValue
|
||||||
private Integer value;
|
private Integer value;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import lombok.EqualsAndHashCode;
|
|||||||
import lombok.experimental.Accessors;
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 号源池明细Entity
|
* 号源池明细Entity
|
||||||
*
|
*
|
||||||
@@ -29,7 +31,7 @@ public class ScheduleSlot extends HisBaseEntity {
|
|||||||
/** 序号 */
|
/** 序号 */
|
||||||
private Integer seqNo;
|
private Integer seqNo;
|
||||||
|
|
||||||
/** 序号状态: 0-可用,1-已预约,2-已取消,3-已过期等 */
|
/** 序号状态: 0-可用,1-已预约,2-已取消/已停诊,3-已锁定,4-已签到,5-已退号 */
|
||||||
private Integer status;
|
private Integer status;
|
||||||
|
|
||||||
/** 预约订单ID */
|
/** 预约订单ID */
|
||||||
@@ -37,4 +39,7 @@ public class ScheduleSlot extends HisBaseEntity {
|
|||||||
|
|
||||||
/** 预计叫号时间 */
|
/** 预计叫号时间 */
|
||||||
private LocalTime expectTime;
|
private LocalTime expectTime;
|
||||||
|
|
||||||
|
/** 签到时间 */
|
||||||
|
private Date checkInTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import java.time.LocalTime;
|
|||||||
public class TicketSlotDTO {
|
public class TicketSlotDTO {
|
||||||
// 基础信息
|
// 基础信息
|
||||||
private Long slotId;
|
private Long slotId;
|
||||||
|
private Integer seqNo;
|
||||||
private Long scheduleId;
|
private Long scheduleId;
|
||||||
private String doctor;
|
private String doctor;
|
||||||
private Long doctorId;
|
private Long doctorId;
|
||||||
@@ -22,6 +23,13 @@ public class TicketSlotDTO {
|
|||||||
private Long patientId;
|
private Long patientId;
|
||||||
private String phone;
|
private String phone;
|
||||||
private Integer orderStatus;
|
private Integer orderStatus;
|
||||||
|
private Long orderId;
|
||||||
|
private String orderNo;
|
||||||
|
private String patientGender;
|
||||||
|
private Integer genderEnum;
|
||||||
|
private String idCard;
|
||||||
|
private String encounterId;
|
||||||
|
private String appointmentTime;
|
||||||
|
|
||||||
// 底层逻辑判断专属字段
|
// 底层逻辑判断专属字段
|
||||||
private Integer slotStatus;
|
private Integer slotStatus;
|
||||||
|
|||||||
@@ -37,4 +37,21 @@ public interface SchedulePoolMapper extends BaseMapper<SchedulePool> {
|
|||||||
AND p.delete_flag = '0'
|
AND p.delete_flag = '0'
|
||||||
""")
|
""")
|
||||||
int refreshPoolStats(@Param("poolId") Long poolId);
|
int refreshPoolStats(@Param("poolId") Long poolId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 签到时更新号源池统计:锁定数-1,已预约数+1
|
||||||
|
*
|
||||||
|
* @param poolId 号源池ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
@Update("""
|
||||||
|
UPDATE adm_schedule_pool
|
||||||
|
SET locked_num = locked_num - 1,
|
||||||
|
booked_num = booked_num + 1,
|
||||||
|
update_time = NOW()
|
||||||
|
WHERE id = #{poolId}
|
||||||
|
AND locked_num > 0
|
||||||
|
AND delete_flag = '0'
|
||||||
|
""")
|
||||||
|
int updatePoolStatsOnCheckIn(@Param("poolId") Integer poolId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.openhis.appointmentmanage.domain.ScheduleSlot;
|
|||||||
import com.openhis.appointmentmanage.domain.TicketSlotDTO;
|
import com.openhis.appointmentmanage.domain.TicketSlotDTO;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.openhis.appointmentmanage.dto.TicketQueryDTO;
|
import com.openhis.appointmentmanage.dto.TicketQueryDTO;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
@@ -30,6 +31,16 @@ public interface ScheduleSlotMapper extends BaseMapper<ScheduleSlot> {
|
|||||||
*/
|
*/
|
||||||
int updateSlotStatus(@Param("slotId") Long slotId, @Param("status") Integer status);
|
int updateSlotStatus(@Param("slotId") Long slotId, @Param("status") Integer status);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新槽位状态并记录签到时间
|
||||||
|
*
|
||||||
|
* @param slotId 槽位ID
|
||||||
|
* @param status 状态
|
||||||
|
* @param checkInTime 签到时间
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updateSlotStatusAndCheckInTime(@Param("slotId") Long slotId, @Param("status") Integer status, @Param("checkInTime") Date checkInTime);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据槽位ID查询所属号源池ID。
|
* 根据槽位ID查询所属号源池ID。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import lombok.experimental.Accessors;
|
|||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class Order extends HisBaseEntity {
|
public class Order extends HisBaseEntity {
|
||||||
|
|
||||||
@TableId(type = IdType.ASSIGN_ID)
|
@TableId(type = IdType.AUTO)
|
||||||
@JsonSerialize(using = ToStringSerializer.class)
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
|||||||
@@ -32,4 +32,14 @@ public interface OrderMapper extends BaseMapper<Order> {
|
|||||||
int updateOrderStatusById(Long id, Integer status);
|
int updateOrderStatusById(Long id, Integer status);
|
||||||
|
|
||||||
int updateOrderCancelInfoById(Long id, Date cancelTime, String cancelReason);
|
int updateOrderCancelInfoById(Long id, Date cancelTime, String cancelReason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新订单支付状态
|
||||||
|
*
|
||||||
|
* @param orderId 订单ID
|
||||||
|
* @param payStatus 支付状态:0-未支付,1-已支付
|
||||||
|
* @param payTime 支付时间
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
int updatePayStatus(@Param("orderId") Long orderId, @Param("payStatus") Integer payStatus, @Param("payTime") Date payTime);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
Order order = new Order();
|
Order order = new Order();
|
||||||
|
order.setId(null); // 显式置空,确保触发数据库自增,避免 MP 预分配雪花 ID 的干扰
|
||||||
String orderNo = assignSeqUtil.getSeq(AssignSeqEnum.ORDER_NUM.getPrefix(), 18);
|
String orderNo = assignSeqUtil.getSeq(AssignSeqEnum.ORDER_NUM.getPrefix(), 18);
|
||||||
order.setOrderNo(orderNo);
|
order.setOrderNo(orderNo);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||||||
import com.openhis.appointmentmanage.domain.AppointmentConfig;
|
import com.openhis.appointmentmanage.domain.AppointmentConfig;
|
||||||
import com.openhis.appointmentmanage.service.IAppointmentConfigService;
|
import com.openhis.appointmentmanage.service.IAppointmentConfigService;
|
||||||
import com.openhis.appointmentmanage.domain.TicketSlotDTO;
|
import com.openhis.appointmentmanage.domain.TicketSlotDTO;
|
||||||
|
import com.openhis.appointmentmanage.domain.ScheduleSlot;
|
||||||
import com.openhis.appointmentmanage.mapper.SchedulePoolMapper;
|
import com.openhis.appointmentmanage.mapper.SchedulePoolMapper;
|
||||||
import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper;
|
import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper;
|
||||||
import com.openhis.clinical.domain.Order;
|
import com.openhis.clinical.domain.Order;
|
||||||
@@ -52,6 +53,9 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
@Resource
|
@Resource
|
||||||
private SchedulePoolMapper schedulePoolMapper;
|
private SchedulePoolMapper schedulePoolMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private com.openhis.clinical.mapper.OrderMapper orderMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private IAppointmentConfigService appointmentConfigService;
|
private IAppointmentConfigService appointmentConfigService;
|
||||||
|
|
||||||
@@ -146,7 +150,25 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
|
|
||||||
logger.debug("开始执行纯净打单路线,slotId: {}, patientName: {}", slotId, dto.getPatientName());
|
logger.debug("开始执行纯净打单路线,slotId: {}, patientName: {}", slotId, dto.getPatientName());
|
||||||
|
|
||||||
// 1. 直查物理大底座!
|
// 1. 检查患者取消预约次数限制(应在预约挂号时限制,而非取消预约时)
|
||||||
|
Integer tenantId = dto.getTenant_id();
|
||||||
|
Long patientId = dto.getPatientId();
|
||||||
|
if (tenantId != null && patientId != null) {
|
||||||
|
AppointmentConfig config = appointmentConfigService.getConfigByTenantId(tenantId);
|
||||||
|
if (config != null && config.getCancelAppointmentCount() != null
|
||||||
|
&& config.getCancelAppointmentCount() > 0) {
|
||||||
|
// 计算当前周期的起始时间
|
||||||
|
LocalDateTime startTime = calculatePeriodStartTime(config.getCancelAppointmentType());
|
||||||
|
// 统计已取消次数
|
||||||
|
long cancelledCount = orderService.countPatientCancellations(patientId, tenantId, startTime);
|
||||||
|
if (cancelledCount >= config.getCancelAppointmentCount()) {
|
||||||
|
String periodName = getPeriodName(config.getCancelAppointmentType());
|
||||||
|
throw new RuntimeException("由于您在" + periodName + "内累计取消预约已达" + cancelledCount + "次,触发系统限制,暂时无法在线预约,请联系分诊台或咨询客服。");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 直查物理大底座!
|
||||||
TicketSlotDTO slot = scheduleSlotMapper.selectTicketSlotById(slotId);
|
TicketSlotDTO slot = scheduleSlotMapper.selectTicketSlotById(slotId);
|
||||||
|
|
||||||
if (slot == null) {
|
if (slot == null) {
|
||||||
@@ -242,26 +264,11 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
throw new RuntimeException("当前号源没有可取消的预约订单");
|
throw new RuntimeException("当前号源没有可取消的预约订单");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 核心逻辑:获取订单信息并检查机构取消限制
|
// 获取订单信息
|
||||||
Order latestOrder = orders.get(0);
|
Order latestOrder = orders.get(0);
|
||||||
Integer tenantId = latestOrder.getTenantId();
|
|
||||||
Long patientId = latestOrder.getPatientId();
|
|
||||||
|
|
||||||
if (tenantId != null && patientId != null) {
|
|
||||||
AppointmentConfig config = appointmentConfigService.getConfigByTenantId(tenantId);
|
|
||||||
if (config != null && config.getCancelAppointmentCount() != null
|
|
||||||
&& config.getCancelAppointmentCount() > 0) {
|
|
||||||
// 计算当前周期的起始时间
|
|
||||||
LocalDateTime startTime = calculatePeriodStartTime(config.getCancelAppointmentType());
|
|
||||||
// 统计已取消次数
|
|
||||||
long cancelledCount = orderService.countPatientCancellations(patientId, tenantId, startTime);
|
|
||||||
if (cancelledCount >= config.getCancelAppointmentCount()) {
|
|
||||||
String periodName = getPeriodName(config.getCancelAppointmentType());
|
|
||||||
throw new RuntimeException("您在" + periodName + "内已达到该机构取消预约次数上限(" + config.getCancelAppointmentCount() + "次),禁止取消");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 直接执行取消,不再检查取消限制
|
||||||
|
// 根据需求,取消限制应在预约挂号时检查,而非取消预约时
|
||||||
for (Order order : orders) {
|
for (Order order : orders) {
|
||||||
orderService.cancelAppointmentOrder(order.getId(), "患者取消预约");
|
orderService.cancelAppointmentOrder(order.getId(), "患者取消预约");
|
||||||
}
|
}
|
||||||
@@ -274,7 +281,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 取号
|
* 取号(签到)
|
||||||
*
|
*
|
||||||
* @param slotId 槽位ID
|
* @param slotId 槽位ID
|
||||||
* @return 结果
|
* @return 结果
|
||||||
@@ -287,7 +294,24 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
throw new RuntimeException("当前号源没有可取号的预约订单");
|
throw new RuntimeException("当前号源没有可取号的预约订单");
|
||||||
}
|
}
|
||||||
Order latestOrder = orders.get(0);
|
Order latestOrder = orders.get(0);
|
||||||
return orderService.updateOrderStatusById(latestOrder.getId(), AppointmentOrderStatus.CHECKED_IN);
|
|
||||||
|
// 1. 更新订单状态为已取号,并更新支付状态和支付时间
|
||||||
|
orderService.updateOrderStatusById(latestOrder.getId(), AppointmentOrderStatus.CHECKED_IN);
|
||||||
|
// 更新支付状态为已支付,记录支付时间
|
||||||
|
orderMapper.updatePayStatus(latestOrder.getId(), 1, new Date());
|
||||||
|
|
||||||
|
// 2. 查询号源槽位信息
|
||||||
|
ScheduleSlot slot = scheduleSlotMapper.selectById(slotId);
|
||||||
|
|
||||||
|
// 3. 更新号源槽位状态为已签到,记录签到时间
|
||||||
|
scheduleSlotMapper.updateSlotStatusAndCheckInTime(slotId, SlotStatus.CHECKED_IN, new Date());
|
||||||
|
|
||||||
|
// 4. 更新号源池统计:锁定数-1,已预约数+1
|
||||||
|
if (slot != null && slot.getPoolId() != null) {
|
||||||
|
schedulePoolMapper.updatePoolStatsOnCheckIn(slot.getPoolId());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -309,7 +333,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
|
|||||||
orderService.cancelAppointmentOrder(order.getId(), "医生停诊");
|
orderService.cancelAppointmentOrder(order.getId(), "医生停诊");
|
||||||
}
|
}
|
||||||
|
|
||||||
int updated = scheduleSlotMapper.updateSlotStatus(slotId, SlotStatus.STOPPED);
|
int updated = scheduleSlotMapper.updateSlotStatus(slotId, SlotStatus.CANCELLED);
|
||||||
if (updated > 0) {
|
if (updated > 0) {
|
||||||
refreshPoolStatsBySlotId(slotId);
|
refreshPoolStatsBySlotId(slotId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import java.util.Date;
|
|||||||
* @date 2025-06-03
|
* @date 2025-06-03
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@TableName("doc_ital_signs")
|
@TableName("doc_vital_signs")
|
||||||
@Accessors(chain = true)
|
@Accessors(chain = true)
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
public class VitalSigns extends HisBaseEntity {
|
public class VitalSigns extends HisBaseEntity {
|
||||||
|
|||||||
@@ -46,16 +46,24 @@ public class PaymentRecStaticServiceImpl extends ServiceImpl<PaymentRecStaticMap
|
|||||||
Map<String, List<ChargeItemDefInfo>> collect;
|
Map<String, List<ChargeItemDefInfo>> collect;
|
||||||
List<PaymentRecStatic> paymentRecStatics = new ArrayList<>();
|
List<PaymentRecStatic> paymentRecStatics = new ArrayList<>();
|
||||||
if (paymentStatisticalMethod == PaymentStatisticalMethod.FIN_TYPE_CODE) {
|
if (paymentStatisticalMethod == PaymentStatisticalMethod.FIN_TYPE_CODE) {
|
||||||
collect = chargeItemDefInfoList.stream().collect(Collectors.groupingBy(ChargeItemDefInfo::getTypeCode));
|
collect = chargeItemDefInfoList.stream()
|
||||||
|
.filter(info -> info.getTypeCode() != null)
|
||||||
|
.collect(Collectors.groupingBy(ChargeItemDefInfo::getTypeCode));
|
||||||
getPaymentRecStaticList(paymentId, paymentType, paymentStatisticalMethod, collect, paymentRecStatics);
|
getPaymentRecStaticList(paymentId, paymentType, paymentStatisticalMethod, collect, paymentRecStatics);
|
||||||
} else if (paymentStatisticalMethod == PaymentStatisticalMethod.MED_CHRGITM_TYPE) {
|
} else if (paymentStatisticalMethod == PaymentStatisticalMethod.MED_CHRGITM_TYPE) {
|
||||||
collect = chargeItemDefInfoList.stream().collect(Collectors.groupingBy(ChargeItemDefInfo::getYbType));
|
collect = chargeItemDefInfoList.stream()
|
||||||
|
.filter(info -> info.getYbType() != null)
|
||||||
|
.collect(Collectors.groupingBy(ChargeItemDefInfo::getYbType));
|
||||||
getPaymentRecStaticList(paymentId, paymentType, paymentStatisticalMethod, collect, paymentRecStatics);
|
getPaymentRecStaticList(paymentId, paymentType, paymentStatisticalMethod, collect, paymentRecStatics);
|
||||||
} else {
|
} else {
|
||||||
collect = chargeItemDefInfoList.stream().collect(Collectors.groupingBy(ChargeItemDefInfo::getTypeCode));
|
collect = chargeItemDefInfoList.stream()
|
||||||
|
.filter(info -> info.getTypeCode() != null)
|
||||||
|
.collect(Collectors.groupingBy(ChargeItemDefInfo::getTypeCode));
|
||||||
getPaymentRecStaticList(paymentId, paymentType, PaymentStatisticalMethod.FIN_TYPE_CODE, collect,
|
getPaymentRecStaticList(paymentId, paymentType, PaymentStatisticalMethod.FIN_TYPE_CODE, collect,
|
||||||
paymentRecStatics);
|
paymentRecStatics);
|
||||||
collect = chargeItemDefInfoList.stream().collect(Collectors.groupingBy(ChargeItemDefInfo::getYbType));
|
collect = chargeItemDefInfoList.stream()
|
||||||
|
.filter(info -> info.getYbType() != null)
|
||||||
|
.collect(Collectors.groupingBy(ChargeItemDefInfo::getYbType));
|
||||||
getPaymentRecStaticList(paymentId, paymentType, PaymentStatisticalMethod.MED_CHRGITM_TYPE, collect,
|
getPaymentRecStaticList(paymentId, paymentType, PaymentStatisticalMethod.MED_CHRGITM_TYPE, collect,
|
||||||
paymentRecStatics);
|
paymentRecStatics);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,9 +24,14 @@ import java.util.Date;
|
|||||||
public class InspectionLabApply extends HisBaseEntity {
|
public class InspectionLabApply extends HisBaseEntity {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主键ID,申请单编号
|
* 主键ID(自增)
|
||||||
|
*/
|
||||||
|
@TableId(type = IdType.AUTO)
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long id;
|
||||||
|
/**
|
||||||
|
* 申请单编号
|
||||||
*/
|
*/
|
||||||
@TableId(type = IdType.NONE)
|
|
||||||
private String applyNo;
|
private String applyNo;
|
||||||
/**
|
/**
|
||||||
* 患者主索引
|
* 患者主索引
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ public class InspectionPackageDetail {
|
|||||||
/** 单位 */
|
/** 单位 */
|
||||||
private String unit;
|
private String unit;
|
||||||
|
|
||||||
/** 单价 */
|
/** 原始单价(未折扣前的价格,用于折扣变更时恢复原价) */
|
||||||
|
private BigDecimal originalPrice;
|
||||||
|
|
||||||
|
/** 单价(折后单价 = 原始单价 × 折扣比例) */
|
||||||
private BigDecimal unitPrice;
|
private BigDecimal unitPrice;
|
||||||
|
|
||||||
/** 金额 */
|
/** 金额 */
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package com.openhis.lab.domain;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
|
import com.core.common.core.domain.HisBaseEntity;
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.experimental.Accessors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目定义实体(独立表 lab_activity_definition,不依赖 wor_activity_definition)
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@TableName("lab_activity_definition")
|
||||||
|
@Accessors(chain = true)
|
||||||
|
@EqualsAndHashCode(callSuper = false)
|
||||||
|
public class LabActivityDefinition extends HisBaseEntity {
|
||||||
|
|
||||||
|
/** 主键ID */
|
||||||
|
@TableId(type = IdType.ASSIGN_ID)
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/** 目录类别 */
|
||||||
|
private String categoryCode;
|
||||||
|
|
||||||
|
/** 编码 */
|
||||||
|
private String busNo;
|
||||||
|
|
||||||
|
/** 项目名称 */
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/** 项目名称拼音 */
|
||||||
|
private String pyStr;
|
||||||
|
|
||||||
|
/** 五笔拼音 */
|
||||||
|
private String wbStr;
|
||||||
|
|
||||||
|
/** 类型 */
|
||||||
|
private Integer typeEnum;
|
||||||
|
|
||||||
|
/** 使用单位 */
|
||||||
|
private String permittedUnitCode;
|
||||||
|
|
||||||
|
/** 所属科室 */
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long orgId;
|
||||||
|
|
||||||
|
/** 所在位置 */
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long locationId;
|
||||||
|
|
||||||
|
/** 医保标记 */
|
||||||
|
private Integer ybFlag;
|
||||||
|
|
||||||
|
/** 医保编码 */
|
||||||
|
private String ybNo;
|
||||||
|
|
||||||
|
/** 医保对码标记 */
|
||||||
|
private Integer ybMatchFlag;
|
||||||
|
|
||||||
|
/** 状态 */
|
||||||
|
private Integer statusEnum;
|
||||||
|
|
||||||
|
/** 身体部位 */
|
||||||
|
private String bodySiteCode;
|
||||||
|
|
||||||
|
/** 所需标本 */
|
||||||
|
private String specimenCode;
|
||||||
|
|
||||||
|
/** 说明 */
|
||||||
|
private String descriptionText;
|
||||||
|
|
||||||
|
/** 规则id */
|
||||||
|
private Integer ruleId;
|
||||||
|
|
||||||
|
/** 医保等级 */
|
||||||
|
private Integer chrgitmLv;
|
||||||
|
|
||||||
|
/** 子项json */
|
||||||
|
private String childrenJson;
|
||||||
|
|
||||||
|
/** 划价标记 */
|
||||||
|
private Integer pricingFlag;
|
||||||
|
|
||||||
|
/** 序号 */
|
||||||
|
private Integer sortOrder;
|
||||||
|
|
||||||
|
/** 服务范围 */
|
||||||
|
private String serviceRange;
|
||||||
|
|
||||||
|
/** 检验类型ID(关联 inspection_type 大类,逻辑关联无外键) */
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long inspectionTypeId;
|
||||||
|
|
||||||
|
/** 费用套餐ID(关联 inspection_basic_information,逻辑关联无外键) */
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long feePackageId;
|
||||||
|
|
||||||
|
/** 下级医技类型ID(关联 inspection_type 子类,逻辑关联无外键) */
|
||||||
|
@JsonSerialize(using = ToStringSerializer.class)
|
||||||
|
private Long subItemId;
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.openhis.lab.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
|
import com.openhis.lab.domain.LabActivityDefinition;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目定义 Mapper 接口
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface LabActivityDefinitionMapper extends BaseMapper<LabActivityDefinition> {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.openhis.lab.service;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.service.IService;
|
||||||
|
import com.openhis.lab.domain.LabActivityDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目定义 Service 接口
|
||||||
|
*/
|
||||||
|
public interface ILabActivityDefinitionService extends IService<LabActivityDefinition> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增检验项目
|
||||||
|
*
|
||||||
|
* @param labActivityDefinition 检验项目实体
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
boolean addLabActivityDefinition(LabActivityDefinition labActivityDefinition);
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.openhis.lab.service.impl;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.core.common.utils.SecurityUtils;
|
||||||
|
import com.core.common.core.domain.model.LoginUser;
|
||||||
|
import com.openhis.lab.domain.LabActivityDefinition;
|
||||||
|
import com.openhis.lab.mapper.LabActivityDefinitionMapper;
|
||||||
|
import com.openhis.lab.service.ILabActivityDefinitionService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目定义 Service 实现类
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class LabActivityDefinitionServiceImpl
|
||||||
|
extends ServiceImpl<LabActivityDefinitionMapper, LabActivityDefinition>
|
||||||
|
implements ILabActivityDefinitionService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 新增检验项目(检查编码唯一性)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public boolean addLabActivityDefinition(LabActivityDefinition labActivityDefinition) {
|
||||||
|
// 根据编码判断是否已存在
|
||||||
|
List<LabActivityDefinition> existing = baseMapper.selectList(
|
||||||
|
new LambdaQueryWrapper<LabActivityDefinition>()
|
||||||
|
.eq(LabActivityDefinition::getBusNo, labActivityDefinition.getBusNo()));
|
||||||
|
if (!existing.isEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setRequiredFields(labActivityDefinition);
|
||||||
|
return baseMapper.insert(labActivityDefinition) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 补全必填字段(create_by、tenant_id、create_time)
|
||||||
|
*/
|
||||||
|
private void setRequiredFields(LabActivityDefinition entity) {
|
||||||
|
String createBy = "system";
|
||||||
|
Integer tenantId = 1;
|
||||||
|
try {
|
||||||
|
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||||
|
if (loginUser != null) {
|
||||||
|
createBy = loginUser.getUsername();
|
||||||
|
tenantId = loginUser.getTenantId() != null ? loginUser.getTenantId() : 1;
|
||||||
|
}
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
entity.setCreateBy(createBy);
|
||||||
|
entity.setTenantId(tenantId);
|
||||||
|
if (entity.getCreateTime() == null) {
|
||||||
|
entity.setCreateTime(new Date());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,10 @@ public class OpSchedule extends HisBaseEntity {
|
|||||||
/** 就诊ID */
|
/** 就诊ID */
|
||||||
private Long visitId;
|
private Long visitId;
|
||||||
|
|
||||||
|
/** 就诊卡号 */
|
||||||
|
@TableField(exist = false)
|
||||||
|
private String identifierNo;
|
||||||
|
|
||||||
/** 手术编码 */
|
/** 手术编码 */
|
||||||
private String operCode;
|
private String operCode;
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,46 @@
|
|||||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
<mapper namespace="com.openhis.appointmentmanage.mapper.ScheduleSlotMapper">
|
<mapper namespace="com.openhis.appointmentmanage.mapper.ScheduleSlotMapper">
|
||||||
|
|
||||||
|
<!-- 统一状态值(兼容数字/英文字符串存储),输出 Integer,避免 resultType 映射 NumberFormatException -->
|
||||||
|
<sql id="slotStatusNormExpr">
|
||||||
|
CASE
|
||||||
|
WHEN LOWER(CONCAT('', s.status)) IN ('0', 'unbooked', 'available') THEN 0
|
||||||
|
WHEN LOWER(CONCAT('', s.status)) IN ('1', 'booked') THEN 1
|
||||||
|
WHEN LOWER(CONCAT('', s.status)) IN ('2', 'cancelled', 'canceled', 'stopped') THEN 2
|
||||||
|
WHEN LOWER(CONCAT('', s.status)) IN ('3', 'locked') THEN 3
|
||||||
|
WHEN LOWER(CONCAT('', s.status)) IN ('4', 'checked', 'checked_in', 'checkin') THEN 4
|
||||||
|
WHEN LOWER(CONCAT('', s.status)) IN ('5', 'returned') THEN 5
|
||||||
|
ELSE NULL
|
||||||
|
END
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<sql id="orderStatusNormExpr">
|
||||||
|
CASE
|
||||||
|
WHEN LOWER(CONCAT('', o.status)) IN ('1', 'booked') THEN 1
|
||||||
|
WHEN LOWER(CONCAT('', o.status)) IN ('2', 'checked', 'checked_in', 'checkin') THEN 2
|
||||||
|
WHEN LOWER(CONCAT('', o.status)) IN ('3', 'cancelled', 'canceled') THEN 3
|
||||||
|
WHEN LOWER(CONCAT('', o.status)) IN ('4', 'returned') THEN 4
|
||||||
|
ELSE NULL
|
||||||
|
END
|
||||||
|
</sql>
|
||||||
|
|
||||||
|
<sql id="poolStatusNormExpr">
|
||||||
|
CASE
|
||||||
|
WHEN LOWER(CONCAT('', p.status)) IN ('0', 'unbooked', 'available') THEN 0
|
||||||
|
WHEN LOWER(CONCAT('', p.status)) IN ('1', 'booked') THEN 1
|
||||||
|
WHEN LOWER(CONCAT('', p.status)) IN ('2', 'cancelled', 'canceled', 'stopped') THEN 2
|
||||||
|
WHEN LOWER(CONCAT('', p.status)) IN ('3', 'locked') THEN 3
|
||||||
|
WHEN LOWER(CONCAT('', p.status)) IN ('4', 'checked', 'checked_in', 'checkin') THEN 4
|
||||||
|
WHEN LOWER(CONCAT('', p.status)) IN ('5', 'returned') THEN 5
|
||||||
|
ELSE NULL
|
||||||
|
END
|
||||||
|
</sql>
|
||||||
|
|
||||||
<!-- 注意这里的 resultType 指向了您刚建好的 DTO 实体类 -->
|
<!-- 注意这里的 resultType 指向了您刚建好的 DTO 实体类 -->
|
||||||
<select id="selectAllTicketSlots" resultType="com.openhis.appointmentmanage.domain.TicketSlotDTO">
|
<select id="selectAllTicketSlots" resultType="com.openhis.appointmentmanage.domain.TicketSlotDTO">
|
||||||
SELECT
|
SELECT
|
||||||
s.id AS slotId,
|
s.id AS slotId,
|
||||||
|
s.seq_no AS seqNo,
|
||||||
p.schedule_id AS scheduleId,
|
p.schedule_id AS scheduleId,
|
||||||
p.doctor_name AS doctor,
|
p.doctor_name AS doctor,
|
||||||
p.dept_id AS departmentId,
|
p.dept_id AS departmentId,
|
||||||
@@ -16,12 +52,12 @@
|
|||||||
o.patient_name AS patientName,
|
o.patient_name AS patientName,
|
||||||
o.medical_card AS medicalCard,
|
o.medical_card AS medicalCard,
|
||||||
o.phone AS phone,
|
o.phone AS phone,
|
||||||
o.status AS orderStatus,
|
<include refid="orderStatusNormExpr" /> AS orderStatus,
|
||||||
s.status AS slotStatus,
|
<include refid="slotStatusNormExpr" /> AS slotStatus,
|
||||||
s.expect_time AS expectTime,
|
s.expect_time AS expectTime,
|
||||||
p.schedule_date AS scheduleDate,
|
p.schedule_date AS scheduleDate,
|
||||||
d.reg_type AS regType,
|
d.reg_type AS regType,
|
||||||
p.status AS poolStatus,
|
<include refid="poolStatusNormExpr" /> AS poolStatus,
|
||||||
p.stop_reason AS stopReason,
|
p.stop_reason AS stopReason,
|
||||||
d.is_stopped AS isStopped
|
d.is_stopped AS isStopped
|
||||||
FROM
|
FROM
|
||||||
@@ -39,7 +75,7 @@
|
|||||||
FROM
|
FROM
|
||||||
order_main
|
order_main
|
||||||
WHERE
|
WHERE
|
||||||
status IN (1, 2)
|
LOWER(CONCAT('', status)) IN ('1', '2', '4', 'booked', 'checked', 'checked_in', 'checkin', 'returned')
|
||||||
ORDER BY
|
ORDER BY
|
||||||
slot_id,
|
slot_id,
|
||||||
create_time DESC
|
create_time DESC
|
||||||
@@ -56,6 +92,7 @@
|
|||||||
<select id="selectTicketSlotById" resultType="com.openhis.appointmentmanage.domain.TicketSlotDTO">
|
<select id="selectTicketSlotById" resultType="com.openhis.appointmentmanage.domain.TicketSlotDTO">
|
||||||
SELECT
|
SELECT
|
||||||
s.id AS slotId,
|
s.id AS slotId,
|
||||||
|
s.seq_no AS seqNo,
|
||||||
p.schedule_id AS scheduleId,
|
p.schedule_id AS scheduleId,
|
||||||
p.doctor_name AS doctor,
|
p.doctor_name AS doctor,
|
||||||
p.doctor_id AS doctorId,
|
p.doctor_id AS doctorId,
|
||||||
@@ -66,12 +103,18 @@
|
|||||||
o.patient_name AS patientName,
|
o.patient_name AS patientName,
|
||||||
o.medical_card AS medicalCard,
|
o.medical_card AS medicalCard,
|
||||||
o.phone AS phone,
|
o.phone AS phone,
|
||||||
o.status AS orderStatus,
|
o.id AS orderId,
|
||||||
s.status AS slotStatus,
|
o.order_no AS orderNo,
|
||||||
|
COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender,
|
||||||
|
pinfo.gender_enum AS genderEnum,
|
||||||
|
pinfo.id_card AS idCard,
|
||||||
|
o.appointment_time AS appointmentTime,
|
||||||
|
<include refid="orderStatusNormExpr" /> AS orderStatus,
|
||||||
|
<include refid="slotStatusNormExpr" /> AS slotStatus,
|
||||||
s.expect_time AS expectTime,
|
s.expect_time AS expectTime,
|
||||||
p.schedule_date AS scheduleDate,
|
p.schedule_date AS scheduleDate,
|
||||||
d.reg_type AS regType,
|
d.reg_type AS regType,
|
||||||
p.status AS poolStatus,
|
<include refid="poolStatusNormExpr" /> AS poolStatus,
|
||||||
p.stop_reason AS stopReason,
|
p.stop_reason AS stopReason,
|
||||||
d.is_stopped AS isStopped
|
d.is_stopped AS isStopped
|
||||||
FROM
|
FROM
|
||||||
@@ -87,15 +130,20 @@
|
|||||||
patient_name,
|
patient_name,
|
||||||
medical_card,
|
medical_card,
|
||||||
phone,
|
phone,
|
||||||
|
id,
|
||||||
|
order_no,
|
||||||
|
gender,
|
||||||
|
appointment_time,
|
||||||
status
|
status
|
||||||
FROM
|
FROM
|
||||||
order_main
|
order_main
|
||||||
WHERE
|
WHERE
|
||||||
status IN (1, 2)
|
LOWER(CONCAT('', status)) IN ('1', '2', '4', 'booked', 'checked', 'checked_in', 'checkin', 'returned')
|
||||||
ORDER BY
|
ORDER BY
|
||||||
slot_id,
|
slot_id,
|
||||||
create_time DESC
|
create_time DESC
|
||||||
) o ON o.slot_id = s.id
|
) o ON o.slot_id = s.id
|
||||||
|
LEFT JOIN adm_patient pinfo ON o.patient_id = pinfo.id
|
||||||
WHERE
|
WHERE
|
||||||
s.id = #{id}
|
s.id = #{id}
|
||||||
</select>
|
</select>
|
||||||
@@ -115,7 +163,7 @@
|
|||||||
UPDATE adm_schedule_slot
|
UPDATE adm_schedule_slot
|
||||||
SET
|
SET
|
||||||
status = #{status},
|
status = #{status},
|
||||||
<if test="status == 0">
|
<if test="status != null and '0'.equals(status.toString())">
|
||||||
order_id = NULL,
|
order_id = NULL,
|
||||||
</if>
|
</if>
|
||||||
update_time = now()
|
update_time = now()
|
||||||
@@ -124,11 +172,25 @@
|
|||||||
AND delete_flag = '0'
|
AND delete_flag = '0'
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="updateSlotStatusAndCheckInTime">
|
||||||
|
UPDATE adm_schedule_slot
|
||||||
|
SET
|
||||||
|
status = #{status},
|
||||||
|
check_in_time = #{checkInTime},
|
||||||
|
update_time = NOW()
|
||||||
|
WHERE
|
||||||
|
id = #{slotId}
|
||||||
|
AND delete_flag = '0'
|
||||||
|
</update>
|
||||||
|
|
||||||
<select id="selectPoolIdBySlotId" resultType="java.lang.Long">
|
<select id="selectPoolIdBySlotId" resultType="java.lang.Long">
|
||||||
SELECT pool_id
|
SELECT
|
||||||
FROM adm_schedule_slot
|
pool_id
|
||||||
WHERE id = #{slotId}
|
FROM
|
||||||
AND delete_flag = '0'
|
adm_schedule_slot
|
||||||
|
WHERE
|
||||||
|
id = #{slotId}
|
||||||
|
AND delete_flag = '0'
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<update id="bindOrderToSlot">
|
<update id="bindOrderToSlot">
|
||||||
@@ -145,6 +207,7 @@
|
|||||||
<select id="selectTicketSlotsPage" resultType="com.openhis.appointmentmanage.domain.TicketSlotDTO">
|
<select id="selectTicketSlotsPage" resultType="com.openhis.appointmentmanage.domain.TicketSlotDTO">
|
||||||
SELECT
|
SELECT
|
||||||
s.id AS slotId,
|
s.id AS slotId,
|
||||||
|
s.seq_no AS seqNo,
|
||||||
p.schedule_id AS scheduleId,
|
p.schedule_id AS scheduleId,
|
||||||
p.doctor_name AS doctor,
|
p.doctor_name AS doctor,
|
||||||
p.doctor_id AS doctorId,
|
p.doctor_id AS doctorId,
|
||||||
@@ -155,12 +218,18 @@
|
|||||||
o.patient_name AS patientName,
|
o.patient_name AS patientName,
|
||||||
o.medical_card AS medicalCard,
|
o.medical_card AS medicalCard,
|
||||||
o.phone AS phone,
|
o.phone AS phone,
|
||||||
o.status AS orderStatus,
|
o.id AS orderId,
|
||||||
s.status AS slotStatus,
|
o.order_no AS orderNo,
|
||||||
|
COALESCE(CAST(o.gender AS VARCHAR), CAST(pinfo.gender_enum AS VARCHAR)) AS patientGender,
|
||||||
|
pinfo.gender_enum AS genderEnum,
|
||||||
|
pinfo.id_card AS idCard,
|
||||||
|
o.appointment_time AS appointmentTime,
|
||||||
|
<include refid="orderStatusNormExpr" /> AS orderStatus,
|
||||||
|
<include refid="slotStatusNormExpr" /> AS slotStatus,
|
||||||
s.expect_time AS expectTime,
|
s.expect_time AS expectTime,
|
||||||
p.schedule_date AS scheduleDate,
|
p.schedule_date AS scheduleDate,
|
||||||
d.reg_type AS regType,
|
d.reg_type AS regType,
|
||||||
p.status AS poolStatus,
|
<include refid="poolStatusNormExpr" /> AS poolStatus,
|
||||||
p.stop_reason AS stopReason,
|
p.stop_reason AS stopReason,
|
||||||
d.is_stopped AS isStopped
|
d.is_stopped AS isStopped
|
||||||
FROM
|
FROM
|
||||||
@@ -176,15 +245,20 @@
|
|||||||
patient_name,
|
patient_name,
|
||||||
medical_card,
|
medical_card,
|
||||||
phone,
|
phone,
|
||||||
|
id,
|
||||||
|
order_no,
|
||||||
|
gender,
|
||||||
|
appointment_time,
|
||||||
status
|
status
|
||||||
FROM
|
FROM
|
||||||
order_main
|
order_main
|
||||||
WHERE
|
WHERE
|
||||||
status IN (1, 2)
|
LOWER(CONCAT('', status)) IN ('1', '2', '4', 'booked', 'checked', 'checked_in', 'checkin', 'returned')
|
||||||
ORDER BY
|
ORDER BY
|
||||||
slot_id,
|
slot_id,
|
||||||
create_time DESC
|
create_time DESC
|
||||||
) o ON o.slot_id = s.id
|
) o ON o.slot_id = s.id
|
||||||
|
LEFT JOIN adm_patient pinfo ON o.patient_id = pinfo.id
|
||||||
<where>
|
<where>
|
||||||
p.delete_flag = '0'
|
p.delete_flag = '0'
|
||||||
AND s.delete_flag = '0' <!-- 1. 按日期查 -->
|
AND s.delete_flag = '0' <!-- 1. 按日期查 -->
|
||||||
@@ -225,35 +299,49 @@
|
|||||||
<!-- 5. 核心:解答您疑问的 4 种业务状态的复合查询! -->
|
<!-- 5. 核心:解答您疑问的 4 种业务状态的复合查询! -->
|
||||||
<if test="query.status != null and query.status != '' and query.status != 'all'">
|
<if test="query.status != null and query.status != '' and query.status != 'all'">
|
||||||
<choose>
|
<choose>
|
||||||
<when test="query.status == 'unbooked'">
|
<when test="'unbooked'.equals(query.status) or '未预约'.equals(query.status)">
|
||||||
AND s.status = 0
|
AND <include refid="slotStatusNormExpr" /> = 0
|
||||||
AND (
|
AND (
|
||||||
d.is_stopped IS NULL
|
d.is_stopped IS NULL
|
||||||
OR d.is_stopped = FALSE
|
OR d.is_stopped = FALSE
|
||||||
)
|
)
|
||||||
</when>
|
</when>
|
||||||
<when test="query.status == 'booked'">
|
<when test="'booked'.equals(query.status) or '已预约'.equals(query.status)">
|
||||||
AND s.status = 1
|
AND <include refid="slotStatusNormExpr" /> = 1
|
||||||
AND o.status = 1
|
AND <include refid="orderStatusNormExpr" /> = 1
|
||||||
AND (
|
AND (
|
||||||
d.is_stopped IS NULL
|
d.is_stopped IS NULL
|
||||||
OR d.is_stopped = FALSE
|
OR d.is_stopped = FALSE
|
||||||
)
|
)
|
||||||
</when>
|
</when>
|
||||||
<when test="query.status == 'checked'">
|
<when test="'checked'.equals(query.status) or '已取号'.equals(query.status)">
|
||||||
AND s.status = 1
|
AND (
|
||||||
AND o.status = 2
|
<include refid="slotStatusNormExpr" /> = 4
|
||||||
|
OR (
|
||||||
|
<include refid="slotStatusNormExpr" /> = 1
|
||||||
|
AND <include refid="orderStatusNormExpr" /> = 2
|
||||||
|
)
|
||||||
|
)
|
||||||
AND (
|
AND (
|
||||||
d.is_stopped IS NULL
|
d.is_stopped IS NULL
|
||||||
OR d.is_stopped = FALSE
|
OR d.is_stopped = FALSE
|
||||||
)
|
)
|
||||||
</when>
|
</when>
|
||||||
<when test="query.status == 'cancelled'">
|
<when test="'cancelled'.equals(query.status) or '已停诊'.equals(query.status) or '已取消'.equals(query.status)">
|
||||||
AND (
|
AND (
|
||||||
s.status = 2
|
<include refid="slotStatusNormExpr" /> = 2
|
||||||
OR d.is_stopped = TRUE
|
OR d.is_stopped = TRUE
|
||||||
)
|
)
|
||||||
</when>
|
</when>
|
||||||
|
<when test="'returned'.equals(query.status) or '已退号'.equals(query.status)">
|
||||||
|
AND (
|
||||||
|
<include refid="slotStatusNormExpr" /> = 5
|
||||||
|
OR <include refid="orderStatusNormExpr" /> = 4
|
||||||
|
)
|
||||||
|
</when>
|
||||||
|
<otherwise>
|
||||||
|
AND 1 = 2
|
||||||
|
</otherwise>
|
||||||
</choose>
|
</choose>
|
||||||
</if>
|
</if>
|
||||||
</where>
|
</where>
|
||||||
@@ -266,9 +354,22 @@
|
|||||||
SELECT
|
SELECT
|
||||||
p.doctor_id AS doctorId,
|
p.doctor_id AS doctorId,
|
||||||
p.doctor_name AS doctorName,
|
p.doctor_name AS doctorName,
|
||||||
COALESCE(SUM(GREATEST(COALESCE(p.total_quota, 0) - COALESCE(p.booked_num, 0) - COALESCE(p.locked_num, 0), 0)), 0) AS available,
|
COALESCE(
|
||||||
|
SUM(
|
||||||
|
GREATEST(
|
||||||
|
COALESCE(p.total_quota, 0) - COALESCE(p.booked_num, 0) - COALESCE(p.locked_num, 0),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
),
|
||||||
|
0
|
||||||
|
) AS available,
|
||||||
CASE
|
CASE
|
||||||
WHEN MAX(CASE WHEN d.reg_type = 1 THEN 1 ELSE 0 END) = 1 THEN 'expert'
|
WHEN MAX(
|
||||||
|
CASE
|
||||||
|
WHEN d.reg_type = 1 THEN 1
|
||||||
|
ELSE 0
|
||||||
|
END
|
||||||
|
) = 1 THEN 'expert'
|
||||||
ELSE 'general'
|
ELSE 'general'
|
||||||
END AS ticketType
|
END AS ticketType
|
||||||
FROM
|
FROM
|
||||||
@@ -290,7 +391,10 @@
|
|||||||
AND d.reg_type = 1
|
AND d.reg_type = 1
|
||||||
</when>
|
</when>
|
||||||
<when test="query.type == 'general'">
|
<when test="query.type == 'general'">
|
||||||
AND (d.reg_type != 1 OR d.reg_type IS NULL)
|
AND (
|
||||||
|
d.reg_type != 1
|
||||||
|
OR d.reg_type IS NULL
|
||||||
|
)
|
||||||
</when>
|
</when>
|
||||||
</choose>
|
</choose>
|
||||||
</if>
|
</if>
|
||||||
|
|||||||
@@ -127,7 +127,7 @@
|
|||||||
select * from order_main where slot_id = #{slotId} and status = 1
|
select * from order_main where slot_id = #{slotId} and status = 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<insert id="insertOrder" parameterType="com.openhis.clinical.domain.Order">
|
<insert id="insertOrder" parameterType="com.openhis.clinical.domain.Order" useGeneratedKeys="true" keyProperty="id">
|
||||||
insert into order_main
|
insert into order_main
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
<if test="orderNo != null and orderNo != ''">order_no,</if>
|
<if test="orderNo != null and orderNo != ''">order_no,</if>
|
||||||
@@ -225,6 +225,12 @@
|
|||||||
update order_main set status = 3, cancel_time = #{cancelTime}, cancel_reason = #{cancelReason} where id = #{id}
|
update order_main set status = 3, cancel_time = #{cancelTime}, cancel_reason = #{cancelReason} where id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="updatePayStatus">
|
||||||
|
update order_main
|
||||||
|
set pay_status = #{payStatus}, pay_time = #{payTime}, update_time = NOW()
|
||||||
|
where id = #{orderId}
|
||||||
|
</update>
|
||||||
|
|
||||||
<delete id="deleteOrderById">
|
<delete id="deleteOrderById">
|
||||||
delete from order_main where id = #{id}
|
delete from order_main where id = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper
|
||||||
|
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||||
|
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="com.openhis.lab.mapper.LabActivityDefinitionMapper">
|
||||||
|
|
||||||
|
</mapper>
|
||||||
12700
openhis-ui-vue3/package-lock.json
generated
12700
openhis-ui-vue3/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,25 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
/**
|
/**
|
||||||
* Fix lodash.template assignWith issue - Manual fix script
|
* Emergency patch for lodash.template@4.18.x (broken assignWith).
|
||||||
* Run this after npm/yarn install and before build
|
* When package.json "overrides" pins lodash.template@4.5.0, do NOT run this — it is unnecessary and may corrupt the file.
|
||||||
*
|
*
|
||||||
* Usage: node fix-lodash-manual.js
|
* Usage: node fix-lodash-manual.js
|
||||||
*/
|
*/
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
|
const lodashTemplatePkg = path.join(__dirname, 'node_modules', 'lodash.template', 'package.json');
|
||||||
|
if (fs.existsSync(lodashTemplatePkg)) {
|
||||||
|
try {
|
||||||
|
const ver = JSON.parse(fs.readFileSync(lodashTemplatePkg, 'utf8')).version || '';
|
||||||
|
if (ver.startsWith('4.5.')) {
|
||||||
|
console.log('✓ lodash.template is already 4.5.x (overrides); skip manual patch');
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
/* continue to patch path */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const lodashTemplatePath = path.join(__dirname, 'node_modules', 'lodash.template', 'index.js');
|
const lodashTemplatePath = path.join(__dirname, 'node_modules', 'lodash.template', 'index.js');
|
||||||
|
|
||||||
if (!fs.existsSync(lodashTemplatePath)) {
|
if (!fs.existsSync(lodashTemplatePath)) {
|
||||||
@@ -18,34 +30,35 @@ if (!fs.existsSync(lodashTemplatePath)) {
|
|||||||
|
|
||||||
let content = fs.readFileSync(lodashTemplatePath, 'utf8');
|
let content = fs.readFileSync(lodashTemplatePath, 'utf8');
|
||||||
|
|
||||||
// Check if already patched
|
// Check if already patched with new version
|
||||||
if (content.includes('/* LODASH_TEMPLATE_PATCHED */')) {
|
if (content.includes('/* LODASH_TEMPLATE_PATCHED_V2 */')) {
|
||||||
console.log('✓ lodash.template already patched');
|
console.log('✓ lodash.template already patched with v2');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if assignWith is actually missing
|
// Remove old patch if exists
|
||||||
if (content.includes('assignWith')) {
|
if (content.includes('/* LODASH_TEMPLATE_PATCHED */')) {
|
||||||
// Check if it's used but not defined
|
console.log('🔄 Removing old patch...');
|
||||||
const hasFunctionDefinition = /function\s+assignWith|var\s+assignWith\s*=/.test(content);
|
content = content.replace(/\/\* LODASH_TEMPLATE_PATCHED \*\/\n.*assignWith[\s\S]*?^\}/m, '');
|
||||||
if (hasFunctionDefinition) {
|
|
||||||
console.log('✓ assignWith is already defined in lodash.template');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('🔧 Patching lodash.template...');
|
console.log('🔧 Patching lodash.template with v2...');
|
||||||
|
|
||||||
// Simple assignWith implementation
|
// Correct assignWith implementation that handles undefined customizer
|
||||||
const assignWithImpl = `/* LODASH_TEMPLATE_PATCHED */
|
const assignWithImpl = `/* LODASH_TEMPLATE_PATCHED_V2 */
|
||||||
// assignWith polyfill for lodash.template
|
// assignWith polyfill for lodash.template - Fixed version
|
||||||
function assignWith(object, source, customizer) {
|
function assignWith(object, source, customizer) {
|
||||||
if (object == null) return object;
|
if (object == null) return object;
|
||||||
|
if (typeof customizer !== 'function') {
|
||||||
|
customizer = function(objValue, srcValue) {
|
||||||
|
return srcValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
var props = Object.keys(Object(source));
|
var props = Object.keys(Object(source));
|
||||||
for (var i = 0; i < props.length; i++) {
|
for (var i = 0; i < props.length; i++) {
|
||||||
var key = props[i];
|
var key = props[i];
|
||||||
var value = source[key];
|
var value = source[key];
|
||||||
var assignedValue = customizer ? customizer(object[key], value, key, object, source) : value;
|
var assignedValue = customizer(object[key], value, key, object, source);
|
||||||
if (assignedValue !== undefined) {
|
if (assignedValue !== undefined) {
|
||||||
object[key] = assignedValue;
|
object[key] = assignedValue;
|
||||||
}
|
}
|
||||||
@@ -74,5 +87,5 @@ const after = content.substring(insertPos);
|
|||||||
content = before + '\n' + assignWithImpl + after;
|
content = before + '\n' + assignWithImpl + after;
|
||||||
|
|
||||||
fs.writeFileSync(lodashTemplatePath, content);
|
fs.writeFileSync(lodashTemplatePath, content);
|
||||||
console.log('✅ Successfully patched lodash.template with assignWith function');
|
console.log('✅ Successfully patched lodash.template with assignWith function (v2)');
|
||||||
console.log(' File:', lodashTemplatePath);
|
console.log(' File:', lodashTemplatePath);
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# Fix lodash.template assignWith issue for Linux/Mac servers
|
# Emergency patch for lodash.template@4.18.x only. Skip when overrides pin 4.5.0.
|
||||||
# Run this script after npm/yarn install
|
# Run after npm install on Linux/Mac if needed.
|
||||||
|
|
||||||
|
if [ -f "node_modules/lodash.template/package.json" ]; then
|
||||||
|
VER=$(node -p "require('./node_modules/lodash.template/package.json').version" 2>/dev/null || echo "")
|
||||||
|
case "$VER" in
|
||||||
|
4.5.*) echo "✓ lodash.template is $VER; skip manual patch"; exit 0 ;;
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
LODGASH_TEMPLATE="node_modules/lodash.template/index.js"
|
LODGASH_TEMPLATE="node_modules/lodash.template/index.js"
|
||||||
|
|
||||||
@@ -9,34 +16,43 @@ if [ ! -f "$LODGASH_TEMPLATE" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if already patched
|
# Check if already patched with v2
|
||||||
if grep -q "LODASH_TEMPLATE_PATCHED" "$LODGASH_TEMPLATE"; then
|
if grep -q "LODASH_TEMPLATE_PATCHED_V2" "$LODGASH_TEMPLATE"; then
|
||||||
echo "✓ lodash.template already patched"
|
echo "✓ lodash.template already patched with v2"
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "🔧 Patching lodash.template..."
|
# Remove old patch if exists
|
||||||
|
if grep -q "LODASH_TEMPLATE_PATCHED" "$LODGASH_TEMPLATE"; then
|
||||||
|
echo "🔄 Removing old patch..."
|
||||||
|
# Use sed to remove old patch (multi-line)
|
||||||
|
sed -i '/\/\* LODASH_TEMPLATE_PATCHED \*\//,/^}$/d' "$LODGASH_TEMPLATE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "🔧 Patching lodash.template with v2..."
|
||||||
|
|
||||||
# Create a temporary file with the patch
|
# Create a temporary file with the patch
|
||||||
PATCH=$(cat <<'EOF'
|
PATCH='/* LODASH_TEMPLATE_PATCHED_V2 */
|
||||||
/* LODASH_TEMPLATE_PATCHED */
|
// assignWith polyfill for lodash.template - Fixed version
|
||||||
// assignWith polyfill for lodash.template
|
|
||||||
function assignWith(object, source, customizer) {
|
function assignWith(object, source, customizer) {
|
||||||
if (object == null) return object;
|
if (object == null) return object;
|
||||||
|
if (typeof customizer !== "function") {
|
||||||
|
customizer = function(objValue, srcValue) {
|
||||||
|
return srcValue;
|
||||||
|
};
|
||||||
|
}
|
||||||
var props = Object.keys(Object(source));
|
var props = Object.keys(Object(source));
|
||||||
for (var i = 0; i < props.length; i++) {
|
for (var i = 0; i < props.length; i++) {
|
||||||
var key = props[i];
|
var key = props[i];
|
||||||
var value = source[key];
|
var value = source[key];
|
||||||
var assignedValue = customizer ? customizer(object[key], value, key, object, source) : value;
|
var assignedValue = customizer(object[key], value, key, object, source);
|
||||||
if (assignedValue !== undefined) {
|
if (assignedValue !== undefined) {
|
||||||
object[key] = assignedValue;
|
object[key] = assignedValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
'
|
||||||
EOF
|
|
||||||
)
|
|
||||||
|
|
||||||
# Insert after the first line (license comment)
|
# Insert after the first line (license comment)
|
||||||
{
|
{
|
||||||
@@ -45,4 +61,4 @@ EOF
|
|||||||
tail -n +2 "$LODGASH_TEMPLATE"
|
tail -n +2 "$LODGASH_TEMPLATE"
|
||||||
} > "$LODGASH_TEMPLATE.tmp" && mv "$LODGASH_TEMPLATE.tmp" "$LODGASH_TEMPLATE"
|
} > "$LODGASH_TEMPLATE.tmp" && mv "$LODGASH_TEMPLATE.tmp" "$LODGASH_TEMPLATE"
|
||||||
|
|
||||||
echo "✅ Successfully patched lodash.template with assignWith function"
|
echo "✅ Successfully patched lodash.template with assignWith function (v2)"
|
||||||
|
|||||||
@@ -9,20 +9,24 @@
|
|||||||
"predev": "node utils/check.js dev && vdoing",
|
"predev": "node utils/check.js dev && vdoing",
|
||||||
"prebuild": "node utils/check.js build && vdoing",
|
"prebuild": "node utils/check.js build && vdoing",
|
||||||
"updateTheme": "yarn remove vuepress-theme-vdoing && rm -rf node_modules && yarn && yarn add vuepress-theme-vdoing -D",
|
"updateTheme": "yarn remove vuepress-theme-vdoing && rm -rf node_modules && yarn && yarn add vuepress-theme-vdoing -D",
|
||||||
"editFm": "node utils/editFrontmatter.js"
|
"editFm": "node utils/editFrontmatter.js",
|
||||||
|
"fix-lodash": "node fix-lodash-manual.js",
|
||||||
|
"build:fixed": "npm run fix-lodash && npm run build",
|
||||||
|
"build:win:fixed": "npm run fix-lodash && npm run build:win"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
"lodash": "4.17.21",
|
||||||
"lodash.template": "4.5.0"
|
"lodash.template": "4.5.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"dayjs": "^1.9.7",
|
"dayjs": "^1.9.7",
|
||||||
"inquirer": "^7.1.0",
|
"inquirer": "^7.1.0",
|
||||||
"json2yaml": "^1.1.0",
|
"json2yaml": "^1.1.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "4.17.21",
|
||||||
"vuepress": "1.9.9",
|
"vuepress": "1.9.9",
|
||||||
"vuepress-plugin-baidu-tongji": "^1.0.1",
|
"vuepress-plugin-baidu-tongji": "^1.0.1",
|
||||||
"vuepress-plugin-demo-block": "^0.7.2",
|
"vuepress-plugin-demo-block": "^0.7.2",
|
||||||
|
|||||||
60
openhis-ui-vue3/src/api/lab/labActivityDefinition.js
Normal file
60
openhis-ui-vue3/src/api/lab/labActivityDefinition.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检验项目维护专属 API(操作 lab_activity_definition 表)
|
||||||
|
* 后端路径前缀:/lab/activity-definition
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 分页查询检验项目列表
|
||||||
|
export function getLabActivityDefinitionPage(query) {
|
||||||
|
return request({
|
||||||
|
url: '/lab/activity-definition/page',
|
||||||
|
method: 'get',
|
||||||
|
params: query,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询检验项目详情
|
||||||
|
export function getLabActivityDefinitionOne(id) {
|
||||||
|
return request({
|
||||||
|
url: '/lab/activity-definition/one',
|
||||||
|
method: 'get',
|
||||||
|
params: { id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增检验项目
|
||||||
|
export function addLabActivityDefinition(data) {
|
||||||
|
return request({
|
||||||
|
url: '/lab/activity-definition/add',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 编辑检验项目
|
||||||
|
export function editLabActivityDefinition(data) {
|
||||||
|
return request({
|
||||||
|
url: '/lab/activity-definition/edit',
|
||||||
|
method: 'put',
|
||||||
|
data: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停用检验项目
|
||||||
|
export function stopLabActivityDefinition(ids) {
|
||||||
|
return request({
|
||||||
|
url: '/lab/activity-definition/stop',
|
||||||
|
method: 'put',
|
||||||
|
data: ids,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启用检验项目
|
||||||
|
export function startLabActivityDefinition(ids) {
|
||||||
|
return request({
|
||||||
|
url: '/lab/activity-definition/start',
|
||||||
|
method: 'put',
|
||||||
|
data: ids,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -29,10 +29,17 @@ export function formatDateStr(cellValue, format = 'YYYY-MM-DD HH:mm:ss') {
|
|||||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
const seconds = String(date.getSeconds()).padStart(2, '0');
|
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||||
|
|
||||||
|
// 支持不带前导零的格式
|
||||||
|
const monthNoPad = String(date.getMonth() + 1);
|
||||||
|
const dayNoPad = String(date.getDate());
|
||||||
|
|
||||||
return format
|
return format
|
||||||
.replace('YYYY', year)
|
.replace('YYYY', year)
|
||||||
.replace('MM', month)
|
.replace('MM', month)
|
||||||
.replace('DD', day)
|
.replace('DD', day)
|
||||||
|
.replace('M/', monthNoPad + '/') // 支持 M/ 格式
|
||||||
|
.replace('D ', dayNoPad + ' ') // 支持 D 格式(后跟空格)
|
||||||
|
.replace('/D', '/' + dayNoPad) // 支持 /D 格式
|
||||||
.replace('HH', hours)
|
.replace('HH', hours)
|
||||||
.replace('mm', minutes)
|
.replace('mm', minutes)
|
||||||
.replace('ss', seconds);
|
.replace('ss', seconds);
|
||||||
|
|||||||
@@ -162,3 +162,61 @@ export const STATUS = {
|
|||||||
NORMAL: '0', // 正常/启用
|
NORMAL: '0', // 正常/启用
|
||||||
DISABLE: '1' // 停用
|
DISABLE: '1' // 停用
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 号源槽位状态(与后端 CommonConstants.SlotStatus 保持一致)
|
||||||
|
* adm_schedule_slot.status 字段
|
||||||
|
*/
|
||||||
|
export const SlotStatus = {
|
||||||
|
/** 可用 / 待预约 */
|
||||||
|
AVAILABLE: 0,
|
||||||
|
/** 已预约 */
|
||||||
|
BOOKED: 1,
|
||||||
|
/** 已取消 / 已停诊 */
|
||||||
|
CANCELLED: 2,
|
||||||
|
/** 已锁定 */
|
||||||
|
LOCKED: 3,
|
||||||
|
/** 已签到 / 已取号 */
|
||||||
|
CHECKED_IN: 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 号源槽位状态说明信息
|
||||||
|
*/
|
||||||
|
export const SlotStatusDescriptions = {
|
||||||
|
0: '未预约',
|
||||||
|
1: '已预约',
|
||||||
|
2: '已停诊',
|
||||||
|
3: '已锁定',
|
||||||
|
4: '已取号',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 号源槽位状态对应的CSS类名
|
||||||
|
*/
|
||||||
|
export const SlotStatusClassMap = {
|
||||||
|
'未预约': 'status-unbooked',
|
||||||
|
'已预约': 'status-booked',
|
||||||
|
'已取号': 'status-checked',
|
||||||
|
'已停诊': 'status-cancelled',
|
||||||
|
'已取消': 'status-cancelled',
|
||||||
|
'已锁定': 'status-locked',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取号源槽位状态的说明
|
||||||
|
* @param {number} value - 状态值
|
||||||
|
* @returns {string} - 说明信息
|
||||||
|
*/
|
||||||
|
export function getSlotStatusDescription(value) {
|
||||||
|
return SlotStatusDescriptions[value] || '未知状态';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取号源槽位状态对应的CSS类名
|
||||||
|
* @param {string} status - 状态说明
|
||||||
|
* @returns {string} - CSS类名
|
||||||
|
*/
|
||||||
|
export function getSlotStatusClass(status) {
|
||||||
|
return SlotStatusClassMap[status] || 'status-unbooked';
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
<option value="booked">已预约</option>
|
<option value="booked">已预约</option>
|
||||||
<option value="checked">已取号</option>
|
<option value="checked">已取号</option>
|
||||||
<option value="cancelled">已停诊</option>
|
<option value="cancelled">已停诊</option>
|
||||||
|
<option value="returned">已退号</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div id="patientSearch" class="patient-search">
|
<div id="patientSearch" class="patient-search">
|
||||||
@@ -105,7 +106,7 @@
|
|||||||
<div class="ticket-grid" v-if="filteredTickets.length > 0">
|
<div class="ticket-grid" v-if="filteredTickets.length > 0">
|
||||||
<div v-for="(item, index) in filteredTickets" :key="item.slot_id" class="ticket-card" @dblclick="handleDoubleClick(item)" @contextmenu.prevent="handleRightClick($event, item)">
|
<div v-for="(item, index) in filteredTickets" :key="item.slot_id" class="ticket-card" @dblclick="handleDoubleClick(item)" @contextmenu.prevent="handleRightClick($event, item)">
|
||||||
<!-- 序号放在最右侧 -->
|
<!-- 序号放在最右侧 -->
|
||||||
<div class="ticket-index">{{ index + 1 }}</div>
|
<div class="ticket-index">{{ item.seqNo != null ? item.seqNo : index + 1 }}</div>
|
||||||
<!-- 1.时间 -->
|
<!-- 1.时间 -->
|
||||||
<div class="ticket-id-time">{{ item.dateTime }}</div>
|
<div class="ticket-id-time">{{ item.dateTime }}</div>
|
||||||
<!-- 2. 状态标签 -->
|
<!-- 2. 状态标签 -->
|
||||||
@@ -125,7 +126,7 @@
|
|||||||
<div class="ticket-type">{{ item.ticketType === 'general' ? '普通' : '专家' }}</div>
|
<div class="ticket-type">{{ item.ticketType === 'general' ? '普通' : '专家' }}</div>
|
||||||
<!-- 7. 已预约患者信息 -->
|
<!-- 7. 已预约患者信息 -->
|
||||||
<div v-if="(item.status === '已预约' || item.status === '已取号') && item.patientName" class="ticket-patient">
|
<div v-if="(item.status === '已预约' || item.status === '已取号') && item.patientName" class="ticket-patient">
|
||||||
{{ item.patientName }}({{ item.patientId }})
|
{{ item.patientName }}({{ item.patientId }},{{ getGenderText(item.gender || item.patientGender) }})
|
||||||
</div>
|
</div>
|
||||||
<div class="ticket-actions">
|
<div class="ticket-actions">
|
||||||
<button class="action-button book-button" @click="openPatientSelectModal(item.slot_id)" :disabled="item.status !== '未预约'" :class="{ 'disabled': item.status !== '未预约' }">
|
<button class="action-button book-button" @click="openPatientSelectModal(item.slot_id)" :disabled="item.status !== '未预约'" :class="{ 'disabled': item.status !== '未预约' }">
|
||||||
@@ -194,7 +195,8 @@
|
|||||||
>
|
>
|
||||||
<td>{{ index + 1 }}</td>
|
<td>{{ index + 1 }}</td>
|
||||||
<td>{{ patient.name }}</td>
|
<td>{{ patient.name }}</td>
|
||||||
<td>{{ patient.id || patient.medicalCard }}</td>
|
<td>{{ patient.identifierNo || patient.medicalCard || patient.id }}</td>
|
||||||
|
<td>{{ patient.identifierNo }}</td>
|
||||||
<td>{{ getGenderText(patient.genderEnum_enumText || patient.genderEnum || patient.gender || patient.sex) }}</td>
|
<td>{{ getGenderText(patient.genderEnum_enumText || patient.genderEnum || patient.gender || patient.sex) }}</td>
|
||||||
<td>{{ patient.idCard }}</td>
|
<td>{{ patient.idCard }}</td>
|
||||||
<td>{{ patient.phone }}</td>
|
<td>{{ patient.phone }}</td>
|
||||||
@@ -254,6 +256,7 @@ const STATUS_CLASS_MAP = {
|
|||||||
'未预约': 'status-unbooked',
|
'未预约': 'status-unbooked',
|
||||||
'已预约': 'status-booked',
|
'已预约': 'status-booked',
|
||||||
'已取号': 'status-checked',
|
'已取号': 'status-checked',
|
||||||
|
'已退号': 'status-returned',
|
||||||
'已停诊': 'status-cancelled',
|
'已停诊': 'status-cancelled',
|
||||||
'已取消': 'status-cancelled'
|
'已取消': 'status-cancelled'
|
||||||
};
|
};
|
||||||
@@ -364,14 +367,23 @@ export default {
|
|||||||
this.searchPatients();
|
this.searchPatients();
|
||||||
},
|
},
|
||||||
getPatientUniqueId(patient, index = null) {
|
getPatientUniqueId(patient, index = null) {
|
||||||
return patient.idCard || patient.medicalCard || patient.id || (index !== null ? `temp_${index}` : null);
|
return patient.id || patient.patientId || patient.identifierNo || patient.medicalCard || patient.idCard ||
|
||||||
|
(index !== null ? `temp_${index}` : null);
|
||||||
},
|
},
|
||||||
matchPatientKeyword(patient, keyword) {
|
matchPatientKeyword(patient, keyword) {
|
||||||
const normalizedKeyword = String(keyword || '').trim().toLowerCase();
|
const normalizedKeyword = String(keyword || '').trim().toLowerCase();
|
||||||
if (!normalizedKeyword) {
|
if (!normalizedKeyword) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const fields = [patient.name, patient.id, patient.medicalCard, patient.idCard, patient.phone];
|
const fields = [
|
||||||
|
patient.name,
|
||||||
|
patient.id,
|
||||||
|
patient.patientId,
|
||||||
|
patient.identifierNo,
|
||||||
|
patient.medicalCard,
|
||||||
|
patient.idCard,
|
||||||
|
patient.phone
|
||||||
|
];
|
||||||
return fields.some(field => String(field || '').toLowerCase().includes(normalizedKeyword));
|
return fields.some(field => String(field || '').toLowerCase().includes(normalizedKeyword));
|
||||||
},
|
},
|
||||||
searchPatients() {
|
searchPatients() {
|
||||||
@@ -394,6 +406,8 @@ export default {
|
|||||||
const rowKey = this.getPatientUniqueId(patient, index);
|
const rowKey = this.getPatientUniqueId(patient, index);
|
||||||
return {
|
return {
|
||||||
...patient,
|
...patient,
|
||||||
|
// 统一口径:预约场景的就诊卡号使用患者标识表中的 identifierNo
|
||||||
|
medicalCard: patient.identifierNo || patient.medicalCard || '',
|
||||||
_rowKey: rowKey
|
_rowKey: rowKey
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -494,6 +508,7 @@ export default {
|
|||||||
this.tickets[ticketIndex].patientName = null;
|
this.tickets[ticketIndex].patientName = null;
|
||||||
this.tickets[ticketIndex].patientId = null;
|
this.tickets[ticketIndex].patientId = null;
|
||||||
this.tickets[ticketIndex].patientGender = null;
|
this.tickets[ticketIndex].patientGender = null;
|
||||||
|
this.tickets[ticketIndex].gender = null;
|
||||||
this.tickets[ticketIndex].medicalCard = null;
|
this.tickets[ticketIndex].medicalCard = null;
|
||||||
this.tickets[ticketIndex].phone = null;
|
this.tickets[ticketIndex].phone = null;
|
||||||
}
|
}
|
||||||
@@ -554,12 +569,22 @@ export default {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
const patientPrimaryId = this.selectedPatient.id || this.selectedPatient.patientId;
|
||||||
|
const medicalCard = this.selectedPatient.identifierNo || this.selectedPatient.medicalCard;
|
||||||
|
if (!patientPrimaryId) {
|
||||||
|
ElMessage.error('患者ID缺失,无法预约,请重新选择患者');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!medicalCard) {
|
||||||
|
ElMessage.error('就诊卡号缺失,无法预约,请先维护患者就诊卡号');
|
||||||
|
return;
|
||||||
|
}
|
||||||
const appointmentData = {
|
const appointmentData = {
|
||||||
ticketId: this.currentTicket.slot_id,
|
ticketId: this.currentTicket.slot_id,
|
||||||
slotId: this.currentTicket.slot_id,
|
slotId: this.currentTicket.slot_id,
|
||||||
patientId: this.selectedPatient.id || this.selectedPatient.idCard || this.selectedPatient.medicalCard,
|
patientId: patientPrimaryId,
|
||||||
patientName: this.selectedPatient.name,
|
patientName: this.selectedPatient.name,
|
||||||
medicalCard: this.selectedPatient.medicalCard || this.selectedPatient.id,
|
medicalCard,
|
||||||
phone: this.selectedPatient.phone,
|
phone: this.selectedPatient.phone,
|
||||||
gender: this.getGenderValueForBackend(this.selectedPatient),
|
gender: this.getGenderValueForBackend(this.selectedPatient),
|
||||||
fee: Number(this.currentTicket.fee) || 0,
|
fee: Number(this.currentTicket.fee) || 0,
|
||||||
@@ -578,8 +603,9 @@ export default {
|
|||||||
if (ticketIndex !== -1) {
|
if (ticketIndex !== -1) {
|
||||||
this.tickets[ticketIndex].status = '已预约';
|
this.tickets[ticketIndex].status = '已预约';
|
||||||
this.tickets[ticketIndex].patientName = this.selectedPatient.name;
|
this.tickets[ticketIndex].patientName = this.selectedPatient.name;
|
||||||
this.tickets[ticketIndex].patientId = this.selectedPatient.medicalCard || this.selectedPatient.id;
|
this.tickets[ticketIndex].patientId = medicalCard;
|
||||||
this.tickets[ticketIndex].patientGender = this.selectedPatient.genderEnum_enumText || this.selectedPatient.genderEnum || this.selectedPatient.gender || this.selectedPatient.sex;
|
this.tickets[ticketIndex].patientGender = this.selectedPatient.genderEnum_enumText || this.selectedPatient.genderEnum || this.selectedPatient.gender || this.selectedPatient.sex;
|
||||||
|
this.tickets[ticketIndex].gender = this.getGenderText(this.tickets[ticketIndex].patientGender);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.closePatientSelectModal();
|
this.closePatientSelectModal();
|
||||||
@@ -601,9 +627,9 @@ export default {
|
|||||||
},
|
},
|
||||||
// 获取性别文本
|
// 获取性别文本
|
||||||
getGenderText(genderValue) {
|
getGenderText(genderValue) {
|
||||||
// 如果值为null或undefined,返回'-'
|
// 如果值为null或undefined,返回"未知"
|
||||||
if (genderValue === null || genderValue === undefined) {
|
if (genderValue === null || genderValue === undefined) {
|
||||||
return '-';
|
return '未知';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将值转换为字符串进行比较
|
// 将值转换为字符串进行比较
|
||||||
@@ -623,8 +649,8 @@ export default {
|
|||||||
return '女';
|
return '女';
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果都不是,返回原值或'-'
|
// 如果都不是,返回"未知"
|
||||||
return '-';
|
return '未知';
|
||||||
},
|
},
|
||||||
// 获取用于后端的性别值
|
// 获取用于后端的性别值
|
||||||
getGenderValueForBackend(patient) {
|
getGenderValueForBackend(patient) {
|
||||||
@@ -703,10 +729,36 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const records = payload.list || payload.records || [];
|
const records = payload.list || payload.records || [];
|
||||||
|
const filteredRecords = this.applyStatusFilter(records);
|
||||||
const total = Number(payload.total);
|
const total = Number(payload.total);
|
||||||
this.tickets = [...records];
|
this.tickets = [...filteredRecords];
|
||||||
this.allTickets = [...records];
|
this.allTickets = [...filteredRecords];
|
||||||
this.totalTickets = Number.isFinite(total) ? total : this.tickets.length;
|
// 当按状态筛选时,优先使用前端过滤后的数量,避免后端状态未生效导致“显示全部”
|
||||||
|
if (this.selectedStatus && this.selectedStatus !== 'all') {
|
||||||
|
this.totalTickets = this.tickets.length;
|
||||||
|
} else {
|
||||||
|
this.totalTickets = Number.isFinite(total) ? total : this.tickets.length;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
applyStatusFilter(records = []) {
|
||||||
|
if (!Array.isArray(records) || records.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
if (!this.selectedStatus || this.selectedStatus === 'all') {
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
const statusMap = {
|
||||||
|
unbooked: ['未预约'],
|
||||||
|
booked: ['已预约'],
|
||||||
|
checked: ['已取号'],
|
||||||
|
cancelled: ['已停诊', '已取消'],
|
||||||
|
returned: ['已退号']
|
||||||
|
};
|
||||||
|
const matchedStatusList = statusMap[this.selectedStatus] || [];
|
||||||
|
if (matchedStatusList.length === 0) {
|
||||||
|
return records;
|
||||||
|
}
|
||||||
|
return records.filter(item => matchedStatusList.includes(item?.status));
|
||||||
},
|
},
|
||||||
updateDoctorsListFromApi(doctorResponse) {
|
updateDoctorsListFromApi(doctorResponse) {
|
||||||
let doctorList = [];
|
let doctorList = [];
|
||||||
@@ -1376,6 +1428,11 @@ export default {
|
|||||||
color: #52c41a;
|
color: #52c41a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.status-returned {
|
||||||
|
background-color: #fff7e6;
|
||||||
|
color: #d46b08;
|
||||||
|
}
|
||||||
|
|
||||||
.status-cancelled {
|
.status-cancelled {
|
||||||
background-color: #fff1f0;
|
background-color: #fff1f0;
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
|
|||||||
@@ -571,7 +571,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {getOrgTree, saveOrderGroup} from './api';
|
import {getOrgTree, saveOrderGroup} from './api';
|
||||||
import adviceBaseList from './adviceBaseList';
|
import adviceBaseList from './adviceBaseList';
|
||||||
import {getCurrentInstance, nextTick, watch} from 'vue';
|
import {computed, getCurrentInstance, nextTick, ref, watch} from 'vue';
|
||||||
import {calculateQuantityByDays, formatNumber} from '@/utils/his';
|
import {calculateQuantityByDays, formatNumber} from '@/utils/his';
|
||||||
|
|
||||||
const emit = defineEmits(['selectDiagnosis']);
|
const emit = defineEmits(['selectDiagnosis']);
|
||||||
@@ -620,31 +620,31 @@ const stockList = ref([]);
|
|||||||
const { proxy } = getCurrentInstance();
|
const { proxy } = getCurrentInstance();
|
||||||
const inputRefs = ref({}); // 存储输入框实例
|
const inputRefs = ref({}); // 存储输入框实例
|
||||||
const requiredProps = ref([]); // 存储必填项 prop 顺序
|
const requiredProps = ref([]); // 存储必填项 prop 顺序
|
||||||
const { method_code, unit_code, rate_code, distribution_category_code } = proxy.useDict(
|
const { method_code, unit_code, rate_code, distribution_category_code, drord_doctor_type } = proxy.useDict(
|
||||||
'method_code',
|
'method_code',
|
||||||
'unit_code',
|
'unit_code',
|
||||||
'rate_code',
|
'rate_code',
|
||||||
'distribution_category_code'
|
'distribution_category_code',
|
||||||
|
'drord_doctor_type'
|
||||||
);
|
);
|
||||||
|
|
||||||
const adviceTypeList = ref([
|
// 使用 drord_doctor_type 字典
|
||||||
{
|
const adviceTypeList = computed(() => {
|
||||||
label: '西药中成药',
|
if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
|
||||||
value: 1,
|
const list = drord_doctor_type.value.map(item => ({
|
||||||
},
|
label: item.label,
|
||||||
{
|
value: parseInt(item.value) || item.value
|
||||||
label: '耗材',
|
}));
|
||||||
value: 2,
|
return [...list, { label: '全部', value: undefined }];
|
||||||
},
|
}
|
||||||
{
|
// 默认值
|
||||||
label: '诊疗',
|
return [
|
||||||
value: 3,
|
{ label: '西药中成药', value: 1 },
|
||||||
},
|
{ label: '耗材', value: 4 },
|
||||||
{
|
{ label: '诊疗', value: 3 },
|
||||||
label: '全部',
|
{ label: '全部', value: undefined },
|
||||||
value: undefined,
|
];
|
||||||
},
|
});
|
||||||
]);
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
document.addEventListener('keydown', escKeyListener);
|
document.addEventListener('keydown', escKeyListener);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<div style="display: flex; align-items: center; width: 100%">
|
<div style="display: flex; align-items: center; width: 100%">
|
||||||
<span style="font-size: 16px; font-weight: bold; margin-right: 20px;">门诊挂号</span>
|
<span style="font-size: 16px; font-weight: bold; margin-right: 20px;">门诊挂号</span>
|
||||||
<div style="flex: 1; display: flex; justify-content: center; align-items: center;">
|
<div style="flex: 1; display: flex; justify-content: center; align-items: center;">
|
||||||
|
<el-button type="success" icon="Check" @click="handleCheckIn" size="small">预约签到</el-button>
|
||||||
<el-button type="primary" icon="Document" @click="goToPatientRecord" size="small">档案</el-button>
|
<el-button type="primary" icon="Document" @click="goToPatientRecord" size="small">档案</el-button>
|
||||||
<el-button type="primary" icon="Plus" @click="handleAddPatient" size="small">新建</el-button>
|
<el-button type="primary" icon="Plus" @click="handleAddPatient" size="small">新建</el-button>
|
||||||
<el-button type="primary" plain icon="Search" @click="handleSearch" size="small">查询</el-button>
|
<el-button type="primary" plain icon="Search" @click="handleSearch" size="small">查询</el-button>
|
||||||
@@ -15,7 +16,7 @@
|
|||||||
<el-button type="primary" plain @click="handleReadCard('03')" size="small">医保卡</el-button>
|
<el-button type="primary" plain @click="handleReadCard('03')" size="small">医保卡</el-button>
|
||||||
<el-button type="warning" plain icon="CircleClose" @click="handleClear" size="small">清空</el-button>
|
<el-button type="warning" plain icon="CircleClose" @click="handleClear" size="small">清空</el-button>
|
||||||
<el-button type="primary" icon="Plus" @click="handleAdd" size="small">保存挂号</el-button>
|
<el-button type="primary" icon="Plus" @click="handleAdd" size="small">保存挂号</el-button>
|
||||||
<el-button type="success" icon="Printer" @click="handleReprint" size="small">补打挂号</el-button>
|
<el-button type="info" icon="Printer" @click="handleReprint" size="small">补打挂号</el-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -615,6 +616,74 @@
|
|||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<!-- 预约签到患者选择弹窗 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="showCheckInPatientModal"
|
||||||
|
title="请选择预约的患者"
|
||||||
|
width="1200px"
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
>
|
||||||
|
<div style="margin-bottom: 20px; display: flex; gap: 10px;">
|
||||||
|
<el-input
|
||||||
|
v-model="checkInSearchKey"
|
||||||
|
placeholder="输入患者姓名回车查询"
|
||||||
|
style="width: 400px"
|
||||||
|
@keyup.enter="loadCheckInPatientList"
|
||||||
|
/>
|
||||||
|
<el-button type="primary" @click="loadCheckInPatientList">查询</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-table
|
||||||
|
v-loading="checkInLoading"
|
||||||
|
:data="checkInPatientList"
|
||||||
|
border
|
||||||
|
style="width: 100%"
|
||||||
|
@row-click="selectRow"
|
||||||
|
highlight-current-row
|
||||||
|
>
|
||||||
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
<el-table-column prop="patientId" label="就诊卡号" width="120" align="center" />
|
||||||
|
<el-table-column prop="patientName" label="姓名" width="120" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<span style="color: #ff4d4f">{{ scope.row.patientName }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="gender" label="性别" width="80" align="center" />
|
||||||
|
<el-table-column label="证件类型" width="150" align="center">
|
||||||
|
<template #default>居民身份证</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="idCard" label="证件号码" width="200" align="center" />
|
||||||
|
<el-table-column prop="phone" label="手机号码" width="150" align="center" />
|
||||||
|
<el-table-column label="号源类型" width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-tag :type="scope.row.ticketType === 'expert' ? 'danger' : 'success'">
|
||||||
|
{{ scope.row.ticketType === 'expert' ? '专家号' : '普通号' }}
|
||||||
|
</el-tag>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="fee" label="预约金额" width="100" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<span style="font-weight: bold; color: #f5222d">¥{{ scope.row.fee }}</span>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column prop="dateTime" label="就诊时间" width="180" align="center" />
|
||||||
|
</el-table>
|
||||||
|
|
||||||
|
<div style="margin-top: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||||
|
<el-pagination
|
||||||
|
v-model:current-page="checkInPage"
|
||||||
|
v-model:page-size="checkInLimit"
|
||||||
|
:total="checkInTotal"
|
||||||
|
layout="prev, pager, next"
|
||||||
|
@current-change="loadCheckInPatientList"
|
||||||
|
/>
|
||||||
|
<div class="dialog-footer">
|
||||||
|
<el-button @click="showCheckInPatientModal = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="confirmCheckIn" :disabled="!selectedCheckInPatient">确定</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -632,7 +701,8 @@ import {
|
|||||||
returnRegister,
|
returnRegister,
|
||||||
updatePatientPhone,
|
updatePatientPhone,
|
||||||
} from './components/outpatientregistration';
|
} from './components/outpatientregistration';
|
||||||
import {invokeYbPlugin5000, invokeYbPlugin5001} from '@/api/public';
|
import { listTicket, checkInTicket } from '@/api/appoinmentmanage/ticket';
|
||||||
|
import { invokeYbPlugin5000, invokeYbPlugin5001 } from '@/api/public';
|
||||||
import patientInfoDialog from './components/patientInfoDialog';
|
import patientInfoDialog from './components/patientInfoDialog';
|
||||||
import PatientAddDialog from './components/patientAddDialog';
|
import PatientAddDialog from './components/patientAddDialog';
|
||||||
import patientList from './components/patientList';
|
import patientList from './components/patientList';
|
||||||
@@ -644,7 +714,7 @@ import {handleColor} from '@/utils/his';
|
|||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import {formatDateStr} from '@/utils/index';
|
import {formatDateStr} from '@/utils/index';
|
||||||
import {isValidCNPhoneNumber} from '../../../utils/validate';
|
import {isValidCNPhoneNumber} from '../../../utils/validate';
|
||||||
import {ElMessage} from 'element-plus';
|
import {ElMessage, ElMessageBox} from 'element-plus';
|
||||||
import {hiprint} from 'vue-plugin-hiprint';
|
import {hiprint} from 'vue-plugin-hiprint';
|
||||||
import outpatientRegistrationTemplate from '@/components/Print/OutpatientRegistration.json';
|
import outpatientRegistrationTemplate from '@/components/Print/OutpatientRegistration.json';
|
||||||
|
|
||||||
@@ -687,14 +757,25 @@ const ybTypeRef = ref(null);
|
|||||||
const openDialog = ref(false);
|
const openDialog = ref(false);
|
||||||
const openRefundDialog = ref(false);
|
const openRefundDialog = ref(false);
|
||||||
const openReprintDialog = ref(false);
|
const openReprintDialog = ref(false);
|
||||||
|
|
||||||
|
// 预约签到相关变量
|
||||||
|
const showCheckInPatientModal = ref(false);
|
||||||
|
const checkInPatientList = ref([]);
|
||||||
|
const selectedCheckInPatient = ref(null);
|
||||||
const totalAmount = ref(0);
|
const totalAmount = ref(0);
|
||||||
const chargeItemIdList = ref([]);
|
const chargeItemIdList = ref([]);
|
||||||
const chrgBchnoList = ref([]);
|
const chrgBchnoList = ref([]);
|
||||||
const paymentId = ref('');
|
const paymentId = ref('');
|
||||||
const loadingText = ref('');
|
const loadingText = ref('');
|
||||||
|
const checkInSearchKey = ref('');
|
||||||
|
const checkInPage = ref(1);
|
||||||
|
const checkInLimit = ref(10);
|
||||||
|
const checkInTotal = ref(0);
|
||||||
|
const checkInLoading = ref(false);
|
||||||
const registerInfo = ref({}); // 原挂号记录信息
|
const registerInfo = ref({}); // 原挂号记录信息
|
||||||
const queryType = ref('all'); // 查询类型:all-全部, normal-正常挂号, returned-退号记录
|
const queryType = ref('all'); // 查询类型:all-全部, normal-正常挂号, returned-退号记录
|
||||||
const guardianAgeConfig = ref(''); // 监护人规定年龄配置
|
const guardianAgeConfig = ref(''); // 监护人规定年龄配置
|
||||||
|
const currentSlotId = ref(null); // 当前预约签到的号源ID
|
||||||
|
|
||||||
// 使用 ref 定义查询所得用户信息数据
|
// 使用 ref 定义查询所得用户信息数据
|
||||||
const patientInfoList = ref(undefined);
|
const patientInfoList = ref(undefined);
|
||||||
@@ -1584,6 +1665,189 @@ function handleReprint() {
|
|||||||
openReprintDialog.value = true;
|
openReprintDialog.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 预约签到 - 打开患者选择弹窗 */
|
||||||
|
function handleCheckIn() {
|
||||||
|
// 打开患者选择弹窗,显示已预约但未签到的患者列表
|
||||||
|
showCheckInPatientModal.value = true;
|
||||||
|
// 加载已预约未签到的患者列表
|
||||||
|
loadCheckInPatientList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 加载预约签到患者列表 */
|
||||||
|
function loadCheckInPatientList() {
|
||||||
|
checkInLoading.value = true;
|
||||||
|
const today = formatDateStr(new Date(), 'YYYY-MM-DD');
|
||||||
|
listTicket({
|
||||||
|
date: today,
|
||||||
|
status: 'booked',
|
||||||
|
name: checkInSearchKey.value, // 支持姓名等模糊查询,后端需适配
|
||||||
|
page: checkInPage.value,
|
||||||
|
limit: checkInLimit.value
|
||||||
|
}).then(res => {
|
||||||
|
const data = res.data?.list || res.list || res.data || [];
|
||||||
|
const total = res.data?.total || res.total || data.length;
|
||||||
|
|
||||||
|
checkInPatientList.value = data.map(item => ({
|
||||||
|
...item,
|
||||||
|
appointmentDate: item.scheduleDate + ' ' + (item.expectTime || '')
|
||||||
|
}));
|
||||||
|
checkInTotal.value = total;
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('加载预约导出失败:', err);
|
||||||
|
ElMessage.error('获取预约列表失败');
|
||||||
|
}).finally(() => {
|
||||||
|
checkInLoading.value = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 弹窗行点击处理 */
|
||||||
|
function selectRow(row) {
|
||||||
|
selectedCheckInPatient.value = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 确认签到(一键签到:直接构建挂号参数 → 预结算 → 弹收费窗口) */
|
||||||
|
async function confirmCheckIn() {
|
||||||
|
if (!selectedCheckInPatient.value) {
|
||||||
|
ElMessage.warning('请先选择患者');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const patient = selectedCheckInPatient.value;
|
||||||
|
// 每次开始新的签到流程先清理残留 slotId,避免历史脏值串单
|
||||||
|
currentSlotId.value = null;
|
||||||
|
|
||||||
|
// 弹出确认提示
|
||||||
|
try {
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确认为患者【${patient.patientName}】办理签到挂号?\n` +
|
||||||
|
`科室:${patient.department || '-'}\n` +
|
||||||
|
`医生:${patient.doctor || '-'}\n` +
|
||||||
|
`费用:¥${patient.fee || '0.00'}`,
|
||||||
|
'签到确认',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确认签到',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'info',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
// 用户点了取消
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showCheckInPatientModal.value = false;
|
||||||
|
|
||||||
|
readCardLoading.value = true;
|
||||||
|
loadingText.value = '正在处理签到挂号...';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. 用科室ID加载该科室的挂号类型列表,获取 serviceTypeId 和 definitionId
|
||||||
|
const healthcareRes = await getHealthcareMetadata({ organizationId: patient.departmentId });
|
||||||
|
const healthcareRecords = healthcareRes.data?.records || [];
|
||||||
|
|
||||||
|
if (healthcareRecords.length === 0) {
|
||||||
|
ElMessage.error('该科室未配置挂号类型,无法自动签到');
|
||||||
|
readCardLoading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 按号源类型(专家/普通)模糊匹配挂号类型
|
||||||
|
const matchTypeName = (patient.ticketType === 'expert') ? '专家' : '普通';
|
||||||
|
const matchedService = healthcareRecords.find(h => h.name && h.name.includes(matchTypeName));
|
||||||
|
|
||||||
|
if (!matchedService) {
|
||||||
|
// 匹配不到就取第一个作为兜底
|
||||||
|
ElMessage.warning('未精确匹配到挂号类型,已使用默认类型');
|
||||||
|
}
|
||||||
|
|
||||||
|
const service = matchedService || healthcareRecords[0];
|
||||||
|
const realPatientId = patient.realPatientId; // 后端新增的真实患者数据库ID
|
||||||
|
|
||||||
|
if (!realPatientId) {
|
||||||
|
ElMessage.error('患者ID缺失,请联系管理员检查预约数据');
|
||||||
|
readCardLoading.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 构建挂号参数(与 transformFormData 结构一致)
|
||||||
|
const registrationParam = {
|
||||||
|
encounterFormData: {
|
||||||
|
patientId: realPatientId,
|
||||||
|
priorityEnum: 3, // 默认优先级
|
||||||
|
serviceTypeId: service.id,
|
||||||
|
organizationId: patient.departmentId,
|
||||||
|
},
|
||||||
|
encounterLocationFormData: {
|
||||||
|
locationId: null,
|
||||||
|
},
|
||||||
|
encounterParticipantFormData: {
|
||||||
|
practitionerId: patient.doctorId,
|
||||||
|
},
|
||||||
|
accountFormData: {
|
||||||
|
patientId: realPatientId,
|
||||||
|
typeCode: 1, // 个人现金账户
|
||||||
|
contractNo: '0000', // 默认自费
|
||||||
|
},
|
||||||
|
chargeItemFormData: {
|
||||||
|
patientId: realPatientId,
|
||||||
|
definitionId: service.definitionId,
|
||||||
|
serviceId: service.id,
|
||||||
|
totalPrice: parseFloat(patient.fee) || ((service.price || 0) + (service.activityPrice || 0)),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// 4. 设置 patientInfo(ChargeDialog 需要展示)
|
||||||
|
patientInfo.value = {
|
||||||
|
patientId: realPatientId,
|
||||||
|
patientName: patient.patientName,
|
||||||
|
genderEnum_enumText: patient.gender || '-',
|
||||||
|
age: '',
|
||||||
|
contractName: '自费',
|
||||||
|
idCard: patient.idCard,
|
||||||
|
phone: patient.phone,
|
||||||
|
categoryEnum: '门诊',
|
||||||
|
organizationName: patient.department || '',
|
||||||
|
practitionerName: patient.doctor || '',
|
||||||
|
healthcareName: service.name || '',
|
||||||
|
};
|
||||||
|
|
||||||
|
// 同步设置 form 的 contractNo,ChargeDialog 的 feeType 会读取它
|
||||||
|
form.value.contractNo = '0000';
|
||||||
|
|
||||||
|
// 5. 调用预结算接口(reg-pre-pay)
|
||||||
|
const res = await addOutpatientRegistration(registrationParam);
|
||||||
|
|
||||||
|
if (res.code == 200) {
|
||||||
|
// 仅在预结算成功后记录待签到的号源,避免失败路径残留脏数据
|
||||||
|
currentSlotId.value = patient.slot_id;
|
||||||
|
|
||||||
|
// 6. 设置收费弹窗所需的数据
|
||||||
|
chrgBchno.value = res.data.chrgBchno;
|
||||||
|
registerBusNo.value = res.data.busNo;
|
||||||
|
totalAmount.value = res.data.psnCashPay;
|
||||||
|
patientInfo.value.encounterId = res.data.encounterId || '';
|
||||||
|
patientInfo.value.busNo = res.data.busNo || '';
|
||||||
|
transformedData.value = registrationParam;
|
||||||
|
chargeItemIdList.value = [];
|
||||||
|
|
||||||
|
// 7. 打开收费弹窗
|
||||||
|
openDialog.value = true;
|
||||||
|
|
||||||
|
// 打印挂号单
|
||||||
|
printRegistrationByHiprint(res.data);
|
||||||
|
} else {
|
||||||
|
currentSlotId.value = null;
|
||||||
|
ElMessage.error(res.msg || '预结算失败');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
currentSlotId.value = null;
|
||||||
|
console.error('预约签到失败:', err);
|
||||||
|
ElMessage.error('签到处理失败: ' + (err.message || '未知错误'));
|
||||||
|
} finally {
|
||||||
|
readCardLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 点击患者列表给表单赋值
|
* 点击患者列表给表单赋值
|
||||||
*/
|
*/
|
||||||
@@ -1656,20 +1920,29 @@ function handleClose(value) {
|
|||||||
proxy.$modal.msgSuccess('操作成功');
|
proxy.$modal.msgSuccess('操作成功');
|
||||||
// 更新患者手机号
|
// 更新患者手机号
|
||||||
updatePhone();
|
updatePhone();
|
||||||
// getList();
|
|
||||||
// reset();
|
// 先取出并清空,避免接口失败/取消等路径导致 slotId 残留污染下一单
|
||||||
// addOutpatientRegistration(transformedData.value).then((response) => {
|
const pendingSlotId = currentSlotId.value;
|
||||||
// reset();
|
currentSlotId.value = null;
|
||||||
// proxy.$modal.msgSuccess('新增成功');
|
|
||||||
// getList();
|
// 如果是预约签到的挂号,执行签到状态更新
|
||||||
// });
|
if (pendingSlotId) {
|
||||||
|
checkInTicket(pendingSlotId).then(() => {
|
||||||
|
console.log('预约状态已更新为已取号');
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('更新预约状态失败:', err);
|
||||||
|
ElMessage.error('预约状态更新失败,请手动签到');
|
||||||
|
});
|
||||||
|
}
|
||||||
} else if (value == 'cancel') {
|
} else if (value == 'cancel') {
|
||||||
|
currentSlotId.value = null;
|
||||||
// cancelRegister(patientInfo.value.encounterId).then((res) => {
|
// cancelRegister(patientInfo.value.encounterId).then((res) => {
|
||||||
// if (res.code == 200) {
|
// if (res.code == 200) {
|
||||||
// getList();
|
// getList();
|
||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
} else {
|
} else {
|
||||||
|
currentSlotId.value = null;
|
||||||
openRefundDialog.value = false;
|
openRefundDialog.value = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -273,7 +273,10 @@ function fetchFromApi(searchKey) {
|
|||||||
minUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '',
|
minUnitCode_dictText: item.minUnitCode_dictText || item.unitCode_dictText || '',
|
||||||
volume: item.size || item.totalVolume || '',
|
volume: item.size || item.totalVolume || '',
|
||||||
partPercent: item.partPercent || 1,
|
partPercent: item.partPercent || 1,
|
||||||
inventoryList: [],
|
// 🔧 Bug Fix: 如果后端提供了inventoryList,则使用;否则为空数组
|
||||||
|
inventoryList: item.inventoryList || [],
|
||||||
|
// 🔧 Bug Fix: 构造stockList用于库存显示
|
||||||
|
stockList: item.inventoryList || [],
|
||||||
adviceDefinitionId: item.id,
|
adviceDefinitionId: item.id,
|
||||||
chargeItemDefinitionId: item.id,
|
chargeItemDefinitionId: item.id,
|
||||||
positionId: item.locationId,
|
positionId: item.locationId,
|
||||||
@@ -354,6 +357,11 @@ function handleQuantity(row) {
|
|||||||
const totalQuantity = row.inventoryList.reduce((sum, item) => sum + (item.quantity || 0), 0);
|
const totalQuantity = row.inventoryList.reduce((sum, item) => sum + (item.quantity || 0), 0);
|
||||||
return totalQuantity.toString() + row.minUnitCode_dictText;
|
return totalQuantity.toString() + row.minUnitCode_dictText;
|
||||||
}
|
}
|
||||||
|
// 🔧 Bug Fix: 耗材类型可能没有inventoryList,但可能有stockList
|
||||||
|
if (row.stockList && row.stockList.length > 0) {
|
||||||
|
const totalQuantity = row.stockList.reduce((sum, item) => sum + (item.quantity || 0), 0);
|
||||||
|
return totalQuantity.toString() + row.minUnitCode_dictText;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -280,6 +280,7 @@ import {
|
|||||||
saveDiagnosis,
|
saveDiagnosis,
|
||||||
} from '../api';
|
} from '../api';
|
||||||
import { DIAG_TYPE } from '@/utils/medicalConstants';
|
import { DIAG_TYPE } from '@/utils/medicalConstants';
|
||||||
|
import { formatDateStr } from '@/utils';
|
||||||
import diagnosisdialog from '../diagnosis/diagnosisdialog.vue';
|
import diagnosisdialog from '../diagnosis/diagnosisdialog.vue';
|
||||||
import AddDiagnosisDialog from './addDiagnosisDialog.vue';
|
import AddDiagnosisDialog from './addDiagnosisDialog.vue';
|
||||||
import diagnosislist from '../diagnosis/diagnosislist.vue';
|
import diagnosislist from '../diagnosis/diagnosislist.vue';
|
||||||
@@ -628,11 +629,11 @@ async function handleSaveDiagnosis() {
|
|||||||
// 开始加载状态,防止重复提交
|
// 开始加载状态,防止重复提交
|
||||||
saveLoading.value = true;
|
saveLoading.value = true;
|
||||||
|
|
||||||
// 保存前按排序号排序,并转换日期格式为ISO字符串
|
// 保存前按排序号排序,并转换日期格式为后端期望的格式 yyyy/M/d HH:mm:ss
|
||||||
const diagnosisChildList = form.value.diagnosisList.map(item => ({
|
const diagnosisChildList = form.value.diagnosisList.map(item => ({
|
||||||
...item,
|
...item,
|
||||||
onsetDate: item.onsetDate ? new Date(item.onsetDate).toISOString() : null,
|
onsetDate: item.onsetDate ? formatDateStr(item.onsetDate, 'YYYY/M/D HH:mm:ss') : null,
|
||||||
diagnosisTime: item.diagnosisTime ? new Date(item.diagnosisTime).toISOString() : null
|
diagnosisTime: item.diagnosisTime ? formatDateStr(item.diagnosisTime, 'YYYY/M/D HH:mm:ss') : null
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// 调用保存诊断接口
|
// 调用保存诊断接口
|
||||||
@@ -657,7 +658,9 @@ async function handleSaveDiagnosis() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存诊断失败:', error);
|
console.error('保存诊断失败:', error);
|
||||||
proxy.$modal.msgError('保存诊断失败,请稍后重试');
|
// 显示后端返回的具体错误信息
|
||||||
|
const errorMsg = error?.response?.data?.msg || error?.message || '保存诊断失败,请稍后重试';
|
||||||
|
proxy.$modal.msgError(errorMsg);
|
||||||
} finally {
|
} finally {
|
||||||
// 结束加载状态
|
// 结束加载状态
|
||||||
saveLoading.value = false;
|
saveLoading.value = false;
|
||||||
|
|||||||
@@ -164,7 +164,14 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="检查方法">
|
<el-form-item label="检查方法">
|
||||||
<el-input v-model="form.inspectionMethod" readonly />
|
<el-select v-model="form.inspectionMethod" placeholder="请选择" clearable filterable style="width: 100%;">
|
||||||
|
<el-option
|
||||||
|
v-for="method in availableMethods"
|
||||||
|
:key="method.id"
|
||||||
|
:label="method.name"
|
||||||
|
:value="method.name"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -308,6 +315,7 @@ import { ElMessage, ElMessageBox } from 'element-plus';
|
|||||||
import { Printer, Delete } from '@element-plus/icons-vue';
|
import { Printer, Delete } from '@element-plus/icons-vue';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
|
import { listCheckMethod } from '@/api/system/checkType';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
patientInfo: { type: Object, default: () => ({}) },
|
patientInfo: { type: Object, default: () => ({}) },
|
||||||
@@ -373,10 +381,69 @@ const categoryList = ref([]); // 原始分类+项目数据
|
|||||||
const dictSearchKey = ref('');
|
const dictSearchKey = ref('');
|
||||||
const activeNames = ref([]); // 当前展开的折叠项
|
const activeNames = ref([]); // 当前展开的折叠项
|
||||||
|
|
||||||
|
const allMethods = ref([]);
|
||||||
|
|
||||||
|
// 加载所有检查方法
|
||||||
|
async function loadAllMethods() {
|
||||||
|
try {
|
||||||
|
const res = await listCheckMethod(); // 使用已导入的或者直接利用 request 请求
|
||||||
|
let methods = [];
|
||||||
|
if (res && res.data) {
|
||||||
|
if (Array.isArray(res.data)) {
|
||||||
|
methods = res.data;
|
||||||
|
} else if (res.data.records) {
|
||||||
|
methods = res.data.records;
|
||||||
|
} else if (res.data.data && Array.isArray(res.data.data)) {
|
||||||
|
methods = res.data.data;
|
||||||
|
}
|
||||||
|
} else if (Array.isArray(res)) {
|
||||||
|
methods = res;
|
||||||
|
} else if (res && res.rows) {
|
||||||
|
methods = res.rows;
|
||||||
|
}
|
||||||
|
allMethods.value = methods;
|
||||||
|
} catch (err) {
|
||||||
|
console.error('加载检查方法失败', err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
|
await loadAllMethods();
|
||||||
await loadCategoryList();
|
await loadCategoryList();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 动态可用的检查方法(根据已选部位所属的检查类型进行过滤)
|
||||||
|
const normalizeTypeValue = value => String(value ?? '').trim().toLowerCase();
|
||||||
|
|
||||||
|
const availableMethods = computed(() => {
|
||||||
|
// 获取当前已选部位的检查类型(可取第一个选中的部位的 checkType)
|
||||||
|
const currentType = form.examTypeCode || (selectedItems.value.length > 0 ? selectedItems.value[0].checkType : '');
|
||||||
|
const normalizedCurrentType = normalizeTypeValue(currentType);
|
||||||
|
if (normalizedCurrentType) {
|
||||||
|
// 兼容脏数据:method 的类型可能落在 checkType/type/typeCode/code/typeName/categoryName 中
|
||||||
|
const filtered = allMethods.value.filter(m => {
|
||||||
|
const typeCandidates = [
|
||||||
|
m.checkType,
|
||||||
|
m.type,
|
||||||
|
m.typeCode,
|
||||||
|
m.code,
|
||||||
|
m.typeName,
|
||||||
|
m.categoryName
|
||||||
|
].map(normalizeTypeValue).filter(Boolean);
|
||||||
|
return typeCandidates.includes(normalizedCurrentType);
|
||||||
|
});
|
||||||
|
return filtered.length > 0 ? filtered : allMethods.value;
|
||||||
|
}
|
||||||
|
return allMethods.value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当可选方法列表改变时,如果当前选中的方法不在新列表中,则清空
|
||||||
|
watch(availableMethods, (newMethods) => {
|
||||||
|
if (form.inspectionMethod && !newMethods.find(m => m.name === form.inspectionMethod)) {
|
||||||
|
form.inspectionMethod = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 加载检查类型(分类)和检查项目(部位/项目),按类型分组展示
|
* 加载检查类型(分类)和检查项目(部位/项目),按类型分组展示
|
||||||
*/
|
*/
|
||||||
@@ -390,25 +457,45 @@ async function loadCategoryList() {
|
|||||||
params: { pageNo: 1, pageSize: 500 } // 取全量分类数据
|
params: { pageNo: 1, pageSize: 500 } // 取全量分类数据
|
||||||
});
|
});
|
||||||
let types = [];
|
let types = [];
|
||||||
if (typeRes.data?.records) types = typeRes.data.records;
|
if (typeRes && typeRes.data) {
|
||||||
else if (Array.isArray(typeRes.data)) types = typeRes.data;
|
if (Array.isArray(typeRes.data)) {
|
||||||
else if (Array.isArray(typeRes.rows)) types = typeRes.rows;
|
types = typeRes.data;
|
||||||
|
} else if (typeRes.data.records) {
|
||||||
|
types = typeRes.data.records;
|
||||||
|
} else if (typeRes.data.data && Array.isArray(typeRes.data.data)) {
|
||||||
|
types = typeRes.data.data;
|
||||||
|
}
|
||||||
|
} else if (Array.isArray(typeRes)) {
|
||||||
|
types = typeRes;
|
||||||
|
} else if (typeRes && typeRes.rows) {
|
||||||
|
types = typeRes.rows;
|
||||||
|
}
|
||||||
|
|
||||||
// 2. 加载检查项目(检查部位项目)
|
// 2. 加载检查项目(检查部位项目)
|
||||||
const partRes = await request({ url: '/check/part/list', method: 'get' });
|
const partRes = await request({ url: '/check/part/list', method: 'get' });
|
||||||
let parts = [];
|
let parts = [];
|
||||||
if (Array.isArray(partRes)) parts = partRes;
|
if (partRes && partRes.data) {
|
||||||
else if (Array.isArray(partRes.data?.data)) parts = partRes.data.data; // 双层嵌套:{ data: { data: [...] } }
|
if (Array.isArray(partRes.data)) {
|
||||||
else if (Array.isArray(partRes.data)) parts = partRes.data;
|
parts = partRes.data;
|
||||||
else if (Array.isArray(partRes.rows)) parts = partRes.rows;
|
} else if (partRes.data.records) {
|
||||||
else if (partRes.data?.records) parts = partRes.data.records;
|
parts = partRes.data.records;
|
||||||
|
} else if (partRes.data.data && Array.isArray(partRes.data.data)) {
|
||||||
|
parts = partRes.data.data;
|
||||||
|
}
|
||||||
|
} else if (Array.isArray(partRes)) {
|
||||||
|
parts = partRes;
|
||||||
|
} else if (partRes && partRes.rows) {
|
||||||
|
parts = partRes.rows;
|
||||||
|
}
|
||||||
|
|
||||||
// 3. 按 checkType 归类
|
// 3. 按 checkType 归类
|
||||||
const dict = [];
|
const dict = [];
|
||||||
for (const t of types) {
|
for (const t of types) {
|
||||||
dict.push({
|
dict.push({
|
||||||
typeId: t.id,
|
typeId: t.id,
|
||||||
typeCode: t.type,
|
typeCode: t.code, // 保存 code 用于后备匹配
|
||||||
|
orgType: t.type, // 保存 type 用于后备匹配
|
||||||
|
typeName: t.name, // 保存 name
|
||||||
categoryName: t.name,
|
categoryName: t.name,
|
||||||
items: []
|
items: []
|
||||||
});
|
});
|
||||||
@@ -425,7 +512,15 @@ async function loadCategoryList() {
|
|||||||
nationalCode: p.nationalCode || '',
|
nationalCode: p.nationalCode || '',
|
||||||
checked: false
|
checked: false
|
||||||
};
|
};
|
||||||
const target = dict.find(d => d.typeCode === p.checkType);
|
|
||||||
|
// 增强匹配逻辑:部位的 checkType (如 'ECG', 'CT') 优先去匹配大类的 orgType,
|
||||||
|
// 如果大类的 type 字段脏了(比如填了中文),则尝试匹配 code,甚至是分类名称
|
||||||
|
const target = dict.find(d =>
|
||||||
|
d.orgType === p.checkType ||
|
||||||
|
d.typeCode === p.checkType ||
|
||||||
|
d.typeName === p.checkType
|
||||||
|
);
|
||||||
|
|
||||||
if (target) target.items.push(mapped);
|
if (target) target.items.push(mapped);
|
||||||
else unclassified.push(mapped);
|
else unclassified.push(mapped);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
<el-container class="inspection-application-container">
|
<el-container class="inspection-application-container">
|
||||||
|
|
||||||
<!-- 顶部操作按钮区 -->
|
<!-- 顶部操作按钮区 -->
|
||||||
<el-header class="top-action-bar" height="50px">
|
<el-header class="top-action-bar" height="60px">
|
||||||
<el-row class="action-buttons" type="flex" justify="end" :gutter="10">
|
<el-row class="action-buttons" type="flex" justify="end" :gutter="10">
|
||||||
<el-button type="success" size="large" @click="handleSave" class="save-btn" :loading="saving">
|
<el-button type="primary" size="large" @click="handleSave" class="save-btn" :loading="saving">
|
||||||
<el-icon><Document /></el-icon>
|
<el-icon><Document /></el-icon>
|
||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
border
|
border
|
||||||
stripe
|
stripe
|
||||||
size="small"
|
size="small"
|
||||||
max-height="300px"
|
max-height="280px"
|
||||||
style="width: 100%; min-width: 100%"
|
style="width: 100%; min-width: 100%"
|
||||||
class="inspection-table"
|
class="inspection-table"
|
||||||
highlight-current-row
|
highlight-current-row
|
||||||
@@ -39,12 +39,12 @@
|
|||||||
@cell-click="handleCellClick"
|
@cell-click="handleCellClick"
|
||||||
>
|
>
|
||||||
<el-table-column type="selection" width="55" align="center" header-align="center" />
|
<el-table-column type="selection" width="55" align="center" header-align="center" />
|
||||||
<el-table-column label="序号" width="60" align="center" header-align="center">
|
<el-table-column label="申请ID" prop="applicationId" width="80" align="center" header-align="center">
|
||||||
<template #default="{ $index }">
|
<template #default="scope">
|
||||||
<span>{{ $index + 1 }}</span>
|
<span>{{ scope.row.applicationId || '-' }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="申请单号" prop="applyNo" min-width="180" align="center" header-align="center" />
|
<el-table-column label="申请单号" prop="applyNo" min-width="160" align="center" header-align="center" />
|
||||||
<el-table-column label="检验项目" prop="itemName" min-width="170px" align="center" header-align="center" />
|
<el-table-column label="检验项目" prop="itemName" min-width="170px" align="center" header-align="center" />
|
||||||
<el-table-column label="申请医生" prop="applyDocName" width="120" align="center" header-align="center" />
|
<el-table-column label="申请医生" prop="applyDocName" width="120" align="center" header-align="center" />
|
||||||
<el-table-column label="急" width="60" align="center" header-align="center">
|
<el-table-column label="急" width="60" align="center" header-align="center">
|
||||||
@@ -82,49 +82,50 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<!-- 分页 -->
|
<!-- 分页 -->
|
||||||
<el-row class="pagination-container" justify="center" style="margin-top: 10px">
|
<div style="width: 100%; text-align: center; margin-top: 8px;">
|
||||||
<el-pagination
|
<el-pagination
|
||||||
v-model:current-page="queryParams.pageNo"
|
v-model:current-page="queryParams.pageNo"
|
||||||
v-model:page-size="queryParams.pageSize"
|
v-model:page-size="queryParams.pageSize"
|
||||||
:page-sizes="[10, 20, 50, 100]"
|
|
||||||
:total="total"
|
:total="total"
|
||||||
layout="prev, pager, next, jumper, total"
|
layout="prev, pager, next"
|
||||||
:pager-count="5"
|
:pager-count="5"
|
||||||
:hide-on-single-page="false"
|
:hide-on-single-page="true"
|
||||||
|
small
|
||||||
@size-change="handleSizeChange"
|
@size-change="handleSizeChange"
|
||||||
@current-change="handleCurrentChange"
|
@current-change="handleCurrentChange"
|
||||||
|
style="display: inline-flex;"
|
||||||
/>
|
/>
|
||||||
</el-row>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-main>
|
</el-main>
|
||||||
|
|
||||||
<!-- 底部表单与项目选择区 -->
|
<!-- 底部表单与项目选择区 -->
|
||||||
<el-main class="bottom-content-area">
|
<el-main class="bottom-content-area">
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="12">
|
||||||
<!-- 左侧:申请单表单区(65%) -->
|
<!-- 左侧:申请单表单区(60%) -->
|
||||||
<el-col :span="15" class="form-area">
|
<el-col :span="14" class="form-area">
|
||||||
<el-card class="form-card" style="width: 100%">
|
<el-card class="form-card" style="width: 100%">
|
||||||
<el-tabs v-model="leftActiveTab" class="form-tabs">
|
<el-tabs v-model="leftActiveTab" class="form-tabs">
|
||||||
<el-tab-pane label="申请单" name="application">
|
<el-tab-pane label="申请单" name="application">
|
||||||
<el-form class="application-form" :model="formData" label-width="auto">
|
<el-form class="application-form" :model="formData" label-width="auto">
|
||||||
<el-form-item label="申请单号" style="margin-bottom: 1px">
|
<el-form-item label="申请单号" style="margin-bottom: 2px">
|
||||||
<el-input v-model="formData.applyNo" disabled size="small" />
|
<el-input v-model="formData.applyNo" disabled size="small" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 患者信息行 -->
|
<!-- 患者信息行 -->
|
||||||
<el-row :gutter="20" style="margin-bottom: 1px">
|
<el-row :gutter="12" style="margin-bottom: 0">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="姓名" required>
|
<el-form-item label="姓名" required style="margin-bottom: 4px">
|
||||||
<el-input v-model="formData.patientName" readonly size="small" />
|
<el-input v-model="formData.patientName" readonly size="small" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="就诊卡号" required>
|
<el-form-item label="就诊卡号" required style="margin-bottom: 4px">
|
||||||
<el-input v-model="formData.medicalrecordNumber" readonly size="small" />
|
<el-input v-model="formData.medicalrecordNumber" readonly size="small" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="费用性质" required>
|
<el-form-item label="费用性质" required style="margin-bottom: 4px">
|
||||||
<el-select v-model="formData.natureofCost" placeholder="请选择费用性质" size="small" style="width: 100%">
|
<el-select v-model="formData.natureofCost" placeholder="请选择费用性质" size="small" style="width: 100%">
|
||||||
<el-option label="自费医疗" value="self" />
|
<el-option label="自费医疗" value="self" />
|
||||||
<el-option label="医保" value="medical" />
|
<el-option label="医保" value="medical" />
|
||||||
@@ -137,10 +138,10 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 申请信息行 -->
|
<!-- 申请信息行 -->
|
||||||
<el-row :gutter="20" style="margin-bottom: 1px">
|
<el-row :gutter="12" style="margin-bottom: 0">
|
||||||
<!--申请日期-->
|
<!--申请日期-->
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="申请日期" required>
|
<el-form-item label="申请日期" required style="margin-bottom: 4px">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.applyTime"
|
v-model="formData.applyTime"
|
||||||
readonly
|
readonly
|
||||||
@@ -150,13 +151,13 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<!--申请科室-->
|
<!--申请科室-->
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="申请科室" required>
|
<el-form-item label="申请科室" required style="margin-bottom: 4px">
|
||||||
<el-input v-model="formData.applyDepartment" readonly size="small" />
|
<el-input v-model="formData.applyDepartment" readonly size="small" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!--申请医生-->
|
<!--申请医生-->
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="申请医生" required>
|
<el-form-item label="申请医生" required style="margin-bottom: 4px">
|
||||||
<el-input v-model="formData.applyDocName" readonly size="small" />
|
<el-input v-model="formData.applyDocName" readonly size="small" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -166,7 +167,7 @@
|
|||||||
<el-form-item
|
<el-form-item
|
||||||
label="执行科室"
|
label="执行科室"
|
||||||
required
|
required
|
||||||
style="margin-bottom: 1px"
|
style="margin-bottom: 4px"
|
||||||
:class="{ 'form-item-error': validationErrors.executeDepartment }"
|
:class="{ 'form-item-error': validationErrors.executeDepartment }"
|
||||||
:error="validationErrors.executeDepartment ? '请选择执行科室' : ''"
|
:error="validationErrors.executeDepartment ? '请选择执行科室' : ''"
|
||||||
>
|
>
|
||||||
@@ -186,19 +187,20 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 诊断描述 -->
|
<!-- 诊断描述与临床诊断 -->
|
||||||
<el-row :gutter="20" style="margin-bottom: 1px">
|
<el-row :gutter="12" style="margin-bottom: 0">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="诊断描述"
|
label="诊断描述"
|
||||||
required
|
required
|
||||||
|
style="margin-bottom: 4px"
|
||||||
:class="{ 'form-item-error': validationErrors.clinicDesc }"
|
:class="{ 'form-item-error': validationErrors.clinicDesc }"
|
||||||
:error="validationErrors.clinicDesc ? '请输入诊断描述' : ''"
|
:error="validationErrors.clinicDesc ? '请输入诊断描述' : ''"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.clinicDesc"
|
v-model="formData.clinicDesc"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="2"
|
:rows="1"
|
||||||
size="small"
|
size="small"
|
||||||
:class="{ 'is-error': validationErrors.clinicDesc }"
|
:class="{ 'is-error': validationErrors.clinicDesc }"
|
||||||
/>
|
/>
|
||||||
@@ -208,13 +210,14 @@
|
|||||||
<el-form-item
|
<el-form-item
|
||||||
label="临床诊断"
|
label="临床诊断"
|
||||||
required
|
required
|
||||||
|
style="margin-bottom: 4px"
|
||||||
:class="{ 'form-item-error': validationErrors.clinicDiag }"
|
:class="{ 'form-item-error': validationErrors.clinicDiag }"
|
||||||
:error="validationErrors.clinicDiag ? '请输入临床诊断' : ''"
|
:error="validationErrors.clinicDiag ? '请输入临床诊断' : ''"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.clinicDiag"
|
v-model="formData.clinicDiag"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="2"
|
:rows="1"
|
||||||
size="small"
|
size="small"
|
||||||
:class="{ 'is-error': validationErrors.clinicDiag }"
|
:class="{ 'is-error': validationErrors.clinicDiag }"
|
||||||
/>
|
/>
|
||||||
@@ -222,24 +225,20 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 禁忌症、病史摘要、检验目的、体格检查 -->
|
<!-- 病史摘要与检验目的 -->
|
||||||
<el-row :gutter="20" style="margin-bottom: 1px">
|
<el-row :gutter="12" style="margin-bottom: 0">
|
||||||
<el-col :span="12">
|
|
||||||
<el-form-item label="禁忌症">
|
|
||||||
<el-input v-model="formData.contraindication" type="textarea" :rows="2" size="small" />
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
label="病史摘要"
|
label="病史摘要"
|
||||||
required
|
required
|
||||||
|
style="margin-bottom: 4px"
|
||||||
:class="{ 'form-item-error': validationErrors.medicalHistorySummary }"
|
:class="{ 'form-item-error': validationErrors.medicalHistorySummary }"
|
||||||
:error="validationErrors.medicalHistorySummary ? '请输入病史摘要' : ''"
|
:error="validationErrors.medicalHistorySummary ? '请输入病史摘要' : ''"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.medicalHistorySummary"
|
v-model="formData.medicalHistorySummary"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="2"
|
:rows="1"
|
||||||
size="small"
|
size="small"
|
||||||
:class="{ 'is-error': validationErrors.medicalHistorySummary }"
|
:class="{ 'is-error': validationErrors.medicalHistorySummary }"
|
||||||
/>
|
/>
|
||||||
@@ -249,47 +248,57 @@
|
|||||||
<el-form-item
|
<el-form-item
|
||||||
label="检验目的"
|
label="检验目的"
|
||||||
required
|
required
|
||||||
|
style="margin-bottom: 4px"
|
||||||
:class="{ 'form-item-error': validationErrors.purposeofInspection }"
|
:class="{ 'form-item-error': validationErrors.purposeofInspection }"
|
||||||
:error="validationErrors.purposeofInspection ? '请输入检验目的' : ''"
|
:error="validationErrors.purposeofInspection ? '请输入检验目的' : ''"
|
||||||
>
|
>
|
||||||
<el-input
|
<el-input
|
||||||
v-model="formData.purposeofInspection"
|
v-model="formData.purposeofInspection"
|
||||||
type="textarea"
|
type="textarea"
|
||||||
:rows="2"
|
:rows="1"
|
||||||
size="small"
|
size="small"
|
||||||
:class="{ 'is-error': validationErrors.purposeofInspection }"
|
:class="{ 'is-error': validationErrors.purposeofInspection }"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 禁忌症与体格检查 -->
|
||||||
|
<el-row :gutter="12" style="margin-bottom: 0">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="体格检查">
|
<el-form-item label="禁忌症" style="margin-bottom: 4px">
|
||||||
<el-input v-model="formData.physicalExam" type="textarea" :rows="2" size="small" />
|
<el-input v-model="formData.contraindication" size="small" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="体格检查" style="margin-bottom: 4px">
|
||||||
|
<el-input v-model="formData.physicalExam" size="small" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 检验项目和备注 -->
|
<!-- 检验项目和备注 -->
|
||||||
<el-row :gutter="20" style="margin-bottom: 1px">
|
<el-row :gutter="12" style="margin-bottom: 0">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="检验项目">
|
<el-form-item label="检验项目" style="margin-bottom: 4px">
|
||||||
<el-input v-model="formData.inspectionItemsText" type="textarea" :rows="2" size="small" readonly />
|
<el-input v-model="formData.inspectionItemsText" size="small" readonly />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注" style="margin-bottom: 4px">
|
||||||
<el-input v-model="formData.applyRemark" type="textarea" :rows="2" size="small" />
|
<el-input v-model="formData.applyRemark" size="small" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<!-- 状态复选框组 -->
|
<!-- 状态复选框组 -->
|
||||||
<el-card style="margin-bottom: 16px; padding: 16px; background: #f8f9fa; border-radius: 4px; border: 1px solid #e9ecef" shadow="never">
|
<el-card style="margin-bottom: 4px; padding: 8px 12px; background: #f8f9fa; border-radius: 4px; border: 1px solid #e9ecef" shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<span style="font-weight: bold; color: #1a2b6d; font-size: 14px">
|
<span style="font-weight: bold; color: #1a2b6d; font-size: 13px">
|
||||||
状态设置
|
状态设置
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<el-row type="flex" :gutter="16" wrap>
|
<el-row type="flex" :gutter="12" wrap>
|
||||||
<el-col :xs="12" :sm="6" :md="6" :lg="6">
|
<el-col :xs="12" :sm="6" :md="6" :lg="6">
|
||||||
<!-- 只有急标记能编辑 -->
|
<!-- 只有急标记能编辑 -->
|
||||||
<el-checkbox v-model="formData.priorityCode" :true-value="1" :false-value="0">急</el-checkbox>
|
<el-checkbox v-model="formData.priorityCode" :true-value="1" :false-value="0">急</el-checkbox>
|
||||||
@@ -311,8 +320,8 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="检验信息" name="inspectionInfo">
|
<el-tab-pane label="检验信息" name="inspectionInfo">
|
||||||
<el-card style="padding: 20px; height: 700px; overflow-y: auto; border: 1px solid #e4e7ed; border-radius: 4px; margin: 10px; width: 100%">
|
<el-card style="padding: 10px; overflow-y: auto; border: 1px solid #e4e7ed; border-radius: 4px; margin: 5px; width: 100%">
|
||||||
<el-form :model="formData" label-width="100px" style="margin-bottom: 20px">
|
<el-form :model="formData" label-width="100px" style="margin-bottom: 10px">
|
||||||
<el-row :gutter="15">
|
<el-row :gutter="15">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="检验医生">
|
<el-form-item label="检验医生">
|
||||||
@@ -354,11 +363,11 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<!-- 检验信息详情表格 -->
|
<!-- 检验信息详情表格 -->
|
||||||
<el-card style="margin-top: 20px; width: 100%" shadow="never">
|
<el-card style="margin-top: 10px; width: 100%" shadow="never">
|
||||||
<template #header>
|
<template #header>
|
||||||
<h4 style="margin: 0; font-weight: bold">检验信息详情</h4>
|
<h4 style="margin: 0; font-weight: bold">检验信息详情</h4>
|
||||||
</template>
|
</template>
|
||||||
<el-table :data="selectedInspectionItems" border size="small" style="width: 100%; min-width: 100%" max-height="350">
|
<el-table :data="selectedInspectionItems" border size="small" style="width: 100%; min-width: 100%" max-height="250">
|
||||||
<el-table-column label="项目名称" prop="itemName" width="200" />
|
<el-table-column label="项目名称" prop="itemName" width="200" />
|
||||||
<el-table-column label="样本类型" prop="sampleType" width="80" align="center" />
|
<el-table-column label="样本类型" prop="sampleType" width="80" align="center" />
|
||||||
<el-table-column label="单位" prop="unit" width="60" align="center" />
|
<el-table-column label="单位" prop="unit" width="60" align="center" />
|
||||||
@@ -395,8 +404,8 @@
|
|||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
<!-- 右侧:项目选择区(35%) -->
|
<!-- 右侧:项目选择区(40%) -->
|
||||||
<el-col :span="9" class="selection-area">
|
<el-col :span="10" class="selection-area">
|
||||||
<!-- 检验项目选择区(上部50%) -->
|
<!-- 检验项目选择区(上部50%) -->
|
||||||
<el-card class="inspection-selector" v-loading="inspectionLoading" element-loading-text="正在加载检验项目...">
|
<el-card class="inspection-selector" v-loading="inspectionLoading" element-loading-text="正在加载检验项目...">
|
||||||
<template #header>
|
<template #header>
|
||||||
@@ -429,7 +438,7 @@
|
|||||||
<!-- 分类树 -->
|
<!-- 分类树 -->
|
||||||
<el-scrollbar
|
<el-scrollbar
|
||||||
class="category-tree"
|
class="category-tree"
|
||||||
style="max-height: 280px"
|
style="max-height: 220px"
|
||||||
@scroll="handleScroll"
|
@scroll="handleScroll"
|
||||||
>
|
>
|
||||||
<!-- 无数据提示 -->
|
<!-- 无数据提示 -->
|
||||||
@@ -504,7 +513,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 已选项目列表 -->
|
<!-- 已选项目列表 -->
|
||||||
<el-scrollbar class="selected-tree" style="max-height: 300px">
|
<el-scrollbar class="selected-tree" style="max-height: 220px">
|
||||||
<el-list v-if="selectedInspectionItems.length > 0" :data="selectedInspectionItems" class="selected-items-list">
|
<el-list v-if="selectedInspectionItems.length > 0" :data="selectedInspectionItems" class="selected-items-list">
|
||||||
<el-list-item
|
<el-list-item
|
||||||
v-for="item in selectedInspectionItems"
|
v-for="item in selectedInspectionItems"
|
||||||
@@ -638,7 +647,7 @@ const initData = async () => {
|
|||||||
// 查询参数
|
// 查询参数
|
||||||
const queryParams = reactive({
|
const queryParams = reactive({
|
||||||
pageNo: 1,
|
pageNo: 1,
|
||||||
pageSize: 10,
|
pageSize: 3,
|
||||||
encounterId: props.patientInfo.encounterId
|
encounterId: props.patientInfo.encounterId
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -987,14 +996,14 @@ const getInspectionList = () => {
|
|||||||
if (res.data && typeof res.data === 'object') {
|
if (res.data && typeof res.data === 'object') {
|
||||||
// 如果返回的是分页对象 {records: [...], total: 100}
|
// 如果返回的是分页对象 {records: [...], total: 100}
|
||||||
if (Array.isArray(res.data.records)) {
|
if (Array.isArray(res.data.records)) {
|
||||||
// 处理数据:将同一个申请单的多个明细合并成一条记录
|
// 直接使用后端返回的数据(后端已按申请单返回,无需合并)
|
||||||
inspectionList.value = mergeInspectionApplyRecords(res.data.records)
|
inspectionList.value = res.data.records
|
||||||
total.value = res.data.total || 0
|
total.value = res.data.total || res.data.records.length
|
||||||
}
|
}
|
||||||
// 如果返回的是普通数组
|
// 如果返回的是普通数组
|
||||||
else if (Array.isArray(res.data)) {
|
else if (Array.isArray(res.data)) {
|
||||||
// 处理数据:将同一个申请单的多个明细合并成一条记录
|
// 直接使用后端返回的数据
|
||||||
inspectionList.value = mergeInspectionApplyRecords(res.data)
|
inspectionList.value = res.data
|
||||||
total.value = res.data.length
|
total.value = res.data.length
|
||||||
}
|
}
|
||||||
// 如果返回的是其他对象结构
|
// 如果返回的是其他对象结构
|
||||||
@@ -1625,10 +1634,16 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
/* 页面容器 */
|
/* 页面容器 - 紧凑布局 */
|
||||||
.inspection-application-container {
|
.inspection-application-container {
|
||||||
max-height: 750px;
|
height: auto;
|
||||||
overflow-y: auto;
|
max-height: none;
|
||||||
|
overflow: visible;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 覆盖 el-main 默认 padding */
|
||||||
|
.inspection-application-container .el-main {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1647,15 +1662,41 @@ defineExpose({
|
|||||||
gap: 10px;
|
gap: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 检验信息表格区 */
|
/* 新增按钮样式 - PRD要求蓝色背景 #4a89dc */
|
||||||
|
.new-btn {
|
||||||
|
background-color: #4a89dc !important;
|
||||||
|
border-color: #4a89dc !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.new-btn:hover {
|
||||||
|
background-color: #5a9aec !important;
|
||||||
|
border-color: #5a9aec !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 保存按钮样式 - PRD要求绿色背景 #48cfad */
|
||||||
|
.save-btn {
|
||||||
|
background-color: #48cfad !important;
|
||||||
|
border-color: #48cfad !important;
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn:hover {
|
||||||
|
background-color: #58dfbd !important;
|
||||||
|
border-color: #58dfbd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 检验信息表格区 - 紧凑高度 */
|
||||||
.inspection-section {
|
.inspection-section {
|
||||||
padding: 20px;
|
padding: 4px 10px 0 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-card {
|
.table-card {
|
||||||
height: 300px;
|
height: auto;
|
||||||
display: flex;
|
}
|
||||||
flex-direction: column;
|
|
||||||
|
.table-card :deep(.el-card__body) {
|
||||||
|
padding-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-header {
|
.card-header {
|
||||||
@@ -1668,37 +1709,45 @@ defineExpose({
|
|||||||
|
|
||||||
/* 底部内容区域 */
|
/* 底部内容区域 */
|
||||||
.bottom-content-area {
|
.bottom-content-area {
|
||||||
padding: 20px;
|
padding: 4px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表单区域 */
|
/* 表单区域 */
|
||||||
.form-card {
|
.form-card {
|
||||||
height: 700px;
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 表单区域使用主色调 */
|
||||||
|
.form-tabs :deep(.el-tabs__item.is-active) {
|
||||||
|
color: #51A3F3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-tabs :deep(.el-tabs__active-bar) {
|
||||||
|
background-color: #51A3F3 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-tabs {
|
.form-tabs {
|
||||||
height: 100%;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.application-form {
|
.application-form {
|
||||||
height: 650px;
|
overflow: visible;
|
||||||
overflow-y: auto;
|
padding: 6px 8px;
|
||||||
padding: 20px;
|
|
||||||
border: 1px solid #e4e7ed;
|
border: 1px solid #e4e7ed;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin: 10px;
|
margin: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 选择区域 */
|
/* 选择区域 */
|
||||||
.selection-area {
|
.selection-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 20px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inspection-selector,
|
.inspection-selector,
|
||||||
.selected-items-area {
|
.selected-items-area {
|
||||||
height: 350px;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-title {
|
.card-title {
|
||||||
@@ -1707,7 +1756,7 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-header {
|
.selected-header {
|
||||||
@@ -1717,14 +1766,6 @@ defineExpose({
|
|||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination-container {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 10px;
|
|
||||||
padding-top: 10px;
|
|
||||||
border-top: 1px solid var(--el-border-color-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
:deep(.el-pagination) {
|
:deep(.el-pagination) {
|
||||||
.el-pager li {
|
.el-pager li {
|
||||||
@@ -1976,6 +2017,7 @@ defineExpose({
|
|||||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 主色调 #51A3F3 - PRD样式规范 */
|
||||||
:deep(.inspection-table .el-table__header) {
|
:deep(.inspection-table .el-table__header) {
|
||||||
th {
|
th {
|
||||||
background: linear-gradient(to bottom, #f8fafc 0%, #f1f5f9 100%);
|
background: linear-gradient(to bottom, #f8fafc 0%, #f1f5f9 100%);
|
||||||
@@ -1987,6 +2029,17 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 选中状态使用主色调 #51A3F3 */
|
||||||
|
:deep(.inspection-table .el-checkbox__input.is-checked .el-checkbox__inner) {
|
||||||
|
background-color: #51A3F3 !important;
|
||||||
|
border-color: #51A3F3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.inspection-table .el-checkbox__input.is-indeterminate .el-checkbox__inner) {
|
||||||
|
background-color: #51A3F3 !important;
|
||||||
|
border-color: #51A3F3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
:deep(.inspection-table .el-table__body) {
|
:deep(.inspection-table .el-table__body) {
|
||||||
td {
|
td {
|
||||||
border-bottom: 1px solid #f1f5f9;
|
border-bottom: 1px solid #f1f5f9;
|
||||||
@@ -2038,7 +2091,7 @@ defineExpose({
|
|||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 新的树形结构样式 */
|
/* 新的树形结构样式 - PRD要求高度约350px */
|
||||||
.category-tree {
|
.category-tree {
|
||||||
border: 1px solid #ebeef5;
|
border: 1px solid #ebeef5;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
@@ -2072,7 +2125,7 @@ defineExpose({
|
|||||||
|
|
||||||
.category-tree-header.active {
|
.category-tree-header.active {
|
||||||
background-color: #e6f7ff;
|
background-color: #e6f7ff;
|
||||||
color: #409eff;
|
color: #51A3F3;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2081,7 +2134,7 @@ defineExpose({
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
width: 12px;
|
width: 12px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #409eff;
|
color: #51A3F3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-count {
|
.category-count {
|
||||||
@@ -2147,7 +2200,7 @@ defineExpose({
|
|||||||
|
|
||||||
.inspection-tree-item.selected {
|
.inspection-tree-item.selected {
|
||||||
background-color: #ecf5ff;
|
background-color: #ecf5ff;
|
||||||
border-left: 3px solid #409eff;
|
border-left: 3px solid #51A3F3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inspection-tree-item .item-itemName {
|
.inspection-tree-item .item-itemName {
|
||||||
@@ -2162,7 +2215,7 @@ defineExpose({
|
|||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 已选项目区样式 */
|
/* 已选项目区样式 - PRD要求高度约350px */
|
||||||
.selected-items-area {
|
.selected-items-area {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -2170,6 +2223,7 @@ defineExpose({
|
|||||||
|
|
||||||
.selected-tree {
|
.selected-tree {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
max-height: 280px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-tree-item {
|
.selected-tree-item {
|
||||||
|
|||||||
@@ -140,6 +140,12 @@ function handleReceive(row) {
|
|||||||
// }
|
// }
|
||||||
receiveEncounter(row.encounterId).then(() => {
|
receiveEncounter(row.encounterId).then(() => {
|
||||||
emits('toCurrent', row);
|
emits('toCurrent', row);
|
||||||
|
}).catch(error => {
|
||||||
|
// 如果接诊失败,检查是否是"已接诊"的错误
|
||||||
|
if (error && error.message && error.message.includes('已接诊')) {
|
||||||
|
// 自动刷新列表,移除已接诊的患者
|
||||||
|
getPatientList();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -546,6 +546,11 @@
|
|||||||
expandOrder = [];
|
expandOrder = [];
|
||||||
// 当医嘱类型改变时,清空当前选择的项目名称,因为不同类型项目的数据结构可能不兼容
|
// 当医嘱类型改变时,清空当前选择的项目名称,因为不同类型项目的数据结构可能不兼容
|
||||||
prescriptionList[scope.$index].adviceName = undefined;
|
prescriptionList[scope.$index].adviceName = undefined;
|
||||||
|
prescriptionList[scope.$index].adviceType_dictText = '';
|
||||||
|
// 🔧 Bug Fix: 医嘱类型改变时,重置minUnitQuantity和minUnitCode,避免null值
|
||||||
|
prescriptionList[scope.$index].minUnitQuantity = prescriptionList[scope.$index].quantity || 1;
|
||||||
|
prescriptionList[scope.$index].minUnitCode = prescriptionList[scope.$index].unitCode;
|
||||||
|
prescriptionList[scope.$index].minUnitCode_dictText = prescriptionList[scope.$index].unitCode_dictText;
|
||||||
adviceQueryParams.adviceTypes = value; // 🎯 修复:改为 adviceTypes(复数)
|
adviceQueryParams.adviceTypes = value; // 🎯 修复:改为 adviceTypes(复数)
|
||||||
|
|
||||||
// 根据选择的类型设置categoryCode,用于药品分类筛选
|
// 根据选择的类型设置categoryCode,用于药品分类筛选
|
||||||
@@ -952,37 +957,42 @@ const { method_code, unit_code, rate_code, distribution_category_code, drord_doc
|
|||||||
'drord_doctor_type'
|
'drord_doctor_type'
|
||||||
);
|
);
|
||||||
|
|
||||||
// 删除硬编码的adviceTypeList,直接使用drord_doctor_type字典
|
// 使用 drord_doctor_type 字典,不再硬编码
|
||||||
// drord_doctor_type: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=全部
|
// drord_doctor_type: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=手术
|
||||||
const adviceTypeList = ref([
|
const adviceTypeList = computed(() => {
|
||||||
{
|
// 如果字典已加载,使用字典数据;否则使用默认值
|
||||||
label: '西药',
|
let list = [];
|
||||||
value: 1,
|
if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
|
||||||
},
|
// 过滤掉字典中已有的"全部"选项,避免重复
|
||||||
{
|
list = drord_doctor_type.value
|
||||||
label: '中成药',
|
.filter(item => item.label !== '全部')
|
||||||
value: 2,
|
.map(item => ({
|
||||||
},
|
label: item.label,
|
||||||
{
|
value: parseInt(item.value) || item.value
|
||||||
label: '诊疗',
|
}));
|
||||||
value: 3,
|
} else {
|
||||||
},
|
// 默认返回值,确保页面正常显示
|
||||||
{
|
list = [
|
||||||
label: '耗材',
|
{ label: '西药', value: 1 },
|
||||||
value: 4,
|
{ label: '中成药', value: 2 },
|
||||||
},
|
{ label: '诊疗', value: 3 },
|
||||||
{
|
{ label: '耗材', value: 4 },
|
||||||
label: '会诊',
|
{ label: '会诊', value: 5 },
|
||||||
value: 5,
|
{ label: '手术', value: 6 },
|
||||||
},
|
];
|
||||||
{
|
}
|
||||||
label: '全部',
|
// 在最后添加"全部"选项
|
||||||
value: '',
|
list.push({ label: '全部', value: 0 });
|
||||||
},
|
return list;
|
||||||
]);
|
});
|
||||||
|
|
||||||
// 根据类型值获取显示标签,避免非编辑态出现空标签
|
// 根据类型值获取显示标签,避免非编辑态出现空标签
|
||||||
const mapAdviceTypeLabel = (type) => {
|
const mapAdviceTypeLabel = (type, adviceTableName) => {
|
||||||
|
// 🔧 Bug Fix: 根据adviceTableName判断耗材类型
|
||||||
|
// 后端adviceType=2既表示中成药又表示耗材,需要通过表名区分
|
||||||
|
if (type === 2 && adviceTableName === 'adm_device_definition') {
|
||||||
|
return '耗材';
|
||||||
|
}
|
||||||
const found = adviceTypeList.value.find((item) => item.value === type);
|
const found = adviceTypeList.value.find((item) => item.value === type);
|
||||||
return found ? found.label : '';
|
return found ? found.label : '';
|
||||||
};
|
};
|
||||||
@@ -1610,11 +1620,8 @@ function getListInfo(addNewRow) {
|
|||||||
// 🔧 Bug Fix: 后端保存时将耗材(4)转换为中成药(2),显示时需要转换回来
|
// 🔧 Bug Fix: 后端保存时将耗材(4)转换为中成药(2),显示时需要转换回来
|
||||||
// 检查 adviceTableName,如果是耗材表则应该是耗材类型
|
// 检查 adviceTableName,如果是耗材表则应该是耗材类型
|
||||||
const adviceTableName = contentJson?.adviceTableName || item.adviceTableName;
|
const adviceTableName = contentJson?.adviceTableName || item.adviceTableName;
|
||||||
if (adviceType === 2 && adviceTableName === 'adm_device_definition') {
|
|
||||||
adviceType = 4; // 后端2(中成药) -> 前端4(耗材)
|
|
||||||
}
|
|
||||||
|
|
||||||
let adviceType_dictText = item.adviceType_dictText || mapAdviceTypeLabel(adviceType);
|
let adviceType_dictText = item.adviceType_dictText || mapAdviceTypeLabel(adviceType, adviceTableName);
|
||||||
|
|
||||||
// 如果是会诊类型,设置为会诊类型
|
// 如果是会诊类型,设置为会诊类型
|
||||||
if (isConsultation) {
|
if (isConsultation) {
|
||||||
@@ -2351,6 +2358,13 @@ function handleSave(prescriptionId) {
|
|||||||
item.accountId = finalAccountId;
|
item.accountId = finalAccountId;
|
||||||
}
|
}
|
||||||
item.dbOpType = '1';
|
item.dbOpType = '1';
|
||||||
|
|
||||||
|
// 🔧 Bug Fix: 确保耗材的minUnitQuantity被正确设置
|
||||||
|
if (item.adviceType == 4) {
|
||||||
|
item.minUnitQuantity = item.quantity;
|
||||||
|
item.minUnitCode = item.unitCode;
|
||||||
|
item.minUnitCode_dictText = item.unitCode_dictText;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
@@ -2374,17 +2388,24 @@ function handleSave(prescriptionId) {
|
|||||||
finalUnitCode = item.minUnitCode;
|
finalUnitCode = item.minUnitCode;
|
||||||
}
|
}
|
||||||
item.minUnitQuantity = finalQuantity;
|
item.minUnitQuantity = finalQuantity;
|
||||||
|
} else if (item.adviceType == 4) {
|
||||||
|
// 🔧 Bug Fix: 耗材类型只有一个单位,minUnitQuantity等于quantity
|
||||||
|
item.minUnitQuantity = item.quantity;
|
||||||
|
// 🔧 Bug Fix: 确保minUnitCode等于unitCode
|
||||||
|
item.minUnitCode = item.unitCode;
|
||||||
|
item.minUnitCode_dictText = item.unitCode_dictText;
|
||||||
|
finalUnitCode = item.unitCode;
|
||||||
} else {
|
} else {
|
||||||
item.minUnitQuantity = item.quantity;
|
item.minUnitQuantity = item.quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- 【修改点3:Bug 1 修复 (类型转换)】 ---
|
// --- 【修改点3:Bug 1 修复 (类型转换)】 ---
|
||||||
let saveAdviceType = item.adviceType;
|
let saveAdviceType = item.adviceType;
|
||||||
if (item.adviceType == 4) {
|
// 🔧 Bug Fix: 保持原类型,不进行转换
|
||||||
saveAdviceType = 2; // 耗材:前端4 -> 后端2
|
// 前端类型: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=手术
|
||||||
} else if (item.adviceType == 2) {
|
// 后端类型: 1=药品, 2=耗材, 3=医疗活动, 6=手术
|
||||||
saveAdviceType = 1; // 中成药:前端2 -> 后端1
|
// 后端会通过 ItemType.DEVICE.getValue() || adviceType == 4 来识别耗材
|
||||||
} else if (item.adviceType == 5) {
|
if (item.adviceType == 5) {
|
||||||
saveAdviceType = 3; // 会诊:前端5 -> 后端3(诊疗类)
|
saveAdviceType = 3; // 会诊:前端5 -> 后端3(诊疗类)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2395,6 +2416,21 @@ function handleSave(prescriptionId) {
|
|||||||
console.warn('Fixed NaN totalPrice for item:', item.adviceName);
|
console.warn('Fixed NaN totalPrice for item:', item.adviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔧 BugFix#318: 从 parsedContent 提取标准医嘱字段,排除手术特有字段
|
||||||
|
const standardFields = [
|
||||||
|
'accountId', 'chargeItemId', 'conditionDefinitionId', 'conditionId',
|
||||||
|
'contentJson', 'definitionDetailId', 'definitionId', 'diagnosisName',
|
||||||
|
'dosageInstruction', 'effectiveOrgId', 'encounterDiagnosisId',
|
||||||
|
'encounterId', 'lotNumber', 'patientId', 'practitionerId',
|
||||||
|
'prescriptionNo', 'skinTestFlag', 'unitPrice', 'volume', 'ybClassEnum'
|
||||||
|
];
|
||||||
|
let filteredContent = {};
|
||||||
|
standardFields.forEach(field => {
|
||||||
|
if (parsedContent[field] !== undefined) {
|
||||||
|
filteredContent[field] = parsedContent[field];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 构造请求参数
|
// 构造请求参数
|
||||||
// 🔧 Bug Fix: 确保库存匹配成功的关键字段
|
// 🔧 Bug Fix: 确保库存匹配成功的关键字段
|
||||||
// 耗材使用 adm_device_definition 表
|
// 耗材使用 adm_device_definition 表
|
||||||
@@ -2418,16 +2454,20 @@ function handleSave(prescriptionId) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...parsedContent,
|
...filteredContent, // 🔧 BugFix#318: 使用过滤后的字段,排除手术特有字段
|
||||||
adviceType: saveAdviceType, // 使用转换后的类型
|
adviceType: saveAdviceType, // 使用转换后的类型
|
||||||
requestId: item.requestId,
|
requestId: item.requestId,
|
||||||
dbOpType: '1',
|
dbOpType: item.requestId ? '2' : '1', // 🔧 BugFix: 根据requestId判断是新增还是修改
|
||||||
|
encounterId: item.encounterId || props.patientInfo.encounterId, // 🔧 BugFix: 确保encounterId
|
||||||
|
patientId: item.patientId || props.patientInfo.patientId, // 🔧 BugFix: 确保patientId
|
||||||
groupId: item.groupId,
|
groupId: item.groupId,
|
||||||
uniqueKey: undefined,
|
uniqueKey: undefined,
|
||||||
// 使用转换后的数量和单位
|
// 使用转换后的数量和单位
|
||||||
quantity: finalQuantity,
|
quantity: finalQuantity,
|
||||||
unitCode: finalUnitCode,
|
unitCode: finalUnitCode,
|
||||||
totalPrice: item.totalPrice, // Ensure totalPrice is valid
|
totalPrice: item.totalPrice, // Ensure totalPrice is valid
|
||||||
|
// 🔧 Bug Fix: 确保 categoryEnum 被传递(耗材必填字段)
|
||||||
|
categoryEnum: item.categoryEnum || parsedContent.categoryEnum,
|
||||||
// 🔧 Bug Fix: 确保库存匹配成功的关键字段
|
// 🔧 Bug Fix: 确保库存匹配成功的关键字段
|
||||||
adviceTableName: adviceTableNameVal,
|
adviceTableName: adviceTableNameVal,
|
||||||
locationId: locationIdVal,
|
locationId: locationIdVal,
|
||||||
@@ -2435,6 +2475,13 @@ function handleSave(prescriptionId) {
|
|||||||
methodCode: item.methodCode || parsedContent.methodCode,
|
methodCode: item.methodCode || parsedContent.methodCode,
|
||||||
// 🔧 确保 accountId 被传递(用于预结算)
|
// 🔧 确保 accountId 被传递(用于预结算)
|
||||||
accountId: item.accountId || parsedContent.accountId,
|
accountId: item.accountId || parsedContent.accountId,
|
||||||
|
// 🔧 Bug Fix: 确保minUnitQuantity被传递(耗材必填字段)
|
||||||
|
minUnitQuantity: item.minUnitQuantity,
|
||||||
|
minUnitCode: item.minUnitCode,
|
||||||
|
minUnitCode_dictText: item.minUnitCode_dictText,
|
||||||
|
// 🔧 Bug Fix: 确保 definitionId 和 definitionDetailId 被传递(费用项必填字段)
|
||||||
|
definitionId: item.definitionId || parsedContent.definitionId,
|
||||||
|
definitionDetailId: item.definitionDetailId || parsedContent.definitionDetailId,
|
||||||
// 🔧 更新 contentJson 中的 adviceType,确保后端分类正确
|
// 🔧 更新 contentJson 中的 adviceType,确保后端分类正确
|
||||||
contentJson: JSON.stringify({
|
contentJson: JSON.stringify({
|
||||||
...parsedContent,
|
...parsedContent,
|
||||||
@@ -2624,12 +2671,17 @@ function handleOrderBindInfo(bindIdInfo, currentMethodCode) {
|
|||||||
encounterDiagnosisId: encounterDiagnosisId.value,
|
encounterDiagnosisId: encounterDiagnosisId.value,
|
||||||
// 🔧 确保 adviceType 和显示文本正确设置
|
// 🔧 确保 adviceType 和显示文本正确设置
|
||||||
adviceType: item.adviceType,
|
adviceType: item.adviceType,
|
||||||
adviceType_dictText: mapAdviceTypeLabel(item.adviceType),
|
adviceType_dictText: mapAdviceTypeLabel(item.adviceType, item.adviceTableName),
|
||||||
};
|
};
|
||||||
|
|
||||||
// 计算价格和总量
|
// 计算价格和总量
|
||||||
const unitInfo = unitCodeList.value.find((k) => k.value == item.unitCode);
|
const unitInfo = unitCodeList.value.find((k) => k.value == item.unitCode);
|
||||||
if (unitInfo && unitInfo.type == 'minUnit') {
|
// 🔧 Bug Fix: 耗材类型只有一个单位,minUnitQuantity等于quantity
|
||||||
|
if (item.adviceType == 4) {
|
||||||
|
newRow.price = newRow.unitPrice;
|
||||||
|
newRow.totalPrice = (item.quantity * newRow.unitPrice).toFixed(6);
|
||||||
|
newRow.minUnitQuantity = item.quantity;
|
||||||
|
} else if (unitInfo && unitInfo.type == 'minUnit') {
|
||||||
newRow.price = newRow.minUnitPrice;
|
newRow.price = newRow.minUnitPrice;
|
||||||
newRow.totalPrice = (item.quantity * newRow.minUnitPrice).toFixed(6);
|
newRow.totalPrice = (item.quantity * newRow.minUnitPrice).toFixed(6);
|
||||||
newRow.minUnitQuantity = item.quantity;
|
newRow.minUnitQuantity = item.quantity;
|
||||||
@@ -2694,6 +2746,12 @@ function handleSaveSign(row, index, prescriptionId) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔧 Bug Fix: 验证医嘱类型不能为"全部"
|
||||||
|
if (row.adviceType === 0) {
|
||||||
|
proxy.$modal.msgWarning('请选择医嘱类型');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 重新查找索引,确保使用当前处方列表中的正确索引
|
// 重新查找索引,确保使用当前处方列表中的正确索引
|
||||||
const actualIndex = prescriptionList.value.findIndex(item => item.uniqueKey === row.uniqueKey);
|
const actualIndex = prescriptionList.value.findIndex(item => item.uniqueKey === row.uniqueKey);
|
||||||
if (actualIndex === -1) {
|
if (actualIndex === -1) {
|
||||||
@@ -2728,28 +2786,32 @@ function handleSaveSign(row, index, prescriptionId) {
|
|||||||
|
|
||||||
formRef.validate((valid) => {
|
formRef.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
if (row.adviceType != 2) {
|
// 🔧 BugFix#318: 手术类型(adviceType=6)不需要检查绑定耗材/药品
|
||||||
|
if (row.adviceType != 2 && row.adviceType != 6) {
|
||||||
// 1:用法绑东西 2:诊疗绑东西
|
// 1:用法绑东西 2:诊疗绑东西
|
||||||
let typeCode = row.adviceType == 1 ? '1' : '2';
|
let typeCode = row.adviceType == 1 ? '1' : '2';
|
||||||
// 用法字典值/诊疗定义id
|
// 用法字典值/诊疗定义id
|
||||||
let itemNo = row.adviceType == 1 ? row.methodCode : row.adviceDefinitionId;
|
let itemNo = row.adviceType == 1 ? row.methodCode : row.adviceDefinitionId;
|
||||||
getBindDevice({ typeCode: typeCode, itemNo: itemNo }).then((res) => {
|
// 🔧 确保 itemNo 有值才调用接口
|
||||||
if (res.data.length == 0) {
|
if (itemNo) {
|
||||||
return;
|
getBindDevice({ typeCode: typeCode, itemNo: itemNo }).then((res) => {
|
||||||
}
|
if (res.data.length == 0) {
|
||||||
// 是否需要打开弹窗
|
return;
|
||||||
let openBindDialog = localStorage.getItem('doctor' + userStore.id);
|
|
||||||
if (!JSON.parse(openBindDialog)) {
|
|
||||||
proxy.$refs['orderBindInfoRef'].open(res.data);
|
|
||||||
} else {
|
|
||||||
// 如果弹窗不提示带出的项目,自动带出
|
|
||||||
// 如果有未签发的项目,并且当前的项目没有带出过绑定项目,则自动带出
|
|
||||||
if (!bindMethod.value[itemNo]) {
|
|
||||||
handleOrderBindInfo(res.data, row.methodCode);
|
|
||||||
bindMethod.value[itemNo] = true;
|
|
||||||
}
|
}
|
||||||
}
|
// 是否需要打开弹窗
|
||||||
});
|
let openBindDialog = localStorage.getItem('doctor' + userStore.id);
|
||||||
|
if (!JSON.parse(openBindDialog)) {
|
||||||
|
proxy.$refs['orderBindInfoRef'].open(res.data);
|
||||||
|
} else {
|
||||||
|
// 如果弹窗不提示带出的项目,自动带出
|
||||||
|
// 如果有未签发的项目,并且当前的项目没有带出过绑定项目,则自动带出
|
||||||
|
if (!bindMethod.value[itemNo]) {
|
||||||
|
handleOrderBindInfo(res.data, row.methodCode);
|
||||||
|
bindMethod.value[itemNo] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
row.isEdit = false;
|
row.isEdit = false;
|
||||||
isAdding.value = false;
|
isAdding.value = false;
|
||||||
@@ -2759,27 +2821,36 @@ function handleSaveSign(row, index, prescriptionId) {
|
|||||||
row.encounterId = props.patientInfo.encounterId;
|
row.encounterId = props.patientInfo.encounterId;
|
||||||
row.accountId = accountId.value;
|
row.accountId = accountId.value;
|
||||||
// 确保非编辑态显示正确的医嘱类型标签
|
// 确保非编辑态显示正确的医嘱类型标签
|
||||||
row.adviceType_dictText = mapAdviceTypeLabel(row.adviceType);
|
row.adviceType_dictText = mapAdviceTypeLabel(row.adviceType, row.adviceTableName);
|
||||||
|
|
||||||
// 更新本地显示的最小单位数量(仅用于前端逻辑,不影响显示单位)
|
// 更新本地显示的最小单位数量(仅用于前端逻辑,不影响显示单位)
|
||||||
if (row.adviceType == 1 || row.adviceType == 2) {
|
if (row.adviceType == 1 || row.adviceType == 2) {
|
||||||
row.minUnitQuantity =
|
row.minUnitQuantity =
|
||||||
row.minUnitCode == row.unitCode ? row.quantity : row.quantity * row.partPercent;
|
row.minUnitCode == row.unitCode ? row.quantity : row.quantity * row.partPercent;
|
||||||
} else {
|
} else {
|
||||||
|
// 🔧 Bug Fix: 耗材和其他类型,minUnitQuantity等于quantity
|
||||||
row.minUnitQuantity = row.quantity;
|
row.minUnitQuantity = row.quantity;
|
||||||
|
// 🔧 Bug Fix: 确保minUnitCode等于unitCode(耗材只有一个单位)
|
||||||
|
row.minUnitCode = row.unitCode;
|
||||||
|
row.minUnitCode_dictText = row.unitCode_dictText;
|
||||||
}
|
}
|
||||||
|
|
||||||
row.conditionId = conditionId.value;
|
row.conditionId = conditionId.value;
|
||||||
// 处理总量为小单位情况,需要把单价也保存成小单位的
|
// 处理总量为小单位情况,需要把单价也保存成小单位的
|
||||||
if (row.unitCodeList.find((item) => item.value == row.unitCode).type == 'unit') {
|
// 🔧 BugFix#318: 手术类型(adviceType=6)可能没有unitCodeList,需要判断
|
||||||
if (row.adviceType != 3) {
|
if (row.unitCodeList && row.unitCodeList.length > 0) {
|
||||||
row.unitPrice = row.unitTempPrice;
|
const foundUnit = row.unitCodeList.find((item) => item.value == row.unitCode);
|
||||||
|
if (foundUnit && foundUnit.type == 'unit') {
|
||||||
|
if (row.adviceType != 3) {
|
||||||
|
row.unitPrice = row.unitTempPrice;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const minUnitItem = row.unitCodeList.find((item) => item.value == row.minUnitCode);
|
||||||
|
if (minUnitItem) {
|
||||||
|
row.unitCode_dictText = minUnitItem.label;
|
||||||
|
}
|
||||||
|
row.unitPrice = row.minUnitPrice;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
row.unitCode_dictText = row.unitCodeList.find(
|
|
||||||
(item) => item.value == row.minUnitCode
|
|
||||||
).label;
|
|
||||||
row.unitPrice = row.minUnitPrice;
|
|
||||||
}
|
}
|
||||||
row.conditionDefinitionId = conditionDefinitionId.value;
|
row.conditionDefinitionId = conditionDefinitionId.value;
|
||||||
row.encounterDiagnosisId = encounterDiagnosisId.value;
|
row.encounterDiagnosisId = encounterDiagnosisId.value;
|
||||||
@@ -2956,14 +3027,35 @@ function handleSaveBatch(prescriptionId) {
|
|||||||
|
|
||||||
// --- Bug 1 修复:类型转换 ---
|
// --- Bug 1 修复:类型转换 ---
|
||||||
let saveAdviceType = item.adviceType;
|
let saveAdviceType = item.adviceType;
|
||||||
if (item.adviceType == 4) {
|
// 🔧 Bug Fix: 保持原类型,不进行转换
|
||||||
saveAdviceType = 2; // 耗材前端4 -> 后端2
|
// 前端类型: 1=西药, 2=中成药, 3=诊疗, 4=耗材, 5=会诊, 6=手术
|
||||||
} else if (item.adviceType == 2) {
|
// 后端类型: 1=药品, 2=耗材, 3=医疗活动, 6=手术
|
||||||
saveAdviceType = 1; // 中成药前端2 -> 后端1
|
// 后端会通过 ItemType.DEVICE.getValue() || adviceType == 4 来识别耗材
|
||||||
} else if (item.adviceType == 5) {
|
if (item.adviceType == 5) {
|
||||||
saveAdviceType = 3; // 会诊前端5 -> 后端3(诊疗类)
|
saveAdviceType = 3; // 会诊前端5 -> 后端3(诊疗类)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 🔧 BugFix#318: 过滤掉手术特有字段,只保留标准医嘱字段
|
||||||
|
const standardItemFields = [
|
||||||
|
'adviceDefinitionId', 'adviceName', 'adviceTableName', 'adviceType',
|
||||||
|
'basedOnId', 'chargeItemId', 'chargeStatus', 'conditionDefinitionId',
|
||||||
|
'conditionId', 'contentJson', 'dose', 'doseUnitCode', 'encounterDiagnosisId',
|
||||||
|
'encounterId', 'groupId', 'injectFlag', 'lotNumber', 'methodCode', 'partPercent',
|
||||||
|
'patientId', 'positionId', 'positionName', 'prescriptionNo', 'quantity', 'rateCode',
|
||||||
|
'requestId', 'skinTestFlag', 'sortNumber', 'statusEnum', 'totalPrice',
|
||||||
|
'unitCode', 'unitPrice', 'volume', 'ybClassEnum',
|
||||||
|
// 🔧 Bug Fix: 添加 definitionId 和 definitionDetailId 字段
|
||||||
|
'definitionId', 'definitionDetailId',
|
||||||
|
// 🔧 Bug Fix: 添加 categoryEnum 字段(耗材必填)
|
||||||
|
'categoryEnum'
|
||||||
|
];
|
||||||
|
let filteredItem = {};
|
||||||
|
standardItemFields.forEach(field => {
|
||||||
|
if (item[field] !== undefined) {
|
||||||
|
filteredItem[field] = item[field];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// 构造 contentJson (保持前端UI原始数据)
|
// 构造 contentJson (保持前端UI原始数据)
|
||||||
const itemToSave = {
|
const itemToSave = {
|
||||||
...item,
|
...item,
|
||||||
@@ -3011,7 +3103,7 @@ function handleSaveBatch(prescriptionId) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...item,
|
...filteredItem, // 🔧 BugFix#318: 使用过滤后的字段
|
||||||
patientId: props.patientInfo.patientId,
|
patientId: props.patientInfo.patientId,
|
||||||
encounterId: props.patientInfo.encounterId,
|
encounterId: props.patientInfo.encounterId,
|
||||||
adviceType: saveAdviceType,
|
adviceType: saveAdviceType,
|
||||||
@@ -3154,17 +3246,26 @@ function syncGroupFields(row) {
|
|||||||
function setValue(row) {
|
function setValue(row) {
|
||||||
unitCodeList.value = [];
|
unitCodeList.value = [];
|
||||||
unitCodeList.value.push({ value: row.unitCode, label: row.unitCode_dictText, type: 'unit' });
|
unitCodeList.value.push({ value: row.unitCode, label: row.unitCode_dictText, type: 'unit' });
|
||||||
unitCodeList.value.push({
|
|
||||||
value: row.doseUnitCode,
|
|
||||||
label: row.doseUnitCode_dictText,
|
|
||||||
type: 'dose',
|
|
||||||
});
|
|
||||||
|
|
||||||
unitCodeList.value.push({
|
// 🔧 Bug Fix: 耗材类型只有一个单位,不需要dose和minUnit选项
|
||||||
value: row.minUnitCode,
|
if (row.adviceType == 4) {
|
||||||
label: row.minUnitCode_dictText,
|
// 耗材只添加一个单位选项
|
||||||
type: 'minUnit',
|
row.minUnitCode = row.unitCode;
|
||||||
});
|
row.minUnitCode_dictText = row.unitCode_dictText;
|
||||||
|
} else {
|
||||||
|
// 药品类型添加dose和minUnit选项
|
||||||
|
unitCodeList.value.push({
|
||||||
|
value: row.doseUnitCode,
|
||||||
|
label: row.doseUnitCode_dictText,
|
||||||
|
type: 'dose',
|
||||||
|
});
|
||||||
|
|
||||||
|
unitCodeList.value.push({
|
||||||
|
value: row.minUnitCode,
|
||||||
|
label: row.minUnitCode_dictText,
|
||||||
|
type: 'minUnit',
|
||||||
|
});
|
||||||
|
}
|
||||||
if (row.adviceType == 2 && row.minUnitCode != row.unitCode) {
|
if (row.adviceType == 2 && row.minUnitCode != row.unitCode) {
|
||||||
unitCodeList.value.push({
|
unitCodeList.value.push({
|
||||||
value: row.minUnitCode,
|
value: row.minUnitCode,
|
||||||
@@ -3198,8 +3299,15 @@ function setValue(row) {
|
|||||||
prescriptionList.value[rowIndex.value].unitCodeList = unitCodeList.value;
|
prescriptionList.value[rowIndex.value].unitCodeList = unitCodeList.value;
|
||||||
prescriptionList.value[rowIndex.value].doseUnitCode = row.doseUnitCode;
|
prescriptionList.value[rowIndex.value].doseUnitCode = row.doseUnitCode;
|
||||||
prescriptionList.value[rowIndex.value].minUnitCode = row.minUnitCode;
|
prescriptionList.value[rowIndex.value].minUnitCode = row.minUnitCode;
|
||||||
prescriptionList.value[rowIndex.value].unitCode =
|
// 🔧 Bug Fix: 耗材类型只有一个单位,minUnitCode应该等于unitCode
|
||||||
row.partAttributeEnum == 1 ? row.minUnitCode : row.unitCode;
|
if (Number(row.adviceType) == 4) {
|
||||||
|
prescriptionList.value[rowIndex.value].minUnitCode = row.unitCode;
|
||||||
|
prescriptionList.value[rowIndex.value].minUnitCode_dictText = row.unitCode_dictText;
|
||||||
|
prescriptionList.value[rowIndex.value].unitCode = row.unitCode;
|
||||||
|
} else {
|
||||||
|
prescriptionList.value[rowIndex.value].unitCode =
|
||||||
|
row.partAttributeEnum == 1 ? row.minUnitCode : row.unitCode;
|
||||||
|
}
|
||||||
prescriptionList.value[rowIndex.value].categoryEnum = row.categoryCode;
|
prescriptionList.value[rowIndex.value].categoryEnum = row.categoryCode;
|
||||||
prescriptionList.value[rowIndex.value].skinTestFlag = row.skinTestFlag;
|
prescriptionList.value[rowIndex.value].skinTestFlag = row.skinTestFlag;
|
||||||
prescriptionList.value[rowIndex.value].definitionId = row.chargeItemDefinitionId;
|
prescriptionList.value[rowIndex.value].definitionId = row.chargeItemDefinitionId;
|
||||||
@@ -3268,6 +3376,10 @@ function setValue(row) {
|
|||||||
// 🔧 Bug #218 修复:保留组套中的quantity,如果没有则默认1
|
// 🔧 Bug #218 修复:保留组套中的quantity,如果没有则默认1
|
||||||
prescriptionList.value[rowIndex.value].quantity = row.quantity || 1;
|
prescriptionList.value[rowIndex.value].quantity = row.quantity || 1;
|
||||||
prescriptionList.value[rowIndex.value].totalPrice = validPrice * (row.quantity || 1);
|
prescriptionList.value[rowIndex.value].totalPrice = validPrice * (row.quantity || 1);
|
||||||
|
// 🔧 Bug Fix: 设置耗材的minUnitQuantity,避免保存时null错误
|
||||||
|
prescriptionList.value[rowIndex.value].minUnitQuantity = row.quantity || 1;
|
||||||
|
// 🔧 Bug Fix: 设置耗材的categoryEnum,避免数据库约束错误
|
||||||
|
prescriptionList.value[rowIndex.value].categoryEnum = row.categoryCode || 3; // 默认为3
|
||||||
prescriptionList.value[rowIndex.value].positionName = row.positionName || '';
|
prescriptionList.value[rowIndex.value].positionName = row.positionName || '';
|
||||||
// 🔧 Bug Fix: 使用 positionId,如果为空则使用患者信息中的 orgId
|
// 🔧 Bug Fix: 使用 positionId,如果为空则使用患者信息中的 orgId
|
||||||
console.log('设置耗材locationId:', {
|
console.log('设置耗材locationId:', {
|
||||||
@@ -3286,6 +3398,10 @@ function setValue(row) {
|
|||||||
prescriptionList.value[rowIndex.value].minUnitPrice = 0;
|
prescriptionList.value[rowIndex.value].minUnitPrice = 0;
|
||||||
prescriptionList.value[rowIndex.value].quantity = row.quantity || 1;
|
prescriptionList.value[rowIndex.value].quantity = row.quantity || 1;
|
||||||
prescriptionList.value[rowIndex.value].totalPrice = 0;
|
prescriptionList.value[rowIndex.value].totalPrice = 0;
|
||||||
|
// 🔧 Bug Fix: 设置耗材的minUnitQuantity,避免保存时null错误
|
||||||
|
prescriptionList.value[rowIndex.value].minUnitQuantity = row.quantity || 1;
|
||||||
|
// 🔧 Bug Fix: 设置耗材的categoryEnum,避免数据库约束错误
|
||||||
|
prescriptionList.value[rowIndex.value].categoryEnum = row.categoryCode || 3; // 默认为3
|
||||||
prescriptionList.value[rowIndex.value].positionName = row.positionName || '';
|
prescriptionList.value[rowIndex.value].positionName = row.positionName || '';
|
||||||
const finalLocationId = row.positionId || props.patientInfo.orgId;
|
const finalLocationId = row.positionId || props.patientInfo.orgId;
|
||||||
prescriptionList.value[rowIndex.value].locationId = finalLocationId;
|
prescriptionList.value[rowIndex.value].locationId = finalLocationId;
|
||||||
@@ -3928,6 +4044,16 @@ function convertDoseValues(row, index) {
|
|||||||
// 总量计算,仅适用只有两种单位的情况
|
// 总量计算,仅适用只有两种单位的情况
|
||||||
function calculateTotalAmount(row, index) {
|
function calculateTotalAmount(row, index) {
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
// 🔧 Bug Fix: 处理耗材类型的总金额计算
|
||||||
|
if (row.adviceType == 4) {
|
||||||
|
row.totalPrice = (row.quantity * row.unitPrice).toFixed(6);
|
||||||
|
// 🔧 Bug Fix: 确保耗材的minUnitQuantity和minUnitCode正确设置
|
||||||
|
row.minUnitQuantity = row.quantity;
|
||||||
|
row.minUnitCode = row.unitCode;
|
||||||
|
row.minUnitCode_dictText = row.unitCode_dictText;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (row.adviceType == 2) {
|
if (row.adviceType == 2) {
|
||||||
calculateTotalPrice(row, index);
|
calculateTotalPrice(row, index);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -25,6 +25,15 @@
|
|||||||
>
|
>
|
||||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
|
||||||
|
<!-- 手术单号 -->
|
||||||
|
<el-table-column label="手术单号" align="center" width="150">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-link type="primary" @click="handleView(scope.row)">
|
||||||
|
{{ scope.row.surgeryNo || '-' }}
|
||||||
|
</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
|
||||||
<!-- 申请日期 -->
|
<!-- 申请日期 -->
|
||||||
<el-table-column label="申请日期" align="center" prop="createTime" width="180">
|
<el-table-column label="申请日期" align="center" prop="createTime" width="180">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -32,9 +41,6 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
<!-- 手术单号 -->
|
|
||||||
<el-table-column label="手术单号" align="center" prop="surgeryNo" width="150" show-overflow-tooltip />
|
|
||||||
|
|
||||||
<!-- 患者姓名 -->
|
<!-- 患者姓名 -->
|
||||||
<el-table-column label="患者姓名" align="center" prop="patientName" width="100" />
|
<el-table-column label="患者姓名" align="center" prop="patientName" width="100" />
|
||||||
|
|
||||||
@@ -499,7 +505,8 @@ import { useDict } from '@/utils/dict'
|
|||||||
const { surgery_type, surgery_level, incision_level, anesthesia_type } = useDict('surgery_type', 'surgery_level', 'incision_level', 'anesthesia_type')
|
const { surgery_type, surgery_level, incision_level, anesthesia_type } = useDict('surgery_type', 'surgery_level', 'incision_level', 'anesthesia_type')
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance()
|
const { proxy } = getCurrentInstance()
|
||||||
const userStore = useUserStore()
|
const userStore = useUserStore() // 🔧 BugFix: 初始化 userStore,否则 applyDoctorName 和 applyDeptName 会是 undefined
|
||||||
|
const emit = defineEmits(['saved'])
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
patientInfo: {
|
patientInfo: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@@ -957,9 +964,13 @@ function doSearchAnesthesia(query) {
|
|||||||
|
|
||||||
// 手术项目选择变更
|
// 手术项目选择变更
|
||||||
function handleSurgeryChange(val) {
|
function handleSurgeryChange(val) {
|
||||||
|
// 🔧 BugFix#318: 确保 surgeryName 被正确设置
|
||||||
|
form.value.surgeryName = val
|
||||||
const selected = surgeryNameList.value.find(item => item.name === val)
|
const selected = surgeryNameList.value.find(item => item.name === val)
|
||||||
if (selected) {
|
if (selected) {
|
||||||
form.value.surgeryCode = selected.busNo
|
form.value.surgeryCode = selected.busNo
|
||||||
|
// 🔧 BugFix#318: 确保 surgeryName 从选中项获取(避免空值)
|
||||||
|
form.value.surgeryName = selected.name
|
||||||
// 设置手术费用 (增加对多种字段名和类型的兼容)
|
// 设置手术费用 (增加对多种字段名和类型的兼容)
|
||||||
const price = selected.retailPrice ?? selected.retail_price ?? selected.price ?? selected.salePrice ?? 0
|
const price = selected.retailPrice ?? selected.retail_price ?? selected.price ?? selected.salePrice ?? 0
|
||||||
form.value.surgeryFee = parseFloat(price)
|
form.value.surgeryFee = parseFloat(price)
|
||||||
@@ -1045,6 +1056,27 @@ function submitForm() {
|
|||||||
console.log('【提交表单】手术指征字段值:', form.value.surgeryIndication)
|
console.log('【提交表单】手术指征字段值:', form.value.surgeryIndication)
|
||||||
console.log('【提交表单】手术指征字段类型:', typeof form.value.surgeryIndication)
|
console.log('【提交表单】手术指征字段类型:', typeof form.value.surgeryIndication)
|
||||||
|
|
||||||
|
// 🔧 BugFix#318: 验证 surgeryName 和 surgeryCode
|
||||||
|
if (!form.value.surgeryName) {
|
||||||
|
console.error('【提交表单】错误: surgeryName 为空!')
|
||||||
|
proxy.$modal.msgError('手术名称不能为空,请重新选择手术项目')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!form.value.surgeryCode) {
|
||||||
|
console.error('【提交表单】错误: surgeryCode 为空!')
|
||||||
|
// 尝试从 surgeryNameList 获取
|
||||||
|
const selected = surgeryNameList.value.find(item => item.name === form.value.surgeryName)
|
||||||
|
if (selected) {
|
||||||
|
form.value.surgeryCode = selected.busNo
|
||||||
|
console.log('【提交表单】自动填充 surgeryCode:', form.value.surgeryCode)
|
||||||
|
} else {
|
||||||
|
proxy.$modal.msgError('手术编码不能为空,请重新选择手术项目')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('【提交表单】最终数据 - surgeryName:', form.value.surgeryName, 'surgeryCode:', form.value.surgeryCode)
|
||||||
|
|
||||||
if (form.value.id == undefined) {
|
if (form.value.id == undefined) {
|
||||||
// 新增手术
|
// 新增手术
|
||||||
addSurgery(form.value).then((res) => {
|
addSurgery(form.value).then((res) => {
|
||||||
@@ -1054,6 +1086,7 @@ function submitForm() {
|
|||||||
sessionStorage.setItem('anesthesiaType', form.value.anesthesiaTypeEnum)
|
sessionStorage.setItem('anesthesiaType', form.value.anesthesiaTypeEnum)
|
||||||
open.value = false
|
open.value = false
|
||||||
getList()
|
getList()
|
||||||
|
emit('saved') // 🔧 触发保存事件,通知父组件刷新医嘱列表
|
||||||
} else {
|
} else {
|
||||||
proxy.$modal.msgError(res.msg || '新增手术失败,请检查表单信息')
|
proxy.$modal.msgError(res.msg || '新增手术失败,请检查表单信息')
|
||||||
}
|
}
|
||||||
@@ -1070,6 +1103,7 @@ function submitForm() {
|
|||||||
sessionStorage.setItem('anesthesiaType', form.value.anesthesiaTypeEnum)
|
sessionStorage.setItem('anesthesiaType', form.value.anesthesiaTypeEnum)
|
||||||
open.value = false
|
open.value = false
|
||||||
getList()
|
getList()
|
||||||
|
emit('saved') // 🔧 触发保存事件,通知父组件刷新医嘱列表
|
||||||
} else {
|
} else {
|
||||||
proxy.$modal.msgError(res.msg || '更新手术失败,请检查表单信息')
|
proxy.$modal.msgError(res.msg || '更新手术失败,请检查表单信息')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,7 +150,8 @@
|
|||||||
@saved="() => prescriptionRef?.getListInfo()" />
|
@saved="() => prescriptionRef?.getListInfo()" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="手术申请" name="surgery">
|
<el-tab-pane label="手术申请" name="surgery">
|
||||||
<surgeryApplication :patientInfo="patientInfo" :activeTab="activeTab" ref="surgeryRef" />
|
<surgeryApplication :patientInfo="patientInfo" :activeTab="activeTab" ref="surgeryRef"
|
||||||
|
@saved="() => prescriptionRef?.getListInfo()" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="电子处方" name="eprescription">
|
<el-tab-pane label="电子处方" name="eprescription">
|
||||||
<eprescriptionlist :patientInfo="patientInfo" ref="eprescriptionRef" />
|
<eprescriptionlist :patientInfo="patientInfo" ref="eprescriptionRef" />
|
||||||
@@ -168,7 +169,7 @@
|
|||||||
<div class="overlay" :class="{ 'overlay-disabled': disabled }" v-if="disabled"></div>
|
<div class="overlay" :class="{ 'overlay-disabled': disabled }" v-if="disabled"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-drawer v-model="drawer" title="患者队列" direction="ltr" @open="handleOpen">
|
<el-drawer v-model="drawer" title="患者队列" direction="ltr" @open="handleOpen" @closed="handleDrawerClosed">
|
||||||
<PatientList ref="patientDrawerRef" @toCurrent="handleReceive" />
|
<PatientList ref="patientDrawerRef" @toCurrent="handleReceive" />
|
||||||
</el-drawer>
|
</el-drawer>
|
||||||
<RefundListDialog :open="openRefundListDialog" :encounterId="currentEncounterId"
|
<RefundListDialog :open="openRefundListDialog" :encounterId="currentEncounterId"
|
||||||
@@ -562,6 +563,13 @@ function handleOpen() {
|
|||||||
patientDrawerRef.value.refreshList();
|
patientDrawerRef.value.refreshList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleDrawerClosed() {
|
||||||
|
// 关闭患者队列抽屉时,刷新现诊患者列表和待诊患者数量
|
||||||
|
// 这样可以确保如果有其他医生接诊了患者,当前医生能看到最新状态
|
||||||
|
getPatientList();
|
||||||
|
getWaitPatient();
|
||||||
|
}
|
||||||
|
|
||||||
function handleCardClick(item, index) {
|
function handleCardClick(item, index) {
|
||||||
console.log('handleCardClick 被调用');
|
console.log('handleCardClick 被调用');
|
||||||
console.log('点击的患者项目:', item);
|
console.log('点击的患者项目:', item);
|
||||||
@@ -709,6 +717,12 @@ async function handleFinish(encounterId) {
|
|||||||
firstEnum.value = 1; // 重置为初诊
|
firstEnum.value = 1; // 重置为初诊
|
||||||
getPatientList();
|
getPatientList();
|
||||||
}
|
}
|
||||||
|
}).catch(error => {
|
||||||
|
// 如果完诊失败,检查是否是"已完成"的错误
|
||||||
|
if (error && error.message && (error.message.includes('已完成') || error.message.includes('完诊'))) {
|
||||||
|
// 自动刷新现诊患者列表
|
||||||
|
getPatientList();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -726,9 +740,6 @@ function handleTimeChange(value) {
|
|||||||
|
|
||||||
// 处理办理住院点击事件
|
// 处理办理住院点击事件
|
||||||
function handleHospitalizationClick() {
|
function handleHospitalizationClick() {
|
||||||
console.log('handleHospitalizationClick 被调用');
|
|
||||||
console.log('当前patientInfo:', patientInfo.value);
|
|
||||||
console.log('当前patientInfo.encounterId:', patientInfo.value?.encounterId);
|
|
||||||
|
|
||||||
if (!patientInfo.value || !patientInfo.value.encounterId) {
|
if (!patientInfo.value || !patientInfo.value.encounterId) {
|
||||||
console.log('患者信息不完整,无法办理住院');
|
console.log('患者信息不完整,无法办理住院');
|
||||||
|
|||||||
@@ -26,10 +26,16 @@
|
|||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
>
|
>
|
||||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||||
|
<el-table-column label="手术单号" width="160" align="center">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-link type="primary" @click="handleViewDetail(scope.row)">
|
||||||
|
{{ scope.row.prescriptionNo || '-' }}
|
||||||
|
</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="patientName" label="患者姓名" width="120" />
|
<el-table-column prop="patientName" label="患者姓名" width="120" />
|
||||||
<el-table-column prop="name" label="申请单名称" width="140" />
|
<el-table-column prop="name" label="申请单名称" width="140" />
|
||||||
<el-table-column prop="createTime" label="创建时间" width="160" />
|
<el-table-column prop="createTime" label="创建时间" width="160" />
|
||||||
<el-table-column prop="prescriptionNo" label="处方号" width="140" />
|
|
||||||
<el-table-column prop="requesterId_dictText" label="申请者" width="120" />
|
<el-table-column prop="requesterId_dictText" label="申请者" width="120" />
|
||||||
<el-table-column label="操作" align="center" fixed="right">
|
<el-table-column label="操作" align="center" fixed="right">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ function getList() {
|
|||||||
emits('diagnosisSave', false);
|
emits('diagnosisSave', false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
getTcmDiagnosis({ encounterId: patientInfo.value.encounterId }).then((res) => {
|
getTcmDiagnosis({ encounterId: props.patientInfo.encounterId }).then((res) => {
|
||||||
console.log('getTcmDiagnosis=======>', JSON.stringify(res.data.illness));
|
console.log('getTcmDiagnosis=======>', JSON.stringify(res.data.illness));
|
||||||
|
|
||||||
if (res.code == 200) {
|
if (res.code == 200) {
|
||||||
@@ -337,7 +337,6 @@ function init() {
|
|||||||
|
|
||||||
function handleImport() {
|
function handleImport() {
|
||||||
if (!props.patientInfo || !props.patientInfo.encounterId) {
|
if (!props.patientInfo || !props.patientInfo.encounterId) {
|
||||||
console.warn('患者就诊信息不完整,无法导入慢性病信息');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,8 +354,10 @@ function handleImport() {
|
|||||||
diagSrtNo: form.value.diagnosisList.length + 1,
|
diagSrtNo: form.value.diagnosisList.length + 1,
|
||||||
iptDiseTypeCode: 2,
|
iptDiseTypeCode: 2,
|
||||||
diagnosisDesc: '',
|
diagnosisDesc: '',
|
||||||
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
|
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
|
||||||
diagnosisTime: new Date().toLocaleString('zh-CN')
|
diagnosisTime: new Date().toLocaleString('zh-CN'),
|
||||||
|
//添加 patientId
|
||||||
|
patientId: props.patientInfo.patientId
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -469,7 +470,6 @@ function handleAddDiagnosis() {
|
|||||||
* 添加诊断项
|
* 添加诊断项
|
||||||
*/
|
*/
|
||||||
function addDiagnosisItem() {
|
function addDiagnosisItem() {
|
||||||
console.log('执行添加诊断,当前列表长度:', form.value.diagnosisList.length);
|
|
||||||
form.value.diagnosisList.push({
|
form.value.diagnosisList.push({
|
||||||
showPopover: false,
|
showPopover: false,
|
||||||
name: undefined,
|
name: undefined,
|
||||||
@@ -479,12 +479,15 @@ function addDiagnosisItem() {
|
|||||||
iptDiseTypeCode: 2,
|
iptDiseTypeCode: 2,
|
||||||
diagnosisDesc: '',
|
diagnosisDesc: '',
|
||||||
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
|
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
|
||||||
diagnosisTime: new Date().toLocaleString('zh-CN')
|
diagnosisTime: new Date().toLocaleString('zh-CN'),
|
||||||
|
|
||||||
|
// 新增这一行:为每个诊断项添加 patientId
|
||||||
|
patientId: props.patientInfo.patientId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (form.value.diagnosisList.length == 1) {
|
if (form.value.diagnosisList.length == 1) {
|
||||||
form.value.diagnosisList[0].maindiseFlag = 1;
|
form.value.diagnosisList[0].maindiseFlag = 1;
|
||||||
}
|
}
|
||||||
console.log('添加完成,新列表长度:', form.value.diagnosisList.length);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加中医诊断
|
// 添加中医诊断
|
||||||
@@ -565,8 +568,6 @@ function handleMaindise(value, index) {
|
|||||||
* 保存诊断
|
* 保存诊断
|
||||||
*/
|
*/
|
||||||
function handleSaveDiagnosis() {
|
function handleSaveDiagnosis() {
|
||||||
console.log('form.value.diagnosisList=======>', JSON.stringify(form.value.diagnosisList));
|
|
||||||
|
|
||||||
for (let index = 0; index < (form.value.diagnosisList || []).length; index++) {
|
for (let index = 0; index < (form.value.diagnosisList || []).length; index++) {
|
||||||
const item = form.value.diagnosisList[index];
|
const item = form.value.diagnosisList[index];
|
||||||
if (!item.diagSrtNo) {
|
if (!item.diagSrtNo) {
|
||||||
@@ -690,11 +691,13 @@ function handleNodeClick(data) {
|
|||||||
ybNo: data.ybNo,
|
ybNo: data.ybNo,
|
||||||
name: data.name,
|
name: data.name,
|
||||||
verificationStatusEnum: 4,
|
verificationStatusEnum: 4,
|
||||||
medTypeCode: undefined, // 不设默认值
|
medTypeCode: undefined,
|
||||||
diagSrtNo: form.value.diagnosisList.length + 1,
|
diagSrtNo: form.value.diagnosisList.length + 1,
|
||||||
definitionId: data.definitionId,
|
definitionId: data.definitionId,
|
||||||
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
|
diagnosisDoctor: props.patientInfo.practitionerName || props.patientInfo.doctorName || props.patientInfo.physicianName || userStore.name,
|
||||||
diagnosisTime: new Date().toLocaleString('zh-CN')
|
diagnosisTime: new Date().toLocaleString('zh-CN'),
|
||||||
|
// 添加 patientId
|
||||||
|
patientId: props.patientInfo.patientId
|
||||||
});
|
});
|
||||||
if (form.value.diagnosisList.length == 1) {
|
if (form.value.diagnosisList.length == 1) {
|
||||||
form.value.diagnosisList[0].maindiseFlag = 1;
|
form.value.diagnosisList[0].maindiseFlag = 1;
|
||||||
|
|||||||
@@ -371,7 +371,7 @@
|
|||||||
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
|
<div style="display: flex; align-items: center; margin-bottom: 16px; gap: 16px">
|
||||||
<span style="font-size: 16px; font-weight: 600">
|
<span style="font-size: 16px; font-weight: 600">
|
||||||
{{ row.adviceName }}
|
{{ row.adviceName }}
|
||||||
{{ row.unitPrice ? Number(row.unitPrice).toFixed(2) + '/次' : '-' + '元' }}
|
{{ row.unitPrice ? ' -' + Number(row.unitPrice).toFixed(2) + '元' : ' -元' }}
|
||||||
</span>
|
</span>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<el-form-item
|
<el-form-item
|
||||||
|
|||||||
@@ -141,7 +141,10 @@ const submitApplicationForm = () => {
|
|||||||
const submitOk = () => {
|
const submitOk = () => {
|
||||||
applicationFormDialogVisible.value = false;
|
applicationFormDialogVisible.value = false;
|
||||||
applicationFormName.value = null;
|
applicationFormName.value = null;
|
||||||
emits('refResh');
|
// 🔧 BugFix#318: 延迟刷新,确保后端数据已提交
|
||||||
|
setTimeout(() => {
|
||||||
|
emits('refResh');
|
||||||
|
}, 500);
|
||||||
};
|
};
|
||||||
defineExpose({ state });
|
defineExpose({ state });
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ const submit = () => {
|
|||||||
applicationListAllFilter = applicationListAllFilter.map((item) => {
|
applicationListAllFilter = applicationListAllFilter.map((item) => {
|
||||||
return {
|
return {
|
||||||
adviceDefinitionId: item.adviceDefinitionId /** 诊疗定义id */,
|
adviceDefinitionId: item.adviceDefinitionId /** 诊疗定义id */,
|
||||||
|
adviceDefinitionName: item.adviceDefinitionName /** 诊疗定义名称(手术项目名称) */,
|
||||||
quantity: 1, // /** 请求数量 */
|
quantity: 1, // /** 请求数量 */
|
||||||
unitCode: item.priceList[0].unitCode /** 请求单位编码 */,
|
unitCode: item.priceList[0].unitCode /** 请求单位编码 */,
|
||||||
unitPrice: item.priceList[0].price /** 单价 */,
|
unitPrice: item.priceList[0].price /** 单价 */,
|
||||||
|
|||||||
@@ -426,34 +426,35 @@ const inputRefs = ref({}); // 存储输入框实例
|
|||||||
const requiredProps = ref([]); // 存储必填项 prop 顺序
|
const requiredProps = ref([]); // 存储必填项 prop 顺序
|
||||||
const totalAmount = ref(0);
|
const totalAmount = ref(0);
|
||||||
const therapyEnum = ref('');
|
const therapyEnum = ref('');
|
||||||
const { method_code, unit_code, rate_code, distribution_category_code } = proxy.useDict(
|
const { method_code, unit_code, rate_code, distribution_category_code, drord_doctor_type } = proxy.useDict(
|
||||||
'method_code',
|
'method_code',
|
||||||
'unit_code',
|
'unit_code',
|
||||||
'rate_code',
|
'rate_code',
|
||||||
'distribution_category_code'
|
'distribution_category_code',
|
||||||
|
'drord_doctor_type'
|
||||||
);
|
);
|
||||||
const openDrawer = ref(false);
|
const openDrawer = ref(false);
|
||||||
const orderClassCode = ref('');
|
const orderClassCode = ref('');
|
||||||
const orderStatus = ref('');
|
const orderStatus = ref('');
|
||||||
// 医嘱类型
|
// 医嘱类型 - 使用 drord_doctor_type 字典
|
||||||
const adviceTypeList = ref([
|
const adviceTypeList = computed(() => {
|
||||||
{
|
// 如果字典已加载,使用字典数据(过滤掉全部选项)
|
||||||
label: '西药中成药',
|
if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
|
||||||
value: 1,
|
const list = drord_doctor_type.value.map(item => ({
|
||||||
},
|
label: item.label,
|
||||||
// {
|
value: parseInt(item.value) || item.value
|
||||||
// label: '耗材',
|
}));
|
||||||
// value: 2,
|
// 添加全部选项
|
||||||
// },
|
return [...list, { label: '全部', value: '' }];
|
||||||
{
|
}
|
||||||
label: '诊疗',
|
// 默认返回值
|
||||||
value: 3,
|
return [
|
||||||
},
|
{ label: '西药中成药', value: 1 },
|
||||||
{
|
{ label: '诊疗', value: 3 },
|
||||||
label: '全部',
|
{ label: '手术', value: 6 },
|
||||||
value: '',
|
{ label: '全部', value: '' },
|
||||||
},
|
];
|
||||||
]);
|
});
|
||||||
// 医嘱状态
|
// 医嘱状态
|
||||||
const statusOption = [
|
const statusOption = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -151,6 +151,8 @@ const handleItemClick = (node) => {
|
|||||||
// 同时更新本地和全局状态,确保模块内组件和跨模块组件都能正确响应
|
// 同时更新本地和全局状态,确保模块内组件和跨模块组件都能正确响应
|
||||||
updatePatientInfo(node);
|
updatePatientInfo(node);
|
||||||
updateLocalPatientInfo(node);
|
updateLocalPatientInfo(node);
|
||||||
|
// 关键修复:同步更新 currentPatientInfo,确保诊断组件能获取到 patientId 和 encounterId
|
||||||
|
currentPatientInfo.value = node;
|
||||||
|
|
||||||
diagnosisRef.value?.getList();
|
diagnosisRef.value?.getList();
|
||||||
diagnosisRef.value?.getDetail(node?.encounterId);
|
diagnosisRef.value?.getDetail(node?.encounterId);
|
||||||
|
|||||||
@@ -250,12 +250,15 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import {computed, onMounted, reactive, ref, watch} from 'vue';
|
import {computed, getCurrentInstance, onMounted, reactive, ref, watch} from 'vue';
|
||||||
import {ElMessage} from 'element-plus';
|
import {ElMessage} from 'element-plus';
|
||||||
import {formatDateStr} from '@/utils/index';
|
import {formatDateStr} from '@/utils/index';
|
||||||
import {getAdviceBaseInfo, getDiseaseTreatmentInitLoc, getOrgList} from './api.js';
|
import {getAdviceBaseInfo, getDiseaseTreatmentInitLoc, getOrgList} from './api.js';
|
||||||
import useUserStore from '@/store/modules/user';
|
import useUserStore from '@/store/modules/user';
|
||||||
|
|
||||||
|
const { proxy } = getCurrentInstance();
|
||||||
|
const { drord_doctor_type } = proxy.useDict('drord_doctor_type');
|
||||||
|
|
||||||
// Props定义
|
// Props定义
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
visible: {
|
visible: {
|
||||||
@@ -280,11 +283,26 @@ const dialogVisible = computed({
|
|||||||
get: () => props.visible,
|
get: () => props.visible,
|
||||||
set: (value) => emit('update:visible', value),
|
set: (value) => emit('update:visible', value),
|
||||||
});
|
});
|
||||||
const adviceTypeList = ref([
|
// 使用 drord_doctor_type 字典
|
||||||
{ label: '耗材', value: 2 },
|
const adviceTypeList = computed(() => {
|
||||||
{ label: '诊疗', value: 3 },
|
if (drord_doctor_type.value && drord_doctor_type.value.length > 0) {
|
||||||
{ label: '全部', value: '' },
|
// 只保留耗材(4)和诊疗(3)类型,并添加全部选项
|
||||||
]);
|
const filtered = drord_doctor_type.value.filter(item => {
|
||||||
|
const val = parseInt(item.value);
|
||||||
|
return val === 3 || val === 4;
|
||||||
|
}).map(item => ({
|
||||||
|
label: item.label,
|
||||||
|
value: parseInt(item.value)
|
||||||
|
}));
|
||||||
|
return [...filtered, { label: '全部', value: '' }];
|
||||||
|
}
|
||||||
|
// 默认值
|
||||||
|
return [
|
||||||
|
{ label: '耗材', value: 4 },
|
||||||
|
{ label: '诊疗', value: 3 },
|
||||||
|
{ label: '全部', value: '' },
|
||||||
|
];
|
||||||
|
});
|
||||||
const adviceType = ref('');
|
const adviceType = ref('');
|
||||||
const feeItemsList = ref([]);
|
const feeItemsList = ref([]);
|
||||||
const executeTime = ref('');
|
const executeTime = ref('');
|
||||||
|
|||||||
@@ -431,9 +431,9 @@ async function loadData() {
|
|||||||
level: item.packageLevel || '',
|
level: item.packageLevel || '',
|
||||||
dept: item.department || '',
|
dept: item.department || '',
|
||||||
user: item.userId || '',
|
user: item.userId || '',
|
||||||
amount: parseFloat(item.packageAmount || 0),
|
amount: parseFloat((parseFloat(item.packageAmount || 0) - parseFloat(item.serviceFee || 0)).toFixed(2)),
|
||||||
fee: parseFloat(item.serviceFee || 0),
|
fee: parseFloat(item.serviceFee || 0),
|
||||||
total: parseFloat(item.packageAmount || 0) + parseFloat(item.serviceFee || 0),
|
total: parseFloat(item.packageAmount || 0),
|
||||||
combined: item.enablePackagePrice === true ? '是' : '否',
|
combined: item.enablePackagePrice === true ? '是' : '否',
|
||||||
display: item.showPackageName === true ? '是' : '否',
|
display: item.showPackageName === true ? '是' : '否',
|
||||||
enabled: item.isDisabled === true ? '否' : '是',
|
enabled: item.isDisabled === true ? '否' : '是',
|
||||||
|
|||||||
@@ -816,11 +816,14 @@ import {
|
|||||||
} from '@/api/system/inspectionType';
|
} from '@/api/system/inspectionType';
|
||||||
import {
|
import {
|
||||||
getDiagnosisTreatmentList,
|
getDiagnosisTreatmentList,
|
||||||
addDiagnosisTreatment,
|
|
||||||
editDiagnosisTreatment,
|
|
||||||
stopDiseaseTreatment,
|
|
||||||
getDiseaseTreatmentInit
|
getDiseaseTreatmentInit
|
||||||
} from '@/views/catalog/diagnosistreatment/components/diagnosistreatment';
|
} from '@/views/catalog/diagnosistreatment/components/diagnosistreatment';
|
||||||
|
import {
|
||||||
|
getLabActivityDefinitionPage,
|
||||||
|
addLabActivityDefinition,
|
||||||
|
editLabActivityDefinition,
|
||||||
|
stopLabActivityDefinition
|
||||||
|
} from '@/api/lab/labActivityDefinition';
|
||||||
import {listLisGroup} from '@/api/system/checkType';
|
import {listLisGroup} from '@/api/system/checkType';
|
||||||
import {
|
import {
|
||||||
addInspectionPackage,
|
addInspectionPackage,
|
||||||
@@ -1374,7 +1377,7 @@ const loadObservationItems = async (resetPage = false) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await getDiagnosisTreatmentList(params);
|
const response = await getLabActivityDefinitionPage(params);
|
||||||
|
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
let data = [];
|
let data = [];
|
||||||
@@ -1643,25 +1646,37 @@ const cancelEditItem = (index) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 计算套餐金额和服务费
|
// 计算套餐金额和服务费
|
||||||
|
// 规则:
|
||||||
|
// 单价 = 原始单价 × (折扣% / 100)
|
||||||
|
// 金额 = 折后单价 × 数量
|
||||||
|
// 总金额 = 金额 + 服务费
|
||||||
|
// 套餐金额 = 各行总金额之和
|
||||||
const calculateAmounts = () => {
|
const calculateAmounts = () => {
|
||||||
// 更新每个项目的金额(金额 = 数量 × 单价,不受折扣影响)和总金额
|
const discountRate = parseFloat(discount.value);
|
||||||
|
const hasDiscount = !isNaN(discountRate) && discountRate > 0;
|
||||||
|
|
||||||
packageItems.value.forEach(item => {
|
packageItems.value.forEach(item => {
|
||||||
item.amount = parseFloat(((item.quantity || 1) * (item.unitPrice || 0.00)).toFixed(2));
|
// 单价 = 原始单价 × 折扣比例
|
||||||
// serviceFee 由用户手动输入,不覆盖;只更新 totalAmount
|
const originalPrice = item.originalPrice != null ? item.originalPrice : item.unitPrice;
|
||||||
item.totalAmount = parseFloat(((item.amount) + (item.serviceFee || 0)).toFixed(2));
|
item.originalPrice = originalPrice; // 确保 originalPrice 始终保留
|
||||||
|
if (hasDiscount) {
|
||||||
|
item.unitPrice = parseFloat((originalPrice * discountRate / 100).toFixed(2));
|
||||||
|
} else {
|
||||||
|
item.unitPrice = parseFloat(originalPrice.toFixed(2));
|
||||||
|
}
|
||||||
|
// 金额 = 折后单价 × 数量
|
||||||
|
item.amount = parseFloat(((item.quantity || 1) * item.unitPrice).toFixed(2));
|
||||||
|
// 总金额 = 金额 + 服务费
|
||||||
|
item.totalAmount = parseFloat((item.amount + (item.serviceFee || 0)).toFixed(2));
|
||||||
});
|
});
|
||||||
|
|
||||||
// 汇总各明细行服务费到基本信息服务费(只读展示)
|
// 汇总各明细行服务费到基本信息服务费(只读展示)
|
||||||
serviceFee.value = parseFloat(packageItems.value.reduce((sum, item) => sum + (item.serviceFee || 0), 0).toFixed(2));
|
serviceFee.value = parseFloat(packageItems.value.reduce((sum, item) => sum + (item.serviceFee || 0), 0).toFixed(2));
|
||||||
|
|
||||||
// 套餐总金额 = (各行金额之和 + 各行服务费之和) × 折扣比例
|
// 套餐金额 = 各行总金额之和
|
||||||
const rawTotal = packageItems.value.reduce((sum, item) => sum + (item.amount || 0) + (item.serviceFee || 0), 0);
|
packageAmount.value = parseFloat(
|
||||||
let finalTotal = rawTotal;
|
packageItems.value.reduce((sum, item) => sum + (item.totalAmount || 0), 0).toFixed(2)
|
||||||
if (discount.value && !isNaN(parseFloat(discount.value)) && parseFloat(discount.value) > 0) {
|
);
|
||||||
const discountRate = parseFloat(discount.value) / 100; // 80 → 0.8,表示八折保留80%
|
|
||||||
finalTotal = rawTotal * discountRate;
|
|
||||||
}
|
|
||||||
packageAmount.value = parseFloat(finalTotal.toFixed(2));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const itemNameRefs = ref([]);
|
const itemNameRefs = ref([]);
|
||||||
@@ -2030,16 +2045,18 @@ const saveItem = async (item) => {
|
|||||||
|
|
||||||
// 判断是新增还是更新
|
// 判断是新增还是更新
|
||||||
if (typeof item.id === 'number') { // 临时ID(数字类型),新增
|
if (typeof item.id === 'number') { // 临时ID(数字类型),新增
|
||||||
const response = await addDiagnosisTreatment(submitData);
|
const response = await addLabActivityDefinition(submitData);
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
ElMessage.success('添加成功');
|
ElMessage.success('添加成功');
|
||||||
|
// 新增成功后跳到第1页,后端按id降序排列,最新数据在第1页首位
|
||||||
|
inspectionCurrentPage.value = 1;
|
||||||
await loadObservationItems();
|
await loadObservationItems();
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(response.msg || '添加失败');
|
ElMessage.error(response.msg || '添加失败');
|
||||||
}
|
}
|
||||||
} else { // 真实ID(字符串类型),更新
|
} else { // 真实ID(字符串类型),更新
|
||||||
submitData.id = item.id;
|
submitData.id = item.id;
|
||||||
const response = await editDiagnosisTreatment(submitData);
|
const response = await editLabActivityDefinition(submitData);
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
ElMessage.success('更新成功');
|
ElMessage.success('更新成功');
|
||||||
await loadObservationItems();
|
await loadObservationItems();
|
||||||
@@ -2062,7 +2079,7 @@ const deleteItem = async (id) => {
|
|||||||
type: 'warning'
|
type: 'warning'
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await stopDiseaseTreatment([id]);
|
const response = await stopLabActivityDefinition([id]);
|
||||||
if (response.code === 200) {
|
if (response.code === 200) {
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success('删除成功');
|
||||||
await loadObservationItems();
|
await loadObservationItems();
|
||||||
@@ -2208,10 +2225,11 @@ const handleSave = () => {
|
|||||||
days: item.days,
|
days: item.days,
|
||||||
quantity: item.quantity,
|
quantity: item.quantity,
|
||||||
unit: item.unit,
|
unit: item.unit,
|
||||||
unitPrice: item.unitPrice,
|
originalPrice: item.originalPrice != null ? item.originalPrice : item.unitPrice, // 原始单价
|
||||||
|
unitPrice: item.unitPrice, // 折后单价
|
||||||
amount: item.amount,
|
amount: item.amount,
|
||||||
serviceFee: item.serviceFee || 0,
|
serviceFee: item.serviceFee || 0,
|
||||||
totalAmount: parseFloat(((item.amount || 0) + (item.serviceFee || 0)).toFixed(2)),
|
totalAmount: item.totalAmount, // 金额 + 服务费
|
||||||
origin: item.origin,
|
origin: item.origin,
|
||||||
createTime: new Date().toISOString(),
|
createTime: new Date().toISOString(),
|
||||||
updateTime: new Date().toISOString()
|
updateTime: new Date().toISOString()
|
||||||
@@ -2314,7 +2332,16 @@ const handleProjectInlineSearch = async (query, cb, row) => {
|
|||||||
const handleProjectInlineSelect = (selectedItem, row) => {
|
const handleProjectInlineSelect = (selectedItem, row) => {
|
||||||
row.name = selectedItem.name;
|
row.name = selectedItem.name;
|
||||||
row.spec = selectedItem.spec || '';
|
row.spec = selectedItem.spec || '';
|
||||||
row.unitPrice = parseFloat(selectedItem.retailPrice || 0);
|
// 保存原始单价,供折扣计算使用
|
||||||
|
const originalPrice = parseFloat(selectedItem.retailPrice || 0);
|
||||||
|
row.originalPrice = originalPrice;
|
||||||
|
// 单价 = 原始单价 × 折扣比例
|
||||||
|
const discountRate = parseFloat(discount.value);
|
||||||
|
if (!isNaN(discountRate) && discountRate > 0) {
|
||||||
|
row.unitPrice = parseFloat((originalPrice * discountRate / 100).toFixed(2));
|
||||||
|
} else {
|
||||||
|
row.unitPrice = originalPrice;
|
||||||
|
}
|
||||||
row.unit = selectedItem.permittedUnitCode_dictText || selectedItem.unit || '次';
|
row.unit = selectedItem.permittedUnitCode_dictText || selectedItem.unit || '次';
|
||||||
if (!row.quantity) row.quantity = 1;
|
if (!row.quantity) row.quantity = 1;
|
||||||
row.amount = parseFloat((row.unitPrice * row.quantity).toFixed(2));
|
row.amount = parseFloat((row.unitPrice * row.quantity).toFixed(2));
|
||||||
@@ -2557,21 +2584,39 @@ const loadInspectionPackage = async (packageId) => {
|
|||||||
remarks.value = basicData.remarks || '';
|
remarks.value = basicData.remarks || '';
|
||||||
|
|
||||||
// 填充明细数据(必须映射 id,否则取消编辑时会被误判为新增行删除)
|
// 填充明细数据(必须映射 id,否则取消编辑时会被误判为新增行删除)
|
||||||
packageItems.value = detailData.map(item => ({
|
const loadedDiscount = parseFloat(basicData.discount);
|
||||||
id: item.detailId || item.id,
|
packageItems.value = detailData.map(item => {
|
||||||
name: item.itemName || item.name,
|
const savedOriginalPrice = parseFloat(item.originalPrice || 0);
|
||||||
dosage: item.dosage || '',
|
const savedUnitPrice = parseFloat(item.unitPrice || 0);
|
||||||
route: item.route || '',
|
// 恢复原始单价:
|
||||||
frequency: item.frequency || '',
|
// 1. 后端有 originalPrice 时直接用
|
||||||
days: item.days || '',
|
// 2. 旧数据无 originalPrice 时,通过折扣反推:originalPrice = unitPrice / (discount/100)
|
||||||
quantity: item.quantity || 1,
|
let originalPrice;
|
||||||
unit: item.unit || '',
|
if (savedOriginalPrice > 0) {
|
||||||
unitPrice: parseFloat(item.unitPrice || 0),
|
originalPrice = savedOriginalPrice;
|
||||||
amount: parseFloat(item.amount || 0),
|
} else if (!isNaN(loadedDiscount) && loadedDiscount > 0 && loadedDiscount !== 100) {
|
||||||
serviceFee: parseFloat(item.serviceFee || 0),
|
originalPrice = parseFloat((savedUnitPrice / (loadedDiscount / 100)).toFixed(2));
|
||||||
totalAmount: parseFloat(item.totalAmount || 0),
|
} else {
|
||||||
origin: item.origin || ''
|
// 折扣为空或100(原价),originalPrice = unitPrice
|
||||||
}));
|
originalPrice = savedUnitPrice;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
id: item.detailId || item.id,
|
||||||
|
name: item.itemName || item.name,
|
||||||
|
dosage: item.dosage || '',
|
||||||
|
route: item.route || '',
|
||||||
|
frequency: item.frequency || '',
|
||||||
|
days: item.days || '',
|
||||||
|
quantity: item.quantity || 1,
|
||||||
|
unit: item.unit || '',
|
||||||
|
originalPrice,
|
||||||
|
unitPrice: savedUnitPrice,
|
||||||
|
amount: parseFloat(item.amount || 0),
|
||||||
|
serviceFee: parseFloat(item.serviceFee || 0),
|
||||||
|
totalAmount: parseFloat(item.totalAmount || 0),
|
||||||
|
origin: item.origin || ''
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// 恢复监听
|
// 恢复监听
|
||||||
isLoadingPackage.value = false;
|
isLoadingPackage.value = false;
|
||||||
|
|||||||
@@ -89,7 +89,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column label="卫生机构" align="center" prop="orgName" width="120" show-overflow-tooltip />
|
<el-table-column label="卫生机构" align="center" prop="orgName" width="120" show-overflow-tooltip />
|
||||||
<el-table-column label="姓名" align="center" prop="patientName" width="100" />
|
<el-table-column label="姓名" align="center" prop="patientName" width="100" />
|
||||||
<el-table-column label="就诊卡号" align="center" prop="visitId" width="120" />
|
<el-table-column label="就诊卡号" align="center" prop="identifierNo" width="120" />
|
||||||
<el-table-column label="手术名称" align="center" prop="operName" min-width="140" show-overflow-tooltip />
|
<el-table-column label="手术名称" align="center" prop="operName" min-width="140" show-overflow-tooltip />
|
||||||
<el-table-column label="申请科室" align="center" prop="applyDeptName" width="100" show-overflow-tooltip>
|
<el-table-column label="申请科室" align="center" prop="applyDeptName" width="100" show-overflow-tooltip>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
@@ -161,9 +161,9 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-form-item label="就诊卡号" prop="visitId">
|
<el-form-item label="就诊卡号" prop="identifierNo">
|
||||||
<el-tooltip :content="form.visitId" placement="top" :disabled="!form.visitId">
|
<el-tooltip :content="form.identifierNo" placement="top" :disabled="!form.identifierNo">
|
||||||
<el-input v-model="form.visitId" :disabled="true" style="width: 100%" />
|
<el-input v-model="form.identifierNo" :disabled="true" style="width: 100%" />
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -900,6 +900,7 @@ const form = reactive({
|
|||||||
applyId: undefined,
|
applyId: undefined,
|
||||||
patientId: undefined,
|
patientId: undefined,
|
||||||
visitId: undefined,
|
visitId: undefined,
|
||||||
|
identifierNo: undefined,
|
||||||
operCode: undefined,
|
operCode: undefined,
|
||||||
operName: undefined,
|
operName: undefined,
|
||||||
preoperativeDiagnosis: undefined,
|
preoperativeDiagnosis: undefined,
|
||||||
@@ -1783,6 +1784,7 @@ function confirmApply() {
|
|||||||
form.applyId=selectedRow.applyId// 手术申请id
|
form.applyId=selectedRow.applyId// 手术申请id
|
||||||
form.patientId = selectedRow.patientId// 患者id
|
form.patientId = selectedRow.patientId// 患者id
|
||||||
form.visitId = selectedRow.encounterId // id对应填入就诊id
|
form.visitId = selectedRow.encounterId // id对应填入就诊id
|
||||||
|
form.identifierNo = selectedRow.identifierNo || '' // 就诊卡号
|
||||||
form.operCode = selectedRow.surgeryNo // 手术单号作为手术编码
|
form.operCode = selectedRow.surgeryNo // 手术单号作为手术编码
|
||||||
form.operName = selectedRow.descJson?.surgeryName//手术名称
|
form.operName = selectedRow.descJson?.surgeryName//手术名称
|
||||||
form.preoperativeDiagnosis = selectedRow.preoperativeDiagnosis || selectedRow.descJson?.preoperativeDiagnosis
|
form.preoperativeDiagnosis = selectedRow.preoperativeDiagnosis || selectedRow.descJson?.preoperativeDiagnosis
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<div class="patient-info-content">
|
<div class="patient-info-content">
|
||||||
<el-descriptions :column="3" border>
|
<el-descriptions :column="3" border>
|
||||||
<el-descriptions-item label="患者:">{{ patientInfo.patientName || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="患者:">{{ patientInfo.patientName || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="就诊卡号:">{{ patientInfo.visitId || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="就诊卡号:">{{ patientInfo.identifierNo || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="手术单号:">{{ patientInfo.operCode || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="手术单号:">{{ patientInfo.operCode || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="科室:">{{ patientInfo.roomCode || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="科室:">{{ patientInfo.roomCode || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="医师:">{{ patientInfo.doctorName || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="医师:">{{ patientInfo.doctorName || '-' }}</el-descriptions-item>
|
||||||
|
|||||||
351
scripts/repair_bug_318.py
Normal file
351
scripts/repair_bug_318.py
Normal file
@@ -0,0 +1,351 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Bug #318 历史数据修复脚本
|
||||||
|
为已存在但未生成手术医嘱的手术申请单补齐数据
|
||||||
|
"""
|
||||||
|
|
||||||
|
import psycopg2
|
||||||
|
import json
|
||||||
|
import random
|
||||||
|
import string
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# 数据库连接配置
|
||||||
|
DB_CONFIG = {
|
||||||
|
"host": "47.116.196.11",
|
||||||
|
"port": 15432,
|
||||||
|
"database": "postgresql",
|
||||||
|
"user": "postgresql",
|
||||||
|
"password": "postgresql", # 请根据实际情况修改
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def generate_bus_no():
|
||||||
|
"""生成4位随机bus_no"""
|
||||||
|
return "".join(random.choices(string.digits, k=4))
|
||||||
|
|
||||||
|
|
||||||
|
def check_repair_needed(conn):
|
||||||
|
"""检查需要修复的记录数"""
|
||||||
|
cursor = conn.cursor()
|
||||||
|
sql = """
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE'
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL
|
||||||
|
"""
|
||||||
|
cursor.execute(sql)
|
||||||
|
count = cursor.fetchone()[0]
|
||||||
|
cursor.close()
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def get_repair_list(conn):
|
||||||
|
"""获取需要修复的手术申请单列表"""
|
||||||
|
cursor = conn.cursor()
|
||||||
|
sql = """
|
||||||
|
SELECT
|
||||||
|
rf.id,
|
||||||
|
rf.prescription_no,
|
||||||
|
rf.encounter_id,
|
||||||
|
rf.patient_id,
|
||||||
|
rf.requester_id,
|
||||||
|
rf.create_time,
|
||||||
|
rf.org_id,
|
||||||
|
rf.desc_json
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE'
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL
|
||||||
|
ORDER BY rf.create_time DESC
|
||||||
|
"""
|
||||||
|
cursor.execute(sql)
|
||||||
|
results = cursor.fetchall()
|
||||||
|
cursor.close()
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def parse_surgery_info(desc_json):
|
||||||
|
"""解析手术信息"""
|
||||||
|
if not desc_json:
|
||||||
|
return {}
|
||||||
|
try:
|
||||||
|
if isinstance(desc_json, str):
|
||||||
|
return json.loads(desc_json)
|
||||||
|
return desc_json
|
||||||
|
except:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
|
def repair_service_request(conn, repair_list):
|
||||||
|
"""修复手术医嘱(ServiceRequest)"""
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
insert_sql = """
|
||||||
|
INSERT INTO wor_service_request (
|
||||||
|
bus_no, prescription_no, status_enum, generate_source_enum,
|
||||||
|
therapy_enum, quantity, unit_code, category_enum,
|
||||||
|
patient_id, requester_id, encounter_id, authored_time,
|
||||||
|
org_id, content_json, delete_flag, create_time, create_by, tenant_id
|
||||||
|
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
RETURNING id
|
||||||
|
"""
|
||||||
|
|
||||||
|
new_requests = []
|
||||||
|
for record in repair_list:
|
||||||
|
(
|
||||||
|
rf_id,
|
||||||
|
prescription_no,
|
||||||
|
encounter_id,
|
||||||
|
patient_id,
|
||||||
|
requester_id,
|
||||||
|
create_time,
|
||||||
|
org_id,
|
||||||
|
desc_json,
|
||||||
|
) = record
|
||||||
|
|
||||||
|
# 解析手术信息
|
||||||
|
surgery_info = parse_surgery_info(desc_json)
|
||||||
|
content_json = (
|
||||||
|
json.dumps(surgery_info, ensure_ascii=False) if surgery_info else None
|
||||||
|
)
|
||||||
|
|
||||||
|
# 生成bus_no
|
||||||
|
bus_no = generate_bus_no()
|
||||||
|
|
||||||
|
# 插入ServiceRequest
|
||||||
|
cursor.execute(
|
||||||
|
insert_sql,
|
||||||
|
(
|
||||||
|
bus_no, # bus_no
|
||||||
|
prescription_no, # prescription_no
|
||||||
|
1, # status_enum: 1-待签发
|
||||||
|
1, # generate_source_enum: 1-医生处方
|
||||||
|
2, # therapy_enum: 2-临时医嘱
|
||||||
|
1, # quantity
|
||||||
|
"次", # unit_code
|
||||||
|
4, # category_enum: 4-手术
|
||||||
|
patient_id, # patient_id
|
||||||
|
requester_id, # requester_id
|
||||||
|
encounter_id, # encounter_id
|
||||||
|
create_time, # authored_time
|
||||||
|
org_id, # org_id
|
||||||
|
content_json, # content_json
|
||||||
|
"0", # delete_flag
|
||||||
|
create_time, # create_time
|
||||||
|
requester_id, # create_by
|
||||||
|
1, # tenant_id
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
service_request_id = cursor.fetchone()[0]
|
||||||
|
new_requests.append(
|
||||||
|
{
|
||||||
|
"service_request_id": service_request_id,
|
||||||
|
"bus_no": bus_no,
|
||||||
|
"prescription_no": prescription_no,
|
||||||
|
"patient_id": patient_id,
|
||||||
|
"encounter_id": encounter_id,
|
||||||
|
"requester_id": requester_id,
|
||||||
|
"create_time": create_time,
|
||||||
|
"org_id": org_id,
|
||||||
|
"surgery_info": surgery_info,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
return new_requests
|
||||||
|
|
||||||
|
|
||||||
|
def repair_charge_items(conn, new_requests):
|
||||||
|
"""修复收费项目(ChargeItem)"""
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
insert_sql = """
|
||||||
|
INSERT INTO adm_charge_item (
|
||||||
|
bus_no, status_enum, generate_source_enum, patient_id,
|
||||||
|
context_enum, encounter_id, enterer_id, entered_date,
|
||||||
|
service_table, service_id, product_table, requesting_org_id,
|
||||||
|
quantity_value, quantity_unit, unit_price, total_price,
|
||||||
|
delete_flag, create_time, create_by, tenant_id
|
||||||
|
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
|
||||||
|
"""
|
||||||
|
|
||||||
|
for req in new_requests:
|
||||||
|
surgery_info = req["surgery_info"]
|
||||||
|
|
||||||
|
# 手术费用
|
||||||
|
surgery_fee = 0
|
||||||
|
if surgery_info and "surgeryFee" in surgery_info:
|
||||||
|
try:
|
||||||
|
surgery_fee = float(surgery_info["surgeryFee"])
|
||||||
|
except:
|
||||||
|
surgery_fee = 0
|
||||||
|
|
||||||
|
# 插入手术费用收费项目
|
||||||
|
cursor.execute(
|
||||||
|
insert_sql,
|
||||||
|
(
|
||||||
|
"CI" + req["bus_no"], # bus_no
|
||||||
|
1, # status_enum: 1-草稿
|
||||||
|
1, # generate_source_enum: 1-医生处方
|
||||||
|
req["patient_id"], # patient_id
|
||||||
|
3, # context_enum: 3-诊疗
|
||||||
|
req["encounter_id"], # encounter_id
|
||||||
|
req["requester_id"], # enterer_id
|
||||||
|
req["create_time"], # entered_date
|
||||||
|
"wor_service_request", # service_table
|
||||||
|
req["service_request_id"], # service_id
|
||||||
|
"wor_activity_definition", # product_table
|
||||||
|
req["org_id"], # requesting_org_id
|
||||||
|
1, # quantity_value
|
||||||
|
"次", # quantity_unit
|
||||||
|
surgery_fee, # unit_price
|
||||||
|
surgery_fee, # total_price
|
||||||
|
"0", # delete_flag
|
||||||
|
req["create_time"], # create_time
|
||||||
|
req["requester_id"], # create_by
|
||||||
|
1, # tenant_id
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# 麻醉费用(如果存在且大于0)
|
||||||
|
anesthesia_fee = 0
|
||||||
|
if surgery_info and "anesthesiaFee" in surgery_info:
|
||||||
|
try:
|
||||||
|
anesthesia_fee = float(surgery_info["anesthesiaFee"])
|
||||||
|
except:
|
||||||
|
anesthesia_fee = 0
|
||||||
|
|
||||||
|
if anesthesia_fee > 0:
|
||||||
|
cursor.execute(
|
||||||
|
insert_sql,
|
||||||
|
(
|
||||||
|
"CI" + req["bus_no"] + "_A", # bus_no
|
||||||
|
1, # status_enum
|
||||||
|
1, # generate_source_enum
|
||||||
|
req["patient_id"], # patient_id
|
||||||
|
3, # context_enum
|
||||||
|
req["encounter_id"], # encounter_id
|
||||||
|
req["requester_id"], # enterer_id
|
||||||
|
req["create_time"], # entered_date
|
||||||
|
"wor_service_request", # service_table
|
||||||
|
req["service_request_id"], # service_id
|
||||||
|
"wor_activity_definition", # product_table
|
||||||
|
req["org_id"], # requesting_org_id
|
||||||
|
1, # quantity_value
|
||||||
|
"次", # quantity_unit
|
||||||
|
anesthesia_fee, # unit_price
|
||||||
|
anesthesia_fee, # total_price
|
||||||
|
"0", # delete_flag
|
||||||
|
req["create_time"], # create_time
|
||||||
|
req["requester_id"], # create_by
|
||||||
|
1, # tenant_id
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
conn.commit()
|
||||||
|
cursor.close()
|
||||||
|
|
||||||
|
|
||||||
|
def verify_repair(conn):
|
||||||
|
"""验证修复结果"""
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# 统计手术医嘱数量
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM wor_service_request
|
||||||
|
WHERE category_enum = 4 AND delete_flag = '0'
|
||||||
|
""")
|
||||||
|
service_request_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
# 统计收费项目数量
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM adm_charge_item ci
|
||||||
|
WHERE ci.service_table = 'wor_service_request'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM wor_service_request sr
|
||||||
|
WHERE sr.id = ci.service_id AND sr.category_enum = 4
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
charge_item_count = cursor.fetchone()[0]
|
||||||
|
|
||||||
|
cursor.close()
|
||||||
|
return service_request_count, charge_item_count
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""主函数"""
|
||||||
|
print("=" * 60)
|
||||||
|
print("Bug #318 历史数据修复脚本")
|
||||||
|
print("=" * 60)
|
||||||
|
print()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 连接数据库
|
||||||
|
print("正在连接数据库...")
|
||||||
|
conn = psycopg2.connect(**DB_CONFIG)
|
||||||
|
print("✓ 数据库连接成功")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 步骤1:检查需要修复的记录数
|
||||||
|
print("步骤1: 检查需要修复的记录...")
|
||||||
|
need_repair_count = check_repair_needed(conn)
|
||||||
|
print(f"✓ 发现 {need_repair_count} 条需要修复的手术申请单")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if need_repair_count == 0:
|
||||||
|
print("没有需要修复的数据,退出")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 步骤2:获取修复列表
|
||||||
|
print("步骤2: 获取修复列表...")
|
||||||
|
repair_list = get_repair_list(conn)
|
||||||
|
print(f"✓ 获取到 {len(repair_list)} 条记录")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 步骤3:修复ServiceRequest
|
||||||
|
print("步骤3: 生成手术医嘱(ServiceRequest)...")
|
||||||
|
new_requests = repair_service_request(conn, repair_list)
|
||||||
|
print(f"✓ 成功生成 {len(new_requests)} 条手术医嘱")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 步骤4:修复ChargeItem
|
||||||
|
print("步骤4: 生成收费项目(ChargeItem)...")
|
||||||
|
repair_charge_items(conn, new_requests)
|
||||||
|
print(f"✓ 成功生成收费项目")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# 步骤5:验证修复结果
|
||||||
|
print("步骤5: 验证修复结果...")
|
||||||
|
service_count, charge_count = verify_repair(conn)
|
||||||
|
print(f"✓ 当前手术医嘱总数: {service_count}")
|
||||||
|
print(f"✓ 当前手术收费项目总数: {charge_count}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
print("=" * 60)
|
||||||
|
print("✓ 修复完成!")
|
||||||
|
print("=" * 60)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"✗ 错误: {e}")
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
traceback.print_exc()
|
||||||
|
finally:
|
||||||
|
if "conn" in locals():
|
||||||
|
conn.close()
|
||||||
|
print("\n数据库连接已关闭")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
240
sql/bug_318_repair_execute.sql
Normal file
240
sql/bug_318_repair_execute.sql
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- Bug #318 历史数据修复 - 简化版SQL脚本
|
||||||
|
-- 为已存在但未生成手术医嘱的手术申请单补齐数据
|
||||||
|
-- ============================================================
|
||||||
|
-- 执行说明:
|
||||||
|
-- 1. 在数据库管理工具中执行(如 DBeaver、pgAdmin)
|
||||||
|
-- 2. 建议先执行查询部分确认数据
|
||||||
|
-- 3. 备份数据库后再执行修复
|
||||||
|
-- ============================================================
|
||||||
|
|
||||||
|
-- 步骤1: 查看需要修复的记录数
|
||||||
|
-- ============================================================
|
||||||
|
SELECT
|
||||||
|
'需要修复的手术申请单数量' as 检查项,
|
||||||
|
COUNT(*) as 数量
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE'
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL;
|
||||||
|
|
||||||
|
-- 步骤2: 查看详细列表(可选)
|
||||||
|
-- ============================================================
|
||||||
|
/*
|
||||||
|
SELECT
|
||||||
|
rf.id as request_form_id,
|
||||||
|
rf.prescription_no as 手术单号,
|
||||||
|
rf.encounter_id as 就诊ID,
|
||||||
|
rf.patient_id as 患者ID,
|
||||||
|
rf.create_time as 申请时间
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE'
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL
|
||||||
|
ORDER BY rf.create_time DESC
|
||||||
|
LIMIT 10;
|
||||||
|
*/
|
||||||
|
|
||||||
|
-- 步骤3: 执行修复 - 生成手术医嘱(ServiceRequest)
|
||||||
|
-- ============================================================
|
||||||
|
-- ⚠️ 请在确认备份数据库后执行以下语句
|
||||||
|
|
||||||
|
INSERT INTO wor_service_request (
|
||||||
|
bus_no,
|
||||||
|
prescription_no,
|
||||||
|
status_enum,
|
||||||
|
generate_source_enum,
|
||||||
|
therapy_enum,
|
||||||
|
quantity,
|
||||||
|
unit_code,
|
||||||
|
category_enum,
|
||||||
|
patient_id,
|
||||||
|
requester_id,
|
||||||
|
encounter_id,
|
||||||
|
authored_time,
|
||||||
|
org_id,
|
||||||
|
content_json,
|
||||||
|
delete_flag,
|
||||||
|
create_time,
|
||||||
|
create_by,
|
||||||
|
tenant_id
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
LPAD(FLOOR(RANDOM() * 10000)::TEXT, 4, '0') as bus_no, -- 生成4位随机数
|
||||||
|
rf.prescription_no,
|
||||||
|
1 as status_enum, -- 1-待签发
|
||||||
|
1 as generate_source_enum, -- 1-医生处方
|
||||||
|
2 as therapy_enum, -- 2-临时医嘱
|
||||||
|
1 as quantity,
|
||||||
|
'次' as unit_code,
|
||||||
|
4 as category_enum, -- 4-手术
|
||||||
|
rf.patient_id,
|
||||||
|
rf.requester_id,
|
||||||
|
rf.encounter_id,
|
||||||
|
rf.create_time as authored_time,
|
||||||
|
rf.org_id,
|
||||||
|
rf.desc_json as content_json, -- 存储手术详情
|
||||||
|
'0' as delete_flag,
|
||||||
|
rf.create_time,
|
||||||
|
rf.requester_id as create_by,
|
||||||
|
1 as tenant_id
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE'
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL;
|
||||||
|
|
||||||
|
-- 步骤4: 查看生成的手术医嘱数量
|
||||||
|
-- ============================================================
|
||||||
|
SELECT
|
||||||
|
'生成的手术医嘱数量' as 检查项,
|
||||||
|
COUNT(*) as 数量
|
||||||
|
FROM wor_service_request
|
||||||
|
WHERE category_enum = 4
|
||||||
|
AND delete_flag = '0'
|
||||||
|
AND create_time > CURRENT_TIMESTAMP - INTERVAL '1 hour'; -- 最近1小时生成的
|
||||||
|
|
||||||
|
-- 步骤5: 生成手术收费项目(ChargeItem)
|
||||||
|
-- ============================================================
|
||||||
|
-- 先创建临时表存储新生成的ServiceRequest
|
||||||
|
CREATE TEMPORARY TABLE temp_new_service_requests AS
|
||||||
|
SELECT
|
||||||
|
sr.id as service_request_id,
|
||||||
|
sr.bus_no,
|
||||||
|
sr.prescription_no,
|
||||||
|
sr.patient_id,
|
||||||
|
sr.encounter_id,
|
||||||
|
sr.requester_id,
|
||||||
|
sr.create_time,
|
||||||
|
sr.org_id,
|
||||||
|
sr.content_json
|
||||||
|
FROM wor_service_request sr
|
||||||
|
WHERE sr.category_enum = 4
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
AND sr.create_time > CURRENT_TIMESTAMP - INTERVAL '1 hour'; -- 最近1小时生成的
|
||||||
|
|
||||||
|
-- 插入手术费用收费项目
|
||||||
|
INSERT INTO adm_charge_item (
|
||||||
|
bus_no,
|
||||||
|
status_enum,
|
||||||
|
generate_source_enum,
|
||||||
|
patient_id,
|
||||||
|
context_enum,
|
||||||
|
encounter_id,
|
||||||
|
enterer_id,
|
||||||
|
entered_date,
|
||||||
|
service_table,
|
||||||
|
service_id,
|
||||||
|
product_table,
|
||||||
|
requesting_org_id,
|
||||||
|
quantity_value,
|
||||||
|
quantity_unit,
|
||||||
|
unit_price,
|
||||||
|
total_price,
|
||||||
|
delete_flag,
|
||||||
|
create_time,
|
||||||
|
create_by,
|
||||||
|
tenant_id
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'CI' || t.bus_no as bus_no,
|
||||||
|
1 as status_enum, -- 1-草稿
|
||||||
|
1 as generate_source_enum, -- 1-医生处方
|
||||||
|
t.patient_id,
|
||||||
|
3 as context_enum, -- 3-诊疗
|
||||||
|
t.encounter_id,
|
||||||
|
t.requester_id as enterer_id,
|
||||||
|
t.create_time as entered_date,
|
||||||
|
'wor_service_request' as service_table,
|
||||||
|
t.service_request_id as service_id,
|
||||||
|
'wor_activity_definition' as product_table,
|
||||||
|
t.org_id as requesting_org_id,
|
||||||
|
1 as quantity_value,
|
||||||
|
'次' as quantity_unit,
|
||||||
|
COALESCE((t.content_json::jsonb->>'surgeryFee')::numeric, 0) as unit_price,
|
||||||
|
COALESCE((t.content_json::jsonb->>'surgeryFee')::numeric, 0) as total_price,
|
||||||
|
'0' as delete_flag,
|
||||||
|
t.create_time,
|
||||||
|
t.requester_id as create_by,
|
||||||
|
1 as tenant_id
|
||||||
|
FROM temp_new_service_requests t
|
||||||
|
WHERE COALESCE((t.content_json::jsonb->>'surgeryFee')::numeric, 0) >= 0;
|
||||||
|
|
||||||
|
-- 插入麻醉费用收费项目(如果有麻醉费用)
|
||||||
|
INSERT INTO adm_charge_item (
|
||||||
|
bus_no,
|
||||||
|
status_enum,
|
||||||
|
generate_source_enum,
|
||||||
|
patient_id,
|
||||||
|
context_enum,
|
||||||
|
encounter_id,
|
||||||
|
enterer_id,
|
||||||
|
entered_date,
|
||||||
|
service_table,
|
||||||
|
service_id,
|
||||||
|
product_table,
|
||||||
|
requesting_org_id,
|
||||||
|
quantity_value,
|
||||||
|
quantity_unit,
|
||||||
|
unit_price,
|
||||||
|
total_price,
|
||||||
|
delete_flag,
|
||||||
|
create_time,
|
||||||
|
create_by,
|
||||||
|
tenant_id
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'CI' || t.bus_no || '_A' as bus_no,
|
||||||
|
1 as status_enum,
|
||||||
|
1 as generate_source_enum,
|
||||||
|
t.patient_id,
|
||||||
|
3 as context_enum,
|
||||||
|
t.encounter_id,
|
||||||
|
t.requester_id as enterer_id,
|
||||||
|
t.create_time as entered_date,
|
||||||
|
'wor_service_request' as service_table,
|
||||||
|
t.service_request_id as service_id,
|
||||||
|
'wor_activity_definition' as product_table,
|
||||||
|
t.org_id as requesting_org_id,
|
||||||
|
1 as quantity_value,
|
||||||
|
'次' as quantity_unit,
|
||||||
|
(t.content_json::jsonb->>'anesthesiaFee')::numeric as unit_price,
|
||||||
|
(t.content_json::jsonb->>'anesthesiaFee')::numeric as total_price,
|
||||||
|
'0' as delete_flag,
|
||||||
|
t.create_time,
|
||||||
|
t.requester_id as create_by,
|
||||||
|
1 as tenant_id
|
||||||
|
FROM temp_new_service_requests t
|
||||||
|
WHERE t.content_json::jsonb->>'anesthesiaFee' IS NOT NULL
|
||||||
|
AND (t.content_json::jsonb->>'anesthesiaFee')::numeric > 0;
|
||||||
|
|
||||||
|
-- 步骤6: 验证修复结果
|
||||||
|
-- ============================================================
|
||||||
|
SELECT
|
||||||
|
'手术医嘱总数' as 检查项,
|
||||||
|
COUNT(*) as 数量
|
||||||
|
FROM wor_service_request
|
||||||
|
WHERE category_enum = 4
|
||||||
|
AND delete_flag = '0';
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
'手术收费项目总数' as 检查项,
|
||||||
|
COUNT(*) as 数量
|
||||||
|
FROM adm_charge_item ci
|
||||||
|
WHERE ci.service_table = 'wor_service_request'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM wor_service_request sr
|
||||||
|
WHERE sr.id = ci.service_id AND sr.category_enum = 4
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 清理临时表
|
||||||
|
DROP TABLE IF EXISTS temp_new_service_requests;
|
||||||
|
|
||||||
|
-- ============================================================
|
||||||
|
-- ✓ 修复完成!
|
||||||
|
-- ============================================================
|
||||||
254
sql/bug_318_repair_historical_data.sql
Normal file
254
sql/bug_318_repair_historical_data.sql
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
-- ========================================================
|
||||||
|
-- Bug #318 历史数据修复脚本
|
||||||
|
-- 为已存在但未生成手术医嘱的手术申请单补齐数据
|
||||||
|
-- ========================================================
|
||||||
|
|
||||||
|
-- 1. 查询所有未生成手术医嘱的手术申请单
|
||||||
|
SELECT
|
||||||
|
rf.id as request_form_id,
|
||||||
|
rf.prescription_no,
|
||||||
|
rf.encounter_id,
|
||||||
|
rf.patient_id,
|
||||||
|
rf.requester_id,
|
||||||
|
rf.create_time,
|
||||||
|
rf.desc_json
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE' -- 手术申请单
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL -- 没有对应的手术医嘱
|
||||||
|
ORDER BY rf.create_time DESC;
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- 2. 修复脚本:为缺失的手术申请单生成手术医嘱
|
||||||
|
-- ========================================================
|
||||||
|
|
||||||
|
-- 创建临时表存储需要修复的数据
|
||||||
|
CREATE TEMPORARY TABLE IF NOT EXISTS temp_surgery_repair AS
|
||||||
|
SELECT
|
||||||
|
rf.id as request_form_id,
|
||||||
|
rf.prescription_no,
|
||||||
|
rf.encounter_id,
|
||||||
|
rf.patient_id,
|
||||||
|
rf.requester_id,
|
||||||
|
rf.create_time,
|
||||||
|
rf.desc_json,
|
||||||
|
rf.org_id
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE'
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL;
|
||||||
|
|
||||||
|
-- 查看需要修复的记录数
|
||||||
|
SELECT COUNT(*) as need_repair_count FROM temp_surgery_repair;
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- 3. 插入手术医嘱(ServiceRequest)
|
||||||
|
-- ========================================================
|
||||||
|
|
||||||
|
INSERT INTO wor_service_request (
|
||||||
|
id,
|
||||||
|
bus_no,
|
||||||
|
prescription_no,
|
||||||
|
status_enum,
|
||||||
|
generate_source_enum,
|
||||||
|
therapy_enum,
|
||||||
|
quantity,
|
||||||
|
unit_code,
|
||||||
|
category_enum,
|
||||||
|
patient_id,
|
||||||
|
requester_id,
|
||||||
|
encounter_id,
|
||||||
|
authored_time,
|
||||||
|
org_id,
|
||||||
|
content_json,
|
||||||
|
delete_flag,
|
||||||
|
create_time,
|
||||||
|
create_by
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
nextval('wor_service_request_id_seq'), -- 使用序列生成ID
|
||||||
|
LPAD(FLOOR(RANDOM() * 10000)::TEXT, 4, '0'), -- 生成4位随机bus_no
|
||||||
|
prescription_no,
|
||||||
|
1, -- status_enum: 1-待签发(DRAFT)
|
||||||
|
1, -- generate_source_enum: 1-医生处方
|
||||||
|
2, -- therapy_enum: 2-临时医嘱(TEMPORARY)
|
||||||
|
1, -- quantity: 1
|
||||||
|
'次', -- unit_code
|
||||||
|
4, -- category_enum: 4-手术
|
||||||
|
patient_id,
|
||||||
|
requester_id,
|
||||||
|
encounter_id,
|
||||||
|
create_time,
|
||||||
|
org_id,
|
||||||
|
CASE
|
||||||
|
WHEN desc_json IS NOT NULL AND desc_json != '' THEN desc_json
|
||||||
|
ELSE NULL
|
||||||
|
END, -- content_json: 存储手术详情
|
||||||
|
'0', -- delete_flag
|
||||||
|
create_time,
|
||||||
|
requester_id
|
||||||
|
FROM temp_surgery_repair;
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- 4. 插入手术收费项目(ChargeItem)
|
||||||
|
-- ========================================================
|
||||||
|
|
||||||
|
-- 首先创建临时表关联新生成的ServiceRequest
|
||||||
|
CREATE TEMPORARY TABLE IF NOT EXISTS temp_new_service_request AS
|
||||||
|
SELECT
|
||||||
|
sr.id as service_request_id,
|
||||||
|
sr.prescription_no,
|
||||||
|
sr.patient_id,
|
||||||
|
sr.encounter_id,
|
||||||
|
sr.requester_id,
|
||||||
|
sr.create_time,
|
||||||
|
sr.org_id,
|
||||||
|
sr.bus_no,
|
||||||
|
t.desc_json
|
||||||
|
FROM wor_service_request sr
|
||||||
|
JOIN temp_surgery_repair t ON t.prescription_no = sr.prescription_no
|
||||||
|
WHERE sr.category_enum = 4
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
AND sr.create_time > NOW() - INTERVAL '1 hour'; -- 只取最近1小时新增的
|
||||||
|
|
||||||
|
-- 插入手术费用收费项目
|
||||||
|
INSERT INTO adm_charge_item (
|
||||||
|
id,
|
||||||
|
bus_no,
|
||||||
|
status_enum,
|
||||||
|
generate_source_enum,
|
||||||
|
patient_id,
|
||||||
|
context_enum,
|
||||||
|
encounter_id,
|
||||||
|
enterer_id,
|
||||||
|
entered_date,
|
||||||
|
service_table,
|
||||||
|
service_id,
|
||||||
|
product_table,
|
||||||
|
requesting_org_id,
|
||||||
|
quantity_value,
|
||||||
|
quantity_unit,
|
||||||
|
unit_price,
|
||||||
|
total_price,
|
||||||
|
delete_flag,
|
||||||
|
create_time,
|
||||||
|
create_by
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
nextval('adm_charge_item_id_seq'),
|
||||||
|
'CI' || bus_no,
|
||||||
|
1, -- status_enum: 1-草稿(DRAFT)
|
||||||
|
1, -- generate_source_enum: 1-医生处方
|
||||||
|
patient_id,
|
||||||
|
3, -- context_enum: 3-诊疗
|
||||||
|
encounter_id,
|
||||||
|
requester_id,
|
||||||
|
create_time,
|
||||||
|
'wor_service_request', -- service_table
|
||||||
|
service_request_id, -- service_id
|
||||||
|
'wor_activity_definition', -- product_table
|
||||||
|
org_id,
|
||||||
|
1, -- quantity_value
|
||||||
|
'次', -- quantity_unit
|
||||||
|
COALESCE(
|
||||||
|
(desc_json::jsonb->>'surgeryFee')::numeric,
|
||||||
|
0
|
||||||
|
), -- unit_price: 从desc_json解析手术费用
|
||||||
|
COALESCE(
|
||||||
|
(desc_json::jsonb->>'surgeryFee')::numeric,
|
||||||
|
0
|
||||||
|
), -- total_price
|
||||||
|
'0',
|
||||||
|
create_time,
|
||||||
|
requester_id
|
||||||
|
FROM temp_new_service_request;
|
||||||
|
|
||||||
|
-- 插入麻醉费用收费项目(如果有麻醉费用)
|
||||||
|
INSERT INTO adm_charge_item (
|
||||||
|
id,
|
||||||
|
bus_no,
|
||||||
|
status_enum,
|
||||||
|
generate_source_enum,
|
||||||
|
patient_id,
|
||||||
|
context_enum,
|
||||||
|
encounter_id,
|
||||||
|
enterer_id,
|
||||||
|
entered_date,
|
||||||
|
service_table,
|
||||||
|
service_id,
|
||||||
|
product_table,
|
||||||
|
requesting_org_id,
|
||||||
|
quantity_value,
|
||||||
|
quantity_unit,
|
||||||
|
unit_price,
|
||||||
|
total_price,
|
||||||
|
delete_flag,
|
||||||
|
create_time,
|
||||||
|
create_by
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
nextval('adm_charge_item_id_seq'),
|
||||||
|
'CI' || bus_no || '_A',
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
patient_id,
|
||||||
|
3,
|
||||||
|
encounter_id,
|
||||||
|
requester_id,
|
||||||
|
create_time,
|
||||||
|
'wor_service_request',
|
||||||
|
service_request_id,
|
||||||
|
'wor_activity_definition',
|
||||||
|
org_id,
|
||||||
|
1,
|
||||||
|
'次',
|
||||||
|
(desc_json::jsonb->>'anesthesiaFee')::numeric,
|
||||||
|
(desc_json::jsonb->>'anesthesiaFee')::numeric,
|
||||||
|
'0',
|
||||||
|
create_time,
|
||||||
|
requester_id
|
||||||
|
FROM temp_new_service_request
|
||||||
|
WHERE desc_json::jsonb->>'anesthesiaFee' IS NOT NULL
|
||||||
|
AND (desc_json::jsonb->>'anesthesiaFee')::numeric > 0;
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- 5. 验证修复结果
|
||||||
|
-- ========================================================
|
||||||
|
|
||||||
|
-- 查看修复后的手术医嘱数量
|
||||||
|
SELECT
|
||||||
|
'修复后的手术医嘱数量' as check_item,
|
||||||
|
COUNT(*) as count
|
||||||
|
FROM wor_service_request sr
|
||||||
|
WHERE sr.category_enum = 4
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM doc_request_form rf
|
||||||
|
WHERE rf.prescription_no = sr.prescription_no
|
||||||
|
AND rf.type_code = 'PROCEDURE'
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 查看修复后的收费项目数量
|
||||||
|
SELECT
|
||||||
|
'修复后的手术收费项目数量' as check_item,
|
||||||
|
COUNT(*) as count
|
||||||
|
FROM adm_charge_item ci
|
||||||
|
WHERE ci.service_table = 'wor_service_request'
|
||||||
|
AND ci.delete_flag = '0'
|
||||||
|
AND EXISTS (
|
||||||
|
SELECT 1 FROM wor_service_request sr
|
||||||
|
WHERE sr.id = ci.service_id
|
||||||
|
AND sr.category_enum = 4
|
||||||
|
);
|
||||||
|
|
||||||
|
-- 清理临时表
|
||||||
|
DROP TABLE IF EXISTS temp_surgery_repair;
|
||||||
|
DROP TABLE IF EXISTS temp_new_service_request;
|
||||||
|
|
||||||
|
-- ========================================================
|
||||||
|
-- 完成!
|
||||||
|
-- ========================================================
|
||||||
17
sql/bug_318_step1_check.sql
Normal file
17
sql/bug_318_step1_check.sql
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
-- Bug #318 历史数据修复 - 步骤1:查询需要修复的手术申请单
|
||||||
|
-- 执行此SQL查看有多少手术申请单需要修复
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
rf.id as request_form_id,
|
||||||
|
rf.prescription_no as 手术单号,
|
||||||
|
rf.encounter_id as 就诊ID,
|
||||||
|
rf.patient_id as 患者ID,
|
||||||
|
rf.create_time as 申请时间,
|
||||||
|
SUBSTRING(rf.desc_json::text, 1, 100) as 手术信息预览
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE' -- 手术申请单
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL -- 没有对应的手术医嘱
|
||||||
|
ORDER BY rf.create_time DESC;
|
||||||
159
sql/bug_318_step2_repair.sql
Normal file
159
sql/bug_318_step2_repair.sql
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
-- Bug #318 历史数据修复 - 步骤2:执行修复
|
||||||
|
-- ⚠️ 请在执行前备份数据库!
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 步骤 2.1: 创建临时表存储需要修复的手术申请单
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
CREATE TEMPORARY TABLE temp_repair_list AS
|
||||||
|
SELECT
|
||||||
|
rf.id as request_form_id,
|
||||||
|
rf.prescription_no,
|
||||||
|
rf.encounter_id,
|
||||||
|
rf.patient_id,
|
||||||
|
rf.requester_id,
|
||||||
|
rf.create_time,
|
||||||
|
rf.org_id,
|
||||||
|
rf.desc_json
|
||||||
|
FROM doc_request_form rf
|
||||||
|
LEFT JOIN wor_service_request sr ON sr.prescription_no = rf.prescription_no
|
||||||
|
AND sr.delete_flag = '0'
|
||||||
|
WHERE rf.type_code = 'PROCEDURE'
|
||||||
|
AND rf.delete_flag = '0'
|
||||||
|
AND sr.id IS NULL;
|
||||||
|
|
||||||
|
-- 查看需要修复的记录数
|
||||||
|
SELECT COUNT(*) as 需要修复的记录数 FROM temp_repair_list;
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 步骤 2.2: 生成手术医嘱(ServiceRequest)
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
INSERT INTO wor_service_request (
|
||||||
|
bus_no,
|
||||||
|
prescription_no,
|
||||||
|
status_enum,
|
||||||
|
generate_source_enum,
|
||||||
|
therapy_enum,
|
||||||
|
quantity,
|
||||||
|
unit_code,
|
||||||
|
category_enum,
|
||||||
|
patient_id,
|
||||||
|
requester_id,
|
||||||
|
encounter_id,
|
||||||
|
authored_time,
|
||||||
|
org_id,
|
||||||
|
content_json,
|
||||||
|
delete_flag,
|
||||||
|
create_time,
|
||||||
|
create_by,
|
||||||
|
tenant_id
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
LPAD(FLOOR(RANDOM() * 10000)::TEXT, 4, '0'),
|
||||||
|
prescription_no,
|
||||||
|
1, -- 待签发
|
||||||
|
1, -- 医生处方
|
||||||
|
2, -- 临时医嘱
|
||||||
|
1,
|
||||||
|
'次',
|
||||||
|
4, -- 手术
|
||||||
|
patient_id,
|
||||||
|
requester_id,
|
||||||
|
encounter_id,
|
||||||
|
create_time,
|
||||||
|
org_id,
|
||||||
|
desc_json,
|
||||||
|
'0',
|
||||||
|
create_time,
|
||||||
|
requester_id,
|
||||||
|
1 -- tenant_id
|
||||||
|
FROM temp_repair_list;
|
||||||
|
|
||||||
|
-- 查看生成的手术医嘱数量
|
||||||
|
SELECT '生成的手术医嘱数量' as 检查项, COUNT(*) as 数量
|
||||||
|
FROM wor_service_request
|
||||||
|
WHERE prescription_no IN (SELECT prescription_no FROM temp_repair_list);
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 步骤 2.3: 生成手术收费项目(ChargeItem)
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
-- 获取刚生成的ServiceRequest
|
||||||
|
CREATE TEMPORARY TABLE temp_new_requests AS
|
||||||
|
SELECT
|
||||||
|
sr.id as service_request_id,
|
||||||
|
sr.prescription_no,
|
||||||
|
sr.patient_id,
|
||||||
|
sr.encounter_id,
|
||||||
|
sr.requester_id,
|
||||||
|
sr.create_time,
|
||||||
|
sr.org_id,
|
||||||
|
sr.bus_no,
|
||||||
|
t.desc_json
|
||||||
|
FROM wor_service_request sr
|
||||||
|
JOIN temp_repair_list t ON t.prescription_no = sr.prescription_no
|
||||||
|
WHERE sr.category_enum = 4
|
||||||
|
AND sr.delete_flag = '0';
|
||||||
|
|
||||||
|
-- 插入手术费用
|
||||||
|
INSERT INTO adm_charge_item (
|
||||||
|
bus_no,
|
||||||
|
status_enum,
|
||||||
|
generate_source_enum,
|
||||||
|
patient_id,
|
||||||
|
context_enum,
|
||||||
|
encounter_id,
|
||||||
|
enterer_id,
|
||||||
|
entered_date,
|
||||||
|
service_table,
|
||||||
|
service_id,
|
||||||
|
product_table,
|
||||||
|
requesting_org_id,
|
||||||
|
quantity_value,
|
||||||
|
quantity_unit,
|
||||||
|
unit_price,
|
||||||
|
total_price,
|
||||||
|
delete_flag,
|
||||||
|
create_time,
|
||||||
|
create_by,
|
||||||
|
tenant_id
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
'CI' || bus_no,
|
||||||
|
1, -- 草稿
|
||||||
|
1, -- 医生处方
|
||||||
|
patient_id,
|
||||||
|
3, -- 诊疗
|
||||||
|
encounter_id,
|
||||||
|
requester_id,
|
||||||
|
create_time,
|
||||||
|
'wor_service_request',
|
||||||
|
service_request_id,
|
||||||
|
'wor_activity_definition',
|
||||||
|
org_id,
|
||||||
|
1,
|
||||||
|
'次',
|
||||||
|
COALESCE((desc_json::jsonb->>'surgeryFee')::numeric, 0),
|
||||||
|
COALESCE((desc_json::jsonb->>'surgeryFee')::numeric, 0),
|
||||||
|
'0',
|
||||||
|
create_time,
|
||||||
|
requester_id,
|
||||||
|
1
|
||||||
|
FROM temp_new_requests;
|
||||||
|
|
||||||
|
-- 查看生成的收费项目数量
|
||||||
|
SELECT '生成的手术收费项目数量' as 检查项, COUNT(*) as 数量
|
||||||
|
FROM adm_charge_item
|
||||||
|
WHERE service_id IN (SELECT service_request_id FROM temp_new_requests);
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 步骤 2.4: 清理临时表
|
||||||
|
-- =====================================================
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS temp_repair_list;
|
||||||
|
DROP TABLE IF EXISTS temp_new_requests;
|
||||||
|
|
||||||
|
-- =====================================================
|
||||||
|
-- 完成!
|
||||||
|
-- =====================================================
|
||||||
Reference in New Issue
Block a user