diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/DoctorScheduleAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/DoctorScheduleAppServiceImpl.java index c628202a..68e313a7 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/DoctorScheduleAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/DoctorScheduleAppServiceImpl.java @@ -118,6 +118,7 @@ public class DoctorScheduleAppServiceImpl implements IDoctorScheduleAppService { newSchedule.setIsStopped(doctorSchedule.getIsStopped() != null ? doctorSchedule.getIsStopped() : false); newSchedule.setStopReason(doctorSchedule.getStopReason() != null ? doctorSchedule.getStopReason() : ""); newSchedule.setDeptId(doctorSchedule.getDeptId()); + newSchedule.setRegType(doctorSchedule.getRegType() != null ? doctorSchedule.getRegType() : 0); newSchedule.setDoctorId(doctorSchedule.getDoctorId()); // 不设置id字段,让数据库自动生成 @@ -183,6 +184,7 @@ public class DoctorScheduleAppServiceImpl implements IDoctorScheduleAppService { newSchedule.setIsStopped(doctorSchedule.getIsStopped() != null ? doctorSchedule.getIsStopped() : false); newSchedule.setStopReason(doctorSchedule.getStopReason() != null ? doctorSchedule.getStopReason() : ""); newSchedule.setDeptId(doctorSchedule.getDeptId()); + newSchedule.setRegType(doctorSchedule.getRegType() != null ? doctorSchedule.getRegType() : 0); newSchedule.setDoctorId(doctorSchedule.getDoctorId()); // 不设置id字段,让数据库自动生成 @@ -213,14 +215,48 @@ public class DoctorScheduleAppServiceImpl implements IDoctorScheduleAppService { } } + @Transactional @Override public R updateDoctorSchedule(DoctorSchedule doctorSchedule) { if (ObjectUtil.isEmpty(doctorSchedule) || ObjectUtil.isEmpty(doctorSchedule.getId())) { return R.fail("医生排班ID不能为空"); } - // 注意:此为核心更新,暂未处理号源池和号源槽的同步更新 + int result = doctorScheduleMapper.updateDoctorSchedule(doctorSchedule); - return result > 0 ? R.ok(result) : R.fail("更新排班信息失败"); + if (result <= 0) { + return R.fail("更新排班信息失败"); + } + + // 同步更新号源池,避免查询联表时医生/诊室等字段看起来“未更新” + boolean needSyncPool = doctorSchedule.getDoctorId() != null + || doctorSchedule.getDoctor() != null + || doctorSchedule.getClinic() != null + || doctorSchedule.getStartTime() != null + || doctorSchedule.getEndTime() != null + || doctorSchedule.getLimitNumber() != null + || doctorSchedule.getStopReason() != null + || doctorSchedule.getRegType() != null + || doctorSchedule.getRegisterFee() != null; + + if (needSyncPool) { + schedulePoolService.lambdaUpdate() + .eq(SchedulePool::getScheduleId, doctorSchedule.getId()) + .set(doctorSchedule.getDoctorId() != null, SchedulePool::getDoctorId, doctorSchedule.getDoctorId()) + .set(doctorSchedule.getDoctor() != null, SchedulePool::getDoctorName, doctorSchedule.getDoctor()) + .set(doctorSchedule.getClinic() != null, SchedulePool::getClinicRoom, doctorSchedule.getClinic()) + .set(doctorSchedule.getStartTime() != null, SchedulePool::getStartTime, doctorSchedule.getStartTime()) + .set(doctorSchedule.getEndTime() != null, SchedulePool::getEndTime, doctorSchedule.getEndTime()) + .set(doctorSchedule.getLimitNumber() != null, SchedulePool::getTotalQuota, + doctorSchedule.getLimitNumber()) + .set(doctorSchedule.getStopReason() != null, SchedulePool::getStopReason, doctorSchedule.getStopReason()) + .set(doctorSchedule.getRegType() != null, SchedulePool::getRegType, String.valueOf(doctorSchedule.getRegType())) + .set(doctorSchedule.getRegisterFee() != null, SchedulePool::getFee, doctorSchedule.getRegisterFee() / 100.0) + .set(doctorSchedule.getRegisterFee() != null, SchedulePool::getInsurancePrice, + doctorSchedule.getRegisterFee() / 100.0) + .update(); + } + + return R.ok(result); } /** diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/controller/DoctorScheduleController.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/controller/DoctorScheduleController.java index 2a7e8bf6..57d102d8 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/controller/DoctorScheduleController.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/controller/DoctorScheduleController.java @@ -53,7 +53,6 @@ public class DoctorScheduleController { /* * 新增医生排班(带具体日期) - * * */ @PostMapping("/add-with-date") public R addDoctorScheduleWithDate(@RequestBody DoctorSchedule doctorSchedule) { @@ -77,7 +76,7 @@ public class DoctorScheduleController { * */ @DeleteMapping("/delete/{doctorScheduleId}") public R removeDoctorSchedule(@PathVariable Integer doctorScheduleId){ - return R.ok(doctorScheduleAppService.removeDoctorSchedule(doctorScheduleId)); + return doctorScheduleAppService.removeDoctorSchedule(doctorScheduleId); } /* diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationAppServiceImpl.java index 5c50cccf..a2f6e6be 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/appservice/impl/OrganizationAppServiceImpl.java @@ -1,12 +1,14 @@ package com.openhis.web.basedatamanage.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; import com.core.common.utils.AssignSeqUtil; import com.core.common.utils.MessageUtils; import com.core.common.utils.StringUtils; import com.openhis.administration.domain.Organization; +import com.openhis.administration.mapper.OrganizationMapper; import com.openhis.administration.service.IOrganizationService; import com.openhis.common.constant.CommonConstants; import com.openhis.common.constant.PromptMsgConstant; @@ -35,12 +37,15 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { @Resource private AssignSeqUtil assignSeqUtil; + @Resource + private OrganizationMapper organizationMapper; + @Override public Page getOrganizationTree(Integer pageNo, Integer pageSize, String name, Integer typeEnum, List classEnumList, String sortField, String sortOrder, HttpServletRequest request) { - // 使用Page对象进行分页查询 + // 使用 Page 对象进行分页查询 Page page = new Page<>(pageNo, pageSize); // 创建查询条件 @@ -54,7 +59,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { queryWrapper.eq(Organization::getTypeEnum, typeEnum); } if (classEnumList != null && !classEnumList.isEmpty()) { - // 使用OR条件来匹配class_enum字段中包含任一值的记录 + // 使用 OR 条件来匹配 class_enum 字段中包含任一值的记录 queryWrapper.and(wrapper -> { for (int i = 0; i < classEnumList.size(); i++) { String classEnum = classEnumList.get(i); @@ -63,18 +68,18 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { wrapper.and(subWrapper -> { subWrapper.eq(Organization::getClassEnum, classEnum) // 精确匹配 .or() // 或者 - .likeRight(Organization::getClassEnum, classEnum + ",") // 以"值,"开头 + .likeRight(Organization::getClassEnum, classEnum + ",") // 以"值,"开头 .or() // 或者 .likeLeft(Organization::getClassEnum, "," + classEnum) // 以",值"结尾 .or() // 或者 .like(Organization::getClassEnum, "," + classEnum + ","); // 在中间,被逗号包围 }); } else { - // 后续条件使用OR连接 + // 后续条件使用 OR 连接 wrapper.or(subWrapper -> { subWrapper.eq(Organization::getClassEnum, classEnum) // 精确匹配 .or() // 或者 - .likeRight(Organization::getClassEnum, classEnum + ",") // 以"值,"开头 + .likeRight(Organization::getClassEnum, classEnum + ",") // 以"值,"开头 .or() // 或者 .likeLeft(Organization::getClassEnum, "," + classEnum) // 以",值"结尾 .or() // 或者 @@ -88,7 +93,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { // 执行分页查询 Page resultPage = organizationService.page(page, queryWrapper); - // 将查询结果转为DTO并构建树结构 + // 将查询结果转为 DTO 并构建树结构 List organizationList = resultPage.getRecords(); List orgTree = buildTree(organizationList); @@ -109,7 +114,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { * @return tree */ private List buildTree(List records) { - // 按b_no的层级排序,确保父节点先处理 + // 按 b_no 的层级排序,确保父节点先处理 List sortedRecords = records.stream() .sorted(Comparator.comparingInt(r -> r.getBusNo().split("\\.").length)).collect(Collectors.toList()); @@ -131,7 +136,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { // 根节点 tree.add(node); } else { - // 获取父节点的b_no(去掉最后一部分) + // 获取父节点的 b_no(去掉最后一部分) String parentBNo = String.join(".", Arrays.copyOf(parts, parts.length - 1)); OrganizationDto parent = nodeMap.get(parentBNo); @@ -149,7 +154,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { /** * 机构信息详情 * - * @param orgId 机构信息id + * @param orgId 机构信息 id * @return 机构信息详情 */ @Override @@ -159,7 +164,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { return R.fail(MessageUtils.createMessage(PromptMsgConstant.Common.M00006, new Object[] { "机构信息" })); } - // 转换为DTO对象,确保数据格式一致 + // 转换为 DTO 对象,确保数据格式一致 OrganizationDto organizationDto = new OrganizationDto(); BeanUtils.copyProperties(organization, organizationDto); organizationDto @@ -181,7 +186,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { @Override public R addOrEditOrganization(OrganizationDto organizationDto) { - // 新增organization信息 + // 新增 organization 信息 Organization organization = new Organization(); BeanUtils.copyProperties(organizationDto, organization); @@ -191,9 +196,9 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { } else { // 活动标识:有效 organization.setActiveFlag(AccountStatus.ACTIVE.getValue()); - // 采番bus_no三位 + // 采番 bus_no 三位 String code = assignSeqUtil.getSeq(AssignSeqEnum.ORGANIZATION_BUS_NO.getPrefix(), 3); - // 如果传了上级科室 把当前的code拼到后边 + // 如果传了上级科室 把当前的 code 拼到后边 if (StringUtils.isNotEmpty(organization.getBusNo())) { organization.setBusNo(String.format(CommonConstants.Common.MONTAGE_FORMAT, organization.getBusNo(), CommonConstants.Common.POINT, code)); @@ -203,7 +208,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { // 生成待发送的机构信息 organizationService.save(organization); } - // 返回机构id + // 返回机构 id return R.ok(organization.getId(), MessageUtils.createMessage(PromptMsgConstant.Common.M00004, new Object[] { "机构信息更新添加" })); } @@ -211,7 +216,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { /** * 删除机构 * - * @param orgIds 机构信息id + * @param orgIds 机构信息 id * @return 操作结果 */ @Override @@ -232,7 +237,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { /** * 机构启用 * - * @param orgId 机构信息id + * @param orgId 机构信息 id * @return 操作结果 */ @Override @@ -247,7 +252,7 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { /** * 机构停用 * - * @param orgId 机构信息id + * @param orgId 机构信息 id * @return 操作结果 */ @Override @@ -299,38 +304,27 @@ public class OrganizationAppServiceImpl implements IOrganizationAppService { */ @Override public R getRegisterOrganizations(Integer pageNo, Integer pageSize, String name, String orgName) { - // 使用Page对象进行分页查询 + // 使用 Page 对象进行分页查询 Page page = new Page<>(pageNo != null ? pageNo : 1, pageSize != null ? pageSize : 10); - // 创建查询条件,只查询register_flag为1的组织机构 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(Organization::getRegisterFlag, 1); // 只获取挂号科室 - queryWrapper.eq(Organization::getDeleteFlag, "0"); // 确保未删除 + // 使用 Mapper 方法关联查询 sys_tenant 表获取租户名称 + IPage resultPage = organizationMapper.selectRegisterOrganizationsWithTenant( + page, + 1, // register_flag = 1 + "0", // delete_flag = '0' + name, + orgName + ); - // 添加名称过滤条件 - if (StringUtils.isNotEmpty(name)) { - queryWrapper.like(Organization::getName, name); - } - - // 如果有机构名称筛选 - if (StringUtils.isNotEmpty(orgName)) { - // 这里假设 orgName 是父机构名称,如果需要更复杂的关联查询可在此扩展 - // 当前逻辑暂保持与原逻辑一致的过滤方式或根据需求调整 - } - - // 按编码排序 - queryWrapper.orderByAsc(Organization::getBusNo); - - // 执行分页查询 - Page resultPage = organizationService.page(page, queryWrapper); - - // 转换为DTO对象并设置字典文本 + // 转换为 DTO 对象并设置字典文本 List organizationDtoList = resultPage.getRecords().stream().map(org -> { OrganizationDto dto = new OrganizationDto(); BeanUtils.copyProperties(org, dto); dto.setTypeEnum_dictText(EnumUtils.getInfoByValue(OrganizationType.class, dto.getTypeEnum())); dto.setClassEnum_dictText(formatClassEnumDictText(dto.getClassEnum())); dto.setActiveFlag_dictText(EnumUtils.getInfoByValue(AccountStatus.class, dto.getActiveFlag())); + // 设置租户名称 + dto.setOrgName(org.getTenantName()); return dto; }).collect(Collectors.toList()); diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/dto/OrganizationDto.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/dto/OrganizationDto.java index 28a17579..43ef819c 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/dto/OrganizationDto.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/basedatamanage/dto/OrganizationDto.java @@ -8,7 +8,6 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import lombok.Data; import lombok.experimental.Accessors; -import lombok.ToString; import java.util.ArrayList; import java.util.List; @@ -60,18 +59,20 @@ public class OrganizationDto { private Integer displayOrder; /** 子集合 */ - @ToString.Exclude private List children = new ArrayList<>(); - + /** 挂号科室标记 */ private Integer registerFlag; - + /** 科室位置 */ private String location; - + /** 科室简介 */ private String intro; - + /** 备注 */ private String remark; + + /** 租户名称 */ + private String orgName; } diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java index 569d95a8..9a59a2ee 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/datadictionary/appservice/impl/DiagTreatMAppServiceImpl.java @@ -280,24 +280,19 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService { } /** - * 获取诊查项目列表(医保类型为02) + * 获取诊查项目列表(医保类型为02,返回全量数据) * - * @param orgId 科室ID + * @param orgId 科室ID(兼容保留,不参与过滤) * @return 诊查项目列表 */ @Override public R getClinicItems(Long orgId) { - // 构建查询条件,只查询医保类型为02(诊查费)的项目 + // 构建查询条件,只查询医保类型为02(诊察费)的项目,不按科室过滤 QueryWrapper queryWrapper = new QueryWrapper<>(); queryWrapper.eq("T2.yb_type", "02"); // 使用T2表的yb_type字段,避免歧义 queryWrapper.eq("T1.delete_flag", "0"); // 只查询未删除的记录 queryWrapper.eq("T2.instance_table", "wor_activity_definition"); // 确保关联正确 - // 如果提供了科室ID,则过滤该科室的项目 - if (orgId != null) { - queryWrapper.eq("T1.org_id", orgId); // 使用机构ID进行过滤 - } - // 分页查询,设置一个较大的页大小以获取所有诊查项目 IPage diseaseTreatmentPage = activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page(1, 100), queryWrapper); diff --git a/openhis-server-new/openhis-application/src/main/resources/mapper/appointmentmanage/DoctorScheduleMapper.xml b/openhis-server-new/openhis-application/src/main/resources/mapper/appointmentmanage/DoctorScheduleMapper.xml index c8e2f766..f9558c1d 100644 --- a/openhis-server-new/openhis-application/src/main/resources/mapper/appointmentmanage/DoctorScheduleMapper.xml +++ b/openhis-server-new/openhis-application/src/main/resources/mapper/appointmentmanage/DoctorScheduleMapper.xml @@ -23,6 +23,7 @@ is_stopped, stop_reason, dept_id, + reg_type, doctor_id , create_time , update_time @@ -43,6 +44,7 @@ #{isStopped}, #{stopReason}, #{deptId}, + #{regType}, #{doctorId} , #{createTime} , #{updateTime} @@ -68,6 +70,7 @@ is_stopped = #{isStopped}, stop_reason = #{stopReason}, dept_id = #{deptId}, + reg_type = #{regType}, doctor_id = #{doctorId}, update_time = #{updateTime} @@ -97,12 +100,16 @@ ds.is_stopped AS is_stopped, ds.stop_reason AS stop_reason, ds.dept_id AS dept_id, + ds.reg_type AS reg_type, sp.doctor_id AS doctor_id, sp.schedule_date AS schedule_date FROM adm_doctor_schedule ds LEFT JOIN adm_schedule_pool sp ON sp.schedule_id = ds.id + AND sp.delete_flag = '0' LEFT JOIN adm_organization org ON ds.dept_id = org.id + AND org.delete_flag = '0' WHERE ds.dept_id = #{deptId} + AND ds.delete_flag = '0' AND sp.schedule_date BETWEEN #{startDate}::date AND #{endDate}::date ORDER BY sp.schedule_date, ds.time_period @@ -129,12 +136,16 @@ ds.is_stopped AS is_stopped, ds.stop_reason AS stop_reason, ds.dept_id AS dept_id, + ds.reg_type AS reg_type, sp.doctor_id AS doctor_id, sp.schedule_date AS schedule_date FROM adm_doctor_schedule ds INNER JOIN adm_schedule_pool sp ON sp.schedule_id = ds.id + AND sp.delete_flag = '0' LEFT JOIN adm_organization org ON ds.dept_id = org.id + AND org.delete_flag = '0' WHERE sp.schedule_date = #{today}::date + AND ds.delete_flag = '0' AND (ds.is_stopped = false OR ds.is_stopped IS NULL) ORDER BY ds.time_period @@ -161,12 +172,16 @@ ds.is_stopped AS is_stopped, ds.stop_reason AS stop_reason, ds.dept_id AS dept_id, + ds.reg_type AS reg_type, sp.doctor_id AS doctor_id, sp.schedule_date AS schedule_date FROM adm_doctor_schedule ds INNER JOIN adm_schedule_pool sp ON sp.schedule_id = ds.id + AND sp.delete_flag = '0' LEFT JOIN adm_organization org ON ds.dept_id = org.id + AND org.delete_flag = '0' WHERE sp.schedule_date = #{today}::date + AND ds.delete_flag = '0' AND sp.doctor_id = #{doctorId} AND (ds.is_stopped = false OR ds.is_stopped IS NULL) ORDER BY ds.time_period diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/domain/Organization.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/domain/Organization.java index b6475da2..5539a54e 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/domain/Organization.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/domain/Organization.java @@ -1,6 +1,7 @@ package com.openhis.administration.domain; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.core.common.core.domain.HisBaseEntity; @@ -91,4 +92,8 @@ public class Organization extends HisBaseEntity { /** 备注 */ private String remark; + + /** 租户名称(从 sys_tenant 表关联查询,非数据库字段) */ + @TableField(exist = false) + private String tenantName; } diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/mapper/OrganizationMapper.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/mapper/OrganizationMapper.java index db8266ad..e32f25fe 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/mapper/OrganizationMapper.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/administration/mapper/OrganizationMapper.java @@ -1,6 +1,8 @@ package com.openhis.administration.mapper; +import com.baomidou.mybatisplus.annotation.InterceptorIgnore; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.core.metadata.IPage; import com.openhis.administration.domain.Organization; import com.openhis.administration.dto.OrgDataDto; import org.apache.ibatis.annotations.Param; @@ -9,7 +11,7 @@ import org.springframework.stereotype.Repository; import java.util.List; /** - * 机构管理Mapper接口 + * 机构管理 Mapper 接口 * * @author system * @date 2025-02-20 @@ -25,5 +27,21 @@ public interface OrganizationMapper extends BaseMapper { **/ List searchOrgDataByHealth(); - -} \ No newline at end of file + /** + * 分页查询挂号科室列表,关联租户表获取租户名称 + * @param page 分页对象 + * @param registerFlag 挂号标记 + * @param deleteFlag 删除标记 + * @param name 机构名称 + * @param orgName 机构名称筛选 + * @return 分页结果 + */ + @InterceptorIgnore(tenantLine = "true") + IPage selectRegisterOrganizationsWithTenant( + IPage page, + @Param("registerFlag") Integer registerFlag, + @Param("deleteFlag") String deleteFlag, + @Param("name") String name, + @Param("orgName") String orgName + ); +} diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/DoctorSchedule.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/DoctorSchedule.java index 0766f4d5..4c4c3c64 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/DoctorSchedule.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/DoctorSchedule.java @@ -72,6 +72,9 @@ public class DoctorSchedule extends HisBaseEntity { /** 关联科室id */ private Long deptId; + /** 号别:0=普通,1=专家 */ + private Integer regType; + /** 医生ID - 不映射到数据库表字段,仅作传输使用 */ private Long doctorId; diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/DoctorScheduleWithDateDto.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/DoctorScheduleWithDateDto.java index b41b978f..309aa380 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/DoctorScheduleWithDateDto.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/DoctorScheduleWithDateDto.java @@ -61,6 +61,9 @@ public class DoctorScheduleWithDateDto { /** 关联科室ID */ private Long deptId; + /** 号别:0=普通,1=专家 */ + private Integer regType; + /** 医生姓名 */ private String doctorName; diff --git a/openhis-server-new/openhis-domain/src/main/resources/mapper/administration/OrganizationMapper.xml b/openhis-server-new/openhis-domain/src/main/resources/mapper/administration/OrganizationMapper.xml index dcd00ea0..2c68408b 100644 --- a/openhis-server-new/openhis-domain/src/main/resources/mapper/administration/OrganizationMapper.xml +++ b/openhis-server-new/openhis-domain/src/main/resources/mapper/administration/OrganizationMapper.xml @@ -14,5 +14,54 @@ GROUP BY heal.offered_org_id) + + - \ No newline at end of file + diff --git a/openhis-ui-vue3/src/views/appoinmentmanage/deptManage/index.vue b/openhis-ui-vue3/src/views/appoinmentmanage/deptManage/index.vue index 3761bca0..468275e4 100644 --- a/openhis-ui-vue3/src/views/appoinmentmanage/deptManage/index.vue +++ b/openhis-ui-vue3/src/views/appoinmentmanage/deptManage/index.vue @@ -331,7 +331,7 @@ type="danger" size="small" @click="handleDeleteSchedule(scope.row)" - :disabled="!isEditMode" + :disabled="!isEditMode || isLastDraftRowInSlot(scope.row)" > 删除 @@ -430,7 +430,7 @@ const currentDept = ref(null) // 筛选参数 const filterParams = ref({ - orgName: '演示医院', + orgName: '', deptName: '测试内科', clinicRoomName: '', // 添加诊室名称过滤字段 startDate: new Date(), @@ -505,9 +505,9 @@ const fetchDoctorList = async (orgId) => { console.log('原始医生数据:', doctorList) - // 将医生数据按类型分组 - const ordinaryDoctors = [] - const expertDoctors = [] + // 医生下拉统一展示:普通/专家都显示同一批医生 + // 排班回显仍按 schedule.regType 过滤,不受这里影响 + const allDoctors = [] doctorList.forEach(doctor => { // 不再单独检查医生的org_id是否与当前科室匹配 @@ -520,29 +520,26 @@ const fetchDoctorList = async (orgId) => { orgId: doctor.orgId } - ordinaryDoctors.push(doctorInfo) - - // 如果有专家类型的判断逻辑,可以在这里添加 - // 示例:如果职称包含"主任"或"教授"等关键词,则归为专家 - if (doctor.drProfttlCode && (doctor.drProfttlCode.includes('主任') || doctor.drProfttlCode.includes('教授'))) { - expertDoctors.push(doctorInfo) - } + allDoctors.push(doctorInfo) }) - // 更新医生选项 - doctorOptions.value['普通'] = ordinaryDoctors - doctorOptions.value['专家'] = expertDoctors.length > 0 ? expertDoctors : [...ordinaryDoctors] + const uniqueDoctors = Array.from( + new Map(allDoctors.map(doc => [doc.id, doc])).values() + ) + + // 更新医生选项 + doctorOptions.value['普通'] = uniqueDoctors + doctorOptions.value['专家'] = uniqueDoctors - console.log('最终的医生列表:', doctorOptions.value) } else { - console.error('获取医生列表失败:', response.msg) + doctorOptions.value = { '普通': [], '专家': [] } } } catch (error) { - console.error('获取医生列表异常:', error) + doctorOptions.value = { '普通': [], '专家': [] @@ -693,7 +690,7 @@ const fetchClinicItems = async (deptId = null) => { // 根据排班类型获取医生选项 const getDoctorOptions = (appointmentType) => { - return doctorOptions.value[appointmentType] || doctorOptions.value['普通'] + return doctorOptions.value[appointmentType] || [] } // 排班列表数据 @@ -772,10 +769,6 @@ const fetchOrganizationList = async () => { } }); - // 添加默认的机构选项(如"中联医院"、"演示医院"等) - const defaultOrgs = ['中联医院', '演示医院']; // 可以根据需要添加更多默认选项 - defaultOrgs.forEach(org => uniqueOrgNames.add(org)); - // 将机构名称转换为下拉选项格式 organizationOptions.value = Array.from(uniqueOrgNames).map((orgName, index) => ({ id: index, // 使用索引作为ID,因为我们只需要名称 @@ -783,36 +776,27 @@ const fetchOrganizationList = async () => { orgName: orgName })); } else { - console.error('获取卫生机构列表失败:', response.msg) - // 如果获取数据失败,至少显示默认选项 - const defaultOrgs = ['中联医院', '演示医院']; - organizationOptions.value = defaultOrgs.map((orgName, index) => ({ - id: index, - name: orgName, - orgName: orgName - })); + organizationOptions.value = [] } } catch (error) { - console.error('获取卫生机构列表失败:', error) - // 如果出现异常,至少显示默认选项 - const defaultOrgs = ['中联医院', '演示医院']; - organizationOptions.value = defaultOrgs.map((orgName, index) => ({ - id: index, - name: orgName, - orgName: orgName - })); + organizationOptions.value = [] } } // 获取科室列表(通用方法) const fetchDeptList = async (apiFunction) => { try { - // 复制查询参数 + // 统一查询参数口径:后端使用 name 作为科室名称条件 const params = { - ...queryParams.value, - pageNum: pagination.value.currentPage, // 修正为 pageNum + pageNum: pagination.value.currentPage, pageSize: pagination.value.pageSize }; + if (queryParams.value.orgName) { + params.orgName = queryParams.value.orgName; + } + if (queryParams.value.deptName) { + params.name = queryParams.value.deptName; + } // 同时获取配置数据,分页大小与主列表保持一致 // 这样既解决了 9999 导致的性能问题,又保证了当前显示行的数据完整性 @@ -899,9 +883,9 @@ const getDeptList = async () => { } // 查询 -const handleQuery = () => { +const handleQuery = async () => { pagination.value.currentPage = 1; - fetchDeptList(getRegisterOrganizations); // 使用挂号科室API + await fetchDeptList(getRegisterOrganizations); // 使用挂号科室API } // 处理卫生机构选择变化 @@ -914,13 +898,14 @@ const handleOrgChange = async (orgName) => { } // 重置 -const handleReset = () => { +const handleReset = async () => { queryParams.value = { orgName: '', deptName: '' } pagination.value.currentPage = 1 - getDeptList() + await fetchDepartmentOptions() + await getDeptList() } // 预约设置弹窗显示 @@ -1015,85 +1000,104 @@ const reloadScheduleData = async () => { const row = currentDept.value if (!row) return - // 使用组件级别的 workTimeConfig const weekSchedule = generateWeekSchedule(filterParams.value.startDate, workTimeConfig.value) - - // 计算当前周的起止日期,用于联表查询 const startDateStr = formatDateStr(filterParams.value.startDate) const endDate = new Date(filterParams.value.startDate) endDate.setDate(endDate.getDate() + 6) const endDateStr = formatDateStr(endDate) - // 获取该科室在指定日期范围内的排班数据(联表查询 adm_schedule_pool 获取具体日期) try { const response = await getDoctorScheduleListByDeptIdAndDateRange(row.id, startDateStr, endDateStr) if (response.code === 200) { const actualData = response.data - const deptSchedules = Array.isArray(actualData) ? actualData : (actualData && actualData.code === 200 ? actualData.data || [] : []) + const deptSchedules = Array.isArray(actualData) + ? actualData + : (actualData && actualData.code === 200 ? actualData.data || [] : []) + const selectedRegType = filterParams.value.appointmentType === '专家' ? 1 : 0 + const filteredSchedules = deptSchedules.filter(schedule => Number(schedule.regType) === selectedRegType) - // 以 "具体日期-时段" 为 key 创建映射表,替代原来的 "星期-时段" + // 同日期同时段可能存在多条排班,按 key 聚合成数组 const scheduleMap = {} - deptSchedules.forEach(schedule => { - // scheduleDate 来自 adm_schedule_pool.schedule_date,是具体的出诊日期 + filteredSchedules.forEach(schedule => { const key = `${schedule.scheduleDate}-${schedule.timePeriod}` - scheduleMap[key] = schedule - }) - - // 将现有排班数据合并到周计划中(以具体日期匹配) - weekSchedule.forEach(slot => { - // slot.date 是前端生成的具体日期(yyyy-MM-dd),与后端的 scheduleDate 一致 - const key = `${slot.date}-${slot.timeSlot}` - const existingSchedule = scheduleMap[key] - - if (existingSchedule) { - // 更新匹配的时段数据 - slot.doctorName = existingSchedule.doctor - slot.doctorId = String(existingSchedule.doctorId) // 确保为字符串 - - // --- 容错逻辑:校验医生ID是否在当前医生列表中 --- - const allAvailableDoctors = [...doctorOptions.value['普通'], ...doctorOptions.value['专家']]; - const matchedDoctorById = allAvailableDoctors.find(doc => doc.id === slot.doctorId); - - if (!matchedDoctorById) { - // 尝试根据医生姓名进行匹配 - const matchedDoctorByName = allAvailableDoctors.find(doc => doc.label === slot.doctorName); - if (matchedDoctorByName) { - slot.doctorId = matchedDoctorByName.id; - console.warn(`【调试警告】排班记录doctorId ${existingSchedule.doctorId} (姓名: ${existingSchedule.doctor}) 与当前医生列表不匹配。已根据姓名修正为ID: ${matchedDoctorByName.id}`); - } else { - slot.doctorId = null; - slot.doctorName = ''; - console.error(`【调试错误】排班记录doctorId ${existingSchedule.doctorId} 和医生姓名 "${existingSchedule.doctor}" 都未在当前医生列表中找到。`); - } - } - // --- 结束容错逻辑 --- - - slot.room = existingSchedule.clinic - slot.startTime = existingSchedule.startTime - slot.endTime = existingSchedule.endTime - slot.maxNumber = existingSchedule.limitNumber - slot.appointmentItem = existingSchedule.registerItem - slot.registrationFee = existingSchedule.registerFee - slot.clinicItem = existingSchedule.diagnosisItem - slot.treatmentFee = existingSchedule.diagnosisFee - slot.online = existingSchedule.isOnline - slot.stopClinic = existingSchedule.isStopped - slot.stopReason = existingSchedule.stopReason - slot.backendId = existingSchedule.id // 保存后端ID + if (!scheduleMap[key]) { + scheduleMap[key] = [] } + scheduleMap[key].push(schedule) }) + + const allAvailableDoctors = [...doctorOptions.value['普通'], ...doctorOptions.value['专家']] + const mergedSchedule = [] + + const applyScheduleToSlot = (targetSlot, existingSchedule) => { + targetSlot.doctorName = existingSchedule.doctorName || existingSchedule.doctor || '' + targetSlot.doctorId = existingSchedule.doctorId != null ? String(existingSchedule.doctorId) : null + + const matchedDoctorById = allAvailableDoctors.find(doc => doc.id === targetSlot.doctorId) + if (!matchedDoctorById && targetSlot.doctorName) { + const matchedDoctorByName = allAvailableDoctors.find(doc => doc.label === targetSlot.doctorName) + if (matchedDoctorByName) { + targetSlot.doctorId = matchedDoctorByName.id + } + } + + targetSlot.room = existingSchedule.clinic || existingSchedule.clinicRoom || '' + targetSlot.startTime = existingSchedule.startTime + targetSlot.endTime = existingSchedule.endTime + targetSlot.maxNumber = existingSchedule.limitNumber + targetSlot.appointmentItem = existingSchedule.registerItem + targetSlot.registrationFee = existingSchedule.registerFee + targetSlot.clinicItem = existingSchedule.diagnosisItem + targetSlot.treatmentFee = existingSchedule.diagnosisFee + targetSlot.online = existingSchedule.isOnline + targetSlot.stopClinic = existingSchedule.isStopped + targetSlot.stopReason = existingSchedule.stopReason + targetSlot.regType = existingSchedule.regType + targetSlot.backendId = existingSchedule.id + } + + weekSchedule.forEach(slot => { + const key = `${slot.date}-${slot.timeSlot}` + const existingSchedules = scheduleMap[key] || [] + + if (existingSchedules.length === 0) { + mergedSchedule.push(slot) + return + } + + existingSchedules.forEach((existingSchedule, index) => { + const targetSlot = index === 0 + ? slot + : { + ...slot, + id: `${slot.id}-dup-${existingSchedule.id || index}`, + doctorName: '', + doctorId: null, + room: '', + maxNumber: '', + appointmentItem: '', + registrationFee: 0, + clinicItem: '', + treatmentFee: 0, + online: true, + stopClinic: false, + stopReason: '' + } + applyScheduleToSlot(targetSlot, existingSchedule) + mergedSchedule.push(targetSlot) + }) + }) + + scheduleList.value = mergedSchedule + return } } catch (error) { console.error('获取科室排班数据失败:', error) ElMessage.error('获取科室排班数据失败') } - // 设置排班列表 - console.log("【调试信息】即将渲染的排班数据:", JSON.parse(JSON.stringify(weekSchedule.filter(s => s.doctorId)))); scheduleList.value = weekSchedule } - -// 编辑 const handleEdit = async (row) => { // 设置当前科室和模式 currentDept.value = row @@ -1101,7 +1105,7 @@ const handleEdit = async (row) => { scheduleDialogTitle.value = `编辑科室排班 - ${row.name || row.deptName}` // 动态设置筛选参数 - filterParams.value.orgName = row.orgName || '中联医院' + filterParams.value.orgName = row.orgName || row.organizationName || row.org || '' filterParams.value.deptName = row.name || row.deptName // 首先获取科室工作时间配置 @@ -1152,7 +1156,7 @@ const handleView = async (row) => { scheduleDialogTitle.value = `查看科室排班 - ${row.name || row.deptName}` // 动态设置筛选参数 - filterParams.value.orgName = row.orgName || '中联医院' + filterParams.value.orgName = row.orgName || row.organizationName || row.org || '' filterParams.value.deptName = row.name || row.deptName // 首先获取科室工作时间配置 @@ -1249,20 +1253,14 @@ const searchClinicRooms = async (query) => { const doctorMapping = {} // 排班类型变化处理 -const handleAppointmentTypeChange = () => { - // 当排班类型改变时,自动匹配对应的医生 +const handleAppointmentTypeChange = async () => { + if (currentDept.value) { + await reloadScheduleData() + return + } scheduleList.value.forEach(item => { - if (item.doctorName) { - // 获取新类型对应的医生列表 - const newTypeDoctors = getDoctorOptions(filterParams.value.appointmentType) - // 检查当前医生是否在新类型列表中 - const doctorExists = newTypeDoctors.some(doctor => doctor.value === item.doctorName) - - if (!doctorExists) { - // 如果当前医生不在新类型列表中,则清空 - item.doctorName = '' - } - } + item.doctorId = null + item.doctorName = '' }) } @@ -1302,14 +1300,84 @@ const handleDoctorChange = (selectedId, row) => { row.doctorName = ''; return; } - const allDoctors = [...doctorOptions.value['普通'], ...doctorOptions.value['专家']]; - const selectedDoctor = allDoctors.find(doc => doc.id === String(selectedId)); + const typeDoctors = getDoctorOptions(filterParams.value.appointmentType) + const selectedDoctor = typeDoctors.find(doc => doc.id === String(selectedId)); if (selectedDoctor) { row.doctorName = selectedDoctor.label; } } +const resolveDoctorName = (row) => { + if (row.doctorName && row.doctorName.trim() !== '') { + return row.doctorName.trim() + } + if (!row.doctorId) { + return '' + } + const allDoctors = [...doctorOptions.value['普通'], ...doctorOptions.value['专家']] + const matched = allDoctors.find(doc => doc.id === String(row.doctorId)) + return matched ? matched.label : '' +} + // 添加排班 +// 删除后兜底:当某天某时段被删空时,补一条重置行,保证可继续填写 +const createResetScheduleRow = (row) => { + const regTypeValue = Number(row.regType) + return { + id: `reset-${Date.now()}-${Math.random()}`, + date: row.date, + weekday: row.weekday, + timeSlot: row.timeSlot, + startTime: row.startTime || '08:00', + endTime: row.endTime || '12:00', + doctorName: '', + doctorId: null, + room: '', + maxNumber: '', + appointmentItem: '', + registrationFee: 0, + clinicItem: '', + treatmentFee: 0, + online: true, + stopClinic: false, + stopReason: '', + regType: Number.isNaN(regTypeValue) ? 0 : regTypeValue, + isNew: true + } +} + +const ensureResetRowAfterDelete = (row, insertIndex) => { + const hasSameSlot = scheduleList.value.some(item => + item.date === row.date && item.timeSlot === row.timeSlot + ) + if (hasSameSlot) { + return + } + + const resetRow = createResetScheduleRow(row) + if (insertIndex >= 0 && insertIndex <= scheduleList.value.length) { + scheduleList.value.splice(insertIndex, 0, resetRow) + return + } + scheduleList.value.push(resetRow) +} + +const isDraftScheduleRow = (row) => { + return !row.backendId || row.isNew +} + +const isLastDraftRowInSlot = (row) => { + if (!isDraftScheduleRow(row)) { + return false + } + + const sameSlotRows = scheduleList.value.filter(item => + item.date === row.date && item.timeSlot === row.timeSlot + ) + const draftRows = sameSlotRows.filter(item => isDraftScheduleRow(item)) + return draftRows.length <= 1 +} + const handleAddSchedule = (row) => { // 创建新的排班记录,基于当前行的日期和时段 const newSchedule = { @@ -1346,6 +1414,11 @@ const handleAddSchedule = (row) => { // 删除排班 const handleDeleteSchedule = (row) => { + if (isLastDraftRowInSlot(row)) { + ElMessage.warning('当前时段需保留最后一条待填写记录,不能删除') + return + } + ElMessageBox.confirm('确定要删除这条排班记录吗?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', @@ -1354,15 +1427,17 @@ const handleDeleteSchedule = (row) => { // 如果是已保存的记录(有后端ID),调用删除接口 if (row.backendId && !row.isNew) { deleteDoctorSchedule(row.backendId).then(res => { - if (res.code === 200) { + const removed = res?.data?.data === true || res?.data === true + if (res.code === 200 && removed) { // 从列表中移除 const index = scheduleList.value.findIndex(item => item.id === row.id) if (index !== -1) { scheduleList.value.splice(index, 1) + ensureResetRowAfterDelete(row, index) } ElMessage.success('删除成功') } else { - ElMessage.error(res.msg || '删除失败') + ElMessage.error(res.msg || '删除失败,记录可能未真正删除') } }).catch(error => { console.error('删除排班失败:', error) @@ -1373,6 +1448,7 @@ const handleDeleteSchedule = (row) => { const index = scheduleList.value.findIndex(item => item.id === row.id) if (index !== -1) { scheduleList.value.splice(index, 1) + ensureResetRowAfterDelete(row, index) ElMessage.success('删除成功') } } @@ -1445,7 +1521,7 @@ const handleEditSchedule = (row) => { } // 设置科室信息 - filterParams.value.orgName = '中联医院' // 假设固定机构名称 + filterParams.value.orgName = currentDept.value?.orgName || currentDept.value?.organizationName || currentDept.value?.org || '' filterParams.value.deptName = '未知科室' // 这里可能需要根据实际情况设置 // 设置排班列表 @@ -1505,12 +1581,12 @@ const handleSave = async () => { try { // 验证必填字段 - 只验证用户真正填写了信息的记录 const filledSchedules = scheduleList.value.filter(item => { - // 只有当用户为某一行选择了医生,我们才认为他打算保存此条记录 - return item.doctorName && item.doctorName.trim() !== ''; + // 已有排班可能只有 doctorId,没有 doctorName,二者任一存在都视为可保存记录 + return !!resolveDoctorName(item) || !!item.doctorId; }); const incompleteSchedules = filledSchedules.filter(item => { - const isDoctorValid = item.doctorName && item.doctorName.trim() !== ''; + const isDoctorValid = !!resolveDoctorName(item) || !!item.doctorId; const isRoomValid = item.room && item.room.trim() !== ''; const isStartTimeValid = item.startTime && typeof item.startTime === 'string'; const isEndTimeValid = item.endTime && typeof item.endTime === 'string'; @@ -1526,10 +1602,13 @@ const handleSave = async () => { // 转换数据格式 const schedulesToProcess = filledSchedules.map(item => { + const regTypeValue = Number( + item.regType ?? (filterParams.value.appointmentType === '专家' ? 1 : 0) + ); const scheduleData = { weekday: item.weekday, timePeriod: item.timeSlot, - doctor: item.doctorName, + doctor: resolveDoctorName(item), doctorId: item.doctorId, clinic: item.room, startTime: item.startTime, @@ -1543,6 +1622,7 @@ const handleSave = async () => { isStopped: item.stopClinic, stopReason: item.stopClinic ? (item.stopReason || '') : '', deptId: currentDept.value?.id || null, + regType: Number.isNaN(regTypeValue) ? 0 : regTypeValue, scheduledDate: item.date // 添加具体日期字段 }; if (item.backendId) { @@ -2002,4 +2082,4 @@ onMounted(async () => { :deep(.el-dialog__body) { padding: 20px; } - \ No newline at end of file +