Compare commits
11
Commits
b01d5d1d7a
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
97be68db61 | ||
|
|
8fff1db294 | ||
|
|
04e4d66a4c | ||
|
|
b871409361 | ||
|
|
a3566c1f0c | ||
|
|
ae2b585df9 | ||
|
|
b7283db0bd | ||
|
|
aeed30f014 | ||
|
|
51b050bd4c | ||
|
|
754448e370 | ||
|
|
8b32335eee |
+2
-1
@@ -2,6 +2,7 @@
|
||||
target/
|
||||
*.class
|
||||
*.jar
|
||||
dist/
|
||||
|
||||
# 运行时目录(本地联调用,不入 Git)
|
||||
bin/
|
||||
@@ -54,4 +55,4 @@ mvnw.cmd
|
||||
|
||||
# JDK
|
||||
*.jdk
|
||||
*.jre
|
||||
*.jredist/
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
# Hospital Front — 医院前置机程序
|
||||
|
||||
> 基于 Kotlin + Solon 4.0.6 重构的医院前置机对接系统
|
||||
> 基于 Java 17 + Solon 4.0.6 的医院前置机对接系统
|
||||
>
|
||||
> 重构源:[hospitalmiddle](../hospitalmiddle)(SpringBoot 2.7 + MyBatis-Plus + Oracle/SqlServer)
|
||||
>
|
||||
> 完整方案:[E:\data\ob_data\myob\11 健康长庆\医院前置机重构\](../ob_data)
|
||||
> 重构源:hospitalmiddle(SpringBoot 2.7 + MyBatis-Plus + Oracle/SqlServer)
|
||||
|
||||
---
|
||||
|
||||
@@ -12,34 +10,35 @@
|
||||
|
||||
体检预约系统通过本程序与多家医院 HIS 系统对接,实现:
|
||||
- 体检预约的提交、取消
|
||||
- 体检项目查询、状态查询
|
||||
- 体检结果/结论/建议的获取
|
||||
- 体检项目 / 组合查询、体检状态查询
|
||||
- 体检结果 / 结论 / 建议的获取
|
||||
- 单位信息同步
|
||||
|
||||
**支持 5 家医院**(拼音编码):
|
||||
| 编码 | 医院名 | 数据库 |
|
||||
|---|---|---|
|
||||
| `xinglongyuan` | 兴隆园医院 | Oracle |
|
||||
| `qingyang` | 庆阳医院 | Oracle |
|
||||
| `ningxia` | 宁夏宝石花医院 | SqlServer |
|
||||
| `yanan` | 延安医院 | SqlServer |
|
||||
| `jinghe` | 泾河医院 | Oracle |
|
||||
**支持医院**(拼音编码,由 `hospital.active` 指定激活):
|
||||
|
||||
| 编码 | 医院名 | 数据库 | Adapter |
|
||||
|---|---|---|---|
|
||||
| `xinglongyuan` | 兴隆园医院 | Oracle | `XingLongYuanAdapter` |
|
||||
| `qingyang` | 庆阳医院 | Oracle | `QingyangAdapter` |
|
||||
| `ningxia` | 宁夏宝石花医院 | SqlServer | `NingxiaAdapter` |
|
||||
| `yanan` | 延安医院 | SqlServer | `YananAdapter` |
|
||||
| `jinghe` | 泾河医院 | Oracle | `JingheAdapter` |
|
||||
|
||||
医院通过 `HospitalAdapter` 接口 + `HospitalRouter` 路由(策略模式),方言基类:
|
||||
- `BsmAdapterBase`:Oracle 方言(bsm Mapper)
|
||||
- `NxAdapterBase`:SqlServer 方言(nx Mapper)
|
||||
|
||||
---
|
||||
|
||||
## 2. 技术栈
|
||||
|
||||
- **语言**:Kotlin 2.0.21(`jvmTarget=17`)
|
||||
- **框架**:Solon 4.0.6(国产轻量级 Java 框架)
|
||||
- **JDK**:17 LTS(推荐)或 21 LTS
|
||||
- **语言**:Java 17
|
||||
- **框架**:Solon 4.0.6
|
||||
- **ORM**:MyBatis-Plus 3.5.9
|
||||
- **数据库**:Oracle / SqlServer(直连医院库,不可修改)
|
||||
- **日志**:Logback 1.5.12
|
||||
- **HTTP/WS**:OkHttp 4.12.0
|
||||
- **数据库**:Oracle(ojdbc11 + orai18n,ZHS16GBK 字符集支持)/ SqlServer(直连医院库,只读对接,不可修改表结构)
|
||||
- **日志**:Logback(异步 appender,info.log / error.log 分文件滚动)
|
||||
- **构建**:Maven 3.9+
|
||||
|
||||
> ✅ **依赖瘦身**:不接入 Knife4j / Druid / Lombok / Jasypt(详见 [01-技术栈选型.md](../ob_data/01-技术栈选型.md))
|
||||
|
||||
---
|
||||
|
||||
## 3. 项目结构
|
||||
@@ -48,31 +47,22 @@
|
||||
hospital-front/
|
||||
├── pom.xml
|
||||
├── README.md
|
||||
├── .gitignore
|
||||
├── src/
|
||||
│ ├── main/
|
||||
│ │ ├── kotlin/com/hospital/front/
|
||||
│ │ │ ├── HospitalFrontApp.kt # @SolonMain 启动类
|
||||
│ │ │ ├── adapter/ # 医院适配器(策略模式)
|
||||
│ │ │ ├── api/ # HTTP 接口层(按业务域)
|
||||
│ │ │ ├── service/ # 业务服务层
|
||||
│ │ │ ├── mapper/ # 数据访问层
|
||||
│ │ │ ├── vo/ # 值对象
|
||||
│ │ │ ├── dto/ # 数据传输对象
|
||||
│ │ │ ├── infra/ # 基础设施
|
||||
│ │ │ └── task/ # 定时任务
|
||||
│ │ └── resources/
|
||||
│ │ ├── app.yml # Solon 主配置
|
||||
│ │ ├── logback.xml # 日志配置
|
||||
│ │ └── mapper/ # MyBatis XML
|
||||
│ └── test/kotlin/ # 单元测试
|
||||
└── pac/ # 部署包(运行时外置)
|
||||
├── bin/ # 启动脚本
|
||||
├── conf/ # 外置配置
|
||||
├── backup/ # 历史版本
|
||||
├── log/ # 日志
|
||||
├── pid/ # PID 文件
|
||||
└── tmp/ # 临时文件
|
||||
├── conf/ # 各医院外置配置(含生产凭据,不入 Git)
|
||||
└── src/main/
|
||||
├── java/com/hospital/front/
|
||||
│ ├── HospitalFrontApp.java # 启动类
|
||||
│ ├── adapter/ # 医院适配器(策略模式 + 方言基类)
|
||||
│ ├── api/ # HTTP 接口(order / admin)
|
||||
│ ├── service/ # 业务服务层
|
||||
│ ├── mapper/bsm|nx/ # 数据访问层(按方言分包)
|
||||
│ ├── vo/ dto/ # 值对象 / 传输对象
|
||||
│ ├── infra/ # 基础设施(过滤器、异常处理、扫描器)
|
||||
│ └── task/ # 定时任务(Uptime-Kuma 上报)
|
||||
└── resources/
|
||||
├── app.yml # 主配置(框架级 + 公共配置)
|
||||
├── logback.xml # 日志配置
|
||||
├── tls10.security # 延安专用 JDK 安全策略(放开 TLSv1/弱算法)
|
||||
└── mapper/ # MyBatis XML
|
||||
```
|
||||
|
||||
---
|
||||
@@ -89,57 +79,61 @@ mvn clean package -DskipTests
|
||||
## 5. 启动(开发环境)
|
||||
|
||||
```bash
|
||||
# 拷贝外置配置(首次启动)
|
||||
cp -r pac/conf-example pac/conf
|
||||
# 编辑配置
|
||||
vim pac/conf/app-jinghe.yml
|
||||
|
||||
# 启动(默认加载 app.yml + conf/app-{HOSPITAL}.yml)
|
||||
HOSPITAL=jinghe java -jar target/hospital-front-1.0.0.jar
|
||||
# 方式一:默认加载 classpath 的 app.yml(hospital.active 默认 jinghe)
|
||||
java -jar target/hospital-front-1.0.0.jar
|
||||
```
|
||||
|
||||
数据源等医院差异配置在 `app-{医院}.yml` 中,开发期可用 `--solon.config.add` 外挂。
|
||||
|
||||
---
|
||||
|
||||
## 6. 部署
|
||||
## 6. 生产部署注意事项(重要)
|
||||
|
||||
详细部署、升级、回滚 SOP:[05-部署运维.md](../ob_data/05-部署运维.md)
|
||||
### 6.1 外挂医院配置
|
||||
|
||||
**Windows Server 简版**:
|
||||
```batch
|
||||
D:
|
||||
cd D:\hospital-front\bin
|
||||
call start.bat start
|
||||
生产环境配置文件**外置于 jar 同级或 `conf/` 目录**,通过 `--solon.config.add` 追加加载,
|
||||
修改数据库地址 / 鉴权等无需重新打包:
|
||||
|
||||
```bash
|
||||
java -jar hospital-front.jar --solon.config.add=conf/app-yanan.yml --server.port=8003
|
||||
```
|
||||
|
||||
- 配置模板见仓库 `conf/` 目录(app-jinghe / app-ningxia / app-yanan)
|
||||
- `--server.port` 覆盖默认端口 8082
|
||||
- 外挂文件中必须指定 `hospital.active` 与 `hm.type`(bsm / nx / ya),并定义 `solon.dataSources.db1`
|
||||
|
||||
### 6.2 延安医院:TLS 1.0 特殊处理
|
||||
|
||||
延安 SqlServer 为老版本(仅支持 TLS 1.0 / 弱加密算法),JDK 17 默认禁用,
|
||||
必须外挂 JDK 安全属性文件启动,否则连接报 `handshake failure` / `No appropriate protocol`:
|
||||
|
||||
```bash
|
||||
java -Dfile.encoding=UTF-8 -Djava.security.properties=tls10.security -jar hospital-front.jar --solon.config.add=conf/app-yanan.yml --server.port=8003
|
||||
```
|
||||
|
||||
- `tls10.security` 已打包在 jar 内(`src/main/resources/`),上述命令按 classpath 加载,无需单独分发文件;也可用文件系统绝对路径覆盖
|
||||
- `-Dfile.encoding=UTF-8`:Windows 服务器默认 GBK,防止日志与接口中文乱码
|
||||
- 其余医院**不要**带 `tls10.security`(会全局放开弱算法,降低安全基线)
|
||||
|
||||
### 6.3 安全配置(生产必读)
|
||||
|
||||
`app.yml` 中以下配置生产环境必须核对(可在外挂配置中覆盖):
|
||||
|
||||
| 配置 | 说明 |
|
||||
|---|---|
|
||||
| `order.basic` | `/order/**` 的 HTTP Basic 认证(`user:password`),生产必须配置 |
|
||||
| `admin.token` | `/api/admin/**` 的 `X-Admin-Token`,Agent 环回调用 |
|
||||
| `security.ipWhitelistEnabled` / `ipWhitelist` | IP 白名单(支持精确 IP / 通配段 / CIDR),端口暴露公网时务必开启 |
|
||||
| `security.trustProxy` | nginx 反代部署时开启,从 X-Forwarded-For 取真实客户端 IP |
|
||||
|
||||
### 6.4 日志
|
||||
|
||||
- 日志目录默认 `./log`(`-Dlog.path=xxx` 可覆盖)
|
||||
- `info.log`(INFO 及以上)/ `error.log`(仅 ERROR)分文件,50MB 按天滚动,保留 30 天
|
||||
- pattern 不含 `%file:%line`(AsyncAppender 下取不到调用者信息,会打成 `?:?`)
|
||||
|
||||
---
|
||||
|
||||
## 7. 文档
|
||||
|
||||
完整设计文档位于:`E:\data\ob_data\myob\11 健康长庆\医院前置机重构\`
|
||||
|
||||
| 文档 | 内容 |
|
||||
|---|---|
|
||||
| [00-总体方案.md](../ob_data/00-总体方案.md) | 整体方案 |
|
||||
| [01-技术栈选型.md](../ob_data/01-技术栈选型.md) | Solon 选型、版本、注解对照 |
|
||||
| [02-医院差异化矩阵.md](../ob_data/02-医院差异化矩阵.md) | 5 家医院差异、Adapter 拆分 |
|
||||
| [03-架构设计.md](../ob_data/03-架构设计.md) | 系统架构、模块、时序 |
|
||||
| [04-数据流与接口契约.md](../ob_data/04-数据流与接口契约.md) | 接口清单、入参出参 |
|
||||
| [05-部署运维.md](../ob_data/05-部署运维.md) | 部署、升级、回滚 SOP |
|
||||
| [06-变更记录.md](../ob_data/06-变更记录.md) | 所有变更登记 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 任务进度
|
||||
|
||||
| Step | 内容 | 状态 |
|
||||
|---|---|---|
|
||||
| 1 | 工程骨架 | ✅ |
|
||||
| 2 | 5 医院配置中心 | ⏳ |
|
||||
| 3 | 业务接口 Kotlin 重写 | ⏳ |
|
||||
| 4 | 5 套 Mapper 适配 | ⏳ |
|
||||
| 5 | 主程序被控端 API | ⏳ |
|
||||
| 6 | Agent 工程 | ⏳ |
|
||||
| 7 | 升级流程 | ⏳ |
|
||||
| 8 | 日志推送 | ⏳ |
|
||||
| 9 | B 端管理后台 | ⏳ |
|
||||
| 10 | 联调 + 文档 | ⏳ |
|
||||
@@ -79,6 +79,14 @@
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>mybatis-plus-solon-plugin</artifactId>
|
||||
<!-- 排除插件传递的 core 3.5.5:显式声明的 mybatis-plus 3.5.9 已内含 core 类,
|
||||
双版本共存既造成 shade 同类冲突(随机取一边混搭),也白白多出 ~4MB 体积 -->
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-core</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
@@ -99,6 +107,12 @@
|
||||
<artifactId>ojdbc11</artifactId>
|
||||
<version>${ojdbc.version}</version>
|
||||
</dependency>
|
||||
<!-- Oracle NLS 字符集支持:ZHS16GBK 等中文/多字节字符集转换表,缺失报 ORA-17056 -->
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.nls</groupId>
|
||||
<artifactId>orai18n</artifactId>
|
||||
<version>${ojdbc.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- SqlServer -->
|
||||
<dependency>
|
||||
@@ -111,15 +125,8 @@
|
||||
- sqlite-jdbc:原为 B 端 Agent 用,Agent 已拆分为独立 Python 项目
|
||||
- h2:开发 Mock 数据源,需要时本地临时加回
|
||||
- sa-token-solon-plugin:鉴权已改为 OrderApi 手写 HTTP Basic
|
||||
- okhttp:UptimeKuma 心跳已改用 JDK 内置 java.net.http.HttpClient
|
||||
-->
|
||||
|
||||
<!-- ========== HTTP(UptimeKuma 心跳用) ========== -->
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp3</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- ========== JSON 解析(Solon 生态标准库) ========== -->
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>snack3</artifactId>
|
||||
@@ -134,7 +141,7 @@
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>hospital-front-${project.version}</finalName>
|
||||
<finalName>hospital-front</finalName>
|
||||
|
||||
<plugins>
|
||||
<!-- 打 fat jar(包含所有依赖) -->
|
||||
@@ -163,10 +170,19 @@
|
||||
<exclude>META-INF/*.SF</exclude>
|
||||
<exclude>META-INF/*.DSA</exclude>
|
||||
<exclude>META-INF/*.RSA</exclude>
|
||||
<!-- 依赖自带的模块描述文件与 fat jar 不兼容,剔除以消除 shade 警告 -->
|
||||
<exclude>module-info.class</exclude>
|
||||
<exclude>META-INF/versions/*/module-info.class</exclude>
|
||||
<!-- 以下重叠资源均为 IDE 提示/native-image 元数据/许可证文本,
|
||||
运行时不读取,剔除以消除 shade 的 overlapping 警告 -->
|
||||
<exclude>META-INF/solon/solon-configuration-metadata.json</exclude>
|
||||
<exclude>META-INF/native-image/**</exclude>
|
||||
<exclude>META-INF/LICENSE</exclude>
|
||||
<exclude>META-INF/MANIFEST.MF</exclude>
|
||||
</excludes>
|
||||
</filter>
|
||||
</filters>
|
||||
<finalName>hospital-front-${project.version}</finalName>
|
||||
<finalName>hospital-front</finalName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
package com.hospital.front;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.SolonMain;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 医院前置机主程序启动类。
|
||||
@@ -20,29 +21,19 @@ import org.noear.solon.annotation.SolonMain;
|
||||
@SolonMain
|
||||
public class HospitalFrontApp {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HospitalFrontApp.class);
|
||||
|
||||
/**
|
||||
* 主入口。
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
// TODO 临时诊断代码:打印完整异常因果链,定位注入失败根因后移除
|
||||
try {
|
||||
Solon.start(HospitalFrontApp.class, args);
|
||||
} catch (Throwable e) {
|
||||
Throwable t = e;
|
||||
int depth = 0;
|
||||
while (t != null && depth < 10) {
|
||||
System.err.println("=== 因果链[" + depth + "]: " + t.getClass().getName() + ": " + t.getMessage());
|
||||
StackTraceElement[] stackTrace = t.getStackTrace();
|
||||
for (int i = 0; i < Math.min(10, stackTrace.length); i++) {
|
||||
System.err.println(" at " + stackTrace[i]);
|
||||
}
|
||||
t = t.getCause();
|
||||
depth++;
|
||||
}
|
||||
System.exit(1);
|
||||
}
|
||||
Solon.start(HospitalFrontApp.class, args);
|
||||
long pid = ProcessHandle.current().pid();
|
||||
System.out.println("[HospitalFront] 启动完成,PID=" + pid);
|
||||
// 走 logback 落盘(服务方式运行时控制台不可见,System.out 进不了日志文件)
|
||||
log.info("启动完成,PID={},激活医院={},端口={}",
|
||||
pid,
|
||||
Solon.cfg().get("hospital.active", "?"),
|
||||
Solon.cfg().get("server.port", "?"));
|
||||
// 写 PID 文件(供 start.bat stop / Agent 升级流程强杀使用)
|
||||
try {
|
||||
File dir = new File("pid");
|
||||
@@ -58,7 +49,7 @@ public class HospitalFrontApp {
|
||||
new File("pid/hospital-front.pid").delete();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
System.out.println("[HospitalFront] 优雅停机中...");
|
||||
log.info("优雅停机中...");
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.hospital.front.adapter;
|
||||
|
||||
import com.hospital.front.vo.ConclusionVo;
|
||||
import com.hospital.front.vo.ExamListVo;
|
||||
import com.hospital.front.vo.MedicalMiddleResultVo;
|
||||
import com.hospital.front.vo.PeStatusVo;
|
||||
import com.hospital.front.vo.SuggestVo;
|
||||
|
||||
import com.hospital.front.dto.ProcResult;
|
||||
import com.hospital.front.dto.Result;
|
||||
import com.hospital.front.mapper.bsm.BsmOrderMapper;
|
||||
@@ -32,7 +38,7 @@ public abstract class BsmAdapterBase implements HospitalAdapter {
|
||||
try {
|
||||
return Result.success(mapper.ping() == 1);
|
||||
} catch (Exception e) {
|
||||
return Result.error(Result.CODE_DB_UNREACHABLE, "数据库连接失败:" + e.getMessage());
|
||||
return Result.error("数据库连接失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +93,7 @@ public abstract class BsmAdapterBase implements HospitalAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getPhyexamStatus(String peIds) {
|
||||
public List<PeStatusVo> getPhyexamStatus(String peIds) {
|
||||
return mapper.getPhyexamStatus(peIds);
|
||||
}
|
||||
|
||||
@@ -122,65 +128,45 @@ public abstract class BsmAdapterBase implements HospitalAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getConclusion(String peId) {
|
||||
return mapper.getConclusion(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getConclusionAll(String peId) {
|
||||
public List<ConclusionVo> getConclusionAll(String peId) {
|
||||
return mapper.getConclusionAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getSuggest(String peId) {
|
||||
return mapper.getSuggest(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getSuggestAll(String peId) {
|
||||
public List<SuggestVo> getSuggestAll(String peId) {
|
||||
return mapper.getSuggestAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getPeStatusByIdnoAndYear(String idNo, String year) {
|
||||
public PeStatusVo getPeStatusByIdnoAndYear(String idNo, String year) {
|
||||
return mapper.getPeStatusByIdnoAndYear(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdcardAndYear(String idNo, String year) {
|
||||
public List<MedicalMiddleResultVo> getResultByIdcardAndYear(String idNo, String year) {
|
||||
return mapper.getResultByIdcardAndYear(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdcardAndYearAll(String idNo, String year) {
|
||||
public List<MedicalMiddleResultVo> getResultByIdcardAndYearAll(String idNo, String year) {
|
||||
return mapper.getResultByIdcardAndYearAll(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByPeId(String peId) {
|
||||
public List<MedicalMiddleResultVo> getResultByPeId(String peId) {
|
||||
return mapper.getResultByPeId(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getDisResultByAuditDate(String auditDate) {
|
||||
return mapper.getDisResultByAuditDate(auditDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getItemByPeId(String peId) {
|
||||
public List<MedicalMiddleResultVo> getItemByPeId(String peId) {
|
||||
return mapper.getItemByPeId(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getItemByPeIdAll(String peId) {
|
||||
public List<MedicalMiddleResultVo> getItemByPeIdAll(String peId) {
|
||||
return mapper.getItemByPeIdAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdNoOrPeId(String idNo, String peId, String auditYear) {
|
||||
return mapper.getResultByIdNoOrPeId(idNo, peId, auditYear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getPeIdAndDateByIdcard(String idNo) {
|
||||
return mapper.getPeIdAndDateByIdcard(idNo);
|
||||
@@ -192,7 +178,7 @@ public abstract class BsmAdapterBase implements HospitalAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getExamListByDate(String auditDate) {
|
||||
public List<ExamListVo> getExamListByDate(String auditDate) {
|
||||
return mapper.getExamListByDate(auditDate);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.hospital.front.adapter;
|
||||
|
||||
import com.hospital.front.vo.ConclusionVo;
|
||||
import com.hospital.front.vo.ExamListVo;
|
||||
import com.hospital.front.vo.MedicalMiddleResultVo;
|
||||
import com.hospital.front.vo.PeStatusVo;
|
||||
import com.hospital.front.vo.SuggestVo;
|
||||
|
||||
import com.hospital.front.dto.ProcResult;
|
||||
import com.hospital.front.dto.Result;
|
||||
import com.hospital.front.vo.UnitVo;
|
||||
@@ -8,93 +14,76 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 医院适配器接口(策略模式)。
|
||||
* 医院适配器接口(各医院方言实现:bsm/nx,延安复用 nx)。
|
||||
*
|
||||
* 5 家医院各自实现本接口,通过 HospitalRouter 按医院编码路由。
|
||||
* 所有数据库差异(Oracle/SqlServer 方言、存储过程名)均封装在实现内;
|
||||
* 存储过程的入参出参契约由医院 HIS 系统约定,不可修改。
|
||||
*
|
||||
* 查询类方法统一返回 Map 列表(列名与医院视图/存储过程保持一致)。
|
||||
* getConclusion/getSuggest 与其 All 版 SQL 完全重复,已合并为 All 版
|
||||
* (对外接口路径 /getConclusion、/getSuggest 保留,内部走 All 版)。
|
||||
*/
|
||||
public interface HospitalAdapter {
|
||||
|
||||
/** 医院编码(拼音):xinglongyuan / qingyang / ningxia / yanan / jinghe / dev */
|
||||
/** 医院编码(唯一,如 jinghe) */
|
||||
String code();
|
||||
|
||||
/** 医院中文名(日志与展示用) */
|
||||
/** 医院显示名 */
|
||||
String displayName();
|
||||
|
||||
/** Mapper 方言类型:bsm(Oracle)/ nx / ya(SqlServer) */
|
||||
/** 医院方言类型(bsm/nx/ya) */
|
||||
String hmType();
|
||||
|
||||
/** 轻量健康检查(SELECT 1 探测) */
|
||||
/** 数据库健康检查 */
|
||||
Result<Boolean> healthCheck();
|
||||
|
||||
// ================= 存储过程(写) =================
|
||||
|
||||
/** 提交预约(P_ADD_PE_REGIST) */
|
||||
/** 提交预约(存储过程) */
|
||||
ProcResult saveOrder(String peInfoStr, String peItemStr);
|
||||
|
||||
/** 取消预约(P_DEL_PE_REGIST) */
|
||||
/** 取消预约(存储过程) */
|
||||
ProcResult cancelOrder(String peId, String name, String idcard);
|
||||
|
||||
/** 添加/修改单位(P_ADD_UNIT) */
|
||||
/** 添加/修改单位(存储过程,V1/V2 参数不同) */
|
||||
ProcResult addUnit(UnitVo unit, boolean useV2);
|
||||
|
||||
// ================= 查询(视图) =================
|
||||
/** 体检状态查询(多个 peId 逗号分隔) */
|
||||
List<PeStatusVo> getPhyexamStatus(String peIds);
|
||||
|
||||
/** 按体检预约 ID(逗号分隔多个)查询体检状态 */
|
||||
List<Map<String, Object>> getPhyexamStatus(String peIds);
|
||||
|
||||
/** 医院所有体检项目(组合项) */
|
||||
/** 体检项目查询 */
|
||||
List<Map<String, Object>> getItemList();
|
||||
|
||||
/** 医院所有体检项目及指标项 */
|
||||
/** 体检指标项及体检组合数据 */
|
||||
List<Map<String, Object>> getAllItemList();
|
||||
|
||||
/** 医院所有体检指标项 */
|
||||
/** 体检指标项数据 */
|
||||
List<Map<String, Object>> getPeItemList();
|
||||
|
||||
/** 按指标项 CODE 查询所属体检组合 */
|
||||
/** 按体检指标项查所属组合 */
|
||||
List<Map<String, Object>> getItemInfo(String peItemCode);
|
||||
|
||||
/** 员工体检项目 */
|
||||
List<Map<String, Object>> getEmpItem(String peId);
|
||||
|
||||
/** 员工体检结果 */
|
||||
/** 按体检编号查体检结果 */
|
||||
List<Map<String, Object>> getResult(String peId);
|
||||
|
||||
/** 体检结论(列表 / 全量) */
|
||||
List<Map<String, Object>> getConclusion(String peId);
|
||||
/** 体检结论(列表) */
|
||||
List<ConclusionVo> getConclusionAll(String peId);
|
||||
|
||||
List<Map<String, Object>> getConclusionAll(String peId);
|
||||
|
||||
/** 体检建议(列表 / 全量) */
|
||||
List<Map<String, Object>> getSuggest(String peId);
|
||||
|
||||
List<Map<String, Object>> getSuggestAll(String peId);
|
||||
/** 体检建议(全量,内部组装用) */
|
||||
List<SuggestVo> getSuggestAll(String peId);
|
||||
|
||||
/** 按身份证号 + 年份查询体检状态 */
|
||||
Map<String, Object> getPeStatusByIdnoAndYear(String idNo, String year);
|
||||
PeStatusVo getPeStatusByIdnoAndYear(String idNo, String year);
|
||||
|
||||
/** 按身份证号 + 年份查询体检结果(默认 / 全量) */
|
||||
List<Map<String, Object>> getResultByIdcardAndYear(String idNo, String year);
|
||||
List<MedicalMiddleResultVo> getResultByIdcardAndYear(String idNo, String year);
|
||||
|
||||
List<Map<String, Object>> getResultByIdcardAndYearAll(String idNo, String year);
|
||||
List<MedicalMiddleResultVo> getResultByIdcardAndYearAll(String idNo, String year);
|
||||
|
||||
/** 按体检编号查询体检结果 */
|
||||
List<Map<String, Object>> getResultByPeId(String peId);
|
||||
|
||||
/** 按审核日期查询体检报告(去重主表) */
|
||||
List<Map<String, Object>> getDisResultByAuditDate(String auditDate);
|
||||
List<MedicalMiddleResultVo> getResultByPeId(String peId);
|
||||
|
||||
/** 按体检编号查询体检项目子表(默认 / 全量) */
|
||||
List<Map<String, Object>> getItemByPeId(String peId);
|
||||
List<MedicalMiddleResultVo> getItemByPeId(String peId);
|
||||
|
||||
List<Map<String, Object>> getItemByPeIdAll(String peId);
|
||||
|
||||
/** 按身份证号或体检编号 + 审核年份查询体检结果 */
|
||||
List<Map<String, Object>> getResultByIdNoOrPeId(String idNo, String peId, String auditYear);
|
||||
List<MedicalMiddleResultVo> getItemByPeIdAll(String peId);
|
||||
|
||||
/** 按身份证号查询当年 peId 与预约日期(单条 / 列表) */
|
||||
Map<String, Object> getPeIdAndDateByIdcard(String idNo);
|
||||
@@ -102,5 +91,5 @@ public interface HospitalAdapter {
|
||||
List<Map<String, Object>> getPeIdAndDateByIdcardList(String idNo);
|
||||
|
||||
/** 按审核日期查询当天体检人员列表(去重;日期空则当天) */
|
||||
List<Map<String, Object>> getExamListByDate(String auditDate);
|
||||
List<ExamListVo> getExamListByDate(String auditDate);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.hospital.front.adapter;
|
||||
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -17,6 +19,8 @@ import java.util.Set;
|
||||
@Component
|
||||
public class HospitalRouter {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HospitalRouter.class);
|
||||
|
||||
/** 启动激活的医院编码(默认 jinghe) */
|
||||
private final String activeCode = Solon.cfg().get("hospital.active", "jinghe");
|
||||
|
||||
@@ -24,7 +28,8 @@ public class HospitalRouter {
|
||||
private volatile Map<String, HospitalAdapter> map;
|
||||
|
||||
public HospitalRouter() {
|
||||
System.out.println("[HospitalRouter] 启动激活医院:" + activeCode);
|
||||
// 走 logback 落盘(服务方式运行时 System.out 进不了日志文件)
|
||||
log.info("启动激活医院:{}", activeCode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.hospital.front.adapter;
|
||||
|
||||
import com.hospital.front.vo.ConclusionVo;
|
||||
import com.hospital.front.vo.ExamListVo;
|
||||
import com.hospital.front.vo.MedicalMiddleResultVo;
|
||||
import com.hospital.front.vo.PeStatusVo;
|
||||
import com.hospital.front.vo.SuggestVo;
|
||||
|
||||
import com.hospital.front.dto.ProcResult;
|
||||
import com.hospital.front.dto.Result;
|
||||
import com.hospital.front.mapper.nx.NxOrderMapper;
|
||||
@@ -13,7 +19,7 @@ import java.util.Map;
|
||||
/**
|
||||
* NX 方言适配器基类(SqlServer)。
|
||||
*
|
||||
* 适用医院:ningxia(宁夏宝石花)。
|
||||
* 适用医院:ningxia(宁夏宝石花)/ yanan(延安,库结构已与宁夏完全一致)。
|
||||
*/
|
||||
public abstract class NxAdapterBase implements HospitalAdapter {
|
||||
|
||||
@@ -31,7 +37,7 @@ public abstract class NxAdapterBase implements HospitalAdapter {
|
||||
try {
|
||||
return Result.success(mapper.ping() == 1);
|
||||
} catch (Exception e) {
|
||||
return Result.error(Result.CODE_DB_UNREACHABLE, "数据库连接失败:" + e.getMessage());
|
||||
return Result.error("数据库连接失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +89,7 @@ public abstract class NxAdapterBase implements HospitalAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getPhyexamStatus(String peIds) {
|
||||
public List<PeStatusVo> getPhyexamStatus(String peIds) {
|
||||
return mapper.getPhyexamStatus(peIds);
|
||||
}
|
||||
|
||||
@@ -118,65 +124,45 @@ public abstract class NxAdapterBase implements HospitalAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getConclusion(String peId) {
|
||||
return mapper.getConclusion(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getConclusionAll(String peId) {
|
||||
public List<ConclusionVo> getConclusionAll(String peId) {
|
||||
return mapper.getConclusionAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getSuggest(String peId) {
|
||||
return mapper.getSuggest(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getSuggestAll(String peId) {
|
||||
public List<SuggestVo> getSuggestAll(String peId) {
|
||||
return mapper.getSuggestAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getPeStatusByIdnoAndYear(String idNo, String year) {
|
||||
public PeStatusVo getPeStatusByIdnoAndYear(String idNo, String year) {
|
||||
return mapper.getPeStatusByIdnoAndYear(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdcardAndYear(String idNo, String year) {
|
||||
public List<MedicalMiddleResultVo> getResultByIdcardAndYear(String idNo, String year) {
|
||||
return mapper.getResultByIdcardAndYear(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdcardAndYearAll(String idNo, String year) {
|
||||
public List<MedicalMiddleResultVo> getResultByIdcardAndYearAll(String idNo, String year) {
|
||||
return mapper.getResultByIdcardAndYearAll(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByPeId(String peId) {
|
||||
public List<MedicalMiddleResultVo> getResultByPeId(String peId) {
|
||||
return mapper.getResultByPeId(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getDisResultByAuditDate(String auditDate) {
|
||||
return mapper.getDisResultByAuditDate(auditDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getItemByPeId(String peId) {
|
||||
public List<MedicalMiddleResultVo> getItemByPeId(String peId) {
|
||||
return mapper.getItemByPeId(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getItemByPeIdAll(String peId) {
|
||||
public List<MedicalMiddleResultVo> getItemByPeIdAll(String peId) {
|
||||
return mapper.getItemByPeIdAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdNoOrPeId(String idNo, String peId, String auditYear) {
|
||||
return mapper.getResultByIdNoOrPeId(idNo, peId, auditYear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getPeIdAndDateByIdcard(String idNo) {
|
||||
return mapper.getPeIdAndDateByIdcard(idNo);
|
||||
@@ -188,7 +174,7 @@ public abstract class NxAdapterBase implements HospitalAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getExamListByDate(String auditDate) {
|
||||
public List<ExamListVo> getExamListByDate(String auditDate) {
|
||||
return mapper.getExamListByDate(auditDate);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,202 +0,0 @@
|
||||
package com.hospital.front.adapter;
|
||||
|
||||
import com.hospital.front.dto.ProcResult;
|
||||
import com.hospital.front.dto.Result;
|
||||
import com.hospital.front.mapper.ya.YaOrderMapper;
|
||||
import com.hospital.front.vo.UnitVo;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* YA 方言适配器基类(SqlServer)。
|
||||
*
|
||||
* 适用医院:yanan(延安)。
|
||||
*/
|
||||
public abstract class YaAdapterBase implements HospitalAdapter {
|
||||
|
||||
/** 数据库 Mapper(Solon 按类型注入) */
|
||||
@Inject
|
||||
protected YaOrderMapper mapper;
|
||||
|
||||
@Override
|
||||
public String hmType() {
|
||||
return "ya";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Boolean> healthCheck() {
|
||||
try {
|
||||
return Result.success(mapper.ping() == 1);
|
||||
} catch (Exception e) {
|
||||
return Result.error(Result.CODE_DB_UNREACHABLE, "数据库连接失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcResult saveOrder(String peInfoStr, String peItemStr) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("peInfoStr", peInfoStr);
|
||||
map.put("peItemStr", peItemStr);
|
||||
mapper.saveOrder(map);
|
||||
return new ProcResult(
|
||||
str(map.get("resultCode")),
|
||||
str(map.get("errorMsg")),
|
||||
str(map.get("peId"))
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcResult cancelOrder(String peId, String name, String idcard) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("peId", peId);
|
||||
map.put("name", name);
|
||||
map.put("idcard", idcard);
|
||||
mapper.cancelOrder(map);
|
||||
return new ProcResult(
|
||||
str(map.get("resultCode")),
|
||||
str(map.get("errorMsg")),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProcResult addUnit(UnitVo unit, boolean useV2) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("unitCode", unit.getUnitCode());
|
||||
map.put("unitName", unit.getUnitName());
|
||||
map.put("parentUnitCode", unit.getParentUnitCode());
|
||||
map.put("address", unit.getAddress());
|
||||
map.put("connecter1", unit.getConnecter1());
|
||||
map.put("phone1", unit.getPhone1());
|
||||
map.put("connecter2", unit.getConnecter2());
|
||||
map.put("phone2", unit.getPhone2());
|
||||
if (useV2) {
|
||||
mapper.addUnitV2(map);
|
||||
} else {
|
||||
mapper.addUnit(map);
|
||||
}
|
||||
return new ProcResult(
|
||||
str(map.get("resultCode")),
|
||||
str(map.get("errorMsg")),
|
||||
null
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getPhyexamStatus(String peIds) {
|
||||
return mapper.getPhyexamStatus(peIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getItemList() {
|
||||
return mapper.getItemList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getAllItemList() {
|
||||
return mapper.getAllItemList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getPeItemList() {
|
||||
return mapper.getPeItemList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getItemInfo(String peItemCode) {
|
||||
return mapper.getItemInfo(peItemCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getEmpItem(String peId) {
|
||||
return mapper.getEmpItem(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResult(String peId) {
|
||||
return mapper.getResult(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getConclusion(String peId) {
|
||||
return mapper.getConclusion(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getConclusionAll(String peId) {
|
||||
return mapper.getConclusionAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getSuggest(String peId) {
|
||||
return mapper.getSuggest(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getSuggestAll(String peId) {
|
||||
return mapper.getSuggestAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getPeStatusByIdnoAndYear(String idNo, String year) {
|
||||
return mapper.getPeStatusByIdnoAndYear(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdcardAndYear(String idNo, String year) {
|
||||
return mapper.getResultByIdcardAndYear(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdcardAndYearAll(String idNo, String year) {
|
||||
return mapper.getResultByIdcardAndYearAll(idNo, year);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByPeId(String peId) {
|
||||
return mapper.getResultByPeId(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getDisResultByAuditDate(String auditDate) {
|
||||
return mapper.getDisResultByAuditDate(auditDate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getItemByPeId(String peId) {
|
||||
return mapper.getItemByPeId(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getItemByPeIdAll(String peId) {
|
||||
return mapper.getItemByPeIdAll(peId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getResultByIdNoOrPeId(String idNo, String peId, String auditYear) {
|
||||
return mapper.getResultByIdNoOrPeId(idNo, peId, auditYear);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getPeIdAndDateByIdcard(String idNo) {
|
||||
return mapper.getPeIdAndDateByIdcard(idNo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getPeIdAndDateByIdcardList(String idNo) {
|
||||
return mapper.getPeIdAndDateByIdcardList(idNo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getExamListByDate(String auditDate) {
|
||||
return mapper.getExamListByDate(auditDate);
|
||||
}
|
||||
|
||||
/** 等价于 Kotlin 的 map[key]?.toString():值为 null 时返回 null,否则转字符串 */
|
||||
private static String str(Object value) {
|
||||
return value == null ? null : String.valueOf(value);
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,13 @@ package com.hospital.front.adapter;
|
||||
import org.noear.solon.annotation.Component;
|
||||
|
||||
/**
|
||||
* 延安医院适配器(SqlServer,ya 方言)。
|
||||
* 延安医院适配器(SqlServer,nx 方言)。
|
||||
*
|
||||
* 延安数据库结构已与宁夏完全一致(V_PHYEXAM_* 视图 + P_ADD_* 存储过程),
|
||||
* 仅连接配置不同,直接复用 NxAdapterBase。
|
||||
*/
|
||||
@Component
|
||||
public class YananAdapter extends YaAdapterBase {
|
||||
public class YananAdapter extends NxAdapterBase {
|
||||
|
||||
@Override
|
||||
public String code() {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.hospital.front.api.admin;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.net.URI;
|
||||
import java.util.Base64;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@@ -23,6 +25,7 @@ import org.noear.solon.core.handle.MethodType;
|
||||
|
||||
import com.hospital.front.adapter.HospitalRouter;
|
||||
import com.hospital.front.dto.Result;
|
||||
import com.hospital.front.infra.DbHealthMonitor;
|
||||
import com.hospital.front.infra.exception.BusinessException;
|
||||
|
||||
/**
|
||||
@@ -43,6 +46,10 @@ public class AdminApi {
|
||||
@Inject
|
||||
private HospitalRouter router;
|
||||
|
||||
/** DB 健康缓存监测(health 接口读缓存秒回,避免 DB 慢时阻塞被 Agent 误判宕机) */
|
||||
@Inject
|
||||
private DbHealthMonitor dbHealthMonitor;
|
||||
|
||||
/** 日志目录(与 logback.xml 的 log.path 保持一致) */
|
||||
private File getLogDir() {
|
||||
return new File(Solon.cfg().get("log.path", "./log"));
|
||||
@@ -53,26 +60,27 @@ public class AdminApi {
|
||||
private void checkToken(Context ctx) {
|
||||
String expected = Solon.cfg().get("admin.token", "");
|
||||
if (expected != null && !expected.trim().isEmpty() && !expected.equals(ctx.header("X-Admin-Token"))) {
|
||||
throw BusinessException.of(Result.CODE_AUTH_FAILED, "管理接口鉴权失败");
|
||||
throw BusinessException.of("管理接口鉴权失败");
|
||||
}
|
||||
}
|
||||
|
||||
// ================= 1. 健康与指标 =================
|
||||
|
||||
/** 健康检查(含数据库探测) */
|
||||
/** 健康检查(进程健康即时返回;DB 状态读后台探测缓存,不阻塞) */
|
||||
@Mapping("/health")
|
||||
public Result<Map<String, Object>> health(Context ctx) {
|
||||
checkToken(ctx);
|
||||
Runtime mem = Runtime.getRuntime();
|
||||
Result<Boolean> db = router.active().healthCheck();
|
||||
Result<Boolean> db = dbHealthMonitor.last();
|
||||
Map<String, Object> out = new LinkedHashMap<>();
|
||||
out.put("status", db.getCode() == 0 ? "UP" : "DEGRADED");
|
||||
// db=null 表示后台首轮探测未完成(启动/唤醒初期),进程本身健康,报 STARTING 而非 DEGRADED
|
||||
out.put("status", db == null ? "STARTING" : (db.isSuccess() ? "UP" : "DEGRADED"));
|
||||
out.put("hospital", router.activeCode());
|
||||
out.put("hospitalName", router.active().displayName());
|
||||
out.put("registeredHospitals", router.registeredCodes());
|
||||
Map<String, Object> database = new HashMap<>();
|
||||
database.put("ok", db.getCode() == 0);
|
||||
database.put("msg", db.getMsg());
|
||||
database.put("ok", db != null && db.isSuccess());
|
||||
database.put("msg", db != null ? db.getMsg() : "DB 探测进行中");
|
||||
out.put("database", database);
|
||||
Map<String, Object> jvm = new HashMap<>();
|
||||
jvm.put("totalMemoryMb", mem.totalMemory() / 1048576);
|
||||
@@ -273,4 +281,136 @@ public class AdminApi {
|
||||
t.start();
|
||||
return Result.success();
|
||||
}
|
||||
|
||||
// ================= 5. 接口代理(供 B 端接口测试工具直连调用) =================
|
||||
|
||||
/** httpProxy 请求体(Solon 自动绑定 JSON 请求体) */
|
||||
public static class HttpProxyReq {
|
||||
/** HTTP 方法:GET/POST/PUT/DELETE */
|
||||
public String method = "GET";
|
||||
/** 接口路径,如 /order/getItemList */
|
||||
public String path;
|
||||
/** query 参数(拼到 URL 上) */
|
||||
public Map<String, String> query;
|
||||
/** 请求体字符串(POST/PUT 时使用) */
|
||||
public String body;
|
||||
/** 额外请求头 */
|
||||
public Map<String, String> headers;
|
||||
}
|
||||
|
||||
/** 代理专用 HttpClient:环回调用本机接口,读超时 120s 适配大接口 */
|
||||
private final java.net.http.HttpClient proxyHttp = java.net.http.HttpClient.newBuilder()
|
||||
.connectTimeout(java.time.Duration.ofSeconds(5))
|
||||
.build();
|
||||
|
||||
/**
|
||||
* HTTP 代理:在 main 进程内环回调用本机接口,原样透传响应。
|
||||
*
|
||||
* B 端接口测试工具经此代理访问业务接口,免去 Agent WS 通道倒手
|
||||
* (WS 通道有 2MB 消息上限与 60s 等待超时,大接口会超时/掉线)。
|
||||
* 自动按 path 附加鉴权头:/order/** → Basic(order.basic 配置),
|
||||
* /api/admin/** → X-Admin-Token。
|
||||
*/
|
||||
@Mapping(value = "/httpProxy", method = {MethodType.POST})
|
||||
public Result<Map<String, Object>> httpProxy(Context ctx, HttpProxyReq req) {
|
||||
checkToken(ctx);
|
||||
// 参数校验与路径白名单:只允许代理本机 /order/** 与 /api/admin/**
|
||||
if (req == null || req.path == null || req.path.isEmpty()) {
|
||||
throw BusinessException.paramMissing("path 不能为空");
|
||||
}
|
||||
String path = req.path.trim();
|
||||
if (!path.startsWith("/order/") && !path.startsWith("/api/admin/")) {
|
||||
throw BusinessException.businessFailed("仅允许代理 /order/** 与 /api/admin/** 路径:" + path);
|
||||
}
|
||||
// 拼接环回 URL:server.port + path + query
|
||||
String port = Solon.cfg().get("server.port", "8080");
|
||||
StringBuilder url = new StringBuilder("http://127.0.0.1:").append(port).append(path);
|
||||
if (req.query != null && !req.query.isEmpty()) {
|
||||
StringBuilder qs = new StringBuilder();
|
||||
for (Map.Entry<String, String> e : req.query.entrySet()) {
|
||||
if (e.getKey() == null || e.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
if (qs.length() > 0) {
|
||||
qs.append('&');
|
||||
}
|
||||
qs.append(java.net.URLEncoder.encode(e.getKey(), StandardCharsets.UTF_8))
|
||||
.append('=')
|
||||
.append(java.net.URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8));
|
||||
}
|
||||
if (qs.length() > 0) {
|
||||
url.append('?').append(qs);
|
||||
}
|
||||
}
|
||||
// 构建请求:按 path 附加鉴权头
|
||||
java.net.http.HttpRequest.Builder rb = java.net.http.HttpRequest.newBuilder(URI_COMPAT.apply(url.toString()));
|
||||
String m = req.method == null ? "GET" : req.method.toUpperCase();
|
||||
java.net.http.HttpRequest.BodyPublisher pub = req.body == null || req.body.isEmpty()
|
||||
? java.net.http.HttpRequest.BodyPublishers.noBody()
|
||||
: java.net.http.HttpRequest.BodyPublishers.ofString(req.body, StandardCharsets.UTF_8);
|
||||
switch (m) {
|
||||
case "POST" -> rb.POST(pub);
|
||||
case "PUT" -> rb.PUT(pub);
|
||||
case "DELETE" -> rb.DELETE();
|
||||
default -> rb.GET();
|
||||
}
|
||||
if (path.startsWith("/order/")) {
|
||||
String basic = Solon.cfg().get("order.basic", "");
|
||||
boolean authFlag = !"false".equals(Solon.cfg().get("order.authFlag", "true"));
|
||||
if (authFlag && basic != null && !basic.isEmpty()) {
|
||||
// 对齐 OrderApi checkBasic 的校验格式:Basic + Base64(user:password)
|
||||
rb.header("Authorization", "Basic "
|
||||
+ Base64.getEncoder().encodeToString(basic.getBytes(StandardCharsets.UTF_8)));
|
||||
}
|
||||
} else {
|
||||
rb.header("X-Admin-Token", Solon.cfg().get("admin.token", ""));
|
||||
}
|
||||
if (req.headers != null) {
|
||||
for (Map.Entry<String, String> e : req.headers.entrySet()) {
|
||||
if (e.getKey() != null && e.getValue() != null) {
|
||||
rb.header(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
rb.timeout(java.time.Duration.ofSeconds(120));
|
||||
// 执行并透传
|
||||
try {
|
||||
java.net.http.HttpResponse<String> resp = proxyHttp.send(rb.build(),
|
||||
java.net.http.HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
|
||||
Map<String, Object> out = new LinkedHashMap<>();
|
||||
out.put("status", resp.statusCode());
|
||||
out.put("body", resp.body());
|
||||
return Result.success(out);
|
||||
} catch (java.io.IOException e) {
|
||||
throw BusinessException.businessFailed("环回调用失败(本机 " + path + "):" + e.getMessage());
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw BusinessException.businessFailed("环回调用被中断:" + path);
|
||||
}
|
||||
}
|
||||
|
||||
/** URI 构建容错(URL 已校验,异常时给出可读错误) */
|
||||
private static final java.util.function.Function<String, URI> URI_COMPAT = s -> {
|
||||
try {
|
||||
return URI.create(s);
|
||||
} catch (Exception e) {
|
||||
throw BusinessException.paramMissing("非法 URL:" + s);
|
||||
}
|
||||
};
|
||||
|
||||
// ================= 6. 接口清单(供 B 端接口测试工具加载) =================
|
||||
|
||||
/**
|
||||
* 返回 /order 业务接口元数据清单。
|
||||
*
|
||||
* 反射扫描 OrderApi 的 @ApiMeta 注解自动生成,无需手写维护。
|
||||
* B 端因前置机白名单无法直连,通过 Agent 通道拉取本接口清单,
|
||||
* 再经 Agent HTTP_PROXY 代理调用具体接口。
|
||||
* 走 X-Admin-Token 鉴权(与其它管理接口一致)。
|
||||
*/
|
||||
@Mapping("/apis")
|
||||
public Result<List<Map<String, Object>>> apis(Context ctx) {
|
||||
checkToken(ctx);
|
||||
return Result.success(com.hospital.front.infra.ApiScanner.scan(com.hospital.front.api.order.OrderApi.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.hospital.front.api.order;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import com.hospital.front.vo.MedicalMiddleResultVo;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -14,11 +15,14 @@ import org.noear.solon.annotation.Path;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
import org.noear.solon.core.handle.MethodType;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.snack.ONode;
|
||||
|
||||
import com.hospital.front.dto.Result;
|
||||
import com.hospital.front.infra.annotation.ApiMeta;
|
||||
import com.hospital.front.infra.annotation.ApiParam;
|
||||
import com.hospital.front.infra.exception.BusinessException;
|
||||
import com.hospital.front.service.OrderService;
|
||||
import com.hospital.front.vo.ExamListVo;
|
||||
import com.hospital.front.vo.PeStatusPhyVo;
|
||||
|
||||
/**
|
||||
* 体检预约业务接口,路径前缀 /order。
|
||||
@@ -29,6 +33,8 @@ import com.hospital.front.service.OrderService;
|
||||
* 鉴权:对齐原程序 Sa-Token 的 SaBasicUtil.check(),对 /order/** 做 HTTP Basic 认证。
|
||||
* 配置 order.basic(格式 "user:password",未配置时放行——与原程序 authFlag=true 且
|
||||
* basic 为空时行为一致,仅建议生产环境必配)。
|
||||
*
|
||||
* 每个业务方法标注 @ApiMeta,供 /api/admin/apis 反射扫描自动生成接口清单(B 端接口测试工具用)。
|
||||
*/
|
||||
@Controller
|
||||
@Mapping("/order")
|
||||
@@ -70,7 +76,7 @@ public class OrderApi {
|
||||
// 认证失败:401 + 质询头(对齐 Sa-Token SaBasicUtil.check 的响应行为)
|
||||
ctx.status(401);
|
||||
ctx.headerSet("WWW-Authenticate", "Basic realm=\"hospital-front\"");
|
||||
throw BusinessException.of(Result.CODE_AUTH_FAILED, "Basic 认证失败");
|
||||
throw BusinessException.of("Basic 认证失败");
|
||||
}
|
||||
|
||||
/** 恒定时间字符串比较(防时序攻击) */
|
||||
@@ -83,16 +89,22 @@ public class OrderApi {
|
||||
// ================= 1. 预约提交 / 取消 =================
|
||||
|
||||
/** 4. 提交预约保存 */
|
||||
@ApiMeta(desc = "提交预约保存", params = {
|
||||
@ApiParam(name = "body", desc = "预约 JSON 体")
|
||||
})
|
||||
@Mapping(value = "/saveOrder", method = {MethodType.POST})
|
||||
public Result<String> saveOrder(Context ctx, @Body String body) {
|
||||
public Result<String> saveOrder(Context ctx, @Body com.hospital.front.vo.OrderV2Vo body) {
|
||||
checkBasic(ctx);
|
||||
// Solon 对 Map 泛型 body 反序列化支持不佳,用 snack3 手动解析
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) ONode.load(body).toObject(Map.class);
|
||||
return Result.success(service.saveOrder(map));
|
||||
// 强类型 DTO 直收(Solon 对 DTO 反序列化无问题),避免 Map 中转
|
||||
return Result.success(service.saveOrder(body));
|
||||
}
|
||||
|
||||
/** 5. 取消体检预约 */
|
||||
@ApiMeta(desc = "取消体检预约", params = {
|
||||
@ApiParam(name = "peId", desc = "体检编号"),
|
||||
@ApiParam(name = "name", desc = "姓名"),
|
||||
@ApiParam(name = "idcard", desc = "身份证号")
|
||||
})
|
||||
@Mapping(value = "/cancelOrder/{peId}", method = {MethodType.POST})
|
||||
public Result<?> cancelOrder(
|
||||
Context ctx,
|
||||
@@ -107,13 +119,20 @@ public class OrderApi {
|
||||
// ================= 2. 体检状态 =================
|
||||
|
||||
/** 3. 体检状态查询(多个 peId 逗号分隔) */
|
||||
@ApiMeta(desc = "体检状态查询(多个 peId 逗号分隔)", params = {
|
||||
@ApiParam(name = "peIds", desc = "体检编号逗号分隔")
|
||||
})
|
||||
@Mapping("/getPeStatus/{peIds}")
|
||||
public Result<List<Map<String, String>>> getPeStatus(Context ctx, @Path("peIds") String peIds) {
|
||||
public Result<List<PeStatusPhyVo>> getPeStatus(Context ctx, @Path("peIds") String peIds) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getPhyexamStatus(peIds));
|
||||
}
|
||||
|
||||
/** 13. 根据身份证号及年份获取当前体检状态及体检项状态 */
|
||||
@ApiMeta(desc = "体检状态及体检项状态", params = {
|
||||
@ApiParam(name = "idNo", desc = "身份证号"),
|
||||
@ApiParam(name = "year", desc = "年份")
|
||||
})
|
||||
@Mapping("/getPeStatusAndItemList/{idNo}/{year}")
|
||||
public Result<Map<String, Object>> getPeStatusAndItemList(Context ctx, @Path("idNo") String idNo, @Path("year") String year) {
|
||||
checkBasic(ctx);
|
||||
@@ -123,6 +142,9 @@ public class OrderApi {
|
||||
// ================= 3. 体检项目 =================
|
||||
|
||||
/** 1. 查询员工体检项目 */
|
||||
@ApiMeta(desc = "员工体检项目", params = {
|
||||
@ApiParam(name = "peId", desc = "体检编号")
|
||||
})
|
||||
@Mapping("/getEmpItem/{peId}")
|
||||
public Result<List<Map<String, Object>>> getEmpItem(Context ctx, @Path("peId") String peId) {
|
||||
checkBasic(ctx);
|
||||
@@ -130,6 +152,7 @@ public class OrderApi {
|
||||
}
|
||||
|
||||
/** 2. 体检项目查询 */
|
||||
@ApiMeta(desc = "体检项目查询")
|
||||
@Mapping("/getItemList")
|
||||
public Result<List<Map<String, Object>>> getItemList(Context ctx) {
|
||||
checkBasic(ctx);
|
||||
@@ -137,6 +160,7 @@ public class OrderApi {
|
||||
}
|
||||
|
||||
/** 6. 体检指标项数据获取 */
|
||||
@ApiMeta(desc = "体检指标项数据获取")
|
||||
@Mapping("/getPeItemList")
|
||||
public Result<List<Map<String, Object>>> getPeItemList(Context ctx) {
|
||||
checkBasic(ctx);
|
||||
@@ -144,6 +168,7 @@ public class OrderApi {
|
||||
}
|
||||
|
||||
/** 6.1 体检指标项及体检组合数据获取 */
|
||||
@ApiMeta(desc = "体检指标项及体检组合数据获取")
|
||||
@Mapping("/getAllItemList")
|
||||
public Result<List<Map<String, Object>>> getAllItemList(Context ctx) {
|
||||
checkBasic(ctx);
|
||||
@@ -151,6 +176,9 @@ public class OrderApi {
|
||||
}
|
||||
|
||||
/** 7. 根据体检指标项查询所属体检组合项 */
|
||||
@ApiMeta(desc = "按体检指标项查所属组合", params = {
|
||||
@ApiParam(name = "peItemCode", desc = "体检指标项编码")
|
||||
})
|
||||
@Mapping("/getItemInfo/{peItemCode}")
|
||||
public Result<List<Map<String, Object>>> getItemInfo(Context ctx, @Path("peItemCode") String peItemCode) {
|
||||
checkBasic(ctx);
|
||||
@@ -160,92 +188,59 @@ public class OrderApi {
|
||||
// ================= 4. 体检结果 / 结论 / 建议 =================
|
||||
|
||||
/** 8. 根据体检编号获取员工体检结果 */
|
||||
@ApiMeta(desc = "按体检编号查员工体检结果", params = {
|
||||
@ApiParam(name = "peId", desc = "体检编号")
|
||||
})
|
||||
@Mapping("/getResult/{peId}")
|
||||
public Result<List<Map<String, Object>>> getResult(Context ctx, @Path("peId") String peId) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getResult(peId));
|
||||
}
|
||||
|
||||
/** 9. 体检结论(汇总) */
|
||||
@Mapping("/getTotalConclusion/{peId}")
|
||||
public Result<Map<String, String>> getTotalConclusion(Context ctx, @Path("peId") String peId) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getTotalConclusion(peId));
|
||||
}
|
||||
|
||||
/** 10. 体检建议(汇总) */
|
||||
@Mapping("/getTotalSuggest/{peId}")
|
||||
public Result<Map<String, String>> getTotalSuggest(Context ctx, @Path("peId") String peId) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getTotalSuggest(peId));
|
||||
}
|
||||
|
||||
/** 11. 体检结论(列表) */
|
||||
@Mapping("/getConclusion/{peId}")
|
||||
public Result<List<Map<String, Object>>> getConclusion(Context ctx, @Path("peId") String peId) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getConclusion(peId));
|
||||
}
|
||||
|
||||
/** 12. 体检建议(列表) */
|
||||
@Mapping("/getSuggest/{peId}")
|
||||
public Result<List<Map<String, Object>>> getSuggest(Context ctx, @Path("peId") String peId) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getSuggest(peId));
|
||||
}
|
||||
// 9/10/11/12(体检结论/建议 汇总与列表)不再对外暴露:结论/建议仅作为
|
||||
// 体检报告的组成部分在应用层组装,相关查询(getConclusionAll/getSuggestAll)为内部使用
|
||||
|
||||
// ================= 5. 按身份证 / 日期查询 =================
|
||||
|
||||
/** 14. 根据身份证号及年份获取体检结果 */
|
||||
@Mapping("/getResultByIdcardAndYear/{idNo}/{year}")
|
||||
public Result<List<Map<String, Object>>> getResultByIdcardAndYear(Context ctx, @Path("idNo") String idNo, @Path("year") String year) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getResultByIdcardAndYear(idNo, year));
|
||||
}
|
||||
// 14(按身份证及年份查结果)/ 15.3(按审查日期查报告)/ 16(按身份证或编号+年份查报告)
|
||||
// 不再对外暴露:相关查询为内部使用(如 getPeStatusByIdnoAndYear 的宁夏兜底)
|
||||
// 14.1 全量版保留对外
|
||||
|
||||
/** 14.1 根据身份证号及年份获取体检结果(全量) */
|
||||
@ApiMeta(desc = "按身份证及年份查全量结果", params = {
|
||||
@ApiParam(name = "idNo", desc = "身份证号"),
|
||||
@ApiParam(name = "year", desc = "年份")
|
||||
})
|
||||
@Mapping("/getResultByIdcardAndYearAll/{idNo}/{year}")
|
||||
public Result<List<Map<String, Object>>> getResultByIdcardAndYearAll(Context ctx, @Path("idNo") String idNo, @Path("year") String year) {
|
||||
public Result<List<MedicalMiddleResultVo>> getResultByIdcardAndYearAll(Context ctx, @Path("idNo") String idNo, @Path("year") String year) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getResultByIdcardAndYearAll(idNo, year));
|
||||
}
|
||||
|
||||
/** 15.1 根据体检编号获取体检结果 */
|
||||
@ApiMeta(desc = "按体检编号查体检结果", params = {
|
||||
@ApiParam(name = "peId", desc = "体检编号")
|
||||
})
|
||||
@Mapping("/getResultByPeId/{peId}")
|
||||
public Result<List<Map<String, Object>>> getResultByPeId(Context ctx, @Path("peId") String peId) {
|
||||
public Result<List<MedicalMiddleResultVo>> getResultByPeId(Context ctx, @Path("peId") String peId) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getResultByPeId(peId));
|
||||
}
|
||||
|
||||
/** 15.2 根据体检编号获取体检状态(简) */
|
||||
@ApiMeta(desc = "按体检编号查体检状态(简)", params = {
|
||||
@ApiParam(name = "peId", desc = "体检编号")
|
||||
})
|
||||
@Mapping("/getResultStatus/{peId}")
|
||||
public Result<List<Map<String, Object>>> getResultStatus(Context ctx, @Path("peId") String peId) {
|
||||
public Result<List<MedicalMiddleResultVo>> getResultStatus(Context ctx, @Path("peId") String peId) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getResultByPeId(peId));
|
||||
}
|
||||
|
||||
/** 15.3 根据 audit_date 查询当天的体检报告 */
|
||||
@Mapping("/getResultByAuditDate/{auditDate}")
|
||||
public Result<List<Map<String, Object>>> getResultByAuditDate(Context ctx, @Path("auditDate") String auditDate) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getResultByAuditDate(auditDate));
|
||||
}
|
||||
|
||||
/** 16. 根据 id_code 或 pe_id 和审查年份查询体检报告 */
|
||||
@Mapping(value = "/getResultByIdNoOrPeId", method = {MethodType.POST})
|
||||
public Result<List<Map<String, Object>>> getResultByIdNoOrPeId(
|
||||
Context ctx,
|
||||
@Param(value = "idNo", required = false) String idNo,
|
||||
@Param(value = "peId", required = false) String peId,
|
||||
@Param("auditYear") String auditYear) {
|
||||
checkBasic(ctx);
|
||||
if (isNullOrBlank(idNo) && isNullOrBlank(peId)) {
|
||||
throw BusinessException.paramMissing("身份证号或体检编号");
|
||||
}
|
||||
return Result.success(service.getResultByIdNoOrPeId(idNo, peId, auditYear));
|
||||
return Result.success(service.getResultStatus(peId));
|
||||
}
|
||||
|
||||
/** 17. 根据身份证号查询当前年的 peId 和预约日期 */
|
||||
@ApiMeta(desc = "按身份证查当年 peId 和预约日期", params = {
|
||||
@ApiParam(name = "idNo", desc = "身份证号")
|
||||
})
|
||||
@Mapping("/getPeIdAndDateByIdcard/{idNo}")
|
||||
public Result<Map<String, Object>> getPeIdAndDateByIdcard(Context ctx, @Path("idNo") String idNo) {
|
||||
checkBasic(ctx);
|
||||
@@ -253,6 +248,9 @@ public class OrderApi {
|
||||
}
|
||||
|
||||
/** 17.1 同上(数组) */
|
||||
@ApiMeta(desc = "按身份证查 peId 和预约日期(数组)", params = {
|
||||
@ApiParam(name = "idNo", desc = "身份证号")
|
||||
})
|
||||
@Mapping("/getPeIdAndDateByIdcardList/{idNo}")
|
||||
public Result<List<Map<String, Object>>> getPeIdAndDateByIdcardList(Context ctx, @Path("idNo") String idNo) {
|
||||
checkBasic(ctx);
|
||||
@@ -262,25 +260,23 @@ public class OrderApi {
|
||||
// ================= 6. 单位 / 人员列表 =================
|
||||
|
||||
/** 18. 添加修改单位信息 */
|
||||
@ApiMeta(desc = "添加修改单位信息", params = {
|
||||
@ApiParam(name = "body", desc = "单位 JSON 数组")
|
||||
})
|
||||
@Mapping(value = "/addUnit", method = {MethodType.POST})
|
||||
public Result<?> addUnit(Context ctx, @Body String body) {
|
||||
checkBasic(ctx);
|
||||
// Solon 对 List 泛型 body 反序列化支持不佳,此处用 snack3 手动解析
|
||||
List<Map<String, Object>> units;
|
||||
if (body == null || body.trim().isEmpty()) {
|
||||
units = new ArrayList<>();
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Map<String, Object>> parsed = (List<Map<String, Object>>) ONode.load(body).toObject(List.class);
|
||||
units = parsed;
|
||||
}
|
||||
String errors = service.addUnits(units);
|
||||
// Solon 对 List 泛型 body 支持不佳,用 JsonUtils 统一解析(空串返回空列表)
|
||||
String errors = service.addUnits(com.hospital.front.infra.util.JsonUtils.parseList(body));
|
||||
return errors != null ? Result.error(errors) : Result.success();
|
||||
}
|
||||
|
||||
/** 19. 根据日期查询当天体检人员列表(去重),日期为空则查当天 */
|
||||
@ApiMeta(desc = "按日期查当天体检人员列表(去重)", params = {
|
||||
@ApiParam(name = "auditDate", desc = "审查日期(空则查当天)")
|
||||
})
|
||||
@Mapping("/getExamListByDate")
|
||||
public Result<List<Map<String, Object>>> getExamListByDate(Context ctx, @Param("auditDate") String auditDate) {
|
||||
public Result<List<ExamListVo>> getExamListByDate(Context ctx, @Param("auditDate") String auditDate) {
|
||||
checkBasic(ctx);
|
||||
return Result.success(service.getExamListByDate(auditDate));
|
||||
}
|
||||
|
||||
@@ -1,114 +1,49 @@
|
||||
package com.hospital.front.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 统一 API 响应包装。
|
||||
*
|
||||
* 业务接口均使用此结构返回,便于前端统一处理。
|
||||
* 结构与原 hospitalmiddle 的 Result 保持一致(对外 JSON 契约,不可修改):
|
||||
* {"success": true/false, "msg": "成功", "data": ...}
|
||||
*
|
||||
* @param <T> 数据类型
|
||||
* @author hospital-front重构
|
||||
*/
|
||||
@Data
|
||||
public class Result<T> {
|
||||
|
||||
/** 业务码(0=成功) */
|
||||
private final int code;
|
||||
/** 是否成功 */
|
||||
private boolean success = false;
|
||||
|
||||
/** 提示信息 */
|
||||
private final String msg;
|
||||
private String msg;
|
||||
|
||||
/** 业务数据 */
|
||||
private final T data;
|
||||
private T data;
|
||||
|
||||
/**
|
||||
* 全参构造器。
|
||||
*
|
||||
* @param code 业务码(0=成功)
|
||||
* @param msg 提示信息
|
||||
* @param data 业务数据(可为 null)
|
||||
*/
|
||||
public Result(int code, String msg, T data) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
this.data = data;
|
||||
/** 成功响应(无数据),msg 固定"成功"(对齐原项目) */
|
||||
public static Result success() {
|
||||
Result result = new Result();
|
||||
result.setSuccess(true);
|
||||
result.setMsg("成功");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 两参构造器(data 默认为 null,与 Kotlin 默认参数语义一致)。
|
||||
*
|
||||
* @param code 业务码
|
||||
* @param msg 提示信息
|
||||
*/
|
||||
public Result(int code, String msg) {
|
||||
this(code, msg, null);
|
||||
/** 成功响应(带数据) */
|
||||
public static <T> Result success(T t) {
|
||||
Result result = new Result();
|
||||
result.setSuccess(true);
|
||||
result.setMsg("成功");
|
||||
result.setData(t);
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 业务成功码 */
|
||||
public static final int SUCCESS_CODE = 0;
|
||||
|
||||
/** 业务失败默认码 */
|
||||
public static final int ERROR_CODE = 5001;
|
||||
|
||||
/** 参数缺失 */
|
||||
public static final int CODE_PARAM_MISSING = 1001;
|
||||
|
||||
/** 参数格式错误 */
|
||||
public static final int CODE_PARAM_FORMAT = 1002;
|
||||
|
||||
/** 业务校验失败 */
|
||||
public static final int CODE_BUSINESS = 1003;
|
||||
|
||||
/** 存储过程调用失败 */
|
||||
public static final int CODE_PROC_FAILED = 2001;
|
||||
|
||||
/** 数据库连接失败 */
|
||||
public static final int CODE_DB_UNREACHABLE = 2002;
|
||||
|
||||
/** 医院系统返回业务失败 */
|
||||
public static final int CODE_HOSPITAL_FAILED = 2003;
|
||||
|
||||
/** 鉴权失败 */
|
||||
public static final int CODE_AUTH_FAILED = 3001;
|
||||
|
||||
/** Token 过期 */
|
||||
public static final int CODE_TOKEN_EXPIRED = 3002;
|
||||
|
||||
/**
|
||||
* 成功响应(无数据)。
|
||||
*/
|
||||
public static <T> Result<T> success() {
|
||||
return new Result<>(SUCCESS_CODE, "success", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 成功响应。
|
||||
*/
|
||||
public static <T> Result<T> success(T data) {
|
||||
return new Result<>(SUCCESS_CODE, "success", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应(默认错误码)。
|
||||
*/
|
||||
public static <T> Result<T> error(String msg) {
|
||||
return new Result<>(ERROR_CODE, msg, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误响应(指定错误码)。
|
||||
*/
|
||||
public static <T> Result<T> error(int code, String msg) {
|
||||
return new Result<>(code, msg, null);
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
/** 错误响应 */
|
||||
public static Result error(String msg) {
|
||||
Result result = new Result();
|
||||
result.setSuccess(false);
|
||||
result.setMsg(msg);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.hospital.front.infra;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
import org.noear.solon.core.handle.Filter;
|
||||
import org.noear.solon.core.handle.FilterChain;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* 全局接口访问日志过滤器。
|
||||
*
|
||||
* 统一打印每个请求的调用日志:HTTP 方法、路径、来源 IP、请求参数、耗时、响应状态码。
|
||||
* 覆盖所有 Controller(/order、/api/admin),新增接口自动生效,无需逐个手写日志。
|
||||
*
|
||||
* 参数覆盖说明:
|
||||
* - @Param(query/form)与 @Path(路径变量)统一通过 ctx.paramMap() 取;@Path 的值同时也在 ctx.path() 里可见。
|
||||
* - @Body 参数(saveOrder/addUnit)不在此读取,避免消费 body 流破坏 @Body 反序列化;
|
||||
* 由 service 层日志覆盖(saveOrder 打印 peInfoStr/peItemStr,addUnit 打印 units)。
|
||||
*
|
||||
* 顺序:index = -1 保证本过滤器在 GlobalExceptionHandler / IpWhitelistFilter 之前执行(最外层),
|
||||
* 从而能记录到异常被处理后写入 ctx 的最终状态码(401/500 等)。
|
||||
*/
|
||||
@Slf4j
|
||||
@Component(index = -1)
|
||||
public class ApiAccessLogFilter implements Filter {
|
||||
|
||||
/** 无需打印访问日志的路径(高频健康探测等,避免刷屏) */
|
||||
private static final Set<String> SKIP_LOG_PATHS = Set.of("/api/admin/health");
|
||||
|
||||
@Override
|
||||
public void doFilter(Context ctx, FilterChain chain) throws Throwable {
|
||||
long start = System.currentTimeMillis();
|
||||
try {
|
||||
chain.doFilter(ctx);
|
||||
} finally {
|
||||
long cost = System.currentTimeMillis() - start;
|
||||
if (!SKIP_LOG_PATHS.contains(ctx.path())) {
|
||||
log.info("[接口调用] {} {} ip={} 参数=[{}] cost={}ms status={}",
|
||||
ctx.method(), ctx.path(), ctx.remoteIp(), paramsOf(ctx), cost, ctx.status());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** 汇总请求参数(query/form/path,@Body 除外),形如 key1=v1, key2=v2 */
|
||||
private String paramsOf(Context ctx) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (var kv : ctx.paramMap()) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(kv.getKey()).append('=').append(kv.getFirstValue());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.hospital.front.infra;
|
||||
|
||||
import com.hospital.front.infra.annotation.ApiMeta;
|
||||
import com.hospital.front.infra.annotation.ApiParam;
|
||||
import org.noear.solon.annotation.Body;
|
||||
import org.noear.solon.annotation.Mapping;
|
||||
import org.noear.solon.annotation.Param;
|
||||
import org.noear.solon.annotation.Path;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
import org.noear.solon.core.handle.MethodType;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 接口元数据扫描器。
|
||||
*
|
||||
* 反射扫描指定 Controller 类的所有 @ApiMeta 标注方法,自动提取:
|
||||
* - method:从 @Mapping.method()(空数组视为 GET)
|
||||
* - path:类 @Mapping 前缀 + 方法 @Mapping.value()
|
||||
* - params:从方法签名 @Path/@Param/@Body 提取 name/in/required/type,@ApiMeta.params 补充 desc
|
||||
*
|
||||
* 替代手写接口清单,新增/调整接口时只需维护 @ApiMeta 注解即可自动同步。
|
||||
*/
|
||||
public final class ApiScanner {
|
||||
|
||||
private ApiScanner() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 扫描指定 Controller 类,返回带 @ApiMeta 的接口元数据清单。
|
||||
*
|
||||
* @param controllerClass Controller 类(如 OrderApi.class)
|
||||
* @return 接口元数据列表(不可变)
|
||||
*/
|
||||
public static List<Map<String, Object>> scan(Class<?> controllerClass) {
|
||||
// 类级路径前缀(如 /order)
|
||||
String prefix = "";
|
||||
Mapping classMapping = controllerClass.getAnnotation(Mapping.class);
|
||||
if (classMapping != null && !classMapping.value().isEmpty()) {
|
||||
prefix = classMapping.value();
|
||||
}
|
||||
|
||||
List<Map<String, Object>> list = new ArrayList<>();
|
||||
for (Method method : controllerClass.getDeclaredMethods()) {
|
||||
ApiMeta meta = method.getAnnotation(ApiMeta.class);
|
||||
Mapping methodMapping = method.getAnnotation(Mapping.class);
|
||||
if (meta == null || methodMapping == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 拼接完整路径
|
||||
String path = prefix + (methodMapping.value() == null ? "" : methodMapping.value());
|
||||
|
||||
// HTTP 方法:Solon @Mapping 不显式指定时 method() 返回 ALL(支持所有方法),
|
||||
// 接口测试场景下默认按 GET 处理(OrderApi 的 GET 接口均未显式指定 method)
|
||||
String httpMethod = "GET";
|
||||
MethodType[] mtypes = methodMapping.method();
|
||||
if (mtypes != null && mtypes.length > 0) {
|
||||
String name = mtypes[0].name();
|
||||
if (!"ALL".equals(name) && !"UNKNOWN".equals(name)) {
|
||||
httpMethod = name;
|
||||
}
|
||||
}
|
||||
|
||||
// @ApiMeta.params 转 name→desc 映射,供参数补充描述
|
||||
Map<String, String> descMap = new LinkedHashMap<>();
|
||||
for (ApiParam ap : meta.params()) {
|
||||
descMap.put(ap.name(), ap.desc());
|
||||
}
|
||||
|
||||
// 扫描方法参数(跳过 Context)
|
||||
List<Map<String, Object>> params = new ArrayList<>();
|
||||
for (Parameter p : method.getParameters()) {
|
||||
if (p.getType() == Context.class) {
|
||||
continue;
|
||||
}
|
||||
Map<String, Object> param = extractParam(p, descMap);
|
||||
if (param != null) {
|
||||
params.add(param);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> item = new LinkedHashMap<>();
|
||||
item.put("method", httpMethod);
|
||||
item.put("path", path);
|
||||
item.put("desc", meta.desc());
|
||||
item.put("params", params);
|
||||
list.add(item);
|
||||
}
|
||||
return Collections.unmodifiableList(list);
|
||||
}
|
||||
|
||||
/** 从单个方法参数提取元数据 */
|
||||
private static Map<String, Object> extractParam(Parameter p, Map<String, String> descMap) {
|
||||
Map<String, Object> param = new LinkedHashMap<>();
|
||||
Path pathAnno = p.getAnnotation(Path.class);
|
||||
Param paramAnno = p.getAnnotation(Param.class);
|
||||
Body bodyAnno = p.getAnnotation(Body.class);
|
||||
|
||||
if (pathAnno != null) {
|
||||
String name = pathAnno.value().isEmpty() ? p.getName() : pathAnno.value();
|
||||
param.put("name", name);
|
||||
param.put("in", "path");
|
||||
param.put("type", "string");
|
||||
param.put("required", true);
|
||||
} else if (bodyAnno != null) {
|
||||
param.put("name", "body");
|
||||
param.put("in", "body");
|
||||
param.put("type", "json");
|
||||
param.put("required", true);
|
||||
} else if (paramAnno != null) {
|
||||
String name = paramAnno.value().isEmpty() ? p.getName() : paramAnno.value();
|
||||
param.put("name", name);
|
||||
param.put("in", "query");
|
||||
param.put("type", "string");
|
||||
param.put("required", paramAnno.required());
|
||||
} else {
|
||||
// 无 Solon 参数注解,跳过(如注入的 bean 等)
|
||||
return null;
|
||||
}
|
||||
param.put("desc", descMap.getOrDefault((String) param.get("name"), ""));
|
||||
return param;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.hospital.front.infra;
|
||||
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
import org.noear.solon.scheduling.annotation.Scheduled;
|
||||
|
||||
import com.hospital.front.adapter.HospitalRouter;
|
||||
import com.hospital.front.dto.Result;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 数据库健康后台监测(缓存式)。
|
||||
*
|
||||
* 后台周期探测 DB(默认 30 秒),/api/admin/health 直接读缓存秒回——
|
||||
* 避免 DB 建连慢(如机器休眠唤醒后网络未就绪,实测可达 4 分钟)时
|
||||
* 健康接口长时间阻塞,导致 Agent 看门狗 30s 超时误判主程序宕机而反复重启。
|
||||
*
|
||||
* 启动初期缓存为空视为 STARTING(探测线程尚未跑完第一轮),不算故障。
|
||||
*/
|
||||
@Component
|
||||
public class DbHealthMonitor {
|
||||
|
||||
@Inject
|
||||
private HospitalRouter router;
|
||||
|
||||
/** 最近一次探测结果(null = 尚未完成首轮探测) */
|
||||
private final AtomicReference<Result<Boolean>> last = new AtomicReference<>();
|
||||
|
||||
/** 周期探测(首轮延迟由调度器决定,失败不影响后续轮次) */
|
||||
@Scheduled(cron = "*/30 * * * * *")
|
||||
public void probe() {
|
||||
try {
|
||||
last.set(router.active().healthCheck());
|
||||
} catch (Exception e) {
|
||||
// healthCheck 内部已捕获,此处兜底防止调度线程中断
|
||||
last.set(Result.error("探测异常:" + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
/** 最近一次探测结果;未完成首轮探测时返回 null(调用方按 STARTING 处理) */
|
||||
public Result<Boolean> last() {
|
||||
return last.get();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package com.hospital.front.infra;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
import org.noear.solon.core.handle.Filter;
|
||||
import org.noear.solon.core.handle.FilterChain;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* IP 白名单过滤器(应对前置机端口被公网扫描器探测)。
|
||||
*
|
||||
* 配置(app.yml,支持医院配置覆盖):
|
||||
* security:
|
||||
* ipWhitelistEnabled: false # 白名单开关(默认关,行为不变)
|
||||
* ipWhitelist: "10.10.10.228,10.0.0.0/24" # IP 池,逗号分隔
|
||||
*
|
||||
* 规则:
|
||||
* - 开关关闭时全放行(默认)
|
||||
* - 127.0.0.1 / ::1(Agent 环回访问 /api/admin)永远放行,无需配置
|
||||
* - 直连部署:取连接对端 IP(remoteIp)判定
|
||||
* - nginx 反代部署(security.trustProxy=true):连接对端必须是环回或 nginx 所在 IP,
|
||||
* 然后取 X-Forwarded-For 的最右侧 IP 判定(最右侧由可信 nginx 追加,无法伪造;
|
||||
* 不能取最左侧——客户端可自带 XFF 冒充白名单)
|
||||
* - 支持三种写法:精确 IP(10.0.0.5)、通配段(112.113.*.*,每段可单独 *)、
|
||||
* CIDR 网段(10.0.0.0/24)
|
||||
* - 非白名单一律 403 打回,并记 WARN 一行(含来源 IP 与路径,便于追踪扫描源)
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class IpWhitelistFilter implements Filter {
|
||||
|
||||
/** 环回地址(永远放行) */
|
||||
private static final Set<String> LOOPBACK = new HashSet<>(Arrays.asList("127.0.0.1", "0:0:0:0:0:0:0:1", "::1"));
|
||||
|
||||
@Override
|
||||
public void doFilter(Context ctx, FilterChain chain) throws Throwable {
|
||||
if (!enabled()) {
|
||||
chain.doFilter(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
String peer = ctx.remoteIp() != null ? ctx.remoteIp() : "";
|
||||
String ip = peer;
|
||||
|
||||
if (trustProxy()) {
|
||||
// 反代模式:对端必须是环回(同机 nginx)或白名单中的代理 IP,
|
||||
// 否则视为伪造直连,直接打回
|
||||
if (!LOOPBACK.contains(peer)) {
|
||||
log.warn("[IP白名单] 代理模式下非可信代理直连:ip={} {} {}", peer, ctx.method(), ctx.path());
|
||||
reject(ctx, peer);
|
||||
return;
|
||||
}
|
||||
// X-Forwarded-For 最右侧为本机 nginx 追加的真实客户端 IP(不可伪造)
|
||||
String xff = ctx.header("X-Forwarded-For");
|
||||
if (xff != null && !xff.trim().isEmpty()) {
|
||||
String[] hops = xff.split(",");
|
||||
ip = hops[hops.length - 1].trim();
|
||||
}
|
||||
// 无 XFF 的环回请求 = Agent 本机访问,保持环回 IP(放行)
|
||||
}
|
||||
|
||||
if (isAllowed(ip)) {
|
||||
chain.doFilter(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
reject(ctx, ip);
|
||||
}
|
||||
|
||||
/** 非白名单:403 打回(一行日志,避免扫描器刷爆日志) */
|
||||
private void reject(Context ctx, String ip) {
|
||||
log.warn("[IP白名单] 拒绝访问:ip={} {} {}", ip, ctx.method(), ctx.path());
|
||||
ctx.status(403);
|
||||
ctx.contentType("application/json;charset=UTF-8");
|
||||
ctx.output("{\"success\":false,\"msg\":\"禁止访问\",\"data\":null}");
|
||||
}
|
||||
|
||||
/** 白名单开关(惰性读取,支持热更新) */
|
||||
private boolean enabled() {
|
||||
return "true".equals(Solon.cfg().get("security.ipWhitelistEnabled", "false"));
|
||||
}
|
||||
|
||||
/** 代理模式开关:nginx 反代部署时置 true,从 X-Forwarded-For 取真实客户端 IP */
|
||||
private boolean trustProxy() {
|
||||
return "true".equals(Solon.cfg().get("security.trustProxy", "false"));
|
||||
}
|
||||
|
||||
/** IP 是否放行:环回 / 精确匹配 / 通配段匹配 / CIDR 网段匹配 */
|
||||
private boolean isAllowed(String ip) {
|
||||
if (LOOPBACK.contains(ip)) {
|
||||
return true;
|
||||
}
|
||||
for (String entry : pool()) {
|
||||
if (entry.contains("/")) {
|
||||
if (cidrMatch(ip, entry)) {
|
||||
return true;
|
||||
}
|
||||
} else if (entry.contains("*")) {
|
||||
if (wildcardMatch(ip, entry)) {
|
||||
return true;
|
||||
}
|
||||
} else if (entry.equals(ip)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 通配段匹配(仅 IPv4):entry 每段可为 * 或具体数字,如 112.113.*.*。
|
||||
*/
|
||||
private static boolean wildcardMatch(String ip, String entry) {
|
||||
String[] ipParts = ip.split("\\.");
|
||||
String[] entryParts = entry.split("\\.");
|
||||
if (ipParts.length != 4 || entryParts.length != 4) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (!"*".equals(entryParts[i]) && !entryParts[i].equals(ipParts[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 白名单 IP 池(逗号分隔,惰性读取) */
|
||||
private Set<String> pool() {
|
||||
String raw = Solon.cfg().get("security.ipWhitelist", "");
|
||||
Set<String> set = new HashSet<>();
|
||||
if (raw != null && !raw.trim().isEmpty()) {
|
||||
for (String s : raw.split(",")) {
|
||||
if (!s.trim().isEmpty()) {
|
||||
set.add(s.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/** IPv4 CIDR 网段匹配(如 10.0.0.0/24) */
|
||||
private static boolean cidrMatch(String ip, String cidr) {
|
||||
try {
|
||||
String[] parts = cidr.split("/");
|
||||
byte[] net = java.net.InetAddress.getByName(parts[0]).getAddress();
|
||||
int prefix = Integer.parseInt(parts[1]);
|
||||
byte[] addr = java.net.InetAddress.getByName(ip).getAddress();
|
||||
if (net.length != addr.length || net.length != 4) {
|
||||
return false; // 仅支持 IPv4 网段
|
||||
}
|
||||
int fullBytes = prefix / 8;
|
||||
int restBits = prefix % 8;
|
||||
for (int i = 0; i < fullBytes; i++) {
|
||||
if (net[i] != addr[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (restBits > 0 && fullBytes < 4) {
|
||||
int mask = 0xFF << (8 - restBits);
|
||||
if ((net[fullBytes] & mask) != (addr[fullBytes] & mask)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false; // 网段配置非法视为不匹配
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.hospital.front.infra.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 接口元数据注解(标注在 Controller 方法上)。
|
||||
*
|
||||
* 用于 /api/admin/apis 反射扫描自动生成接口清单,供 B 端接口测试工具加载。
|
||||
* 标注后无需手写清单,新增/调整接口时自动同步。
|
||||
*
|
||||
* 参数的 name/in/required/type 由方法签名(@Path/@Param/@Body)反射自动提取,
|
||||
* 此处仅补充方法描述与参数描述(按 name 匹配)。
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ApiMeta {
|
||||
/** 接口描述 */
|
||||
String desc();
|
||||
|
||||
/** 参数描述(按 name 匹配方法参数补充 desc) */
|
||||
ApiParam[] params() default {};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.hospital.front.infra.annotation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.annotation.ElementType;
|
||||
|
||||
/**
|
||||
* 接口参数描述注解(仅作为 {@link ApiMeta#params()} 数组成员,不单独标注)。
|
||||
*
|
||||
* 扫描时按 name 匹配方法参数,补充其 desc。
|
||||
*/
|
||||
@Target(ElementType.ANNOTATION_TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface ApiParam {
|
||||
/** 参数名(须与方法签名 @Path/@Param/@Body 的参数名一致) */
|
||||
String name();
|
||||
|
||||
/** 参数描述 */
|
||||
String desc() default "";
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.hospital.front.infra.exception;
|
||||
|
||||
import com.hospital.front.dto.Result;
|
||||
|
||||
/**
|
||||
* 业务异常。
|
||||
*
|
||||
* 用于业务层显式抛出指定错误码的异常,会被 GlobalExceptionHandler 捕获并包装为 Result。
|
||||
* 对外契约与原 hospitalmiddle 一致:异常统一以 {"success":false,"msg":...} 返回,
|
||||
* 不携带错误码(code 体系已随 Result 对齐移除,分类信息仅用于日志排查)。
|
||||
*
|
||||
* @author hospital-front重构
|
||||
*/
|
||||
@@ -13,46 +12,32 @@ public class BusinessException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 业务错误码(参见 Result 中的常量) */
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 构造业务异常。
|
||||
*
|
||||
* @param code 业务错误码
|
||||
* @param message 错误描述
|
||||
*/
|
||||
public BusinessException(int code, String message) {
|
||||
public BusinessException(String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态工厂方法。
|
||||
*
|
||||
* @param code 业务错误码
|
||||
* @param message 错误描述
|
||||
*/
|
||||
public static BusinessException of(int code, String message) {
|
||||
return new BusinessException(code, message);
|
||||
/** 静态工厂方法 */
|
||||
public static BusinessException of(String message) {
|
||||
return new BusinessException(message);
|
||||
}
|
||||
|
||||
/** 参数缺失异常 */
|
||||
public static BusinessException paramMissing(String field) {
|
||||
return new BusinessException(Result.CODE_PARAM_MISSING, "参数缺失:" + field);
|
||||
return new BusinessException("参数缺失:" + field);
|
||||
}
|
||||
|
||||
/** 业务校验失败异常 */
|
||||
public static BusinessException businessFailed(String msg) {
|
||||
return new BusinessException(Result.CODE_BUSINESS, msg);
|
||||
return new BusinessException(msg);
|
||||
}
|
||||
|
||||
/** 存储过程调用失败异常 */
|
||||
public static BusinessException procFailed(String msg) {
|
||||
return new BusinessException(Result.CODE_PROC_FAILED, msg);
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
return new BusinessException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,36 +23,63 @@ public class GlobalExceptionHandler implements Filter {
|
||||
public void doFilter(Context ctx, FilterChain chain) {
|
||||
try {
|
||||
chain.doFilter(ctx);
|
||||
} catch (org.noear.solon.core.exception.StatusException e) {
|
||||
int code = e.getCode();
|
||||
if (code >= 500) {
|
||||
// 5xx 服务端状态异常:真实故障,ERROR 记堆栈
|
||||
log.error("服务端状态异常:{} {}(HTTP {})", ctx.method(), ctx.path(), code, e);
|
||||
} else if (code == 400) {
|
||||
// 400 请求解析失败(多为 multipart/Content-Type 错误):真实调用失败,WARN 并带 Content-Type 便于定位
|
||||
log.warn("请求解析失败(HTTP 400):{} {},Content-Type={}", ctx.method(), ctx.path(), ctx.header("Content-Type"));
|
||||
} else if (code == 404) {
|
||||
// 404 路由未匹配:多为扫描器探测,DEBUG 静默(INFO 级别下不再输出)
|
||||
log.debug("路由未匹配:{} {}(HTTP 404)", ctx.method(), ctx.path());
|
||||
} else {
|
||||
// 其它 4xx(401/403/405/415 等)
|
||||
log.info("客户端状态异常:{} {}(HTTP {})", ctx.method(), ctx.path(), code);
|
||||
}
|
||||
renderStatus(ctx, code);
|
||||
} catch (BusinessException e) {
|
||||
String msg = e.getMessage() != null ? e.getMessage() : "业务异常";
|
||||
log.warn("业务异常:code={}, msg={}", e.getCode(), e.getMessage());
|
||||
renderResult(ctx, Result.error(e.getCode(), msg));
|
||||
log.warn("业务异常:{}", e.getMessage());
|
||||
renderResult(ctx, Result.error(msg));
|
||||
} catch (IllegalArgumentException e) {
|
||||
String msg = e.getMessage() != null ? e.getMessage() : "参数错误";
|
||||
log.warn("参数异常:{}", e.getMessage());
|
||||
renderResult(ctx, Result.error(Result.CODE_PARAM_FORMAT, msg));
|
||||
renderResult(ctx, Result.error(msg));
|
||||
} catch (Exception e) {
|
||||
log.error("系统异常", e);
|
||||
String msg = e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName();
|
||||
renderResult(ctx, Result.error(Result.ERROR_CODE, "系统异常:" + msg));
|
||||
renderResult(ctx, Result.error("系统异常:" + msg));
|
||||
} catch (Throwable t) {
|
||||
// 兜底:捕获 Error 及其它 Throwable(如 OOM),保证响应不悬挂
|
||||
log.error("严重异常(Throwable)", t);
|
||||
renderResult(ctx, Result.error(Result.ERROR_CODE, "严重异常:" + t.getClass().getSimpleName()));
|
||||
renderResult(ctx, Result.error("严重异常:" + t.getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出 Result JSON 响应。
|
||||
* 输出路由状态异常(404/405 等)响应。
|
||||
*/
|
||||
private void renderStatus(Context ctx, int code) {
|
||||
ctx.status(code);
|
||||
ctx.contentType("application/json;charset=UTF-8");
|
||||
ctx.output("{\"success\":false,\"msg\":\"Not Found\",\"data\":null}");
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出 Result JSON 响应(与原 hospitalmiddle 契约一致:{"success":false,"msg":...})。
|
||||
*/
|
||||
private void renderResult(Context ctx, Result<?> result) {
|
||||
ctx.status(200);
|
||||
// 保留上游预设的 4xx/5xx 状态码(如 checkBasic 认证失败已设 401),否则默认 200。
|
||||
// 若强行刷成 200,Basic 认证失败将不再返回 401,浏览器不会弹出账号密码框。
|
||||
if (ctx.status() < 400) {
|
||||
ctx.status(200);
|
||||
}
|
||||
ctx.contentType("application/json;charset=UTF-8");
|
||||
// 简易 JSON 序列化(避免引入 fastjson 依赖)
|
||||
String dataJson = result.getData() != null ? toJsonValue(result.getData()) : "null";
|
||||
ctx.output("{\"code\":" + result.getCode()
|
||||
ctx.output("{\"success\":" + result.isSuccess()
|
||||
+ ",\"msg\":" + toJsonValue(result.getMsg())
|
||||
+ ",\"data\":" + dataJson + "}");
|
||||
+ ",\"data\":null}");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.hospital.front.infra.util;
|
||||
|
||||
import org.noear.snack.ONode;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* JSON 解析工具(snack3 封装)。
|
||||
*
|
||||
* Solon 对 Map/List 泛型 body 反序列化支持不佳(接口层只能拿 String body),
|
||||
* 此处集中封装手动解析,接口层一行调用;单 DTO 结构应优先用 @Body 强类型直收。
|
||||
*/
|
||||
public final class JsonUtils {
|
||||
|
||||
private JsonUtils() {
|
||||
}
|
||||
|
||||
/** JSON 对象字符串 → Map(解析失败抛 IllegalArgumentException) */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Map<String, Object> parseMap(String json) {
|
||||
try {
|
||||
return (Map<String, Object>) ONode.load(json).toObject(Map.class);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("JSON 对象格式错误:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/** JSON 数组字符串 → List<Map>(空串返回空列表) */
|
||||
@SuppressWarnings("unchecked")
|
||||
public static List<Map<String, Object>> parseList(String json) {
|
||||
if (json == null || json.trim().isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
try {
|
||||
return (List<Map<String, Object>>) ONode.load(json).toObject(List.class);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("JSON 数组格式错误:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.hospital.front.mapper.bsm;
|
||||
|
||||
import com.hospital.front.vo.ConclusionVo;
|
||||
import com.hospital.front.vo.ExamListVo;
|
||||
import com.hospital.front.vo.MedicalMiddleResultVo;
|
||||
import com.hospital.front.vo.PeStatusVo;
|
||||
import com.hospital.front.vo.SuggestVo;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@@ -33,7 +39,7 @@ public interface BsmOrderMapper {
|
||||
void addUnitV2(Map<String, Object> map);
|
||||
|
||||
/** 按体检预约 ID(逗号分隔)查询体检状态 */
|
||||
List<Map<String, Object>> getPhyexamStatus(@Param("peIds") String peIds);
|
||||
List<PeStatusVo> getPhyexamStatus(@Param("peIds") String peIds);
|
||||
|
||||
/** 医院所有体检项目(组合项) */
|
||||
List<Map<String, Object>> getItemList();
|
||||
@@ -53,45 +59,32 @@ public interface BsmOrderMapper {
|
||||
/** 员工体检结果 */
|
||||
List<Map<String, Object>> getResult(@Param("peId") String peId);
|
||||
|
||||
/** 体检结论(列表) */
|
||||
List<Map<String, Object>> getConclusion(@Param("peId") String peId);
|
||||
|
||||
/** 体检结论(全量) */
|
||||
List<Map<String, Object>> getConclusionAll(@Param("peId") String peId);
|
||||
|
||||
/** 体检建议(列表) */
|
||||
List<Map<String, Object>> getSuggest(@Param("peId") String peId);
|
||||
List<ConclusionVo> getConclusionAll(@Param("peId") String peId);
|
||||
|
||||
/** 体检建议(全量) */
|
||||
List<Map<String, Object>> getSuggestAll(@Param("peId") String peId);
|
||||
List<SuggestVo> getSuggestAll(@Param("peId") String peId);
|
||||
|
||||
|
||||
/** 按身份证号及年份查询体检状态 */
|
||||
Map<String, Object> getPeStatusByIdnoAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
PeStatusVo getPeStatusByIdnoAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按身份证号及年份查询体检结果 */
|
||||
List<Map<String, Object>> getResultByIdcardAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
List<MedicalMiddleResultVo> getResultByIdcardAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按身份证号及年份查询体检结果(全量) */
|
||||
List<Map<String, Object>> getResultByIdcardAndYearAll(@Param("idNo") String idNo, @Param("year") String year);
|
||||
List<MedicalMiddleResultVo> getResultByIdcardAndYearAll(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按体检编号查询体检结果 */
|
||||
List<Map<String, Object>> getResultByPeId(@Param("peId") String peId);
|
||||
List<MedicalMiddleResultVo> getResultByPeId(@Param("peId") String peId);
|
||||
|
||||
/** 按审核日期查询体检报告(去重) */
|
||||
List<Map<String, Object>> getDisResultByAuditDate(@Param("auditDate") String auditDate);
|
||||
|
||||
/** 按体检编号查询体检项目子表 */
|
||||
List<Map<String, Object>> getItemByPeId(@Param("peId") String peId);
|
||||
List<MedicalMiddleResultVo> getItemByPeId(@Param("peId") String peId);
|
||||
|
||||
/** 按体检编号查询体检项目子表(全量) */
|
||||
List<Map<String, Object>> getItemByPeIdAll(@Param("peId") String peId);
|
||||
List<MedicalMiddleResultVo> getItemByPeIdAll(@Param("peId") String peId);
|
||||
|
||||
/** 按身份证号或体检编号 + 审核年份查询体检结果 */
|
||||
List<Map<String, Object>> getResultByIdNoOrPeId(
|
||||
@Param("idNo") String idNo,
|
||||
@Param("peId") String peId,
|
||||
@Param("auditYear") String auditYear
|
||||
);
|
||||
|
||||
/** 按身份证号查询当年 peId 与预约日期 */
|
||||
Map<String, Object> getPeIdAndDateByIdcard(@Param("idNo") String idNo);
|
||||
@@ -100,5 +93,5 @@ public interface BsmOrderMapper {
|
||||
List<Map<String, Object>> getPeIdAndDateByIdcardList(@Param("idNo") String idNo);
|
||||
|
||||
/** 按审核日期查询当天体检人员列表(去重) */
|
||||
List<Map<String, Object>> getExamListByDate(@Param("auditDate") String auditDate);
|
||||
List<ExamListVo> getExamListByDate(@Param("auditDate") String auditDate);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.hospital.front.mapper.nx;
|
||||
|
||||
import com.hospital.front.vo.ConclusionVo;
|
||||
import com.hospital.front.vo.ExamListVo;
|
||||
import com.hospital.front.vo.MedicalMiddleResultVo;
|
||||
import com.hospital.front.vo.PeStatusVo;
|
||||
import com.hospital.front.vo.SuggestVo;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
@@ -7,91 +13,70 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* BSM 医院组 Mapper(Oracle 方言)。
|
||||
*
|
||||
* 适用医院:ningxia(宁夏宝石花,SqlServer)
|
||||
* XML 位置:classpath:mapper/nx/OrderMapper.xml
|
||||
*
|
||||
* 存储过程参数与医院 HIS 系统约定,不可修改。
|
||||
* 宁夏医院 Mapper(SqlServer 方言)。
|
||||
* getConclusion/getSuggest 与 All 版 SQL 完全重复,已合并为 All 版。
|
||||
*/
|
||||
@Mapper
|
||||
public interface NxOrderMapper {
|
||||
|
||||
/** 健康探测(SELECT 1) */
|
||||
/** 健康探测 */
|
||||
int ping();
|
||||
|
||||
/** 预约提交(存储过程 P_ADD_PE_REGIST,出参 resultCode/errorMsg/peId) */
|
||||
/** 提交预约(存储过程) */
|
||||
void saveOrder(Map<String, Object> map);
|
||||
|
||||
/** 取消预约(存储过程 P_DEL_PE_REGIST) */
|
||||
/** 取消预约(存储过程) */
|
||||
void cancelOrder(Map<String, Object> map);
|
||||
|
||||
/** 添加/修改单位 V1(存储过程 P_ADD_UNIT) */
|
||||
void addUnit(Map<String, Object> map);
|
||||
|
||||
/** 添加/修改单位 V2(存储过程 P_ADD_UNIT,8 入参版) */
|
||||
/** 添加/修改单位 V2(存储过程) */
|
||||
void addUnitV2(Map<String, Object> map);
|
||||
|
||||
/** 按体检预约 ID(逗号分隔)查询体检状态 */
|
||||
List<Map<String, Object>> getPhyexamStatus(@Param("peIds") String peIds);
|
||||
/** 体检状态查询(多个 peId 逗号分隔) */
|
||||
List<PeStatusVo> getPhyexamStatus(@Param("peIds") String peIds);
|
||||
|
||||
/** 医院所有体检项目(组合项) */
|
||||
/** 体检项目查询 */
|
||||
List<Map<String, Object>> getItemList();
|
||||
|
||||
/** 医院所有体检项目及指标项 */
|
||||
/** 体检指标项及体检组合数据 */
|
||||
List<Map<String, Object>> getAllItemList();
|
||||
|
||||
/** 医院所有体检指标项 */
|
||||
/** 体检指标项数据 */
|
||||
List<Map<String, Object>> getPeItemList();
|
||||
|
||||
/** 按体检指标项查所属组合 */
|
||||
List<Map<String, Object>> getItemInfo(@Param("peItemCode") String peItemCode);
|
||||
|
||||
/** 员工体检项目 */
|
||||
List<Map<String, Object>> getEmpItem(@Param("peId") String peId);
|
||||
|
||||
/** 按指标项 CODE 查询体检组合 */
|
||||
List<Map<String, Object>> getItemInfo(@Param("peItemCode") String peItemCode);
|
||||
|
||||
/** 员工体检结果 */
|
||||
/** 按体检编号查体检结果 */
|
||||
List<Map<String, Object>> getResult(@Param("peId") String peId);
|
||||
|
||||
/** 体检结论(列表) */
|
||||
List<Map<String, Object>> getConclusion(@Param("peId") String peId);
|
||||
|
||||
/** 体检结论(全量) */
|
||||
List<Map<String, Object>> getConclusionAll(@Param("peId") String peId);
|
||||
|
||||
/** 体检建议(列表) */
|
||||
List<Map<String, Object>> getSuggest(@Param("peId") String peId);
|
||||
List<ConclusionVo> getConclusionAll(@Param("peId") String peId);
|
||||
|
||||
/** 体检建议(全量) */
|
||||
List<Map<String, Object>> getSuggestAll(@Param("peId") String peId);
|
||||
List<SuggestVo> getSuggestAll(@Param("peId") String peId);
|
||||
|
||||
/** 按身份证号及年份查询体检状态 */
|
||||
Map<String, Object> getPeStatusByIdnoAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
PeStatusVo getPeStatusByIdnoAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按身份证号及年份查询体检结果 */
|
||||
List<Map<String, Object>> getResultByIdcardAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
List<MedicalMiddleResultVo> getResultByIdcardAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按身份证号及年份查询体检结果(全量) */
|
||||
List<Map<String, Object>> getResultByIdcardAndYearAll(@Param("idNo") String idNo, @Param("year") String year);
|
||||
List<MedicalMiddleResultVo> getResultByIdcardAndYearAll(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按体检编号查询体检结果 */
|
||||
List<Map<String, Object>> getResultByPeId(@Param("peId") String peId);
|
||||
List<MedicalMiddleResultVo> getResultByPeId(@Param("peId") String peId);
|
||||
|
||||
/** 按审核日期查询体检报告(去重) */
|
||||
List<Map<String, Object>> getDisResultByAuditDate(@Param("auditDate") String auditDate);
|
||||
|
||||
/** 按体检编号查询体检项目子表 */
|
||||
List<Map<String, Object>> getItemByPeId(@Param("peId") String peId);
|
||||
List<MedicalMiddleResultVo> getItemByPeId(@Param("peId") String peId);
|
||||
|
||||
/** 按体检编号查询体检项目子表(全量) */
|
||||
List<Map<String, Object>> getItemByPeIdAll(@Param("peId") String peId);
|
||||
List<MedicalMiddleResultVo> getItemByPeIdAll(@Param("peId") String peId);
|
||||
|
||||
/** 按身份证号或体检编号 + 审核年份查询体检结果 */
|
||||
List<Map<String, Object>> getResultByIdNoOrPeId(
|
||||
@Param("idNo") String idNo,
|
||||
@Param("peId") String peId,
|
||||
@Param("auditYear") String auditYear
|
||||
);
|
||||
|
||||
/** 按身份证号查询当年 peId 与预约日期 */
|
||||
Map<String, Object> getPeIdAndDateByIdcard(@Param("idNo") String idNo);
|
||||
@@ -100,5 +85,5 @@ public interface NxOrderMapper {
|
||||
List<Map<String, Object>> getPeIdAndDateByIdcardList(@Param("idNo") String idNo);
|
||||
|
||||
/** 按审核日期查询当天体检人员列表(去重) */
|
||||
List<Map<String, Object>> getExamListByDate(@Param("auditDate") String auditDate);
|
||||
List<ExamListVo> getExamListByDate(@Param("auditDate") String auditDate);
|
||||
}
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
package com.hospital.front.mapper.ya;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* BSM 医院组 Mapper(Oracle 方言)。
|
||||
*
|
||||
* 适用医院:yanan(延安,SqlServer)
|
||||
* XML 位置:classpath:mapper/ya/OrderMapper.xml
|
||||
*
|
||||
* 存储过程参数与医院 HIS 系统约定,不可修改。
|
||||
*/
|
||||
@Mapper
|
||||
public interface YaOrderMapper {
|
||||
|
||||
/** 健康探测(SELECT 1) */
|
||||
int ping();
|
||||
|
||||
/** 预约提交(存储过程 P_ADD_PE_REGIST,出参 resultCode/errorMsg/peId) */
|
||||
void saveOrder(Map<String, Object> map);
|
||||
|
||||
/** 取消预约(存储过程 P_DEL_PE_REGIST) */
|
||||
void cancelOrder(Map<String, Object> map);
|
||||
|
||||
/** 添加/修改单位 V1(存储过程 P_ADD_UNIT) */
|
||||
void addUnit(Map<String, Object> map);
|
||||
|
||||
/** 添加/修改单位 V2(存储过程 P_ADD_UNIT,8 入参版) */
|
||||
void addUnitV2(Map<String, Object> map);
|
||||
|
||||
/** 按体检预约 ID(逗号分隔)查询体检状态 */
|
||||
List<Map<String, Object>> getPhyexamStatus(@Param("peIds") String peIds);
|
||||
|
||||
/** 医院所有体检项目(组合项) */
|
||||
List<Map<String, Object>> getItemList();
|
||||
|
||||
/** 医院所有体检项目及指标项 */
|
||||
List<Map<String, Object>> getAllItemList();
|
||||
|
||||
/** 医院所有体检指标项 */
|
||||
List<Map<String, Object>> getPeItemList();
|
||||
|
||||
/** 员工体检项目 */
|
||||
List<Map<String, Object>> getEmpItem(@Param("peId") String peId);
|
||||
|
||||
/** 按指标项 CODE 查询体检组合 */
|
||||
List<Map<String, Object>> getItemInfo(@Param("peItemCode") String peItemCode);
|
||||
|
||||
/** 员工体检结果 */
|
||||
List<Map<String, Object>> getResult(@Param("peId") String peId);
|
||||
|
||||
/** 体检结论(列表) */
|
||||
List<Map<String, Object>> getConclusion(@Param("peId") String peId);
|
||||
|
||||
/** 体检结论(全量) */
|
||||
List<Map<String, Object>> getConclusionAll(@Param("peId") String peId);
|
||||
|
||||
/** 体检建议(列表) */
|
||||
List<Map<String, Object>> getSuggest(@Param("peId") String peId);
|
||||
|
||||
/** 体检建议(全量) */
|
||||
List<Map<String, Object>> getSuggestAll(@Param("peId") String peId);
|
||||
|
||||
/** 按身份证号及年份查询体检状态 */
|
||||
Map<String, Object> getPeStatusByIdnoAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按身份证号及年份查询体检结果 */
|
||||
List<Map<String, Object>> getResultByIdcardAndYear(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按身份证号及年份查询体检结果(全量) */
|
||||
List<Map<String, Object>> getResultByIdcardAndYearAll(@Param("idNo") String idNo, @Param("year") String year);
|
||||
|
||||
/** 按体检编号查询体检结果 */
|
||||
List<Map<String, Object>> getResultByPeId(@Param("peId") String peId);
|
||||
|
||||
/** 按审核日期查询体检报告(去重) */
|
||||
List<Map<String, Object>> getDisResultByAuditDate(@Param("auditDate") String auditDate);
|
||||
|
||||
/** 按体检编号查询体检项目子表 */
|
||||
List<Map<String, Object>> getItemByPeId(@Param("peId") String peId);
|
||||
|
||||
/** 按体检编号查询体检项目子表(全量) */
|
||||
List<Map<String, Object>> getItemByPeIdAll(@Param("peId") String peId);
|
||||
|
||||
/** 按身份证号或体检编号 + 审核年份查询体检结果 */
|
||||
List<Map<String, Object>> getResultByIdNoOrPeId(
|
||||
@Param("idNo") String idNo,
|
||||
@Param("peId") String peId,
|
||||
@Param("auditYear") String auditYear
|
||||
);
|
||||
|
||||
/** 按身份证号查询当年 peId 与预约日期 */
|
||||
Map<String, Object> getPeIdAndDateByIdcard(@Param("idNo") String idNo);
|
||||
|
||||
/** 按身份证号查询当年 peId 与预约日期(数组) */
|
||||
List<Map<String, Object>> getPeIdAndDateByIdcardList(@Param("idNo") String idNo);
|
||||
|
||||
/** 按审核日期查询当天体检人员列表(去重) */
|
||||
List<Map<String, Object>> getExamListByDate(@Param("auditDate") String auditDate);
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.hospital.front.service;
|
||||
|
||||
import com.hospital.front.vo.MedicalMiddleResultVo;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -17,8 +19,10 @@ import com.hospital.front.adapter.HospitalAdapter;
|
||||
import com.hospital.front.adapter.HospitalRouter;
|
||||
import com.hospital.front.infra.exception.BusinessException;
|
||||
import com.hospital.front.infra.util.DateUtils;
|
||||
import com.hospital.front.vo.ExamListVo;
|
||||
import com.hospital.front.vo.OrderItemVo;
|
||||
import com.hospital.front.vo.OrderV2Vo;
|
||||
import com.hospital.front.vo.PeStatusPhyVo;
|
||||
import com.hospital.front.vo.UnitVo;
|
||||
|
||||
/**
|
||||
@@ -79,8 +83,7 @@ public class OrderService {
|
||||
*
|
||||
* @return 成功时返回 peId
|
||||
*/
|
||||
public String saveOrder(Map<String, Object> body) {
|
||||
OrderV2Vo vo = convertOrderV2(body);
|
||||
public String saveOrder(com.hospital.front.vo.OrderV2Vo vo) {
|
||||
if (isAllsecondFlag()) {
|
||||
vo = vo.applyAllsecondFlag();
|
||||
}
|
||||
@@ -97,8 +100,10 @@ public class OrderService {
|
||||
if (result.getPeId() == null) {
|
||||
throw BusinessException.procFailed("医院未返回体检编号");
|
||||
}
|
||||
log.info("提交预约成功:peId={}", result.getPeId());
|
||||
return result.getPeId();
|
||||
} else {
|
||||
log.warn("提交预约失败:errorMsg={}", result.getErrorMsg());
|
||||
throwHospitalFailed(result.getErrorMsg());
|
||||
// 不可达,仅为满足 Java 返回类型要求
|
||||
throw new IllegalStateException("unreachable");
|
||||
@@ -116,6 +121,7 @@ public class OrderService {
|
||||
|
||||
/** 批量添加/修改单位;返回失败信息(全部成功返回 null) */
|
||||
public String addUnits(List<Map<String, Object>> units) {
|
||||
log.info("添加单位:units={}", units);
|
||||
StringBuilder errors = new StringBuilder();
|
||||
boolean useV2 = "V2".equals(getHmVer());
|
||||
for (int index = 0; index < units.size(); index++) {
|
||||
@@ -160,35 +166,27 @@ public class OrderService {
|
||||
return adapter().getResult(peId);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getConclusion(String peId) {
|
||||
return adapter().getConclusion(peId);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getSuggest(String peId) {
|
||||
return adapter().getSuggest(peId);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getResultByIdcardAndYear(String idNo, String year) {
|
||||
/** 按身份证及年份查体检结果(内部使用:宁夏 getPeStatusByIdnoAndYear 兜底) */
|
||||
public List<MedicalMiddleResultVo> getResultByIdcardAndYear(String idNo, String year) {
|
||||
return adapter().getResultByIdcardAndYear(idNo, year);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getResultByIdcardAndYearAll(String idNo, String year) {
|
||||
return adapter().getResultByIdcardAndYearAll(idNo, year);
|
||||
public List<MedicalMiddleResultVo> getResultByIdcardAndYearAll(String idNo, String year) {
|
||||
return enrichResultAll(adapter().getResultByIdcardAndYearAll(idNo, year));
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getResultByPeId(String peId) {
|
||||
public List<MedicalMiddleResultVo> getResultByPeId(String peId) {
|
||||
return enrichResultAll(adapter().getResultByPeId(peId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 15.2 体检状态(简):返回原始基础字段,不做报告组装(对齐原 hospitalmiddle 的 getResultStatus)。
|
||||
* 与 getResultByPeId 的区别在于不调用 enrichResultAll,故不含 conclusion/suggest/hospitalId/resultVoList。
|
||||
*/
|
||||
public List<MedicalMiddleResultVo> getResultStatus(String peId) {
|
||||
return adapter().getResultByPeId(peId);
|
||||
}
|
||||
|
||||
/** 按审核日期查询体检报告(去重主表) */
|
||||
public List<Map<String, Object>> getResultByAuditDate(String auditDate) {
|
||||
return adapter().getDisResultByAuditDate(auditDate);
|
||||
}
|
||||
|
||||
public List<Map<String, Object>> getResultByIdNoOrPeId(String idNo, String peId, String auditYear) {
|
||||
return adapter().getResultByIdNoOrPeId(idNo, peId, auditYear);
|
||||
}
|
||||
|
||||
public Map<String, Object> getPeIdAndDateByIdcard(String idNo) {
|
||||
return adapter().getPeIdAndDateByIdcard(idNo);
|
||||
}
|
||||
@@ -200,14 +198,13 @@ public class OrderService {
|
||||
/**
|
||||
* 体检状态查询:按医院返回的 PE_STATUS 名转字典数字。
|
||||
*/
|
||||
public List<Map<String, String>> getPhyexamStatus(String peIds) {
|
||||
List<Map<String, String>> out = new ArrayList<>();
|
||||
for (Map<String, Object> row : adapter().getPhyexamStatus(peIds)) {
|
||||
Map<String, String> item = new HashMap<>();
|
||||
item.put("peId", row.get("PE_ID") != null ? String.valueOf(row.get("PE_ID")) : "");
|
||||
String statusName = row.get("PE_STATUS") != null ? String.valueOf(row.get("PE_STATUS")) : "";
|
||||
item.put("peStatus", PE_STATUS_DICT.getOrDefault(statusName, ""));
|
||||
out.add(item);
|
||||
public List<PeStatusPhyVo> getPhyexamStatus(String peIds) {
|
||||
List<PeStatusPhyVo> out = new ArrayList<>();
|
||||
for (com.hospital.front.vo.PeStatusVo row : adapter().getPhyexamStatus(peIds)) {
|
||||
out.add(new PeStatusPhyVo(
|
||||
row.getPeId() != null ? row.getPeId() : "",
|
||||
PE_STATUS_DICT.getOrDefault(
|
||||
row.getPeStatus() != null ? row.getPeStatus() : "", "")));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -215,63 +212,39 @@ public class OrderService {
|
||||
/**
|
||||
* 按日期查询当天体检人员列表(日期空则当天)。
|
||||
*/
|
||||
public List<Map<String, Object>> getExamListByDate(String auditDate) {
|
||||
public List<ExamListVo> getExamListByDate(String auditDate) {
|
||||
return adapter().getExamListByDate(auditDate != null ? auditDate : DateUtils.today());
|
||||
}
|
||||
|
||||
/**
|
||||
* 体检结论(汇总为单字符串)。
|
||||
*/
|
||||
public Map<String, String> getTotalConclusion(String peId) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("totalConclusion", buildSummary(adapter().getConclusion(peId)));
|
||||
return map;
|
||||
}
|
||||
|
||||
/** 体检结论(汇总,全量来源) */
|
||||
public Map<String, String> getTotalConclusionAll(String peId) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("totalConclusion", buildSummary(adapter().getConclusionAll(peId)));
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 体检建议(汇总)。宁夏(nx)仅取首条 GUIDE_CONTENT。
|
||||
*/
|
||||
public Map<String, String> getTotalSuggest(String peId) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("totalSuggest", buildSuggest(adapter().getSuggest(peId), "nx".equals(adapter().hmType())));
|
||||
return map;
|
||||
}
|
||||
|
||||
/** 体检建议(汇总,全量来源) */
|
||||
public Map<String, String> getTotalSuggestAll(String peId) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("totalSuggest", buildSuggest(adapter().getSuggestAll(peId), "nx".equals(adapter().hmType())));
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按身份证号 + 年份查询体检状态及项目(含宁夏体检报告兜底)。
|
||||
*/
|
||||
public Map<String, Object> getPeStatusByIdnoAndYear(String idNo, String year) {
|
||||
Map<String, Object> map = adapter().getPeStatusByIdnoAndYear(idNo, year);
|
||||
if (map != null && map.get("PE_ID") != null) {
|
||||
Map<String, Object> result = new LinkedHashMap<>(map);
|
||||
result.put("peItemList", adapter().getEmpItem(String.valueOf(map.get("PE_ID"))));
|
||||
com.hospital.front.vo.PeStatusVo vo = adapter().getPeStatusByIdnoAndYear(idNo, year);
|
||||
if (vo != null && vo.getPeId() != null) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put("PE_ID", vo.getPeId());
|
||||
result.put("NAME", vo.getName());
|
||||
result.put("ID_NO", vo.getIdNo());
|
||||
result.put("UNIT_NAME", vo.getUnitName());
|
||||
result.put("DEPARTMENT", vo.getDepartment());
|
||||
result.put("PE_PRE_DATE", vo.getPePreDate());
|
||||
result.put("PE_QUEUE_DATE", vo.getPeQueueDate());
|
||||
result.put("PE_STATUS", vo.getPeStatus());
|
||||
result.put("peItemList", adapter().getEmpItem(vo.getPeId()));
|
||||
return result;
|
||||
} else {
|
||||
// 宁夏:从体检报告继续查
|
||||
if ("nx".equals(adapter().hmType())) {
|
||||
List<Map<String, Object>> rows = adapter().getResultByIdcardAndYear(idNo, year);
|
||||
List<MedicalMiddleResultVo> rows = adapter().getResultByIdcardAndYear(idNo, year);
|
||||
if (!rows.isEmpty()) {
|
||||
Map<String, Object> row = rows.get(0);
|
||||
String auditDate = row.get("AUDIT_DATE") != null ? String.valueOf(row.get("AUDIT_DATE")) : null;
|
||||
MedicalMiddleResultVo row = rows.get(0);
|
||||
String auditDate = row.getAuditDate();
|
||||
Map<String, Object> out = new LinkedHashMap<>();
|
||||
out.put("PE_ID", row.get("PE_ID"));
|
||||
out.put("PE_ID", row.getPeId());
|
||||
out.put("PE_PRE_DATE",
|
||||
auditDate != null && auditDate.length() >= 10 ? auditDate.substring(0, 10) : auditDate);
|
||||
out.put("peItemList", adapter().getEmpItem(String.valueOf(row.get("PE_ID"))));
|
||||
out.put("peItemList", adapter().getEmpItem(row.getPeId()));
|
||||
return out;
|
||||
} else {
|
||||
return null;
|
||||
@@ -284,107 +257,58 @@ public class OrderService {
|
||||
|
||||
// ================= 私有工具 =================
|
||||
|
||||
/** 医院侧业务失败:抛出 2003 业务异常 */
|
||||
/**
|
||||
* 报告组装(对齐原 hospitalmiddle 的 dealMiddleChildDataAll):
|
||||
* 为每条结果补 hospitalId、item 子表(全量)、体检结论、体检建议。
|
||||
*/
|
||||
private List<MedicalMiddleResultVo> enrichResultAll(List<MedicalMiddleResultVo> rows) {
|
||||
String hospitalId = Solon.cfg().get("hospital.id", "");
|
||||
for (MedicalMiddleResultVo row : rows) {
|
||||
row.setHospitalId(hospitalId);
|
||||
// item 子表(全量版)
|
||||
row.setResultVoList(adapter().getItemByPeIdAll(row.getPeId()));
|
||||
// 体检结论:多条按 "序号.科室:结论文本;<br/>" 拼接
|
||||
StringBuilder conclusion = new StringBuilder();
|
||||
int cIndex = 1;
|
||||
for (com.hospital.front.vo.ConclusionVo c : adapter().getConclusionAll(row.getPeId())) {
|
||||
String deptName = c.getPeDeptName() != null ? c.getPeDeptName() : "";
|
||||
String text = c.getConclusionText() != null ? c.getConclusionText() : "";
|
||||
conclusion.append(cIndex).append(".").append(deptName).append(":").append(text).append(";<br/>");
|
||||
cIndex++;
|
||||
}
|
||||
row.setConclusion(conclusion.toString());
|
||||
// 体检建议:宁夏取首条 guideContent;其余按 "序号.建议项:建议内容;<br/>" 拼接(跳过建议内容为空的行)
|
||||
StringBuilder suggest = new StringBuilder();
|
||||
List<com.hospital.front.vo.SuggestVo> suggestRows = adapter().getSuggestAll(row.getPeId());
|
||||
if ("nx".equals(adapter().hmType())) {
|
||||
if (!suggestRows.isEmpty() && suggestRows.get(0).getGuideContent() != null) {
|
||||
suggest.append(suggestRows.get(0).getGuideContent());
|
||||
}
|
||||
} else {
|
||||
int sIndex = 1;
|
||||
for (com.hospital.front.vo.SuggestVo s : suggestRows) {
|
||||
if (s.getGuideContent() != null && !s.getGuideContent().isEmpty()) {
|
||||
String rec = s.getRecContent() != null ? s.getRecContent() : "";
|
||||
suggest.append(sIndex).append(".").append(rec).append(":")
|
||||
.append(s.getGuideContent()).append(";<br/>");
|
||||
sIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
row.setSuggest(suggest.toString());
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
/** 医院侧业务失败:抛出业务异常 */
|
||||
private void throwHospitalFailed(String errorMsg) {
|
||||
if (errorMsg != null && !errorMsg.isEmpty()) {
|
||||
throw BusinessException.of(2003, errorMsg);
|
||||
throw BusinessException.of(errorMsg);
|
||||
} else {
|
||||
throw BusinessException.procFailed("医院系统返回业务失败");
|
||||
}
|
||||
}
|
||||
|
||||
/** 结论汇总:1.科室:结论;<br/> */
|
||||
private String buildSummary(List<Map<String, Object>> rows) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
Map<String, Object> row = rows.get(i);
|
||||
String deptName = row.get("PE_DEPT_NAME") != null ? String.valueOf(row.get("PE_DEPT_NAME")) : "";
|
||||
String dept = !deptName.isEmpty() ? deptName + ":" : "";
|
||||
Object conclusion = row.get("CONCLUSION_TEXT");
|
||||
sb.append(i + 1).append(".").append(dept).append(conclusion != null ? conclusion : "").append(";<br/>");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** 建议汇总:宁夏仅取首条 GUIDE_CONTENT;其余 1.建议项:内容;<br/> */
|
||||
private String buildSuggest(List<Map<String, Object>> rows, boolean nxStyle) {
|
||||
if (nxStyle) {
|
||||
if (rows.isEmpty() || rows.get(0).get("GUIDE_CONTENT") == null) {
|
||||
return "";
|
||||
}
|
||||
return String.valueOf(rows.get(0).get("GUIDE_CONTENT"));
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int i = 1;
|
||||
for (Map<String, Object> row : rows) {
|
||||
String guide = row.get("GUIDE_CONTENT") != null ? String.valueOf(row.get("GUIDE_CONTENT")) : "";
|
||||
if (guide.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
Object rec = row.get("REC_CONTENT");
|
||||
sb.append(i).append(".").append(rec != null ? rec : "").append(":").append(guide).append(";<br/>");
|
||||
i++;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/** Map → OrderV2Vo(数值/空值容错) */
|
||||
private OrderV2Vo convertOrderV2(Map<String, Object> body) {
|
||||
List<OrderItemVo> itemList = null;
|
||||
Object rawList = body.get("itemList");
|
||||
if (rawList instanceof List) {
|
||||
itemList = new ArrayList<>();
|
||||
for (Object item : (List<?>) rawList) {
|
||||
if (item instanceof Map) {
|
||||
Map<?, ?> m = (Map<?, ?>) item;
|
||||
itemList.add(new OrderItemVo(
|
||||
m.get("itemNo") != null ? String.valueOf(m.get("itemNo")) : null,
|
||||
m.get("itemName") != null ? String.valueOf(m.get("itemName")) : null));
|
||||
}
|
||||
}
|
||||
}
|
||||
return new OrderV2Vo(
|
||||
str(body, "orderDate"),
|
||||
str(body, "secondDepartId"),
|
||||
str(body, "secondDepartName"),
|
||||
str(body, "thirdDepartName"),
|
||||
str(body, "name"),
|
||||
str(body, "sexName"),
|
||||
str(body, "birthDay"),
|
||||
body.get("age") instanceof Number ? ((Number) body.get("age")).intValue() : null,
|
||||
str(body, "idCard"),
|
||||
str(body, "marrigeStatusName"),
|
||||
str(body, "country"),
|
||||
str(body, "nationName"),
|
||||
str(body, "birthplace"),
|
||||
str(body, "position"),
|
||||
str(body, "profession"),
|
||||
str(body, "feeType"),
|
||||
str(body, "liveSpace"),
|
||||
str(body, "zipCode"),
|
||||
str(body, "mobile"),
|
||||
str(body, "email"),
|
||||
str(body, "empSysno"),
|
||||
str(body, "medicalType"),
|
||||
str(body, "medicalClass"),
|
||||
str(body, "workShape"),
|
||||
str(body, "workDate"),
|
||||
str(body, "jobLevel"),
|
||||
str(body, "workPlace"),
|
||||
str(body, "baseSite"),
|
||||
str(body, "workTypeCode"),
|
||||
str(body, "workTypeOther"),
|
||||
str(body, "education"),
|
||||
str(body, "title"),
|
||||
str(body, "oldDepartName"),
|
||||
str(body, "harmReasonCode"),
|
||||
str(body, "harmReasonOther"),
|
||||
str(body, "harmDate"),
|
||||
str(body, "defendCancer"),
|
||||
itemList);
|
||||
}
|
||||
|
||||
/** 取字符串值(null 安全) */
|
||||
private static String str(Map<String, Object> map, String key) {
|
||||
Object v = map.get(key);
|
||||
|
||||
@@ -2,11 +2,12 @@ package com.hospital.front.task;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.net.URI;
|
||||
import java.net.http.HttpClient;
|
||||
import java.net.http.HttpRequest;
|
||||
import java.net.http.HttpResponse;
|
||||
import java.time.Duration;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
import org.noear.solon.Solon;
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.annotation.Inject;
|
||||
@@ -33,9 +34,9 @@ public class UptimeKumaTask {
|
||||
@Inject
|
||||
private HospitalRouter router;
|
||||
|
||||
private final OkHttpClient http = new OkHttpClient.Builder()
|
||||
.connectTimeout(5, TimeUnit.SECONDS)
|
||||
.readTimeout(10, TimeUnit.SECONDS)
|
||||
/** JDK 内置 HttpClient(替代 OkHttp,免额外依赖):连接 5s、读取 10s */
|
||||
private final HttpClient http = HttpClient.newBuilder()
|
||||
.connectTimeout(Duration.ofSeconds(5))
|
||||
.build();
|
||||
|
||||
/**
|
||||
@@ -51,15 +52,19 @@ public class UptimeKumaTask {
|
||||
}
|
||||
// 检查数据库连接
|
||||
com.hospital.front.dto.Result<Boolean> health = router.active().healthCheck();
|
||||
if (health.getCode() == 0) {
|
||||
if (health.isSuccess()) {
|
||||
try {
|
||||
Response resp = http.newCall(new Request.Builder().url(kumaUrl).get().build()).execute();
|
||||
if (resp.isSuccessful()) {
|
||||
HttpResponse<String> resp = http.send(
|
||||
HttpRequest.newBuilder(URI.create(kumaUrl))
|
||||
.GET()
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.build(),
|
||||
HttpResponse.BodyHandlers.ofString());
|
||||
if (resp.statusCode() >= 200 && resp.statusCode() < 300) {
|
||||
log.info("[Kuma] 心跳推送成功:{}", kumaUrl);
|
||||
} else {
|
||||
log.warn("[Kuma] 心跳推送失败:HTTP {}", resp.code());
|
||||
log.warn("[Kuma] 心跳推送失败:HTTP {}", resp.statusCode());
|
||||
}
|
||||
resp.close();
|
||||
} catch (Exception e) {
|
||||
log.warn("[Kuma] 心跳推送异常:{}", e.getMessage());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.hospital.front.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 体检结论明细 VO(getConclusionAll 强类型映射,内部使用)。
|
||||
*
|
||||
* 一个 peId 按科室返回多条结论(汇总拼接用),故为列表元素。
|
||||
*/
|
||||
@Data
|
||||
public class ConclusionVo {
|
||||
/** 体检编号 */
|
||||
private String peId;
|
||||
/** 就诊编号 */
|
||||
private String peVisitId;
|
||||
/** 科室编码 */
|
||||
private String peDeptCode;
|
||||
/** 科室名称 */
|
||||
private String peDeptName;
|
||||
/** 结论文本(已去换行) */
|
||||
private String conclusionText;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.hospital.front.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 当天体检人员列表 VO(getExamListByDate 对外强类型出参)。
|
||||
*
|
||||
* 三院 SQL 出参统一(列别名即驼峰字段),日期已在 SQL 层转为字符串。
|
||||
* 字段名与 snack3 默认序列化输出 key 一致,可直接返回 HTTP 调用方。
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ExamListVo {
|
||||
/** 体检编号 */
|
||||
private String peId;
|
||||
/** 身份证号 */
|
||||
private String idNo;
|
||||
/** 姓名 */
|
||||
private String name;
|
||||
/** 审查日期 yyyy-MM-dd */
|
||||
private String auditDate;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.hospital.front.vo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* 体检状态简版 VO(getPhyexamStatus 对外强类型出参)。
|
||||
*
|
||||
* 字段名与 snack3 默认序列化输出 key 一致(peId / peStatus),
|
||||
* 可直接返回给 HTTP 调用方,无需手工 Map 包装。
|
||||
* peStatus 已由 OrderService 加工为字典数字(与原 Map 契约一致)。
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PeStatusPhyVo {
|
||||
/** 体检编号(null 时输出空字符串,保持与原 Map 契约一致) */
|
||||
private String peId;
|
||||
/** 体检状态字典数字(原始状态名查不到时输出空字符串) */
|
||||
private String peStatus;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.hospital.front.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 体检状态 VO(getPhyexamStatus / getPeStatusByIdnoAndYear 强类型映射,内部中间态)。
|
||||
*
|
||||
* 对外出参由 OrderService 加工(key 小写 peId/peStatus + 状态字典转换),
|
||||
* 本 VO 仅作 adapter → service 的内部传输,不影响 HTTP 契约。
|
||||
*/
|
||||
@Data
|
||||
public class PeStatusVo {
|
||||
/** 体检编号 */
|
||||
private String peId;
|
||||
/** 姓名 */
|
||||
private String name;
|
||||
/** 身份证号 */
|
||||
private String idNo;
|
||||
/** 单位名称 */
|
||||
private String unitName;
|
||||
/** 部门 */
|
||||
private String department;
|
||||
/** 预约日期 */
|
||||
private String pePreDate;
|
||||
/** 排队日期 */
|
||||
private String peQueueDate;
|
||||
/** 状态名(报到/检中/初审/终审/预约/转向) */
|
||||
private String peStatus;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.hospital.front.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 体检建议 VO(getSuggestAll 强类型映射,内部使用)。
|
||||
*
|
||||
* 按 peId 查询仅一条建议记录,adapter 层取首条返回单对象。
|
||||
*/
|
||||
@Data
|
||||
public class SuggestVo {
|
||||
/** 体检编号 */
|
||||
private String peId;
|
||||
/** 建议项(科室/类别描述) */
|
||||
private String recContent;
|
||||
/** 建议内容(已去换行) */
|
||||
private String guideContent;
|
||||
}
|
||||
@@ -11,6 +11,13 @@ solon:
|
||||
app:
|
||||
name: "hospital-front"
|
||||
group: "hospital"
|
||||
# JSON 序列化对齐原 hospitalmiddle(Jackson 默认保留 null 字段 + 日期格式)
|
||||
serialization:
|
||||
json:
|
||||
nullAsWriteable: true
|
||||
# 对齐原 spring.jackson.date-format / time-zone:Date/Timestamp 序列化为字符串而非毫秒时间戳
|
||||
dateAsFormat: "yyyy-MM-dd HH:mm:ss"
|
||||
dateAsTimeZone: "GMT+8"
|
||||
|
||||
# 应用配置
|
||||
# 医院注册清单由代码决定(各 Adapter 的 @Component),此处仅指定激活哪家
|
||||
@@ -40,6 +47,20 @@ order:
|
||||
admin:
|
||||
token: ""
|
||||
|
||||
# IP 白名单(应对端口暴露公网被扫描器探测;环回地址 Agent 永远放行)
|
||||
# 开启后非白名单 IP 一律 403。
|
||||
# ipWhitelist 三种写法可混用,逗号分隔:
|
||||
# 精确 IP:10.0.0.5
|
||||
# 通配段:112.113.*.*(每段可单独 *)
|
||||
# CIDR 网段:10.0.0.0/24
|
||||
security:
|
||||
ipWhitelistEnabled: false
|
||||
ipWhitelist: ""
|
||||
# ipWhitelist: "112.113.*.*,10.20.30.40,10.0.0.0/24"
|
||||
# nginx 反代部署时开启:从 X-Forwarded-For 最右侧取真实客户端 IP 判定
|
||||
# (对端必须是本机环回的 nginx,防止客户端伪造 XFF 绕过白名单)
|
||||
# trustProxy: false
|
||||
|
||||
# ====================================
|
||||
# MyBatis-Plus 公共配置(db1 为唯一数据源,随医院配置注入)
|
||||
# mappers 条目两种形式(Solon mybatis 约定):
|
||||
@@ -52,10 +73,8 @@ mybatis.db1:
|
||||
mappers:
|
||||
- "com.hospital.front.mapper.bsm"
|
||||
- "com.hospital.front.mapper.nx"
|
||||
- "com.hospital.front.mapper.ya"
|
||||
- "com/hospital/front/mapper/bsm/BsmOrderMapper.xml"
|
||||
- "com/hospital/front/mapper/nx/NxOrderMapper.xml"
|
||||
- "com/hospital/front/mapper/ya/YaOrderMapper.xml"
|
||||
configuration:
|
||||
mapUnderscoreToCamelCase: true
|
||||
logImpl: "org.apache.ibatis.logging.slf4j.Slf4jImpl"
|
||||
@@ -69,7 +88,7 @@ logging:
|
||||
level:
|
||||
root: INFO
|
||||
com.hospital.front: INFO
|
||||
org.noear: WARN
|
||||
org.noear: INFO
|
||||
|
||||
# ====================================
|
||||
# Uptime-Kuma 监控(沿用原 hospitalmiddle 逻辑)
|
||||
|
||||
@@ -7,102 +7,113 @@
|
||||
SELECT 1 FROM DUAL
|
||||
</select>
|
||||
|
||||
<!-- ==================== 存储过程:预约/取消/单位 ==================== -->
|
||||
|
||||
<parameterMap id="pm" type="java.util.Map">
|
||||
<parameter property="peInfoStr" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="peItemStr" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="peId" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="peInfoStr" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="peItemStr" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"/>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"/>
|
||||
<parameter property="peId" jdbcType="VARCHAR" mode="OUT"/>
|
||||
</parameterMap>
|
||||
<insert id="saveOrder" parameterMap="pm" statementType="CALLABLE">
|
||||
{call P_ADD_PE_REGIST(
|
||||
#{peInfoStr,mode=IN,jdbcType=VARCHAR},
|
||||
#{peItemStr,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR},
|
||||
#{peId,mode=OUT,jdbcType=VARCHAR}
|
||||
#{peInfoStr,mode=IN,jdbcType=VARCHAR},
|
||||
#{peItemStr,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR},
|
||||
#{peId,mode=OUT,jdbcType=VARCHAR}
|
||||
)}
|
||||
</insert>
|
||||
|
||||
<parameterMap id="cancenlPm" type="java.util.Map">
|
||||
<parameter property="peId" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="name" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="idcard" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="peId" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="name" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="idcard" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"/>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"/>
|
||||
</parameterMap>
|
||||
<insert id="cancelOrder" parameterMap="cancenlPm" statementType="CALLABLE">
|
||||
{call P_DEL_PE_REGIST(
|
||||
#{peId,mode=IN,jdbcType=VARCHAR},
|
||||
#{name,mode=IN,jdbcType=VARCHAR},
|
||||
#{idcard,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR}
|
||||
#{peId,mode=IN,jdbcType=VARCHAR},
|
||||
#{name,mode=IN,jdbcType=VARCHAR},
|
||||
#{idcard,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR}
|
||||
)}
|
||||
</insert>
|
||||
|
||||
<parameterMap id="unitPm" type="java.util.Map">
|
||||
<parameter property="unitCode" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="unitName" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="unitCode" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="unitName" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"/>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"/>
|
||||
</parameterMap>
|
||||
|
||||
|
||||
<insert id="addUnit" parameterMap="unitPm" statementType="CALLABLE">
|
||||
{call P_ADD_UNIT(
|
||||
#{unitCode,mode=IN,jdbcType=VARCHAR},
|
||||
#{unitName,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR}
|
||||
#{unitCode,mode=IN,jdbcType=VARCHAR},
|
||||
#{unitName,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR}
|
||||
)}
|
||||
</insert>
|
||||
|
||||
<parameterMap id="unitPmV2" type="java.util.Map">
|
||||
<parameter property="unitCode" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="unitName" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="parentUnitCode" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="address" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="connecter1" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="phone1" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="connecter2" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="phone2" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="unitCode" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="unitName" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="parentUnitCode" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="address" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="connecter1" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="phone1" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="connecter2" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="phone2" jdbcType="VARCHAR" mode="IN"/>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"/>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"/>
|
||||
</parameterMap>
|
||||
<insert id="addUnitV2" parameterMap="unitPmV2" statementType="CALLABLE">
|
||||
{call P_ADD_UNIT(
|
||||
#{unitCode,mode=IN,jdbcType=VARCHAR},
|
||||
#{unitName,mode=IN,jdbcType=VARCHAR},
|
||||
#{parentUnitCode,mode=IN,jdbcType=VARCHAR},
|
||||
#{address,mode=IN,jdbcType=VARCHAR},
|
||||
#{connecter1,mode=IN,jdbcType=VARCHAR},
|
||||
#{phone1,mode=IN,jdbcType=VARCHAR},
|
||||
#{connecter2,mode=IN,jdbcType=VARCHAR},
|
||||
#{phone2,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR}
|
||||
#{unitCode,mode=IN,jdbcType=VARCHAR},
|
||||
#{unitName,mode=IN,jdbcType=VARCHAR},
|
||||
#{parentUnitCode,mode=IN,jdbcType=VARCHAR},
|
||||
#{address,mode=IN,jdbcType=VARCHAR},
|
||||
#{connecter1,mode=IN,jdbcType=VARCHAR},
|
||||
#{phone1,mode=IN,jdbcType=VARCHAR},
|
||||
#{connecter2,mode=IN,jdbcType=VARCHAR},
|
||||
#{phone2,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR}
|
||||
)}
|
||||
</insert>
|
||||
|
||||
<select id="getPhyexamStatus" resultType="java.util.Map">
|
||||
<!-- ==================== 体检状态 ==================== -->
|
||||
|
||||
<select id="getPhyexamStatus" resultType="com.hospital.front.vo.PeStatusVo">
|
||||
select PE_ID, NAME, ID_NO, UNIT_NAME, DEPARTMENT, PE_PRE_DATE, PE_QUEUE_DATE, PE_STATUS
|
||||
from V_PHYEXAM_PE_STATUS
|
||||
where instr(',' || #{peIds} || ',', ',' || pe_id || ',') > 0
|
||||
</select>
|
||||
|
||||
<select id="getItemList" resultType="java.util.Map">
|
||||
select distinct item_assem_code, item_assem_name
|
||||
from V_PHYEXAM_ITEM_ASSEMBLED
|
||||
<select id="getPeStatusByIdnoAndYear" resultType="com.hospital.front.vo.PeStatusVo">
|
||||
select * from V_PHYEXAM_PE_STATUS
|
||||
where ID_NO = #{idNo}
|
||||
and to_char(PE_PRE_DATE, 'yyyy') = #{year}
|
||||
</select>
|
||||
|
||||
<!-- ==================== 体检项目 ==================== -->
|
||||
|
||||
<select id="getItemList" resultType="java.util.Map">
|
||||
SELECT DISTINCT ITEM_ASSEM_CODE, ITEM_ASSEM_NAME
|
||||
FROM V_PHYEXAM_ITEM_ASSEMBLED
|
||||
</select>
|
||||
|
||||
<select id="getAllItemList" resultType="java.util.Map">
|
||||
select ITEM_ASSEM_CODE, ITEM_ASSEM_NAME, PE_ITEM_CODE, PE_ITEM_NAME
|
||||
from V_PHYEXAM_ITEM_ASSEMBLED
|
||||
SELECT ITEM_ASSEM_CODE, ITEM_ASSEM_NAME, PE_ITEM_CODE, PE_ITEM_NAME
|
||||
FROM V_PHYEXAM_ITEM_ASSEMBLED
|
||||
</select>
|
||||
|
||||
<select id="getPeItemList" resultType="java.util.Map">
|
||||
select *
|
||||
from V_PHYEXAM_ITEM
|
||||
SELECT PE_ITEM_CODE, PE_ITEM_NAME
|
||||
FROM V_PHYEXAM_ITEM
|
||||
</select>
|
||||
|
||||
<select id="getEmpItem" resultType="java.util.Map">
|
||||
@@ -112,310 +123,217 @@
|
||||
</select>
|
||||
|
||||
<select id="getItemInfo" resultType="java.util.Map">
|
||||
select ITEM_ASSEM_CODE, ITEM_ASSEM_NAME, PE_ITEM_CODE, PE_ITEM_NAME
|
||||
from V_PHYEXAM_ITEM_ASSEMBLED
|
||||
where PE_ITEM_CODE = #{peItemCode}
|
||||
SELECT ITEM_ASSEM_CODE, ITEM_ASSEM_NAME, PE_ITEM_CODE, PE_ITEM_NAME
|
||||
FROM V_PHYEXAM_ITEM_ASSEMBLED
|
||||
WHERE PE_ITEM_CODE = #{peItemCode}
|
||||
</select>
|
||||
|
||||
<!-- ==================== 体检结果 ==================== -->
|
||||
|
||||
<select id="getResult" resultType="java.util.Map">
|
||||
select PE_ID,
|
||||
PE_VISIT_ID,
|
||||
ID_NO,
|
||||
NAME,
|
||||
UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
TO_CHAR(PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss') PE_QUEUE_DATE,
|
||||
TO_CHAR(AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss') AUDIT_DATE,
|
||||
PE_DEPT_CODE,
|
||||
PE_DEPT_NAME,
|
||||
ITEM_ASSEM_CODE,
|
||||
ITEM_ASSEM_NAME,
|
||||
PE_ITEM_CODE,
|
||||
PE_ITEM_NAME,
|
||||
PE_RESULT,
|
||||
UNIT,
|
||||
PRINT_CONTEXT
|
||||
from V_PHYEXAM_RESULT
|
||||
where PE_ID = #{peId}
|
||||
SELECT PE_ID,
|
||||
PE_VISIT_ID,
|
||||
ID_NO,
|
||||
NAME,
|
||||
UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
TO_CHAR(PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss') PE_QUEUE_DATE,
|
||||
TO_CHAR(AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss') AUDIT_DATE,
|
||||
PE_DEPT_CODE,
|
||||
PE_DEPT_NAME,
|
||||
ITEM_ASSEM_CODE,
|
||||
ITEM_ASSEM_NAME,
|
||||
PE_ITEM_CODE,
|
||||
PE_ITEM_NAME,
|
||||
PE_RESULT,
|
||||
UNIT,
|
||||
PRINT_CONTEXT
|
||||
FROM (
|
||||
SELECT b.pe_id, b.pe_visit_id, a.id_no, a.name, b.unit_code,
|
||||
(SELECT t.unit_name FROM pe_unit_dict t WHERE t.unit_code = b.unit_code) unit_name,
|
||||
b.pe_queue_date, b.audit_date,
|
||||
c.pe_dept_code, c.pe_dept_name, c.item_assem_code, c.item_assem_name,
|
||||
c.pe_item_code, c.pe_item_name, c.pe_result, c.unit, c.print_context
|
||||
FROM pe_master_index a, pe_visit b, pe_result_dict c
|
||||
WHERE a.pe_id = b.pe_id
|
||||
AND b.pe_id = c.pe_id
|
||||
AND b.pe_visit_id = c.pe_visit_id
|
||||
)
|
||||
WHERE PE_ID = #{peId}
|
||||
</select>
|
||||
|
||||
<select id="getConclusion" resultType="java.util.Map">
|
||||
select PE_ID,
|
||||
PE_VISIT_ID,
|
||||
PE_DEPT_CODE,
|
||||
PE_DEPT_NAME,
|
||||
REPLACE(REPLACE(REPLACE(DBMS_LOB.SUBSTR(CONCLUSION_TEXT, 4000, 1), chr(13) || chr(10), ''), chr(13), ''), chr(10), '') CONCLUSION_TEXT
|
||||
from V_PHYEXAM_DEPT_RESULT
|
||||
where PE_ID = #{peId}
|
||||
and CONCLUSION_TEXT is not null
|
||||
</select>
|
||||
<select id="getConclusionAll" resultType="java.util.Map">
|
||||
select PE_ID,
|
||||
PE_VISIT_ID,
|
||||
PE_DEPT_CODE,
|
||||
PE_DEPT_NAME,
|
||||
REPLACE(REPLACE(REPLACE(DBMS_LOB.SUBSTR(CONCLUSION_TEXT, 4000, 1), chr(13) || chr(10), ''), chr(13), ''), chr(10), '') CONCLUSION_TEXT
|
||||
from (select a.pe_id,
|
||||
a.pe_visit_id,
|
||||
a.pe_dept_code,
|
||||
a.pe_dept_name,
|
||||
a.conclusion_text
|
||||
from pe_dept_result_dict a,pe_visit b
|
||||
where a.pe_id = b.pe_id
|
||||
and a.pe_visit_id = b.pe_visit_id) a
|
||||
where PE_ID = #{peId}
|
||||
and CONCLUSION_TEXT is not null
|
||||
</select>
|
||||
<!-- getTotalConclusion/getTotalSuggest 已删除:原实现依赖 wm_concat(Oracle 18c 起移除,
|
||||
且接口未引用);汇总逻辑由 OrderService 基于本文件列表查询在应用层完成 -->
|
||||
<!-- ==================== 体检结论 / 建议 ==================== -->
|
||||
|
||||
<select id="getSuggest" resultType="java.util.Map">
|
||||
select PE_ID, PE_VISIT_ID, REC_CONTENT, REPLACE(REPLACE(REPLACE(DBMS_LOB.SUBSTR(GUIDE_CONTENT, 4000, 1), chr(13) || chr(10), ''), chr(13), ''), chr(10), '') GUIDE_CONTENT
|
||||
from V_PHYEXAM_DIAGNOSIS
|
||||
where PE_ID = #{peId}
|
||||
and GUIDE_CONTENT is not null
|
||||
|
||||
<select id="getConclusionAll" resultType="com.hospital.front.vo.ConclusionVo">
|
||||
SELECT PE_ID,
|
||||
PE_VISIT_ID,
|
||||
PE_DEPT_CODE,
|
||||
PE_DEPT_NAME,
|
||||
REPLACE(REPLACE(REPLACE(DBMS_LOB.SUBSTR(CONCLUSION_TEXT, 4000, 1), chr(13) || chr(10), ''), chr(13), ''), chr(10), '') CONCLUSION_TEXT
|
||||
FROM (
|
||||
SELECT a.pe_id, a.pe_visit_id, a.pe_dept_code, a.pe_dept_name, a.conclusion_text
|
||||
FROM pe_dept_result_dict a, pe_visit b
|
||||
WHERE a.pe_id = b.pe_id
|
||||
AND a.pe_visit_id = b.pe_visit_id
|
||||
)
|
||||
WHERE PE_ID = #{peId}
|
||||
AND CONCLUSION_TEXT IS NOT NULL
|
||||
</select>
|
||||
<select id="getSuggestAll" resultType="java.util.HashMap">
|
||||
select PE_ID, PE_VISIT_ID, REC_CONTENT, REPLACE(REPLACE(REPLACE(DBMS_LOB.SUBSTR(GUIDE_CONTENT, 4000, 1), chr(13) || chr(10), ''), chr(13), ''), chr(10), '') GUIDE_CONTENT
|
||||
from (select a.pe_id,
|
||||
a.pe_visit_id,
|
||||
a.rec_content,
|
||||
a.guide_content
|
||||
from pe_diagnosis_record a,pe_visit b
|
||||
where a.pe_id = b.pe_id
|
||||
and a.pe_visit_id = b.pe_visit_id) a
|
||||
where PE_ID = #{peId}
|
||||
and GUIDE_CONTENT is not null
|
||||
</select>
|
||||
<select id="getPeStatusByIdnoAndYear" resultType="java.util.HashMap">
|
||||
select *
|
||||
from V_PHYEXAM_PE_STATUS
|
||||
where ID_NO = #{idNo}
|
||||
and PE_PRE_DATE >= TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD')
|
||||
and PE_PRE_DATE < ADD_MONTHS(TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD'), 12)
|
||||
|
||||
<select id="getSuggestAll" resultType="com.hospital.front.vo.SuggestVo">
|
||||
SELECT PE_ID, PE_VISIT_ID, REC_CONTENT,
|
||||
REPLACE(REPLACE(REPLACE(DBMS_LOB.SUBSTR(GUIDE_CONTENT, 4000, 1), chr(13) || chr(10), ''), chr(13), ''), chr(10), '') GUIDE_CONTENT
|
||||
FROM (
|
||||
SELECT a.pe_id, a.pe_visit_id, a.rec_content, a.guide_content
|
||||
FROM pe_diagnosis_record a, pe_visit b
|
||||
WHERE a.pe_id = b.pe_id
|
||||
AND a.pe_visit_id = b.pe_visit_id
|
||||
)
|
||||
WHERE PE_ID = #{peId}
|
||||
AND GUIDE_CONTENT IS NOT NULL
|
||||
</select>
|
||||
|
||||
<!-- ==================== 按身份证 / 日期 / 编号查询结果 ==================== -->
|
||||
|
||||
<select id="getResultByIdcardAndYear" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
select DISTINCT
|
||||
ID_NO,
|
||||
NAME,
|
||||
PE_ID,
|
||||
PE_VISIT_ID,
|
||||
UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
to_char( PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss' ) PE_QUEUE_DATE,
|
||||
to_char( AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss' ) AUDIT_DATE
|
||||
from V_PHYEXAM_RESULT
|
||||
where ID_NO = #{idNo}
|
||||
and PE_QUEUE_DATE >= TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD')
|
||||
and PE_QUEUE_DATE < ADD_MONTHS(TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD'), 12)
|
||||
SELECT DISTINCT
|
||||
ID_NO, NAME, PE_ID, PE_VISIT_ID, UNIT_CODE, UNIT_NAME,
|
||||
to_char(PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss') PE_QUEUE_DATE,
|
||||
to_char(AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss') AUDIT_DATE
|
||||
FROM (
|
||||
SELECT b.pe_id, b.pe_visit_id, a.id_no, a.name, b.unit_code,
|
||||
(SELECT t.unit_name FROM pe_unit_dict t WHERE t.unit_code = b.unit_code) unit_name,
|
||||
b.pe_queue_date, b.audit_date,
|
||||
c.pe_dept_code, c.pe_dept_name, c.item_assem_code, c.item_assem_name,
|
||||
c.pe_item_code, c.pe_item_name, c.pe_result, c.unit, c.print_context
|
||||
FROM pe_master_index a, pe_visit b, pe_result_dict c
|
||||
WHERE a.pe_id = b.pe_id
|
||||
AND b.pe_id = c.pe_id
|
||||
AND b.pe_visit_id = c.pe_visit_id
|
||||
)
|
||||
WHERE ID_NO = #{idNo}
|
||||
AND PE_QUEUE_DATE >= TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD')
|
||||
AND PE_QUEUE_DATE < ADD_MONTHS(TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD'), 12)
|
||||
</select>
|
||||
|
||||
<select id="getResultByIdcardAndYearAll" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT DISTINCT
|
||||
ID_NO,
|
||||
NAME,
|
||||
PE_ID,
|
||||
PE_VISIT_ID,
|
||||
UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
to_char ( PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss' ) PE_QUEUE_DATE,
|
||||
to_char ( AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss' ) AUDIT_DATE
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
b.pe_id,
|
||||
b.pe_visit_id,
|
||||
a.id_no,
|
||||
a.NAME,
|
||||
b.unit_code,
|
||||
t.unit_name,
|
||||
b.pe_queue_date,
|
||||
b.audit_date,
|
||||
c.pe_dept_code,
|
||||
c.pe_dept_name,
|
||||
c.item_assem_code,
|
||||
c.item_assem_name,
|
||||
c.pe_item_code,
|
||||
c.pe_item_name,
|
||||
c.pe_result,
|
||||
c.unit,
|
||||
c.print_context
|
||||
FROM
|
||||
pe_master_index a
|
||||
JOIN pe_visit b ON b.pe_id = a.pe_id
|
||||
JOIN pe_result_dict c ON c.pe_id = b.pe_id AND c.pe_visit_id = b.pe_visit_id
|
||||
LEFT JOIN pe_unit_dict t ON t.unit_code = b.unit_code
|
||||
WHERE
|
||||
b.audit_date >= TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD')
|
||||
and b.audit_date < ADD_MONTHS(TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD'), 12)
|
||||
and a.id_no = #{idNo}
|
||||
) a
|
||||
</select>
|
||||
|
||||
<select id="getResultByAuditDate" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
select *
|
||||
from V_PHYEXAM_RESULT
|
||||
where to_char(AUDIT_DATE,'yyyy-mm-dd')=#{auditDate}
|
||||
</select>
|
||||
|
||||
<select id="getDisResultByAuditDate" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT DISTINCT
|
||||
ID_NO,
|
||||
NAME,
|
||||
PE_ID,
|
||||
PE_VISIT_ID,
|
||||
UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
to_char( PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss' ) PE_QUEUE_DATE,
|
||||
to_char( AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss' ) AUDIT_DATE
|
||||
FROM
|
||||
V_PHYEXAM_RESULT
|
||||
WHERE
|
||||
AUDIT_DATE >= TO_DATE(#{auditDate}, 'YYYY-MM-DD')
|
||||
and AUDIT_DATE < TO_DATE(#{auditDate}, 'YYYY-MM-DD') + 1
|
||||
ID_NO, NAME, PE_ID, PE_VISIT_ID, UNIT_CODE, UNIT_NAME,
|
||||
to_char(PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss') PE_QUEUE_DATE,
|
||||
to_char(AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss') AUDIT_DATE
|
||||
FROM (
|
||||
SELECT b.pe_id, b.pe_visit_id, a.id_no, a.NAME, b.unit_code, t.unit_name,
|
||||
b.pe_queue_date, b.audit_date,
|
||||
c.pe_dept_code, c.pe_dept_name, c.item_assem_code, c.item_assem_name,
|
||||
c.pe_item_code, c.pe_item_name, c.pe_result, c.unit, c.print_context
|
||||
FROM pe_master_index a
|
||||
JOIN pe_visit b ON b.pe_id = a.pe_id
|
||||
JOIN pe_result_dict c ON c.pe_id = b.pe_id AND c.pe_visit_id = b.pe_visit_id
|
||||
LEFT JOIN pe_unit_dict t ON t.unit_code = b.unit_code
|
||||
WHERE b.audit_date >= TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD')
|
||||
AND b.audit_date < ADD_MONTHS(TO_DATE(#{year} || '-01-01', 'YYYY-MM-DD'), 12)
|
||||
AND a.id_no = #{idNo}
|
||||
)
|
||||
</select>
|
||||
|
||||
<select id="getItemByPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT
|
||||
ITEM_ASSEM_CODE,
|
||||
ITEM_ASSEM_NAME,
|
||||
PE_ITEM_CODE,
|
||||
PE_ITEM_NAME,
|
||||
PE_RESULT,
|
||||
UNIT,
|
||||
PRINT_CONTEXT
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
b.pe_id,
|
||||
b.pe_visit_id,
|
||||
a.id_no,
|
||||
a.NAME,
|
||||
b.unit_code,
|
||||
t.unit_name,
|
||||
b.pe_queue_date,
|
||||
b.audit_date,
|
||||
c.pe_dept_code,
|
||||
c.pe_dept_name,
|
||||
c.item_assem_code,
|
||||
c.item_assem_name,
|
||||
c.pe_item_code,
|
||||
c.pe_item_name,
|
||||
c.pe_result,
|
||||
c.unit,
|
||||
c.print_context
|
||||
FROM
|
||||
pe_master_index a
|
||||
JOIN pe_visit b ON b.pe_id = a.pe_id
|
||||
JOIN pe_result_dict c ON c.pe_id = b.pe_id AND c.pe_visit_id = b.pe_visit_id
|
||||
LEFT JOIN pe_unit_dict t ON t.unit_code = b.unit_code
|
||||
WHERE
|
||||
b.pe_id = #{peId}
|
||||
) a
|
||||
SELECT ITEM_ASSEM_CODE, ITEM_ASSEM_NAME, PE_ITEM_CODE, PE_ITEM_NAME, PE_RESULT, UNIT, PRINT_CONTEXT
|
||||
FROM (
|
||||
SELECT b.pe_id, b.pe_visit_id, a.id_no, a.NAME, b.unit_code, t.unit_name,
|
||||
b.pe_queue_date, b.audit_date,
|
||||
c.pe_dept_code, c.pe_dept_name, c.item_assem_code, c.item_assem_name,
|
||||
c.pe_item_code, c.pe_item_name, c.pe_result, c.unit, c.print_context
|
||||
FROM pe_master_index a
|
||||
JOIN pe_visit b ON b.pe_id = a.pe_id
|
||||
JOIN pe_result_dict c ON c.pe_id = b.pe_id AND c.pe_visit_id = b.pe_visit_id
|
||||
LEFT JOIN pe_unit_dict t ON t.unit_code = b.unit_code
|
||||
WHERE b.pe_id = #{peId}
|
||||
)
|
||||
</select>
|
||||
|
||||
<select id="getItemByPeIdAll" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT
|
||||
ITEM_ASSEM_CODE,
|
||||
ITEM_ASSEM_NAME,
|
||||
PE_ITEM_CODE,
|
||||
PE_ITEM_NAME,
|
||||
PE_RESULT,
|
||||
UNIT,
|
||||
PRINT_CONTEXT
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
b.pe_id,
|
||||
b.pe_visit_id,
|
||||
a.id_no,
|
||||
a.NAME,
|
||||
b.unit_code,
|
||||
t.unit_name,
|
||||
b.pe_queue_date,
|
||||
b.audit_date,
|
||||
c.pe_dept_code,
|
||||
c.pe_dept_name,
|
||||
c.item_assem_code,
|
||||
c.item_assem_name,
|
||||
c.pe_item_code,
|
||||
c.pe_item_name,
|
||||
c.pe_result,
|
||||
c.unit,
|
||||
c.print_context
|
||||
FROM
|
||||
pe_master_index a
|
||||
JOIN pe_visit b ON b.pe_id = a.pe_id
|
||||
JOIN pe_result_dict c ON c.pe_id = b.pe_id AND c.pe_visit_id = b.pe_visit_id
|
||||
LEFT JOIN pe_unit_dict t ON t.unit_code = b.unit_code
|
||||
WHERE
|
||||
b.pe_id = #{peId}
|
||||
) a
|
||||
|
||||
SELECT ITEM_ASSEM_CODE, ITEM_ASSEM_NAME, PE_ITEM_CODE, PE_ITEM_NAME, PE_RESULT, UNIT, PRINT_CONTEXT
|
||||
FROM (
|
||||
SELECT b.pe_id, b.pe_visit_id, a.id_no, a.NAME, b.unit_code, t.unit_name,
|
||||
b.pe_queue_date, b.audit_date,
|
||||
c.pe_dept_code, c.pe_dept_name, c.item_assem_code, c.item_assem_name,
|
||||
c.pe_item_code, c.pe_item_name, c.pe_result, c.unit, c.print_context
|
||||
FROM pe_master_index a
|
||||
JOIN pe_visit b ON b.pe_id = a.pe_id
|
||||
JOIN pe_result_dict c ON c.pe_id = b.pe_id AND c.pe_visit_id = b.pe_visit_id
|
||||
LEFT JOIN pe_unit_dict t ON t.unit_code = b.unit_code
|
||||
WHERE b.pe_id = #{peId}
|
||||
)
|
||||
</select>
|
||||
|
||||
<select id="getResultByIdNoOrPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
select DISTINCT
|
||||
ID_NO,
|
||||
NAME,
|
||||
PE_ID,
|
||||
PE_VISIT_ID,
|
||||
UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
to_char( PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss' ) PE_QUEUE_DATE,
|
||||
to_char( AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss' ) AUDIT_DATE
|
||||
from V_PHYEXAM_RESULT
|
||||
<where>
|
||||
1=1
|
||||
<if test="idNo != null and idNo != '' ">
|
||||
and ID_NO = #{idNo}
|
||||
</if>
|
||||
<if test="peId != null and peId != '' ">
|
||||
and PE_ID = #{peId}
|
||||
</if>
|
||||
|
||||
and AUDIT_DATE >= TO_DATE(#{auditYear} || '-01-01', 'YYYY-MM-DD')
|
||||
and AUDIT_DATE < ADD_MONTHS(TO_DATE(#{auditYear} || '-01-01', 'YYYY-MM-DD'), 12)
|
||||
</where>
|
||||
<select id="getResultByPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT DISTINCT
|
||||
ID_NO, NAME, PE_ID, PE_VISIT_ID, UNIT_CODE, UNIT_NAME,
|
||||
to_char(PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss') PE_QUEUE_DATE,
|
||||
to_char(AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss') AUDIT_DATE
|
||||
FROM (
|
||||
SELECT b.pe_id, b.pe_visit_id, a.id_no, a.name, b.unit_code,
|
||||
(SELECT t.unit_name FROM pe_unit_dict t WHERE t.unit_code = b.unit_code) unit_name,
|
||||
b.pe_queue_date, b.audit_date,
|
||||
c.pe_dept_code, c.pe_dept_name, c.item_assem_code, c.item_assem_name,
|
||||
c.pe_item_code, c.pe_item_name, c.pe_result, c.unit, c.print_context
|
||||
FROM pe_master_index a, pe_visit b, pe_result_dict c
|
||||
WHERE a.pe_id = b.pe_id
|
||||
AND b.pe_id = c.pe_id
|
||||
AND b.pe_visit_id = c.pe_visit_id
|
||||
)
|
||||
WHERE PE_ID = #{peId}
|
||||
</select>
|
||||
|
||||
<!-- ==================== 按身份证查 peId/预约日期 / 人员列表 ==================== -->
|
||||
|
||||
<select id="getPeIdAndDateByIdcard" resultType="java.util.Map">
|
||||
select PE_ID,to_char( PE_PRE_DATE, 'yyyy-mm-dd' ) PE_PRE_DATE from V_PHYEXAM_PE_STATUS
|
||||
SELECT PE_ID, to_char(PE_PRE_DATE, 'yyyy-mm-dd') PE_PRE_DATE
|
||||
FROM (
|
||||
SELECT b.pe_id, b.name, b.id_no,
|
||||
(SELECT unit_name FROM pe_unit_dict t WHERE t.unit_code = a.unit_code) unit_name,
|
||||
a.department, a.pe_pre_date, a.pe_queue_date,
|
||||
DECODE(a.queue_flag, '1',
|
||||
DECODE(result_status, '7', '初审', '9', '终审', '1', '检中', '报到'),
|
||||
DECODE(pe_transfer_hospital, '', '预约', '转向' || pe_transfer_hospital)) pe_status
|
||||
FROM pe_visit a, pe_master_index b
|
||||
WHERE a.pe_id = b.pe_id
|
||||
)
|
||||
<where>
|
||||
<if test="idNo != null and idNo != '' ">
|
||||
and ID_NO = #{idNo}
|
||||
<if test="idNo != null and idNo != ''">
|
||||
AND ID_NO = #{idNo}
|
||||
</if>
|
||||
and PE_PRE_DATE >= TRUNC(SYSDATE, 'YYYY')
|
||||
and PE_PRE_DATE < ADD_MONTHS(TRUNC(SYSDATE, 'YYYY'), 12)
|
||||
AND PE_PRE_DATE >= TRUNC(SYSDATE, 'YYYY')
|
||||
AND PE_PRE_DATE < ADD_MONTHS(TRUNC(SYSDATE, 'YYYY'), 12)
|
||||
</where>
|
||||
order by PE_PRE_DATE desc
|
||||
|
||||
</select>
|
||||
<select id="getResultByPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
select DISTINCT
|
||||
ID_NO,
|
||||
NAME,
|
||||
PE_ID,
|
||||
PE_VISIT_ID,
|
||||
UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
to_char( PE_QUEUE_DATE, 'yyyy-mm-dd HH24:mi:ss' ) PE_QUEUE_DATE,
|
||||
to_char( AUDIT_DATE, 'yyyy-mm-dd HH24:mi:ss' ) AUDIT_DATE
|
||||
from V_PHYEXAM_RESULT
|
||||
where PE_ID = #{peId}
|
||||
ORDER BY PE_PRE_DATE DESC
|
||||
</select>
|
||||
|
||||
<select id="getPeIdAndDateByIdcardList" resultType="java.util.Map">
|
||||
select PE_ID,to_char( PE_PRE_DATE, 'yyyy-mm-dd' ) PE_PRE_DATE from V_PHYEXAM_PE_STATUS
|
||||
SELECT PE_ID, to_char(PE_PRE_DATE, 'yyyy-mm-dd') PE_PRE_DATE
|
||||
FROM (
|
||||
SELECT b.pe_id, b.name, b.id_no,
|
||||
(SELECT unit_name FROM pe_unit_dict t WHERE t.unit_code = a.unit_code) unit_name,
|
||||
a.department, a.pe_pre_date, a.pe_queue_date,
|
||||
DECODE(a.queue_flag, '1',
|
||||
DECODE(result_status, '7', '初审', '9', '终审', '1', '检中', '报到'),
|
||||
DECODE(pe_transfer_hospital, '', '预约', '转向' || pe_transfer_hospital)) pe_status
|
||||
FROM pe_visit a, pe_master_index b
|
||||
WHERE a.pe_id = b.pe_id
|
||||
)
|
||||
<where>
|
||||
<if test="idNo != null and idNo != '' ">
|
||||
and ID_NO = #{idNo}
|
||||
<if test="idNo != null and idNo != ''">
|
||||
AND ID_NO = #{idNo}
|
||||
</if>
|
||||
and PE_PRE_DATE >= TRUNC(SYSDATE, 'YYYY')
|
||||
and PE_PRE_DATE < ADD_MONTHS(TRUNC(SYSDATE, 'YYYY'), 12)
|
||||
AND PE_PRE_DATE >= TRUNC(SYSDATE, 'YYYY')
|
||||
AND PE_PRE_DATE < ADD_MONTHS(TRUNC(SYSDATE, 'YYYY'), 12)
|
||||
</where>
|
||||
order by PE_PRE_DATE desc
|
||||
ORDER BY PE_PRE_DATE DESC
|
||||
</select>
|
||||
|
||||
<!-- 根据audit_date查询当天体检人员列表(去重) -->
|
||||
<select id="getExamListByDate" resultType="java.util.Map">
|
||||
<select id="getExamListByDate" resultType="com.hospital.front.vo.ExamListVo">
|
||||
SELECT DISTINCT PE_ID AS "peId",
|
||||
ID_NO AS "idNo",
|
||||
NAME AS "name",
|
||||
@@ -434,4 +352,5 @@
|
||||
</choose>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
@@ -69,7 +69,7 @@
|
||||
)}
|
||||
</insert>
|
||||
|
||||
<select id="getPhyexamStatus" resultType="java.util.Map">
|
||||
<select id="getPhyexamStatus" resultType="com.hospital.front.vo.PeStatusVo">
|
||||
SELECT
|
||||
PE_ID,
|
||||
NAME,
|
||||
@@ -123,6 +123,9 @@
|
||||
DEPARTMENT,
|
||||
ITEM_ASSEM_CODE,
|
||||
ITEM_ASSEM_NAME,
|
||||
PE_DEPT_CODE,
|
||||
PE_DEPT_NAME,
|
||||
CONVERT ( VARCHAR ( 100 ), REGISTER_DATE, 20 ) REGISTER_DATE,
|
||||
(case when Finished_sign = '1' then N'完成' when Finished_sign != '1' then N'未完成' end) FINISHED_SIGN,
|
||||
CONVERT ( VARCHAR ( 100 ), PE_DATE, 20 ) PE_DATE
|
||||
from V_PHYEXAM_PE_PERSONAL_ITEM
|
||||
@@ -144,35 +147,25 @@
|
||||
|
||||
|
||||
|
||||
<select id="getConclusion" resultType="java.util.Map">
|
||||
<select id="getConclusionAll" resultType="com.hospital.front.vo.ConclusionVo">
|
||||
select PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
PE_DEPT_CODE,
|
||||
PE_DEPT_NAME,
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(CONCLUSION_TEXT,CHAR(10),''), ' ', ''),char(9),''),char(13),'') CONCLUSION_TEXT
|
||||
from V_PHYEXAM_DEPT_RESULT
|
||||
where PE_ID = #{peId}
|
||||
and CONCLUSION_TEXT is not null
|
||||
</select>
|
||||
<select id="getConclusionAll" resultType="java.util.Map">
|
||||
select PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
PE_DEPT_CODE,
|
||||
PE_DEPT_NAME,
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(CONCLUSION_TEXT,CHAR(10),''), ' ', ''),char(9),''),char(13),'') CONCLUSION_TEXT
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(cast(CONCLUSION_TEXT as varchar(8000)),CHAR(10),''), ' ', ''),char(9),''),char(13),'') CONCLUSION_TEXT
|
||||
from V_PHYEXAM_DEPT_RESULT
|
||||
where PE_ID = #{peId}
|
||||
and CONCLUSION_TEXT is not null
|
||||
</select>
|
||||
|
||||
<select id="getSuggest" resultType="java.util.Map">
|
||||
<select id="getSuggestAll" resultType="com.hospital.front.vo.SuggestVo">
|
||||
SELECT top 1
|
||||
PE_ID,
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(REPLACE(GUIDE_CONTENT, CHAR(10), '<br/>'), ' ', ''),
|
||||
REPLACE(REPLACE(CAST (GUIDE_CONTENT AS VARCHAR (8000)), CHAR(10), '<br/>'), ' ', ''),
|
||||
CHAR(9),''
|
||||
), CHAR(13), ''
|
||||
), '<br/><br/>','<br/>'
|
||||
@@ -183,25 +176,7 @@
|
||||
where PE_ID = #{peId}
|
||||
AND REC_CONTENT IS NOT NULL
|
||||
</select>
|
||||
<select id="getSuggestAll" resultType="java.util.Map">
|
||||
SELECT top 1
|
||||
PE_ID,
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(
|
||||
REPLACE(REPLACE(GUIDE_CONTENT, CHAR(10), '<br/>'), ' ', ''),
|
||||
CHAR(9),''
|
||||
), CHAR(13), ''
|
||||
), '<br/><br/>','<br/>'
|
||||
), '<br/>-谢谢合作祝您健康!<br/>',''
|
||||
) GUIDE_CONTENT
|
||||
FROM
|
||||
V_PHYEXAM_DIAGNOSIS
|
||||
where PE_ID = #{peId}
|
||||
AND REC_CONTENT IS NOT NULL
|
||||
</select>
|
||||
<select id="getPeStatusByIdnoAndYear" resultType="java.util.Map">
|
||||
<select id="getPeStatusByIdnoAndYear" resultType="com.hospital.front.vo.PeStatusVo">
|
||||
SELECT
|
||||
PE_ID,
|
||||
NAME,
|
||||
@@ -314,23 +289,6 @@
|
||||
group by id_no,NAME,PE_ID,UNIT_NAME
|
||||
</select>
|
||||
|
||||
<select id="getDisResultByAuditDate" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
select
|
||||
ID_NO,
|
||||
NAME,
|
||||
PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
'' UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
CONVERT(varchar(100),max(PE_QUEUE_DATE),20) PE_QUEUE_DATE,
|
||||
CONVERT(varchar(100),max(AUDIT_DATE),20) AUDIT_DATE
|
||||
from V_PHYEXAM_RESULT
|
||||
where AUDIT_DATE >= CONVERT(DATETIME, #{auditDate})
|
||||
AND AUDIT_DATE < DATEADD(DAY, 1, CONVERT(DATETIME, #{auditDate}))
|
||||
group by id_no,NAME,PE_ID,UNIT_NAME
|
||||
|
||||
</select>
|
||||
|
||||
<select id="getItemByPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT
|
||||
ITEM_ASSEM_CODE,
|
||||
@@ -362,31 +320,6 @@
|
||||
and PE_RESULT is not null
|
||||
</select>
|
||||
|
||||
<select id="getResultByIdNoOrPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
select
|
||||
ID_NO,
|
||||
NAME,
|
||||
PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
'' UNIT_CODE,
|
||||
UNIT_NAME,
|
||||
CONVERT(varchar(100),max(PE_QUEUE_DATE),20) PE_QUEUE_DATE,
|
||||
CONVERT(varchar(100),max(AUDIT_DATE),20) AUDIT_DATE
|
||||
from V_PHYEXAM_RESULT
|
||||
<where>
|
||||
1=1
|
||||
<if test="idNo != null and idNo != '' ">
|
||||
and ID_NO = #{idNo}
|
||||
</if>
|
||||
<if test="peId != null and peId != '' ">
|
||||
and PE_ID = #{peId}
|
||||
</if>
|
||||
|
||||
and AUDIT_DATE >= CONVERT(DATETIME, #{auditYear} + '-01-01')
|
||||
and AUDIT_DATE < DATEADD(YEAR, 1, CONVERT(DATETIME, #{auditYear} + '-01-01'))
|
||||
</where>
|
||||
group by id_no,NAME,PE_ID,UNIT_NAME
|
||||
</select>
|
||||
<select id="getResultByPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
select
|
||||
ID_NO,
|
||||
@@ -403,7 +336,7 @@
|
||||
group by id_no,NAME,PE_ID,UNIT_NAME
|
||||
</select>
|
||||
<!-- 根据audit_date查询当天体检人员列表(去重) -->
|
||||
<select id="getExamListByDate" resultType="java.util.Map">
|
||||
<select id="getExamListByDate" resultType="com.hospital.front.vo.ExamListVo">
|
||||
SELECT DISTINCT PE_ID AS "peId",
|
||||
ID_NO AS "idNo",
|
||||
NAME AS "name",
|
||||
|
||||
@@ -1,414 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.hospital.front.mapper.ya.YaOrderMapper">
|
||||
|
||||
<!-- 健康探测 -->
|
||||
<select id="ping" resultType="int">
|
||||
SELECT 1
|
||||
</select>
|
||||
|
||||
<parameterMap id="pm" type="java.util.Map">
|
||||
<parameter property="peInfoStr" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="peItemStr" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="peId" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
</parameterMap>
|
||||
<insert id="saveOrder" parameterMap="pm" statementType="CALLABLE">
|
||||
{call P_OrderRegister_YARMYY(
|
||||
#{peInfoStr,mode=IN,jdbcType=VARCHAR},
|
||||
#{peItemStr,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR},
|
||||
#{peId,mode=OUT,jdbcType=VARCHAR}
|
||||
)}
|
||||
</insert>
|
||||
|
||||
<parameterMap id="cancenlPm" type="java.util.Map">
|
||||
<parameter property="peId" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="name" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="idcard" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
</parameterMap>
|
||||
<insert id="cancelOrder" parameterMap="cancenlPm" statementType="CALLABLE">
|
||||
{call P_CANCELORDER(
|
||||
#{peId,mode=IN,jdbcType=VARCHAR},
|
||||
#{name,mode=IN,jdbcType=VARCHAR},
|
||||
#{idcard,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR}
|
||||
)}
|
||||
</insert>
|
||||
|
||||
<parameterMap id="unitPm" type="java.util.Map">
|
||||
<parameter property="unitCode" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="unitName" jdbcType="VARCHAR" mode="IN"></parameter>
|
||||
<parameter property="resultCode" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
<parameter property="errorMsg" jdbcType="VARCHAR" mode="OUT"></parameter>
|
||||
</parameterMap>
|
||||
|
||||
<insert id="addUnit" parameterMap="unitPm" statementType="CALLABLE">
|
||||
{call P_ORGINFOUPDATE(
|
||||
#{unitCode,mode=IN,jdbcType=VARCHAR},
|
||||
#{unitName,mode=IN,jdbcType=VARCHAR},
|
||||
#{resultCode,mode=OUT,jdbcType=VARCHAR},
|
||||
#{errorMsg,mode=OUT,jdbcType=VARCHAR}
|
||||
)}
|
||||
</insert>
|
||||
|
||||
<select id="getPhyexamStatus" resultType="java.util.Map">
|
||||
SELECT
|
||||
t.tjh PE_ID,
|
||||
t.xm NAME,
|
||||
t.sfzh ID_NO,
|
||||
t.dwmc UNIT_NAME,
|
||||
t.dwbm DEPARTMENT,
|
||||
(CONVERT(varchar(100), t.yyrq, 20)) PE_PRE_DATE,
|
||||
(
|
||||
CASE t.status_sum
|
||||
WHEN 4 THEN N'终审'
|
||||
WHEN 3 THEN N'初审'
|
||||
WHEN 2 THEN N'检中'
|
||||
WHEN 1 THEN N'报道'
|
||||
WHEN 0 THEN N'预约'
|
||||
ELSE N'预约'
|
||||
END
|
||||
) PE_STATUS
|
||||
FROM
|
||||
( SELECT tjh, xm, sfzh, dwmc, dwbm, yyrq,
|
||||
( ISNULL(bdzt,0) + ISNULL(jczt,0) + ISNULL(cszt,0) + ISNULL(zszt,0) ) status_sum
|
||||
FROM V_YGTJZT ) t
|
||||
WHERE
|
||||
CHARINDEX( ',' + t.tjh + ',', ',' + #{peIds} + ',' ) >0
|
||||
</select>
|
||||
|
||||
<select id="getItemList" resultType="java.util.Map">
|
||||
SELECT DISTINCT
|
||||
tjzhxbm item_assem_code,
|
||||
tjzhxmc item_assem_name
|
||||
FROM
|
||||
V_TJXMZH
|
||||
</select>
|
||||
<select id="getAllItemList" resultType="java.util.Map">
|
||||
SELECT DISTINCT
|
||||
tjzhxbm ITEM_ASSEM_CODE,
|
||||
tjzhxmc ITEM_ASSEM_NAME,
|
||||
tjzbxbm PE_ITEM_CODE,
|
||||
tjzbxmc PE_ITEM_NAME
|
||||
FROM
|
||||
V_TJXMZH
|
||||
</select>
|
||||
|
||||
<select id="getPeItemList" resultType="java.util.Map">
|
||||
SELECT DISTINCT
|
||||
tjzbxbm PE_ITEM_CODE,
|
||||
tjzbxmc PE_ITEM_NAME
|
||||
FROM
|
||||
V_TJXMZH
|
||||
</select>
|
||||
|
||||
<select id="getEmpItem" resultType="java.util.Map">
|
||||
SELECT
|
||||
TJH PE_ID,
|
||||
XM NAME,
|
||||
DWMC UNIT_NAME,
|
||||
DWBM DEPARTMENT,
|
||||
TJZHXBM ITEM_ASSEM_CODE,
|
||||
TJZHXMC ITEM_ASSEM_NAME,
|
||||
(case when WCZT = '1' then N'完成' when WCZT != '1' then N'未完成' end) FINISHED_SIGN,
|
||||
CONVERT ( VARCHAR ( 100 ), JCWCSJ, 20 ) PE_DATE
|
||||
from V_YGYYTJZHX
|
||||
where TJH = #{peId}
|
||||
</select>
|
||||
|
||||
<select id="getItemInfo" resultType="java.util.Map">
|
||||
SELECT
|
||||
tjzhxbm ITEM_ASSEM_CODE,
|
||||
tjzhxmc ITEM_ASSEM_NAME,
|
||||
TJZBXBM PE_ITEM_CODE,
|
||||
TJZBXMC PE_ITEM_NAME
|
||||
FROM
|
||||
V_TJXMZH
|
||||
where tjzhxbm = #{peItemCode}
|
||||
</select>
|
||||
|
||||
<select id="getResult" resultType="java.util.Map">
|
||||
SELECT
|
||||
TJH PE_ID ,
|
||||
XM NAME,
|
||||
SFZH ID_NO,
|
||||
DWMC UNIT_NAME,
|
||||
DWBM PE_DEPT_NAME,
|
||||
TJZHXBM ITEM_ASSEM_CODE,
|
||||
TJZHXMC ITEM_ASSEM_NAME,
|
||||
TJZBXBM PE_ITEM_CODE,
|
||||
TJZBXMC PE_ITEM_NAME,
|
||||
TJZBZ PE_RESULT,
|
||||
TJZBDW UNIT,
|
||||
CONVERT(varchar(100),shsj,20) PE_QUEUE_DATE,
|
||||
CONVERT(varchar(100),shsj,20) AUDIT_DATE,
|
||||
CKFW PRINT_CONTEXT
|
||||
FROM
|
||||
V_TJBGJG
|
||||
WHERE
|
||||
TJH = #{peId}
|
||||
and TJZBXBM is not null
|
||||
</select>
|
||||
|
||||
<select id="getConclusion" resultType="java.util.Map">
|
||||
select TJH PE_ID,'' PE_VISIT_ID,
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(TJJL,CHAR(10),''), ' ', ''),char(9),''),char(13),'') CONCLUSION_TEXT
|
||||
from V_TJJY
|
||||
where TJH = #{peId}
|
||||
and TJJL is not null
|
||||
</select>
|
||||
<select id="getConclusionAll" resultType="java.util.Map">
|
||||
select TJH PE_ID,'' PE_VISIT_ID,
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(TJJL,CHAR(10),''), ' ', ''),char(9),''),char(13),'') CONCLUSION_TEXT
|
||||
from V_TJJY
|
||||
where TJH = #{peId}
|
||||
and TJJL is not null
|
||||
</select>
|
||||
<!--<select id="getTotalConclusion" resultType="java.util.HashMap">
|
||||
select wm_concat(PE_DEPT_NAME || ':' || REPLACE(REPLACE(REPLACE(to_lob(CONCLUSION_TEXT), chr(13) || chr(10), ''), chr(13), ''), chr(10), '') || '###') CONCLUSION_TEXT
|
||||
from V_PHYEXAM_DEPT_RESULT
|
||||
where PE_ID = #{peId}
|
||||
and CONCLUSION_TEXT is not null
|
||||
</select>-->
|
||||
|
||||
<select id="getSuggest" resultType="java.util.Map">
|
||||
select TJH PE_ID,'' PE_VISIT_ID,
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(TJJL,CHAR(10),''), ' ', ''),char(9),''),char(13),'') REC_CONTENT,
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(TJJY,CHAR(10),''), ' ', ''),char(9),''),char(13),'') GUIDE_CONTENT
|
||||
from V_TJJY
|
||||
where TJH = #{peId}
|
||||
and TJJL is not null
|
||||
</select>
|
||||
<select id="getSuggestAll" resultType="java.util.Map">
|
||||
select TJH PE_ID,'' PE_VISIT_ID,
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(TJJL,CHAR(10),''), ' ', ''),char(9),''),char(13),'') REC_CONTENT,
|
||||
REPLACE(REPLACE(REPLACE(REPLACE(TJJY,CHAR(10),''), ' ', ''),char(9),''),char(13),'') GUIDE_CONTENT
|
||||
from V_TJJY
|
||||
where TJH = #{peId}
|
||||
and TJJL is not null
|
||||
</select>
|
||||
<!--<select id="getTotalSuggest" resultType="java.util.HashMap">
|
||||
select wm_concat(REC_CONTENT || ':' || REPLACE(REPLACE(REPLACE(GUIDE_CONTENT, chr(13) || chr(10), ''), chr(13), ''), chr(10), '') || '###') GUIDE_CONTENT
|
||||
from V_PHYEXAM_DIAGNOSIS
|
||||
where PE_ID = #{peId}
|
||||
and GUIDE_CONTENT is not null
|
||||
</select>-->
|
||||
<select id="getPeStatusByIdnoAndYear" resultType="java.util.Map">
|
||||
SELECT
|
||||
t.tjh PE_ID,
|
||||
t.xm NAME,
|
||||
t.sfzh ID_NO,
|
||||
t.dwmc UNIT_NAME,
|
||||
t.dwbm DEPARTMENT,
|
||||
(CONVERT(varchar(100), t.yyrq, 20)) PE_PRE_DATE,
|
||||
(
|
||||
CASE t.status_sum
|
||||
WHEN 4 THEN N'终审'
|
||||
WHEN 3 THEN N'初审'
|
||||
WHEN 2 THEN N'检中'
|
||||
WHEN 1 THEN N'报道'
|
||||
WHEN 0 THEN N'预约'
|
||||
ELSE N'预约'
|
||||
END
|
||||
) PE_STATUS
|
||||
FROM
|
||||
( SELECT tjh, xm, sfzh, dwmc, dwbm, yyrq,
|
||||
( ISNULL(bdzt,0) + ISNULL(jczt,0) + ISNULL(cszt,0) + ISNULL(zszt,0) ) status_sum
|
||||
FROM V_YGTJZT ) t
|
||||
WHERE t.SFZH = #{idNo}
|
||||
AND t.yyrq >= CONVERT(DATETIME, #{year} + '-01-01')
|
||||
AND t.yyrq < DATEADD(YEAR, 1, CONVERT(DATETIME, #{year} + '-01-01'))
|
||||
</select>
|
||||
<select id="getResultByIdcardAndYear" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT
|
||||
SFZH ID_NO,
|
||||
XM NAME,
|
||||
TJH PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
'' UNIT_CODE,
|
||||
DWMC UNIT_NAME,
|
||||
CONVERT(varchar(100),max(shsj),20) PE_QUEUE_DATE,
|
||||
CONVERT(varchar(100),max(shsj),20) AUDIT_DATE
|
||||
FROM
|
||||
V_TJBGJG
|
||||
WHERE
|
||||
SFZH = #{ idNo }
|
||||
AND SHSJ >= CONVERT(DATETIME, #{year} + '-01-01')
|
||||
AND SHSJ < DATEADD(YEAR, 1, CONVERT(DATETIME, #{year} + '-01-01'))
|
||||
group by SFZH,XM,TJH,DWMC
|
||||
</select>
|
||||
<select id="getResultByIdcardAndYearAll" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT
|
||||
SFZH ID_NO,
|
||||
XM NAME,
|
||||
TJH PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
'' UNIT_CODE,
|
||||
DWMC UNIT_NAME,
|
||||
CONVERT(varchar(100),max(shsj),20) PE_QUEUE_DATE,
|
||||
CONVERT(varchar(100),max(shsj),20) AUDIT_DATE
|
||||
FROM
|
||||
V_TJBGJG
|
||||
WHERE
|
||||
SFZH = #{ idNo }
|
||||
AND SHSJ >= CONVERT(DATETIME, #{year} + '-01-01')
|
||||
AND SHSJ < DATEADD(YEAR, 1, CONVERT(DATETIME, #{year} + '-01-01'))
|
||||
group by SFZH,XM,TJH,DWMC
|
||||
</select>
|
||||
|
||||
<!--<select id="getResultByAuditDate" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
select *
|
||||
from V_PHYEXAM_RESULT
|
||||
where to_char(AUDIT_DATE,'yyyy-mm-dd')=#{auditDate}
|
||||
</select>-->
|
||||
|
||||
<select id="getDisResultByAuditDate" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT
|
||||
SFZH ID_NO,
|
||||
XM NAME,
|
||||
TJH PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
'' UNIT_CODE,
|
||||
DWMC UNIT_NAME,
|
||||
CONVERT(varchar(100),max(shsj),20) PE_QUEUE_DATE,
|
||||
CONVERT(varchar(100),max(shsj),20) AUDIT_DATE
|
||||
FROM
|
||||
V_TJBGJG
|
||||
WHERE
|
||||
shsj >= CONVERT(DATETIME, #{auditDate})
|
||||
AND shsj < DATEADD(DAY, 1, CONVERT(DATETIME, #{auditDate}))
|
||||
GROUP BY SFZH,XM,TJH,DWMC
|
||||
</select>
|
||||
|
||||
<select id="getItemByPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT DISTINCT
|
||||
TJZHXBM ITEM_ASSEM_CODE,
|
||||
TJZHXMC ITEM_ASSEM_NAME,
|
||||
TJZBXBM PE_ITEM_CODE,
|
||||
TJZBXMC PE_ITEM_NAME,
|
||||
TJZBZ PE_RESULT,
|
||||
TJZBDW UNIT,
|
||||
CKFW PRINT_CONTEXT
|
||||
FROM
|
||||
V_TJBGJG
|
||||
WHERE
|
||||
TJH = #{peId}
|
||||
and TJZBXBM is not null
|
||||
</select>
|
||||
<select id="getItemByPeIdAll" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT DISTINCT
|
||||
TJZHXBM ITEM_ASSEM_CODE,
|
||||
TJZHXMC ITEM_ASSEM_NAME,
|
||||
TJZBXBM PE_ITEM_CODE,
|
||||
TJZBXMC PE_ITEM_NAME,
|
||||
TJZBZ PE_RESULT,
|
||||
TJZBDW UNIT,
|
||||
CKFW PRINT_CONTEXT
|
||||
FROM
|
||||
V_TJBGJG
|
||||
WHERE
|
||||
TJH = #{peId}
|
||||
and TJZBXBM is not null
|
||||
</select>
|
||||
|
||||
<select id="getResultByIdNoOrPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT
|
||||
SFZH ID_NO,
|
||||
XM NAME,
|
||||
TJH PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
'' UNIT_CODE,
|
||||
DWMC UNIT_NAME,
|
||||
CONVERT(varchar(100),max(shsj),20) PE_QUEUE_DATE,
|
||||
CONVERT(varchar(100),max(shsj),20) AUDIT_DATE
|
||||
FROM
|
||||
V_TJBGJG
|
||||
<where>
|
||||
1=1
|
||||
<if test="idNo != null and idNo != '' ">
|
||||
and SFZH = #{idNo}
|
||||
</if>
|
||||
<if test="peId != null and peId != '' ">
|
||||
and TJH = #{peId}
|
||||
</if>
|
||||
|
||||
and shsj >= CONVERT(DATETIME, #{auditYear} + '-01-01')
|
||||
and shsj < DATEADD(YEAR, 1, CONVERT(DATETIME, #{auditYear} + '-01-01'))
|
||||
</where>
|
||||
GROUP BY SFZH,XM,TJH,DWMC
|
||||
</select>
|
||||
|
||||
<select id="getPeIdAndDateByIdcard" resultType="java.util.Map">
|
||||
SELECT
|
||||
tjh pe_id,
|
||||
CONVERT ( VARCHAR ( 100 ), JCWCSJ, 23 ) PE_PRE_DATE
|
||||
FROM
|
||||
V_YGYYTJZHX
|
||||
<where>
|
||||
<if test="idNo != null and idNo != '' ">
|
||||
and SFZH = #{idNo}
|
||||
</if>
|
||||
and JCWCSJ >= CONVERT(DATETIME, CONVERT(VARCHAR(4), GETDATE(), 23) + '-01-01')
|
||||
and JCWCSJ < DATEADD(YEAR, 1, CONVERT(DATETIME, CONVERT(VARCHAR(4), GETDATE(), 23) + '-01-01'))
|
||||
</where>
|
||||
order by JCWCSJ desc
|
||||
|
||||
</select>
|
||||
<select id="getResultByPeId" resultType="com.hospital.front.vo.MedicalMiddleResultVo">
|
||||
SELECT
|
||||
SFZH ID_NO,
|
||||
XM NAME,
|
||||
TJH PE_ID,
|
||||
'' PE_VISIT_ID,
|
||||
'' UNIT_CODE,
|
||||
DWMC UNIT_NAME,
|
||||
CONVERT(varchar(100),max(shsj),20) PE_QUEUE_DATE,
|
||||
CONVERT(varchar(100),max(shsj),20) AUDIT_DATE
|
||||
FROM
|
||||
V_TJBGJG
|
||||
WHERE
|
||||
TJH = #{peId}
|
||||
GROUP BY SFZH,XM,TJH,DWMC
|
||||
</select>
|
||||
|
||||
<select id="getPeIdAndDateByIdcardList" resultType="java.util.Map">
|
||||
SELECT
|
||||
distinct
|
||||
tjh PE_ID,
|
||||
CONVERT ( VARCHAR ( 100 ), JCWCSJ, 23 ) PE_PRE_DATE
|
||||
FROM
|
||||
V_YGYYTJZHX
|
||||
<where>
|
||||
<if test="idNo != null and idNo != '' ">
|
||||
and SFZH = #{idNo}
|
||||
</if>
|
||||
and JCWCSJ >= CONVERT(DATETIME, CONVERT(VARCHAR(4), GETDATE(), 23) + '-01-01')
|
||||
and JCWCSJ < DATEADD(YEAR, 1, CONVERT(DATETIME, CONVERT(VARCHAR(4), GETDATE(), 23) + '-01-01'))
|
||||
</where>
|
||||
|
||||
</select>
|
||||
<!-- 根据audit_date查询当天体检人员列表(去重) -->
|
||||
<select id="getExamListByDate" resultType="java.util.Map">
|
||||
SELECT DISTINCT TJH AS "peId",
|
||||
SFZH AS "idNo",
|
||||
XM AS "name",
|
||||
CONVERT(VARCHAR(10), shsj, 23) AS "auditDate"
|
||||
FROM V_TJBGJG
|
||||
<where>
|
||||
<choose>
|
||||
<when test="auditDate != null and auditDate != ''">
|
||||
CONVERT(VARCHAR(10), shsj, 23) = #{auditDate}
|
||||
</when>
|
||||
<otherwise>
|
||||
CONVERT(VARCHAR(10), shsj, 23) = CONVERT(VARCHAR(10), GETDATE(), 23)
|
||||
</otherwise>
|
||||
</choose>
|
||||
</where>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -30,7 +30,7 @@
|
||||
<totalSizeCap>5GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
|
||||
<pattern>%date [%thread] %-5level [%logger{50}] - %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<totalSizeCap>2GB</totalSizeCap>
|
||||
</rollingPolicy>
|
||||
<encoder>
|
||||
<pattern>%date [%thread] %-5level [%logger{50}] %file:%line - %msg%n</pattern>
|
||||
<pattern>%date [%thread] %-5level [%logger{50}] - %msg%n</pattern>
|
||||
</encoder>
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>ERROR</level>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
# 重新允许 TLSv1/TLSv1.1(仅本进程生效,为兼容老版 SQL Server 的登录加密)
|
||||
jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, \
|
||||
DH keySize < 1024, EC keySize < 224, 3DES_EDE_CBC, anon, NULL
|
||||
Reference in New Issue
Block a user