diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/IAppointmentConfigAppService.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/IAppointmentConfigAppService.java new file mode 100644 index 00000000..8680e9c6 --- /dev/null +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/IAppointmentConfigAppService.java @@ -0,0 +1,28 @@ +package com.openhis.web.appointmentmanage.appservice; + +import com.core.common.core.domain.R; +import com.openhis.appointmentmanage.domain.AppointmentConfig; + +/** + * 预约配置AppService接口 + * + * @author openhis + * @date 2026-03-23 + */ +public interface IAppointmentConfigAppService { + + /** + * 获取当前机构的预约配置 + * + * @return 预约配置 + */ + R getAppointmentConfig(); + + /** + * 保存预约配置 + * + * @param appointmentConfig 预约配置 + * @return 结果 + */ + R saveAppointmentConfig(AppointmentConfig appointmentConfig); +} \ No newline at end of file diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/AppointmentConfigAppServiceImpl.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/AppointmentConfigAppServiceImpl.java new file mode 100644 index 00000000..dc5a4c99 --- /dev/null +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/AppointmentConfigAppServiceImpl.java @@ -0,0 +1,62 @@ +package com.openhis.web.appointmentmanage.appservice.impl; + +import com.core.common.core.domain.R; +import com.core.common.utils.SecurityUtils; +import com.openhis.appointmentmanage.domain.AppointmentConfig; +import com.openhis.appointmentmanage.service.IAppointmentConfigService; +import com.openhis.web.appointmentmanage.appservice.IAppointmentConfigAppService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * 预约配置AppService实现类 + * + * @author openhis + * @date 2026-03-23 + */ +@Service +public class AppointmentConfigAppServiceImpl implements IAppointmentConfigAppService { + + @Resource + private IAppointmentConfigService appointmentConfigService; + + @Override + public R getAppointmentConfig() { + // 获取当前登录用户的机构ID + Integer tenantId = SecurityUtils.getLoginUser().getTenantId(); + if (tenantId == null) { + return R.fail("获取机构信息失败"); + } + + AppointmentConfig config = appointmentConfigService.getConfigByTenantId(tenantId); + return R.ok(config); + } + + @Override + public R saveAppointmentConfig(AppointmentConfig appointmentConfig) { + // 获取当前登录用户的机构ID + Integer tenantId = SecurityUtils.getLoginUser().getTenantId(); + if (tenantId == null) { + return R.fail("获取机构信息失败"); + } + + // 查询是否已存在配置 + AppointmentConfig existingConfig = appointmentConfigService.getConfigByTenantId(tenantId); + + if (existingConfig != null) { + // 更新现有配置 + existingConfig.setCancelAppointmentType(appointmentConfig.getCancelAppointmentType()); + existingConfig.setCancelAppointmentCount(appointmentConfig.getCancelAppointmentCount()); + existingConfig.setValidFlag(appointmentConfig.getValidFlag()); + appointmentConfigService.saveOrUpdate(existingConfig); + return R.ok(existingConfig); + } else { + // 新增配置 + appointmentConfig.setTenantId(tenantId); + appointmentConfig.setValidFlag(1); + appointmentConfigService.saveOrUpdateConfig(appointmentConfig); + return R.ok(appointmentConfig); + } + } +} \ No newline at end of file diff --git a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/controller/DeptController.java b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/controller/DeptController.java index fe907e61..9f37d04e 100644 --- a/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/controller/DeptController.java +++ b/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/controller/DeptController.java @@ -1,11 +1,10 @@ package com.openhis.web.appointmentmanage.controller; import com.core.common.core.domain.R; +import com.openhis.appointmentmanage.domain.AppointmentConfig; +import com.openhis.web.appointmentmanage.appservice.IAppointmentConfigAppService; import com.openhis.web.appointmentmanage.appservice.IDeptAppService; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; @@ -16,6 +15,9 @@ public class DeptController { @Resource private IDeptAppService deptAppService; + @Resource + private IAppointmentConfigAppService appointmentConfigAppService; + /* * 获取科室列表 * @@ -38,4 +40,22 @@ public class DeptController { ){ return R.ok(deptAppService.searchDept(pageNo,pageSize,orgName,deptName)); } + + /* + * 获取预约配置 + * + * */ + @GetMapping("/config") + public R getAppointmentConfig(){ + return appointmentConfigAppService.getAppointmentConfig(); + } + + /* + * 保存预约配置 + * + * */ + @PostMapping("/config") + public R saveAppointmentConfig(@RequestBody AppointmentConfig appointmentConfig){ + return appointmentConfigAppService.saveAppointmentConfig(appointmentConfig); + } } diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/AppointmentConfig.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/AppointmentConfig.java new file mode 100644 index 00000000..b7c874f8 --- /dev/null +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/domain/AppointmentConfig.java @@ -0,0 +1,45 @@ +package com.openhis.appointmentmanage.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.time.LocalDateTime; + +/** + * 预约配置Entity + * + * @date 2026-03-23 + */ +@Data +@TableName(value = "appointment_config") +@Accessors(chain = true) +public class AppointmentConfig { + + /** 主键ID */ + @TableId(type = IdType.AUTO) + private Long id; + + /** 机构ID(关联 sys_tenant) */ + private Integer tenantId; + + /** 取消预约时间类型:YEAR/MONTH/DAY */ + private String cancelAppointmentType; + + /** 取消预约次数限制 */ + private Integer cancelAppointmentCount; + + /** 有效标志:1=有效,0=无效 */ + private Integer validFlag; + + /** 创建人 */ + private String createBy; + + /** 创建时间 */ + private LocalDateTime createTime; + + /** 更新时间 */ + private LocalDateTime updateTime; +} \ No newline at end of file diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/mapper/AppointmentConfigMapper.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/mapper/AppointmentConfigMapper.java new file mode 100644 index 00000000..02e78dfc --- /dev/null +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/mapper/AppointmentConfigMapper.java @@ -0,0 +1,15 @@ +package com.openhis.appointmentmanage.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.openhis.appointmentmanage.domain.AppointmentConfig; +import org.apache.ibatis.annotations.Mapper; + +/** + * 预约配置Mapper接口 + * + * @author openhis + * @date 2026-03-23 + */ +@Mapper +public interface AppointmentConfigMapper extends BaseMapper { +} \ No newline at end of file diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/service/IAppointmentConfigService.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/service/IAppointmentConfigService.java new file mode 100644 index 00000000..62d3086a --- /dev/null +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/service/IAppointmentConfigService.java @@ -0,0 +1,29 @@ +package com.openhis.appointmentmanage.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.openhis.appointmentmanage.domain.AppointmentConfig; + +/** + * 预约配置Service接口 + * + * @author openhis + * @date 2026-03-23 + */ +public interface IAppointmentConfigService extends IService { + + /** + * 根据机构ID获取预约配置 + * + * @param tenantId 机构ID + * @return 预约配置 + */ + AppointmentConfig getConfigByTenantId(Integer tenantId); + + /** + * 保存或更新预约配置 + * + * @param appointmentConfig 预约配置 + * @return 结果 + */ + int saveOrUpdateConfig(AppointmentConfig appointmentConfig); +} \ No newline at end of file diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/service/impl/AppointmentConfigServiceImpl.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/service/impl/AppointmentConfigServiceImpl.java new file mode 100644 index 00000000..03dd63ca --- /dev/null +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/appointmentmanage/service/impl/AppointmentConfigServiceImpl.java @@ -0,0 +1,44 @@ +package com.openhis.appointmentmanage.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.openhis.appointmentmanage.domain.AppointmentConfig; +import com.openhis.appointmentmanage.mapper.AppointmentConfigMapper; +import com.openhis.appointmentmanage.service.IAppointmentConfigService; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; + +/** + * 预约配置Service实现类 + * + * @author openhis + * @date 2026-03-23 + */ +@Service +public class AppointmentConfigServiceImpl + extends ServiceImpl + implements IAppointmentConfigService { + + @Override + public AppointmentConfig getConfigByTenantId(Integer tenantId) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(AppointmentConfig::getTenantId, tenantId) + .eq(AppointmentConfig::getValidFlag, 1); + return this.getOne(wrapper); + } + + @Override + public int saveOrUpdateConfig(AppointmentConfig appointmentConfig) { + if (appointmentConfig.getId() == null) { + // 新增 + appointmentConfig.setCreateTime(LocalDateTime.now()); + appointmentConfig.setUpdateTime(LocalDateTime.now()); + return this.baseMapper.insert(appointmentConfig) > 0 ? 1 : 0; + } else { + // 更新 + appointmentConfig.setUpdateTime(LocalDateTime.now()); + return this.baseMapper.updateById(appointmentConfig) > 0 ? 1 : 0; + } + } +} \ No newline at end of file diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/IOrderService.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/IOrderService.java index 87c3e66c..cf2aa2ba 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/IOrderService.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/IOrderService.java @@ -33,4 +33,14 @@ public interface IOrderService extends IService { Order createAppointmentOrder(Map params); int cancelAppointmentOrder(Long orderId, String cancelReason); + + /** + * 统计患者在指定机构、指定起始时间后的取消预约次数 + * + * @param patientId 患者ID + * @param tenantId 机构ID + * @param startTime 起始时间 + * @return 取消次数 + */ + long countPatientCancellations(Long patientId, Integer tenantId, java.time.LocalDateTime startTime); } diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/OrderServiceImpl.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/OrderServiceImpl.java index 0543aff3..27c699b1 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/OrderServiceImpl.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/OrderServiceImpl.java @@ -178,4 +178,16 @@ public class OrderServiceImpl extends ServiceImpl implements Date cancelTime = new Date(); return orderMapper.updateOrderCancelInfoById(orderId, cancelTime, cancelReason); } + + @Override + public long countPatientCancellations(Long patientId, Integer tenantId, java.time.LocalDateTime startTime) { + if (patientId == null || tenantId == null || startTime == null) { + return 0; + } + return this.count(new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper() + .eq(Order::getPatientId, patientId) + .eq(Order::getTenantId, tenantId) + .ge(Order::getCancelTime, startTime) + .eq(Order::getStatus, AppointmentOrderStatus.CANCELLED)); + } } diff --git a/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/TicketServiceImpl.java b/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/TicketServiceImpl.java index e9bbb715..01fb025e 100644 --- a/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/TicketServiceImpl.java +++ b/openhis-server-new/openhis-domain/src/main/java/com/openhis/clinical/service/impl/TicketServiceImpl.java @@ -2,6 +2,8 @@ package com.openhis.clinical.service.impl; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.openhis.appointmentmanage.domain.AppointmentConfig; +import com.openhis.appointmentmanage.service.IAppointmentConfigService; import com.openhis.appointmentmanage.domain.TicketSlotDTO; import com.openhis.appointmentmanage.mapper.SchedulePoolMapper; import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper; @@ -23,6 +25,7 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; import java.time.ZoneId; +import java.time.temporal.TemporalAdjusters; import java.util.Date; import java.util.List; import java.util.Map; @@ -49,6 +52,9 @@ public class TicketServiceImpl extends ServiceImpl impleme @Resource private SchedulePoolMapper schedulePoolMapper; + @Resource + private IAppointmentConfigService appointmentConfigService; + /** * 查询号源列表 * @@ -235,6 +241,27 @@ public class TicketServiceImpl extends ServiceImpl impleme if (orders == null || orders.isEmpty()) { throw new RuntimeException("当前号源没有可取消的预约订单"); } + + // 核心逻辑:获取订单信息并检查机构取消限制 + 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) { orderService.cancelAppointmentOrder(order.getId(), "患者取消预约"); } @@ -309,4 +336,35 @@ public class TicketServiceImpl extends ServiceImpl impleme throw new RuntimeException("挂号费格式错误: " + fee); } } + + /** + * 根据类型获取周期名称 + */ + private String getPeriodName(String type) { + if ("YEAR".equalsIgnoreCase(type)) { + return "年度"; + } else if ("MONTH".equalsIgnoreCase(type)) { + return "月度"; + } else { + return "当日"; + } + } + + /** + * 根据取消预约时间类型计算本周期的起始时间 + * + * @param type YEAR/MONTH/DAY + * @return 起始时间 + */ + private LocalDateTime calculatePeriodStartTime(String type) { + LocalDateTime now = LocalDateTime.now(); + if ("YEAR".equalsIgnoreCase(type)) { + return now.with(TemporalAdjusters.firstDayOfYear()).with(LocalTime.MIN); + } else if ("MONTH".equalsIgnoreCase(type)) { + return now.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN); + } else { + // 默认为 DAY + return now.with(LocalTime.MIN); + } + } } diff --git a/openhis-server-new/openhis-domain/src/main/resources/mapper/clinical/OrderMapper.xml b/openhis-server-new/openhis-domain/src/main/resources/mapper/clinical/OrderMapper.xml index 4ade0b2d..593d1165 100644 --- a/openhis-server-new/openhis-domain/src/main/resources/mapper/clinical/OrderMapper.xml +++ b/openhis-server-new/openhis-domain/src/main/resources/mapper/clinical/OrderMapper.xml @@ -239,32 +239,32 @@ diff --git a/openhis-ui-vue3/src/api/appoinmentmanage/appointmentConfig.js b/openhis-ui-vue3/src/api/appoinmentmanage/appointmentConfig.js new file mode 100644 index 00000000..8be83457 --- /dev/null +++ b/openhis-ui-vue3/src/api/appoinmentmanage/appointmentConfig.js @@ -0,0 +1,25 @@ +import request from '@/utils/request' + +/** + * 获取预约配置 + * @returns + */ +export function getAppointmentConfig() { + return request({ + url: '/dept/config', + method: 'get' + }) +} + +/** + * 保存预约配置 + * @param {Object} data - 预约配置数据 + * @returns + */ +export function saveAppointmentConfig(data) { + return request({ + url: '/dept/config', + method: 'post', + data: data + }) +} \ 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 535e10a0..4d36e36b 100644 --- a/openhis-ui-vue3/src/views/appoinmentmanage/deptManage/index.vue +++ b/openhis-ui-vue3/src/views/appoinmentmanage/deptManage/index.vue @@ -100,9 +100,9 @@ - - - + + + @@ -390,6 +390,7 @@ import {useRouter} from 'vue-router' import {ElDialog, ElForm, ElFormItem, ElInput, ElMessage, ElMessageBox, ElOption, ElSelect} from 'element-plus' import {DocumentRemove, EditPen, View, Delete} from '@element-plus/icons-vue' import {listDept, searchDept} from '@/api/appoinmentmanage/dept' +import {getAppointmentConfig, saveAppointmentConfig} from '@/api/appoinmentmanage/appointmentConfig' import {getLocationTree, getPractitionerMetadata, getHealthcareMetadata} from '@/views/charge/outpatientregistration/components/outpatientregistration' import {addDoctorSchedule, addDoctorScheduleWithDate, updateDoctorSchedule, deleteDoctorSchedule, getRegisterOrganizations, getDoctorScheduleListByDeptId, getDoctorScheduleListByDeptIdAndDateRange} from './api' import {getClinicRoomList} from '@/api/appoinmentmanage/clinicRoom' @@ -922,16 +923,51 @@ const handleReset = async () => { } // 预约设置弹窗显示 -const handleAppointmentSetting = () => { +const handleAppointmentSetting = async () => { + // 获取当前机构的预约配置 + try { + const res = await getAppointmentConfig() + if (res.code === 200 && res.data) { + // 回显已有配置 + appointmentSettingForm.value = { + cancelAppointmentType: res.data.cancelAppointmentType || 'YEAR', + cancelAppointmentCount: res.data.cancelAppointmentCount || 0 + } + } else { + // 无配置时使用默认值 + appointmentSettingForm.value = { + cancelAppointmentType: 'YEAR', + cancelAppointmentCount: 0 + } + } + } catch (error) { + console.error('获取预约配置失败:', error) + appointmentSettingForm.value = { + cancelAppointmentType: 'YEAR', + cancelAppointmentCount: 0 + } + } appointmentSettingDialog.value = true } // 预约设置确定 -const handleAppointmentSettingConfirm = () => { - // 这里可以添加表单验证和提交逻辑 - console.log('预约设置提交:', appointmentSettingForm.value) - ElMessage.success('预约设置保存成功') - appointmentSettingDialog.value = false +const handleAppointmentSettingConfirm = async () => { + try { + const res = await saveAppointmentConfig({ + cancelAppointmentType: appointmentSettingForm.value.cancelAppointmentType, + cancelAppointmentCount: appointmentSettingForm.value.cancelAppointmentCount, + validFlag: 1 + }) + if (res.code === 200) { + ElMessage.success('预约设置保存成功') + appointmentSettingDialog.value = false + } else { + ElMessage.error(res.msg || '保存失败') + } + } catch (error) { + console.error('保存预约配置失败:', error) + ElMessage.error('保存失败') + } } // 预约设置取消 diff --git a/openhis-ui-vue3/src/views/appoinmentmanage/deptappthoursManage/index.vue b/openhis-ui-vue3/src/views/appoinmentmanage/deptappthoursManage/index.vue index 0cbf46dc..46d9a814 100644 --- a/openhis-ui-vue3/src/views/appoinmentmanage/deptappthoursManage/index.vue +++ b/openhis-ui-vue3/src/views/appoinmentmanage/deptappthoursManage/index.vue @@ -11,7 +11,7 @@ { - const errorMsg = error.message || '取消预约失败,请稍后重试'; - ElMessage.error(`取消预约失败:${errorMsg}`); + console.error('取消预约失败:', error); this.closeContextMenu(); }); }, @@ -590,12 +589,10 @@ export default { ElMessage.success('预约成功,号源已锁定。患者到院签到时需缴费取号。'); }).catch(error => { - // 显示具体的错误信息 - const errorMessage = error.response?.data?.msg || error.response?.data?.message || '预约失败,请稍后重试。'; - ElMessage.error(errorMessage); + console.error('预约失败:', error); }); } catch (error) { - ElMessage.error('预约信息格式错误,请重新操作。'); + console.error('操作异常:', error); } }, // 切换侧边栏显示/隐藏