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;
|
|
/**
|
* 基础出入院信息<b>查询 / CRUD 端点</b> —— 从 {@code ruoyi-admin} 的
|
* {@code PatMedInhospController} 迁入("其它模块只能从本模块调用出入院信息"的落地点之一)。
|
*
|
* <h3>⚠️ URL 一个都不能变</h3>
|
* 类级路径 {@code /smartor/patinhosp} 与原 Controller 逐字一致(本类与
|
* {@link InhospVisitController} 共用该前缀,但<b>方法级路径完全不重叠</b>,
|
* 因此不会 {@code Ambiguous mapping});11 个方法级路径也逐字照抄。
|
* 真实前端在仓库外({@code D:\daima\smartor\smartor-web}),改了地址就无法回归。
|
* 由 {@code sql/_probe/verify_inhospvisit_url_equivalence.py} 把关。
|
*
|
* <h3>数据访问路径</h3>
|
* 本类<b>不注入任何 smartor 的 Service</b>,一律走本模块门面
|
* {@link InhospVisitFacade}(它实现了 {@code InhospVisitDataService})。
|
* 这也正是本次改造要达成的事实:出入院信息只有本模块一处实现。
|
*
|
* <h3>哪 4 个端点<b>没有</b>迁进来(及其原因)</h3>
|
* <ul>
|
* <li>{@code /getDeptRanking} —— SQL 在 {@code ServiceSubtaskMapper.getDeptRanking},
|
* 属子任务域而非出入院信息;</li>
|
* <li>{@code /selectPatMedInhospByApplication} —— 依赖 {@code ServiceSubtaskMapper}
|
* 与 {@code PatMedInhospDTO} 转换;<b>且原实现有反向逻辑缺陷</b>(见 10.4.10 注释);</li>
|
* <li>{@code /getDocAndPat} —— 要合并 {@code PatArchiveImport}(档案导入域)的数据;</li>
|
* <li>{@code /getDeptCodeByPatId} —— 依赖 {@code PatMedInhospDTO} 转换链。</li>
|
* </ul>
|
* 这 4 个仍由 {@code com.ruoyi.web.controller.smartor.PatMedInhospController} 承载,URL 不变。
|
*
|
* <h3>开关如何生效</h3>
|
* 本模块的 {@code InhospVisitAvailabilityInterceptor} 只挂在<b>随访触发的精确路径</b>上
|
* ({@code /dealOutHospInfo}、{@code /dealOutHospInfoBySchedule}),
|
* <b>不含本类的任何数据端点</b> —— 与迁入前的行为完全一致:
|
* 关闭 {@code inhospvisit.enabled} 只停"随访生成",不会让出入院记录的查询/CRUD 不可用。
|
* 依据是 {@code sys_config: inhospvisit.enabled} 的本意(关闭 = 当天不再生成随访),
|
* 而不是"关闭整个模块"。这一点在 {@code InhospVisitWebConfig} 里有对应注释。
|
*/
|
@Slf4j
|
@Api(description = "基础出入院信息")
|
@RestController
|
@RequestMapping("/smartor/patinhosp")
|
public class InhospVisitDataController extends BaseController {
|
|
/**
|
* 本模块常驻门面(同时实现随访契约与数据契约)。
|
* <p>
|
* ⚠️ 注入门面而不是 {@code PatMedInhospMapper}:门面永远存在,
|
* 不会因开关状态或装配差异导致本 Controller 启动失败。
|
*/
|
@Autowired
|
private InhospVisitFacade inhospVisitFacade;
|
|
/**
|
* 查询患者住院记录列表。
|
* <p>
|
* 原 {@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<PatMedInhosp> list = inhospVisitFacade.selectPatMedInhospList(patMedInhosp);
|
// startPage 之后 PageHelper 已经自动执行过一次 count 查询,直接复用 Page 里的 total,
|
// 避免用 PageUtils.count 把带 JOIN 的统计语句再跑一遍
|
long count = new PageInfo<>(list).getTotal();
|
return getDataTable2(count, list);
|
}
|
|
/**
|
* 查询当前登陆人自己(病区、部门)的患者住院记录列表。
|
* <p>
|
* 原 {@code PatMedInhospController#selectPatMedInhospListByCondition}(L126-142)逐行对应。
|
* <p>
|
* ⚠️ 原实现里两个分支调用的是<b>同一个方法</b>(只是条件不同),此处原样保留 ——
|
* 合并分支会改变"两个条件都为空时 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<PatMedInhosp> 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);
|
}
|
|
/**
|
* 查询患者住院记录通过入院申请单信息。
|
* <p>
|
* 原 {@code PatMedInhospController#selectPatMedInhospByApplication} 逐行对应
|
* (含分页、{@code @AddOrgId}、以及 count 用的 {@code ISelect})。
|
* <p>
|
* ⚠️ <b>本端点原有的反向判断缺陷被原样保留</b>(见 {@code InhospVisitDataService}
|
* 对该方法的说明):查到记录时服务层返回 {@code null},所以本端点实际恒返回空数据。
|
* 前端当前没有调用它(已核对 {@code smartor-web/src})。
|
* 按"原实现怪癖一律原样保留、只在注释标注"的纪律,本步<b>不修</b>它。
|
*/
|
@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<PatMedInhospDTO> list = inhospVisitFacade.selectPatMedInhospByApplication(patMedInhosp);
|
long count = PageUtils.count(new ISelect() {
|
@Override
|
public void doSelect() {
|
inhospVisitFacade.selectPatMedInhospByApplication(patMedInhosp);
|
}
|
});
|
return getDataTable2(count, list);
|
}
|
|
/**
|
* 查询出、入院看病人次和人数(人数分为首次服务、再次服务、专病服务)。
|
* <p>
|
* 原 {@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));
|
}
|
|
/**
|
* 导出患者住院记录列表。
|
* <p>
|
* 原 {@code PatMedInhospController#export}(L165-173)逐行对应。
|
* <p>
|
* {@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<PatMedInhosp> list = inhospVisitFacade.selectPatMedInhospList(patMedInhosp);
|
ExcelUtil<PatMedInhosp> util = new ExcelUtil<PatMedInhosp>(PatMedInhosp.class);
|
util.exportExcel(response, list, "患者住院记录数据");
|
}
|
|
/**
|
* 获取患者住院记录详细信息。
|
* <p>
|
* 原 {@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));
|
}
|
|
/**
|
* 新增患者住院记录。
|
* <p>
|
* 原 {@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));
|
}
|
|
/**
|
* 修改患者住院记录。
|
* <p>
|
* 原 {@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));
|
}
|
|
/**
|
* 删除患者住院记录。
|
* <p>
|
* 原 {@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));
|
}
|
|
/**
|
* 归一化"入院床位排序"参数。
|
* <p>
|
* 行为与 <b>{@code 接口文档/PatMedInhosp 患者住院记录接口文档.md} 里 bedSort 的说明</b>
|
* 以及迁出前的 {@code PatMedInhospServiceImpl#normalizeBedSort}(smartor,L213-219)
|
* 完全一致:
|
* <pre>
|
* asc / 1 -> "asc" 床位正序
|
* desc / 2 -> "desc" 床位倒序
|
* 其余(含不传、空串、非法值)-> null 不排序,保持原有默认排序
|
* 只对「在院」查询(cry=0)生效;出院 / 转科 / 预入院 一律忽略该参数
|
* </pre>
|
* <p>
|
* ⚠️ <b>为什么必须在 Java 侧归一,而不是让 SQL 也认 "1"/"2"</b>:
|
* <ul>
|
* <li>前端传的是 <b>数字</b> {@code bedSort:1},Jackson 落到 {@code String} 字段是
|
* {@code "1"},而 mapper 的 {@code <choose>} 只匹配字符串 {@code "asc"/"desc"}
|
* —— 不归一就静默落回默认排序,"按床位排序"这个功能等于没生效(真实线上缺陷);</li>
|
* <li>同一个排序契约还出现在 {@code VisitInhospMapper.xml}(随访扫描那条链,
|
* 入参是 {@code VisitInhospRow}),把"只认 asc/desc"留在 SQL 里,
|
* 两条链对外的约定才是一致的;</li>
|
* <li>迁到本模块后这条链<b>不再经过</b> {@code PatMedInhospServiceImpl},
|
* 原归一化会随迁出一起丢掉,所以搬到这里补回来。</li>
|
* </ul>
|
* 由 {@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 的 <otherwise> 之外的行为
|
return null;
|
}
|
}
|