fix(consultation): 解决会诊流程中的多个功能问题

- 在 deptappthoursManage.js 中添加 status 参数以仅获取已启动的机构
- 为 consultationapplication 组件添加已确认和已签名状态选项
- 扩展操作列宽度并添加打印功能按钮
- 优化 handlePrint 方法以支持行参数和性别枚举转换
- 为 consultationconfirmation 组件添加必填验证和编辑权限控制
- 修复会诊确认医师信息回显逻辑
- 在 inspectionApplication 组件中修复表格行点击事件和检验项目加载
- 禁用非紧急标记的编辑权限以解决Bug #268
- 为 surgeryApplication 组件添加响应码验证和错误处理
- 在 consultation 组件中添加表单验证清除功能
- 为 PackageManagement 组件实现动态机构选项加载
- 重构 PackageSettings 组件的套餐金额显示和只读模式
- 为检查项目设置组件添加套餐筛选和下级类型选择功能
- 实现检验套餐的编辑和查看模式切换功能
This commit is contained in:
2026-03-26 18:22:21 +08:00
parent c509a804ec
commit 91a0b48662
20 changed files with 631 additions and 266 deletions

View File

@@ -260,7 +260,10 @@ public class DoctorScheduleAppServiceImpl implements IDoctorScheduleAppService {
|| doctorSchedule.getLimitNumber() != null
|| doctorSchedule.getStopReason() != null
|| doctorSchedule.getRegType() != null
|| doctorSchedule.getRegisterFee() != null;
|| doctorSchedule.getRegisterFee() != null
|| doctorSchedule.getRegisterItem() != null
|| doctorSchedule.getDiagnosisItem() != null
|| doctorSchedule.getDiagnosisFee() != null;
if (needSyncPool) {
schedulePoolService.lambdaUpdate()
@@ -277,6 +280,7 @@ public class DoctorScheduleAppServiceImpl implements IDoctorScheduleAppService {
.set(doctorSchedule.getRegisterFee() != null, SchedulePool::getFee, Double.valueOf(doctorSchedule.getRegisterFee().toString()))
.set(doctorSchedule.getRegisterFee() != null, SchedulePool::getInsurancePrice,
Double.valueOf(doctorSchedule.getRegisterFee().toString()))
.set(doctorSchedule.getRegisterItem() != null, SchedulePool::getRegType, doctorSchedule.getRegisterItem())
.update();
}

View File

@@ -24,5 +24,5 @@ public interface ICheckMethodAppService{
R<?> searchCheckMethodList(Integer pageNo, Integer pageSize, String checkType, String name, String packageName);
R<?> exportCheckMethod(String checkType, String name, String packageName, HttpServletResponse response);
void exportCheckMethod(String checkType, String name, String packageName, HttpServletResponse response);
}

View File

@@ -16,5 +16,5 @@ public interface ICheckPartAppService {
R<?> searchCheckPartList(Integer pageNo, Integer pageSize, String checkType, String name, String packageName);
R<?> exportCheckPart(String checkType, String name, String packageName, HttpServletResponse response);
void exportCheckPart(String checkType, String name, String packageName, HttpServletResponse response);
}

View File

@@ -89,7 +89,7 @@ public class CheckMethodAppServiceImpl implements ICheckMethodAppService {
}
@Override
public R<?> exportCheckMethod(String checkType, String name, String packageName, HttpServletResponse response) {
public void exportCheckMethod(String checkType, String name, String packageName, HttpServletResponse response) {
LambdaQueryWrapper<CheckMethod> wrapper = new LambdaQueryWrapper<>();
if (checkType != null && ObjectUtil.isNotEmpty(checkType)) {
wrapper.eq(CheckMethod::getCheckType, checkType);
@@ -103,7 +103,13 @@ public class CheckMethodAppServiceImpl implements ICheckMethodAppService {
List<CheckMethod> list = checkMethodService.list(wrapper);
if (list.isEmpty()) {
return R.fail("导出Excel失败,无数据。");
try {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":500,\"msg\":\"导出Excel失败,无数据。\"}");
} catch (IOException e) {
log.error("写入响应失败", e);
}
return;
}
try {
@@ -123,9 +129,12 @@ public class CheckMethodAppServiceImpl implements ICheckMethodAppService {
ExcelFillerUtil.makeExcelFile(response, list, headers, excelName, null);
} catch (IOException | IllegalAccessException e) {
log.error("导出Excel失败", e);
return R.fail("导出Excel失败" + e.getMessage());
try {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":500,\"msg\":\"导出Excel失败" + e.getMessage() + "\"}");
} catch (IOException ex) {
log.error("写入响应失败", ex);
}
}
return R.ok(null, "导出Excel成功");
}
}

View File

@@ -22,7 +22,7 @@ import java.util.List;
import java.util.stream.Collectors;
/**
* 检查套餐AppService实现
* 检查套餐 AppService 实现
*
* @author system
* @date 2025-11-26
@@ -35,6 +35,32 @@ public class CheckPackageAppServiceImpl implements ICheckPackageAppService {
private final ICheckPackageService checkPackageService;
private final ICheckPackageDetailService checkPackageDetailService;
/**
* 转换明细 DTO 列表为实体列表
* @param detailDtos 明细 DTO 列表
* @param packageId 套餐 ID
* @param orderNumStart 起始序号
* @return 明细实体列表
*/
private List<CheckPackageDetail> convertToDetails(List<CheckPackageDetailDto> detailDtos, Long packageId, int orderNumStart) {
if (detailDtos == null || detailDtos.isEmpty()) {
return new ArrayList<>();
}
List<CheckPackageDetail> details = new ArrayList<>();
int orderNum = orderNumStart;
for (CheckPackageDetailDto detailDto : detailDtos) {
CheckPackageDetail detail = new CheckPackageDetail();
BeanUtils.copyProperties(detailDto, detail);
detail.setPackageId(packageId);
detail.setOrderNum(orderNum++);
detail.setCreateTime(LocalDateTime.now());
detail.setUpdateTime(LocalDateTime.now());
details.add(detail);
}
return details;
}
@Override
public R<?> getCheckPackageList() {
try {
@@ -61,7 +87,7 @@ public class CheckPackageAppServiceImpl implements ICheckPackageAppService {
.orderByAsc(CheckPackageDetail::getOrderNum)
);
// 转换为DTO
// 转换为 DTO
CheckPackageDto dto = new CheckPackageDto();
BeanUtils.copyProperties(checkPackage, dto);
@@ -101,17 +127,7 @@ public class CheckPackageAppServiceImpl implements ICheckPackageAppService {
// 保存套餐明细
if (checkPackageDto.getItems() != null && !checkPackageDto.getItems().isEmpty()) {
List<CheckPackageDetail> details = new ArrayList<>();
int orderNum = 1;
for (CheckPackageDetailDto detailDto : checkPackageDto.getItems()) {
CheckPackageDetail detail = new CheckPackageDetail();
BeanUtils.copyProperties(detailDto, detail);
detail.setPackageId(checkPackage.getId());
detail.setOrderNum(orderNum++);
detail.setCreateTime(LocalDateTime.now());
detail.setUpdateTime(LocalDateTime.now());
details.add(detail);
}
List<CheckPackageDetail> details = convertToDetails(checkPackageDto.getItems(), checkPackage.getId(), 1);
checkPackageDetailService.saveBatch(details);
}
@@ -119,10 +135,10 @@ public class CheckPackageAppServiceImpl implements ICheckPackageAppService {
} catch (Exception e) {
log.error("新增检查套餐失败", e);
// 捕获PostgreSQL唯一约束冲突异常
// 捕获 PostgreSQL 唯一约束冲突异常
String errorMessage = e.getMessage();
if (errorMessage != null) {
// PostgreSQL唯一约束错误通常包含 "duplicate key value" 或约束名称
// PostgreSQL 唯一约束错误通常包含 "duplicate key value" 或约束名称
if (errorMessage.contains("duplicate key value") ||
errorMessage.contains("违反唯一约束") ||
errorMessage.contains("unique constraint")) {
@@ -135,7 +151,7 @@ public class CheckPackageAppServiceImpl implements ICheckPackageAppService {
}
}
return R.fail("新增检查套餐失败: " + errorMessage);
return R.fail("新增检查套餐失败" + errorMessage);
}
}
@@ -170,24 +186,14 @@ public class CheckPackageAppServiceImpl implements ICheckPackageAppService {
// 保存新的套餐明细
if (checkPackageDto.getItems() != null && !checkPackageDto.getItems().isEmpty()) {
List<CheckPackageDetail> details = new ArrayList<>();
int orderNum = 1;
for (CheckPackageDetailDto detailDto : checkPackageDto.getItems()) {
CheckPackageDetail detail = new CheckPackageDetail();
BeanUtils.copyProperties(detailDto, detail);
detail.setPackageId(checkPackage.getId());
detail.setOrderNum(orderNum++);
detail.setCreateTime(LocalDateTime.now());
detail.setUpdateTime(LocalDateTime.now());
details.add(detail);
}
List<CheckPackageDetail> details = convertToDetails(checkPackageDto.getItems(), checkPackage.getId(), 1);
checkPackageDetailService.saveBatch(details);
}
return R.ok("更新成功");
} catch (Exception e) {
log.error("更新检查套餐失败", e);
return R.fail("更新检查套餐失败: " + e.getMessage());
return R.fail("更新检查套餐失败" + e.getMessage());
}
}
@@ -201,11 +207,14 @@ public class CheckPackageAppServiceImpl implements ICheckPackageAppService {
return R.fail("套餐不存在");
}
// 删除套餐明细
checkPackageDetailService.remove(
// 删除套餐明细 - 先删除子表数据
boolean removeDetailsResult = checkPackageDetailService.remove(
new LambdaQueryWrapper<CheckPackageDetail>()
.eq(CheckPackageDetail::getPackageId, id)
);
if (!removeDetailsResult) {
log.warn("删除套餐明细失败,套餐 ID: {}", id);
}
// 删除套餐主表
boolean deleteResult = checkPackageService.removeById(id);
@@ -213,11 +222,11 @@ public class CheckPackageAppServiceImpl implements ICheckPackageAppService {
return R.fail("删除套餐失败");
}
log.info("删除检查套餐成功,套餐 ID: {}", id);
return R.ok("删除成功");
} catch (Exception e) {
log.error("删除检查套餐失败", e);
return R.fail("删除检查套餐失败: " + e.getMessage());
return R.fail("删除检查套餐失败" + e.getMessage());
}
}
}

View File

@@ -65,7 +65,7 @@ public class CheckPartAppServiceImpl implements ICheckPartAppService {
}
@Override
public R<?> exportCheckPart(String checkType, String name, String packageName, HttpServletResponse response) {
public void exportCheckPart(String checkType, String name, String packageName, HttpServletResponse response) {
LambdaQueryWrapper<CheckPart> wrapper = new LambdaQueryWrapper<>();
if (checkType != null && ObjectUtil.isNotEmpty(checkType)) {
wrapper.eq(CheckPart::getCheckType, checkType);
@@ -79,7 +79,13 @@ public class CheckPartAppServiceImpl implements ICheckPartAppService {
List<CheckPart> list = checkPartService.list(wrapper);
if (list.isEmpty()) {
return R.fail("导出Excel失败,无数据。");
try {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":500,\"msg\":\"导出Excel失败,无数据。\"}");
} catch (IOException e) {
log.error("写入响应失败", e);
}
return;
}
try {
@@ -102,8 +108,12 @@ public class CheckPartAppServiceImpl implements ICheckPartAppService {
ExcelFillerUtil.makeExcelFile(response, list, headers, excelName, null);
} catch (IOException | IllegalAccessException e) {
log.error("导出Excel失败", e);
return R.fail("导出Excel失败" + e.getMessage());
try {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write("{\"code\":500,\"msg\":\"导出Excel失败" + e.getMessage() + "\"}");
} catch (IOException ex) {
log.error("写入响应失败", ex);
}
}
return R.ok(null, "导出Excel成功");
}
}

View File

@@ -1,5 +1,6 @@
package com.openhis.web.clinicalmanage.appservice.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
@@ -7,6 +8,8 @@ import com.core.common.core.domain.model.LoginUser;
import com.core.common.utils.SecurityUtils;
import com.openhis.administration.domain.Patient;
import com.openhis.administration.service.IPatientService;
import com.openhis.clinical.domain.Surgery;
import com.openhis.clinical.service.ISurgeryService;
import com.openhis.surgicalschedule.domain.OpSchedule;
import com.openhis.surgicalschedule.service.IOpScheduleService;
import com.openhis.web.clinicalmanage.appservice.ISurgicalScheduleAppService;
@@ -47,6 +50,9 @@ public class SurgicalScheduleAppServiceImpl implements ISurgicalScheduleAppServi
@Resource
private SurgicalScheduleAppMapper surgicalScheduleAppMapper;
@Resource
private ISurgeryService surgeryService;
@Resource
private RequestFormManageAppMapper requestFormManageAppMapper;
@@ -183,12 +189,30 @@ public class SurgicalScheduleAppServiceImpl implements ISurgicalScheduleAppServi
// 保存手术安排
boolean saved = opScheduleService.save(opSchedule);
//修改申请单状态为已排期
if (!saved) {
return R.fail("新增手术安排失败");
}
// Bug #247 修复:更新手术申请单状态为已排期 (1)
if (opCreateScheduleDto.getApplyId() != null) {
try {
// 通过手术单号查找手术申请记录并更新状态
LambdaQueryWrapper<com.openhis.clinical.domain.Surgery> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(com.openhis.clinical.domain.Surgery::getSurgeryNo, opSchedule.getOperCode())
.eq(com.openhis.clinical.domain.Surgery::getDeleteFlag, "0");
com.openhis.clinical.domain.Surgery surgery = surgeryService.getOne(queryWrapper);
if (surgery != null) {
surgery.setStatusEnum(1); // 1 = 已排期
surgery.setUpdateTime(new Date());
surgeryService.updateById(surgery);
log.info("更新手术申请单状态为已排期 - surgeryNo: {}, surgeryId: {}", opSchedule.getOperCode(), surgery.getId());
}
} catch (Exception e) {
log.error("更新手术申请单状态失败 - operCode: {}", opSchedule.getOperCode(), e);
// 状态更新失败不影响主流程,只记录日志
}
}
return R.ok("新增手术安排成功");
}

View File

@@ -85,6 +85,7 @@
cs.apply_dept_id,
cs.apply_dept_name,
cs.surgery_type_enum,
cs.status_enum,
fc.contract_name AS fee_type
FROM doc_request_form drf
LEFT JOIN cli_surgery cs ON cs.surgery_no = drf.prescription_no
@@ -106,6 +107,8 @@
AND cs.apply_dept_id = #{requestFormDto.applyDeptId}
</if>
AND drf.delete_flag = '0'
<!-- Bug #249 修复:过滤掉已取消状态的手术申请 -->
AND (cs.status_enum IS NULL OR cs.status_enum != 4)
</where>
ORDER BY drf.create_time DESC
</select>