package com.ruoyi.inhospvisit.controller; import com.github.pagehelper.ISelect; import com.github.pagehelper.PageInfo; import com.ruoyi.common.annotation.AddOrgId; import com.ruoyi.common.annotation.Log; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.service.dto.PatMedReq; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.utils.PageUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.inhospvisit.api.InhospVisitFacade; import com.ruoyi.inhospvisit.domain.PatMedInhosp; import com.ruoyi.inhospvisit.domain.PatMedInhospDTO; import com.ruoyi.inhospvisit.domain.PatMedInhospVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.CollectionUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletResponse; import java.util.List; /** * 基础出入院信息查询 / CRUD 端点 —— 从 {@code ruoyi-admin} 的 * {@code PatMedInhospController} 迁入("其它模块只能从本模块调用出入院信息"的落地点之一)。 * *

⚠️ URL 一个都不能变

* 类级路径 {@code /smartor/patinhosp} 与原 Controller 逐字一致(本类与 * {@link InhospVisitController} 共用该前缀,但方法级路径完全不重叠, * 因此不会 {@code Ambiguous mapping});11 个方法级路径也逐字照抄。 * 真实前端在仓库外({@code D:\daima\smartor\smartor-web}),改了地址就无法回归。 * 由 {@code sql/_probe/verify_inhospvisit_url_equivalence.py} 把关。 * *

数据访问路径

* 本类不注入任何 smartor 的 Service,一律走本模块门面 * {@link InhospVisitFacade}(它实现了 {@code InhospVisitDataService})。 * 这也正是本次改造要达成的事实:出入院信息只有本模块一处实现。 * *

哪 4 个端点没有迁进来(及其原因)

* * 这 4 个仍由 {@code com.ruoyi.web.controller.smartor.PatMedInhospController} 承载,URL 不变。 * *

开关如何生效

* 本模块的 {@code InhospVisitAvailabilityInterceptor} 只挂在随访触发的精确路径上 * ({@code /dealOutHospInfo}、{@code /dealOutHospInfoBySchedule}), * 不含本类的任何数据端点 —— 与迁入前的行为完全一致: * 关闭 {@code inhospvisit.enabled} 只停"随访生成",不会让出入院记录的查询/CRUD 不可用。 * 依据是 {@code sys_config: inhospvisit.enabled} 的本意(关闭 = 当天不再生成随访), * 而不是"关闭整个模块"。这一点在 {@code InhospVisitWebConfig} 里有对应注释。 */ @Slf4j @Api(description = "基础出入院信息") @RestController @RequestMapping("/smartor/patinhosp") public class InhospVisitDataController extends BaseController { /** * 本模块常驻门面(同时实现随访契约与数据契约)。 *

* ⚠️ 注入门面而不是 {@code PatMedInhospMapper}:门面永远存在, * 不会因开关状态或装配差异导致本 Controller 启动失败。 */ @Autowired private InhospVisitFacade inhospVisitFacade; /** * 查询患者住院记录列表。 *

* 原 {@code PatMedInhospController#selectPatMedInhosplist}(L77-87)逐行对应, * 唯一多出来的一行是 {@link #normalizeBedSort} —— 见该方法注释: * 原实现里这段归一化在 {@code PatMedInhospServiceImpl} 里,迁到本模块后这条链 * 直接调门面,必须把它跟着搬过来,否则 {@code bedSort} 静默失效。 */ @ApiOperation("查询患者住院记录列表") //@PreAuthorize("@ss.hasPermi('smartor:patinhosp:list')") @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid") @PostMapping("/selectPatMedInhospList") public TableDataInfo selectPatMedInhosplist(@RequestBody PatMedInhosp patMedInhosp) { PageUtils.startPageByPost(patMedInhosp.getPageNum(), patMedInhosp.getPageSize()); SysUser user = getLoginUser().getUser(); patMedInhosp.setOrgid(user.getOrgid()); // 前端传的是数字 1 / 2,SQL 只认 "asc" / "desc";不在这里归一就等于没传 patMedInhosp.setBedSort(normalizeBedSort(patMedInhosp.getCry(), patMedInhosp.getBedSort())); List list = inhospVisitFacade.selectPatMedInhospList(patMedInhosp); // startPage 之后 PageHelper 已经自动执行过一次 count 查询,直接复用 Page 里的 total, // 避免用 PageUtils.count 把带 JOIN 的统计语句再跑一遍 long count = new PageInfo<>(list).getTotal(); return getDataTable2(count, list); } /** * 查询当前登陆人自己(病区、部门)的患者住院记录列表。 *

* 原 {@code PatMedInhospController#selectPatMedInhospListByCondition}(L126-142)逐行对应。 *

* ⚠️ 原实现里两个分支调用的是同一个方法(只是条件不同),此处原样保留 —— * 合并分支会改变"两个条件都为空时 list 保持 null"这一既有行为。 */ @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid") @ApiOperation("查询当前登陆人自己(病区、部门)的患者住院记录列表") @PostMapping("/selectPatMedInhospListByCondition") public TableDataInfo selectPatMedInhospListByCondition(@RequestBody PatMedInhospVO patMedInhospVO) { PageUtils.startPageByPost(patMedInhospVO.getPageNum(), patMedInhospVO.getPageSize()); List list = null; if (!CollectionUtils.isEmpty(patMedInhospVO.getLeavehospitaldistrictcodes())) { list = inhospVisitFacade.selectPatMedInhospListByCondition(patMedInhospVO); } else if (!CollectionUtils.isEmpty(patMedInhospVO.getLeaveldeptcodes())) { list = inhospVisitFacade.selectPatMedInhospListByCondition(patMedInhospVO); } long count = PageUtils.count(new ISelect() { @Override public void doSelect() { inhospVisitFacade.selectPatMedInhospListByCondition(patMedInhospVO); } }); return getDataTable2(count, list); } /** * 查询患者住院记录通过入院申请单信息。 *

* 原 {@code PatMedInhospController#selectPatMedInhospByApplication} 逐行对应 * (含分页、{@code @AddOrgId}、以及 count 用的 {@code ISelect})。 *

* ⚠️ 本端点原有的反向判断缺陷被原样保留(见 {@code InhospVisitDataService} * 对该方法的说明):查到记录时服务层返回 {@code null},所以本端点实际恒返回空数据。 * 前端当前没有调用它(已核对 {@code smartor-web/src})。 * 按"原实现怪癖一律原样保留、只在注释标注"的纪律,本步不修它。 */ @ApiOperation("查询患者住院记录通过入院申请单信息") //@PreAuthorize("@ss.hasPermi('smartor:patinhosp:list')") @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid") @PostMapping("/selectPatMedInhospByApplication") public TableDataInfo selectPatMedInhospByApplication(@RequestBody PatMedInhosp patMedInhosp) { PageUtils.startPageByPost(patMedInhosp.getPageNum(), patMedInhosp.getPageSize()); SysUser user = getLoginUser().getUser(); patMedInhosp.setOrgid(user.getOrgid()); List list = inhospVisitFacade.selectPatMedInhospByApplication(patMedInhosp); long count = PageUtils.count(new ISelect() { @Override public void doSelect() { inhospVisitFacade.selectPatMedInhospByApplication(patMedInhosp); } }); return getDataTable2(count, list); } /** * 查询出、入院看病人次和人数(人数分为首次服务、再次服务、专病服务)。 *

* 原 {@code PatMedInhospController#selectPatMedInhospListCount}(L153-160)逐行对应。 * 前端首页 ECharts 在用({@code src/api/AiCentre/EChartsdata.js}),地址不可变。 */ @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid") @PostMapping("/selectPatMedInhospListCount") @ApiOperation("查询出、入院看病人次和人数") public AjaxResult selectPatMedInhospListCount(@RequestBody PatMedReq patMedReq) { SysUser user = getLoginUser().getUser(); patMedReq.setOrgid(user.getOrgid()); return success(inhospVisitFacade.selectPatMedInhospCount(patMedReq)); } /** * 导出患者住院记录列表。 *

* 原 {@code PatMedInhospController#export}(L165-173)逐行对应。 *

* {@code bedSort} 也要归一:迁出前的 export 同样走 * {@code patMedInhospService.selectPatMedInhospList(...)}(见 {@code ccf5fc76} 版本), * 归一化是随那次调用生效的。不补这一行就会出现"列表按床号排好了、导出顺序又变回去"。 */ @ApiOperation("导出患者住院记录列表") //@PreAuthorize("@ss.hasPermi('smartor:patinhosp:export')") @Log(title = "患者住院记录", businessType = BusinessType.EXPORT) @PostMapping("/export") public void export(HttpServletResponse response, PatMedInhosp patMedInhosp) { patMedInhosp.setBedSort(normalizeBedSort(patMedInhosp.getCry(), patMedInhosp.getBedSort())); List list = inhospVisitFacade.selectPatMedInhospList(patMedInhosp); ExcelUtil util = new ExcelUtil(PatMedInhosp.class); util.exportExcel(response, list, "患者住院记录数据"); } /** * 获取患者住院记录详细信息。 *

* 原 {@code PatMedInhospController#getInfo}(L178-183)逐行对应。 */ @ApiOperation("获取患者住院记录详细信息") //@PreAuthorize("@ss.hasPermi('smartor:patinhosp:query')") @GetMapping(value = "/getInfo/{inhospid}") public AjaxResult getInfo(@PathVariable("inhospid") Long inhospid) { return success(inhospVisitFacade.selectPatMedInhospByInhospid(inhospid)); } /** * 新增患者住院记录。 *

* 原 {@code PatMedInhospController#add}(L188-197)逐行对应。 */ @ApiOperation("新增患者住院记录") //@PreAuthorize("@ss.hasPermi('smartor:patinhosp:add')") @Log(title = "患者住院记录", businessType = BusinessType.INSERT) @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid") @PostMapping("/add") public AjaxResult add(@RequestBody PatMedInhosp patMedInhosp) { SysUser user = getLoginUser().getUser(); patMedInhosp.setOrgid(user.getOrgid()); return toAjax(inhospVisitFacade.insertPatMedInhosp(patMedInhosp)); } /** * 修改患者住院记录。 *

* 原 {@code PatMedInhospController#edit}(L202-209)逐行对应。 */ @ApiOperation("修改患者住院记录") //@PreAuthorize("@ss.hasPermi('smartor:patinhosp:edit')") @Log(title = "患者住院记录", businessType = BusinessType.UPDATE) @AddOrgId(field = "orgid", paramIndex = 0, campusField = "campusid") @PostMapping("/edit") public AjaxResult edit(@RequestBody PatMedInhosp patMedInhosp) { return toAjax(inhospVisitFacade.updatePatMedInhosp(patMedInhosp)); } /** * 删除患者住院记录。 *

* 原 {@code PatMedInhospController#remove}(L214-220)逐行对应。 */ @ApiOperation("删除患者住院记录") //@PreAuthorize("@ss.hasPermi('smartor:patinhosp:remove')") @Log(title = "患者住院记录", businessType = BusinessType.DELETE) @GetMapping("/remove/{inhospids}") public AjaxResult remove(@PathVariable Long[] inhospids) { return toAjax(inhospVisitFacade.deletePatMedInhospByInhospids(inhospids)); } /** * 归一化"入院床位排序"参数。 *

* 行为与 {@code 接口文档/PatMedInhosp 患者住院记录接口文档.md} 里 bedSort 的说明 * 以及迁出前的 {@code PatMedInhospServiceImpl#normalizeBedSort}(smartor,L213-219) * 完全一致: *

     *   asc  / 1 -> "asc"   床位正序
     *   desc / 2 -> "desc"  床位倒序
     *   其余(含不传、空串、非法值)-> null  不排序,保持原有默认排序
     *   只对「在院」查询(cry=0)生效;出院 / 转科 / 预入院 一律忽略该参数
     * 
*

* ⚠️ 为什么必须在 Java 侧归一,而不是让 SQL 也认 "1"/"2": *

* 由 {@code sql/_probe/verify_patinhosp_bedsort.py} 把关。 * * @param cry 出入院标识:0 入院(在院) 1 出院 2 转科 3 预入院 * @param bedSort 前端传入的床位排序值("asc"/"1"/"desc"/"2"/空) * @return {@code "asc"} / {@code "desc"} / {@code null}(不排序) */ private static String normalizeBedSort(Integer cry, String bedSort) { // 只对「在院」查询生效:cry != 0 一律置空,保证出院等场景排序不变 if (cry == null || cry != 0 || StringUtils.isEmpty(bedSort)) { return null; } String value = bedSort.trim().toLowerCase(); if ("asc".equals(value) || "1".equals(value)) { return "asc"; } if ("desc".equals(value) || "2".equals(value)) { return "desc"; } // 非法值:不排序(与"不传"同义),避免落到 XML 的 之外的行为 return null; } }