53 Commits

Author SHA1 Message Date
d7b3403524 Merge develop into test - sync latest code 2026-04-10 12:31:19 +08:00
Ranyunqiao
e9d4f57815 bug重新发布 2026-04-07 17:49:26 +08:00
e573d9f68b 新增校验,防止删除存在有效患者预约的医生排班。
更新 SurgeryDto,为计划手术时间添加 JSON 格式配置。

改进接诊确认逻辑,使医师确认流程更加健壮。

在 OrderMapper 中新增方法,用于统计患者在指定时间段内的有效预约订单数量。

增强 TicketServiceImpl,防止同一患者在相同科室与时间段内重复预约。
2026-04-07 17:37:53 +08:00
2584c8f076 340 预约管理-门诊预约挂号:选择患者弹窗列表数据字段显示错位 2026-04-07 16:37:09 +08:00
7b6c972a12 340 预约管理-门诊预约挂号:选择患者弹窗列表数据字段显示错位 2026-04-07 16:16:14 +08:00
Ranyunqiao
c3f1b105e9 301
预约管理-》门诊预约挂号:号源信息的序号未进行取值
316门诊医生站-》医嘱TAB页面:会诊医嘱状态从“已签发”变成“草稿”
317【门诊医生站】已签发会诊医嘱未同步至门诊收费系统生成待收费项目
344
门诊预约挂号:未过滤过期号源,允许预约已过时的时间段
347 医生门诊工作已就诊的病人提示未就诊
2026-04-07 15:36:27 +08:00
616c2d21a6 Merge remote-tracking branch 'origin/develop' into develop 2026-04-07 14:01:10 +08:00
63a9e26abf style(mapper): 统一SQL映射文件中的字段别名格式
- 在OutpatientRegistrationAppMapper.xml中将register_time别名添加引号
- 在DoctorStationMainAppMapper.xml中将register_time别名添加引号
- 在TencentAppMapper.xml中为两个register_time别名添加引号
- 确保所有字段别名使用一致的引号格式以避免解析错误
2026-04-07 14:01:00 +08:00
Ranyunqiao
d2dfc714ec 333 门诊医生站开立耗材医嘱时,类型误转为“中成药”且保存报错
341 门诊挂号报错
2026-04-07 10:33:04 +08:00
关羽
5c8bfbc98b Fix: #338 就诊状态校验缺失,#339 药房locationId筛选失效
1. Bug #338: 门诊划价时校验患者就诊状态,仅允许已接诊(1002/1003/1004)患者保存医嘱 2. Bug #339: 添加药房locationId过滤条件 3. 补充practitionerId和founderOrgId自动填充逻辑
2026-04-06 23:18:43 +08:00
关羽
885a147420 test: 关羽 Git 配置测试提交 2026-04-06 07:03:56 +08:00
赵云
afbf3f9075 chore: 添加bug修复进度文档 2026-04-06 07:00:46 +08:00
赵云
720cac8a8f fix: Bug#334 门诊医生站检验申请界面按钮布局优化
- 顶部操作区高度 60px -> 48px
- 按钮尺寸 large -> default
- padding/gap 优化提升垂直空间利用率

Co-Authored-By: 赵云 <zhaoyun@his.local>
2026-04-06 06:55:06 +08:00
5497c99f0c fix: BugFix#338 修复编译错误 - 更正字段名为 getStatusEnum()
- Encounter 类中字段名为 statusEnum 而非 encounterStatusEnum
- 修复 5 处编译错误
- 重新提交
2026-04-05 13:58:10 +08:00
HIS Dev
d8b4aed16c fix: BugFix#339 药房筛选条件失效 - 添加 locationId 过滤条件
- 在 getAdviceBaseInfo 方法中添加 locationId 过滤条件
- 修复药房筛选时返回所有药房数据的问题
- 添加日志记录便于调试
2026-04-05 13:53:03 +08:00
efc97c855c fix: BugFix#338 门诊划价新增时校验就诊状态(患者安全)
- 在保存/签发医嘱前校验就诊状态
- 未接诊患者禁止划价/保存医嘱
- 防止医疗差错和数据不一致

修复范围:
- DoctorStationAdviceAppServiceImpl.saveAdvice()
- 添加就诊状态校验逻辑
- 状态 1001(挂号) 禁止划价
- 状态 1002/1003/1004(已接诊/已收费/已完成) 允许划价
2026-04-05 13:15:28 +08:00
HuangXinQuan
0c5353cf8b 300,301,302预约挂号展示问题 2026-04-03 16:47:03 +08:00
Ranyunqiao
8a84b40ee5 333 门诊医生站开立耗材医嘱时,类型误转为“中成药”且保存报错 2026-04-03 16:42:10 +08:00
f6b39a4815 fix: 更新门诊定价服务以仅返回划价标记为“是”的项目,并修正日志路径和VitalSigns表名
- 修改 OutpatientPricingAppServiceImpl.java,确保仅返回划价标记为“是”的项目
- 修正 VitalSigns.java 中的表名为 "doc_vital_signs"
2026-04-03 16:35:21 +08:00
HuangXinQuan
1b3d4e3dc0 77 门诊挂号-》预约签到 2026-04-03 14:42:13 +08:00
his-dev
cb46461ede fix(#303): 将取消预约限制从取消操作移至预约挂号操作
问题:取消预约时检查次数限制,导致用户无法取消预约
修复:将取消次数限制检查移到预约挂号时进行

变更:
- bookTicket(): 添加取消次数限制检查,达到上限禁止预约
- cancelTicket(): 移除取消限制检查,允许正常取消

提示信息:"由于您在月度内累计取消预约已达X次,触发系统限制,暂时无法在线预约,请联系分诊台或咨询客服。"
2026-04-03 14:08:23 +08:00
3b0a359412 fix: 修复日期格式化函数,支持不带前导零的 M/D 格式
- 修改 formatDateStr 函数,添加对 M/ 和 /D 格式的支持
- 确保生成的日期格式与后端期望的 yyyy/M/d HH:mm:ss 格式匹配
2026-04-03 11:02:58 +08:00
6fa26e895d Merge remote-tracking branch 'origin/develop' into develop 2026-04-03 10:59:04 +08:00
8ab8691c17 fix: 修复禅道Bug #330 门诊医生站诊断保存失败问题
- 修改前端日期格式,从ISO格式改为 yyyy/M/d HH:mm:ss 格式
- 添加后端参数校验,防止NPE异常
- 优化前端错误提示,显示后端返回的具体错误信息
2026-04-03 10:58:23 +08:00
Ranyunqiao
35b8a7d10a 320 手术管理-》门诊手术安排:新增手术安排界面的就诊卡号取值错误 2026-04-03 10:45:19 +08:00
22de02f132 fix: 恢复 IChargeBillServiceImpl.java 中被意外删除的方法
- 恢复 getTotalCcu、getDaySumByTime、getTotalOut 等方法

- 修复编译错误
2026-04-03 09:37:06 +08:00
11244aa48f fix: 修复收费失败错误 'element cannot be mapped to a null key' - 根本原因
- 修复 PaymentRecStaticServiceImpl.java 第 49、52、55、58 行

- 添加对 ChargeItemDefInfo::getTypeCode 和 ChargeItemDefInfo::getYbType 的 null 过滤

- 修复 IChargeBillServiceImpl.java 第 657 行 Invoice::getReconciliationId
2026-04-03 08:32:04 +08:00
0a5f26e9c0 fix: 修复收费失败错误 'element cannot be mapped to a null key' - 补充修复
- 修复 PaymentRecServiceImpl.java 第 2472 行 groupingBy(Account::getId)

- 修复 PaymentRecServiceImpl.java 第 264 行 groupingBy(ChargeItem::getAccountId)

- 修复 IChargeBillServiceImpl.java 多处 groupingBy 可能遇到的 null key 问题
2026-04-02 18:44:06 +08:00
4a8e9b5a22 Merge branch 'develop' of https://gitea.gentronhealth.com/wangyizhe/his into develop 2026-04-02 18:22:35 +08:00
bfb2491842 fix: 修复收费失败错误 'element cannot be mapped to a null key'
- 在 PaymentRecServiceImpl.java 中添加过滤,排除 contractNo 为 null 的数据

- 在 IChargeBillServiceImpl.java 中添加过滤,排除 contractNo 为 null 的数据

- 防止 Java Stream groupingBy 操作时出现 null key 异常
2026-04-02 18:22:18 +08:00
wangjian963
b747f80507 feat(doctorstation): 检验申请单列表添加申请ID字段
- DTO添加applicationId(自增主键)字段
- Mapper返回类型从实体类改为DTO
- 前端表格显示申请ID替代行号
- 调整UI布局和分页器样式
2026-04-02 17:59:21 +08:00
ced931a280 Merge remote-tracking branch 'origin/develop' into develop 2026-04-02 17:54:31 +08:00
b497eb853c fix(surgery): 解决手术申请中的数据绑定和字段映射问题
- 修复了手术申请组件中 userStore 初始化问题,确保 applyDoctorName 和 applyDeptName 正确赋值
- 添加了 surgeryApplication 组件的 saved 事件发射,用于通知父组件刷新医嘱列表
- 修复了手术项目选择变更时 surgeryName 的正确设置和空值处理
- 添加了手术名称和编码的验证逻辑,防止提交时出现空值错误
- 修复了手术排班页面中就诊卡号字段的属性映射(visitId 改为 patientCardNo)
- 在后端 DTO 中添加了 patientCardNo 字段支持
- 修复了数据库查询中就诊卡号的关联查询逻辑,通过患者标识表获取正确的就诊卡号
- 优化了手术医嘱的 contentJson 设置,确保手术名称和编码正确存储
2026-04-02 17:54:07 +08:00
7a2342ea2e 311 检验项目设置-》检验项目:【新增】一条检验项目系统自动在《诊疗目录》增加一条检验收费项目
312检验项目设置-套餐设置:折扣%字段换算公式错误
319 住院管理》-住院医生站》-住院医生站保存患者诊断时报错
2026-04-02 17:25:28 +08:00
Ranyunqiao
09fdfa294a 重新发布 2026-04-02 15:31:56 +08:00
Ranyunqiao
4ef9aa07d2 91 分诊排队管理-》门诊医生站:【完诊】患者队列状态的变化 2026-04-02 15:23:42 +08:00
08085403b3 Merge remote-tracking branch 'origin/develop' into develop 2026-04-02 08:46:09 +08:00
2d7dcb4aeb fix(inpatient): 解决手术申请单数据同步和命名问题
- 在应用表单底部按钮中添加延迟刷新机制,确保后端数据提交完成后再触发刷新事件
- 在手术组件中添加诊疗定义名称字段,完善手术项目信息传递
- 优化手术医嘱生成功能,添加详细的调试日志以便追踪问题
- 修复手术项目名称获取逻辑,优先使用activityList中的手术项目名称
- 完善手术收费项目生成流程,添加异常处理和日志记录
- 在控制器中添加手术申请单保存的日志输出,便于问题排查
2026-04-02 08:15:11 +08:00
ad29502488 Fix: 帮助文档打包失败v2 2026-04-01 18:56:51 +08:00
5b0acede89 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	openhis-ui-vue3/src/views/clinicmanagement/bargain/component/prescriptionlist.vue
2026-04-01 18:27:31 +08:00
ac1cd3afc8 fix(prescription): 解决处方列表中手术类型和其他医嘱类型的问题
- 更新 lodash.template 修复脚本以处理 assignWith 函数的自定义器参数
- 在多个处方组件中引入 drord_doctor_type 字典用于动态生成医嘱类型列表
- 修复手术类型(adviceType=6)的特殊处理逻辑,包括类型映射和字段过滤
- 调整后端医嘱保存服务中的类型分类逻辑,正确处理手术类型
- 更新数据库查询映射以支持手术类型的正确显示和数据传输
- 修复费用对话框和订单表单中的相关类型显示问题
2026-04-01 18:24:24 +08:00
6694ae52ba feat: 手术申请列表-手术单号移到申请日期之前(第一栏) 2026-04-01 14:00:58 +08:00
9491ceaa5d feat: 手术申请列表-手术单号支持点击查看详情 2026-04-01 13:36:44 +08:00
db9a70a99d feat: 手术申请列表-手术单号放第二栏并支持点击查看详情 2026-04-01 13:28:24 +08:00
b1d6c6008e fix: doctorstation手术医嘱advice_type使用category_enum,advice_name支持surgeryName 2026-04-01 12:57:52 +08:00
6b9f9a107e fix: 手术医嘱类型显示修复 - SQL返回category_enum作为advice_type,前端添加手术类型选项 2026-04-01 12:45:15 +08:00
11a7f49162 fix: 手术医嘱therapy_enum默认为2(临时医嘱),避免被前端过滤 2026-04-01 12:16:36 +08:00
b4e5061b73 Merge remote-tracking branch 'origin/develop' into develop 2026-04-01 11:56:27 +08:00
f5a1ad7f3f fix: 手术医嘱advice_name从content_json解析surgeryName 2026-04-01 11:36:50 +08:00
eeac88b1d1 fix: Bug #318 历史数据修复脚本(Python+SQL) 2026-04-01 10:48:44 +08:00
9f619ccdd4 fix: Bug #318 历史数据修复SQL脚本 2026-04-01 10:28:45 +08:00
700e353b79 测试合并v4 2026-01-15 16:42:56 +08:00
0b2c19d2c5 测试合并v3 2026-01-15 15:54:22 +08:00
188 changed files with 18990 additions and 9509 deletions

View File

@@ -0,0 +1,23 @@
- generic [ref=e5]:
- generic [ref=e6]:
- img [ref=e7]
- img [ref=e8]
- generic [ref=e9]:
- generic [ref=e10]:
- heading "经创贺联项目管理系统" [level=2] [ref=e11]
- generic [ref=e12]: 简体
- generic [ref=e13]:
- generic [ref=e14]:
- generic [ref=e16]: 用户名
- textbox [active] [ref=e17]
- generic [ref=e18]:
- generic [ref=e20]: 密码
- textbox [ref=e21]
- generic [ref=e22]:
- generic [ref=e24]:
- checkbox "保持登录" [ref=e25]
- generic [ref=e26] [cursor=pointer]: 保持登录
- link "忘记密码" [ref=e27] [cursor=pointer]:
- /url: /index.php?m=user&f=reset
- button "登录" [ref=e29] [cursor=pointer]:
- generic [ref=e30]: 登录

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,93 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

View File

@@ -0,0 +1,93 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,93 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,314 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- iframe [ref=e66]:
- generic [active] [ref=f11e1]:
- banner [ref=f11e2]:
- generic [ref=f11e3]:
- generic [ref=f11e4]:
- link " 测试" [ref=f11e6] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f11e7]:
- generic [ref=f11e8]: 测试
- button " 开源HIS改造落地" [ref=f11e10] [cursor=pointer]:
- generic [ref=f11e11]:
- generic "开源HIS改造落地" [ref=f11e12]
- navigation [ref=f11e15]:
- list [ref=f11e16]:
- listitem [ref=f11e17]:
- link "仪表盘" [ref=f11e18] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f11e19]: 仪表盘
- listitem [ref=f11e20]
- listitem [ref=f11e21]:
- link "Bug" [ref=f11e22] [cursor=pointer]:
- /url: /index.php?m=bug&f=browse&productID=4
- generic [ref=f11e23]: Bug
- listitem [ref=f11e24]:
- link "用例" [ref=f11e25] [cursor=pointer]:
- /url: /index.php?m=testcase&f=browse&productID=4
- generic [ref=f11e26]: 用例
- listitem [ref=f11e27]:
- link "套件" [ref=f11e28] [cursor=pointer]:
- /url: /index.php?m=testsuite&f=browse&productID=4
- generic [ref=f11e29]: 套件
- listitem [ref=f11e30]
- listitem [ref=f11e31]:
- link "测试单" [ref=f11e32] [cursor=pointer]:
- /url: /index.php?m=testtask&f=browse&productID=4
- generic [ref=f11e33]: 测试单
- listitem [ref=f11e34]:
- link "测试报告" [ref=f11e35] [cursor=pointer]:
- /url: /index.php?m=testreport&f=browse&productID=4
- generic [ref=f11e36]: 测试报告
- listitem [ref=f11e37]
- listitem [ref=f11e38]:
- link "用例库" [ref=f11e39] [cursor=pointer]:
- /url: /index.php?m=caselib&f=browse&libID=0
- generic [ref=f11e40]: 用例库
- listitem [ref=f11e41]
- listitem [ref=f11e42]:
- link "自动化" [ref=f11e43] [cursor=pointer]:
- /url: /index.php?m=zanode&f=instruction
- generic [ref=f11e44]: 自动化
- generic [ref=f11e46]:
- button "" [ref=f11e47] [cursor=pointer]:
- generic [ref=f11e48]:
- button " 9" [ref=f11e49] [cursor=pointer]:
- generic [ref=f11e50]:
- generic [ref=f11e51]: "9"
- generic [ref=f11e54] [cursor=pointer]: A
- generic [ref=f11e57]:
- generic [ref=f11e58]:
- generic [ref=f11e59]:
- button " 返回" [ref=f11e60] [cursor=pointer]:
- generic [ref=f11e61]:
- generic [ref=f11e62]: 返回
- generic [ref=f11e63]:
- generic [ref=f11e64]: "306"
- generic [ref=f11e65]: 手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单
- link " 提Bug" [ref=f11e68] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extras=projectID=11,executionID=0,moduleID=126
- generic [ref=f11e69]:
- generic [ref=f11e70]: 提Bug
- generic [ref=f11e71]:
- generic [ref=f11e72]:
- generic [ref=f11e74]:
- generic [ref=f11e76]: 重现步骤
- generic [ref=f11e78]:
- paragraph [ref=f11e79]: "[步骤]"
- paragraph [ref=f11e80]:
- link "index.php?m=file&f=read&t=png&fileID=1415" [ref=f11e81] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1415
- img "index.php?m=file&f=read&t=png&fileID=1415" [ref=f11e82]
- paragraph [ref=f11e83]: 图1
- paragraph [ref=f11e84]: 1、如上图1所示手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单。
- paragraph [ref=f11e85]: "[结果]"
- paragraph [ref=f11e86]: 1、手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单。
- paragraph [ref=f11e87]: "[期望]"
- paragraph [ref=f11e88]: 1、手术管理-》门诊手术安排:手术申请查询过滤掉已安排的手术申请单。
- generic [ref=f11e90]:
- generic [ref=f11e94]:
- generic [ref=f11e95]: 历史记录
- navigation [ref=f11e96]:
- button "" [ref=f11e97] [cursor=pointer]:
- generic [ref=f11e98]:
- button " 添加备注" [ref=f11e99] [cursor=pointer]:
- generic [ref=f11e100]:
- generic [ref=f11e101]: 添加备注
- list [ref=f11e103]:
- listitem [ref=f11e104]:
- generic [ref=f11e105]:
- generic [ref=f11e107]: "1"
- generic [ref=f11e110]:
- text: 2026-03-30 17:01:33,
- strong [ref=f11e111]: 陈显精
- text: 创建。
- listitem [ref=f11e112]:
- generic [ref=f11e113]:
- generic [ref=f11e115]: "2"
- generic [ref=f11e118]:
- text: 2026-03-30 17:01:45,
- strong [ref=f11e119]: 陈显精
- text: 指派给
- strong [ref=f11e120]: 王怡哲
- text:
- generic [ref=f11e123]:
- button " 返回" [ref=f11e124] [cursor=pointer]:
- generic [ref=f11e125]:
- generic [ref=f11e126]: 返回
- link " 确认" [ref=f11e128] [cursor=pointer]:
- /url: /index.php?m=bug&f=confirm&bugID=306
- generic [ref=f11e129]:
- generic [ref=f11e130]: 确认
- link " 指派" [ref=f11e131] [cursor=pointer]:
- /url: /index.php?m=bug&f=assignTo&bugID=306
- generic [ref=f11e132]:
- generic [ref=f11e133]: 指派
- link " 解决" [ref=f11e134] [cursor=pointer]:
- /url: /index.php?m=bug&f=resolve&bugID=306
- generic [ref=f11e135]:
- generic [ref=f11e136]: 解决
- button " 转研发需求" [ref=f11e137] [cursor=pointer]:
- generic [ref=f11e138]:
- generic [ref=f11e139]: 转研发需求
- button " 转任务" [ref=f11e140] [cursor=pointer]:
- generic [ref=f11e141]:
- generic [ref=f11e142]: 转任务
- link " 创建用例" [ref=f11e143] [cursor=pointer]:
- /url: /index.php?m=testcase&f=create&productID=4&branch=0&moduleID=0&from=bug&bugID=306
- generic [ref=f11e144]:
- generic [ref=f11e145]: 创建用例
- link "" [ref=f11e147] [cursor=pointer]:
- /url: /index.php?m=bug&f=edit&bugID=306
- generic [ref=f11e148]:
- link "" [ref=f11e149] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extra=bugID=306,projectID=11,executionID=0
- generic [ref=f11e150]:
- link "" [ref=f11e151] [cursor=pointer]:
- /url: /index.php?m=bug&f=delete&bugID=306
- generic [ref=f11e152]:
- generic [ref=f11e153]:
- generic [ref=f11e154]:
- generic [ref=f11e155]:
- list [ref=f11e156]:
- listitem [ref=f11e157]:
- link "基本信息" [ref=f11e158] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane"
- generic [ref=f11e159]: 基本信息
- listitem [ref=f11e160]:
- link "Bug的一生" [ref=f11e161] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_1"
- generic [ref=f11e162]: Bug的一生
- button "" [ref=f11e163] [cursor=pointer]:
- generic [ref=f11e164]:
- generic [ref=f11e167]:
- generic [ref=f11e168]:
- generic "所属模块" [ref=f11e169]
- list [ref=f11e171]:
- listitem [ref=f11e172]: 手术麻醉管理
- generic "所属计划" [ref=f11e174]
- generic "来源用例" [ref=f11e177]
- generic [ref=f11e179]:
- generic "Bug类型" [ref=f11e180]
- generic [ref=f11e181]: 代码错误
- generic [ref=f11e182]:
- generic "严重程度" [ref=f11e183]
- generic [ref=f11e185]: 3 3
- generic [ref=f11e186]:
- generic "优先级" [ref=f11e187]
- generic [ref=f11e189]: "3"
- generic [ref=f11e190]:
- generic "Bug状态" [ref=f11e191]
- generic [ref=f11e193]: 激活
- generic "激活次数" [ref=f11e195]
- generic "激活时间" [ref=f11e198]
- generic [ref=f11e200]:
- generic "是否确认" [ref=f11e201]
- generic [ref=f11e202]: 未确认
- generic [ref=f11e203]:
- generic "指派给" [ref=f11e204]
- generic [ref=f11e205]: 王怡哲 于 2026-03-30 17:01:31
- generic "截止日期" [ref=f11e207]
- generic "反馈者" [ref=f11e210]
- generic "通知邮箱" [ref=f11e213]
- generic "操作系统" [ref=f11e216]
- generic "浏览器" [ref=f11e219]
- generic "关键词" [ref=f11e222]
- generic "抄送给" [ref=f11e225]
- generic [ref=f11e227]:
- generic [ref=f11e228]:
- list [ref=f11e229]:
- listitem [ref=f11e230]:
- link "项目/迭代/研发需求/任务" [ref=f11e231] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_2"
- generic [ref=f11e232]: 项目/迭代/研发需求/任务
- listitem [ref=f11e233]:
- link "其他相关" [ref=f11e234] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_3"
- generic [ref=f11e235]: 其他相关
- button "" [ref=f11e236] [cursor=pointer]:
- generic [ref=f11e237]:
- generic [ref=f11e240]:
- generic [ref=f11e241]:
- generic "所属项目" [ref=f11e242]
- link "开源HIS改造落地" [ref=f11e244] [cursor=pointer]:
- /url: /index.php?m=project&f=view&projectID=11
- generic "所属执行" [ref=f11e246]
- generic "相关需求" [ref=f11e249]
- generic "相关任务" [ref=f11e252]
- button "" [ref=f11e255] [cursor=pointer]:
- generic [ref=f11e256]:
- text: "* *"
- generic [ref=e67]:
- button " 研发综合界面" [ref=e69] [cursor=pointer]:
- generic [ref=e70]:
- generic [ref=e71]: 研发综合界面
- list [ref=e73]:
- listitem [ref=e74]:
- generic [ref=e76] [cursor=pointer]: 测试
- generic [ref=e77]:
- textbox [ref=e83]:
- /placeholder: 搜索
- button [ref=e85] [cursor=pointer]:
- img [ref=e87]
- link " 开源版21.7" [ref=e88] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e89]:
- generic [ref=e90]: 开源版21.7
- button "升级 " [ref=e91] [cursor=pointer]:
- generic [ref=e92]: 升级
- generic [ref=e93]:

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,93 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

View File

@@ -0,0 +1,322 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- iframe [ref=e89]:
- generic [active] [ref=f19e1]:
- banner [ref=f19e2]:
- generic [ref=f19e3]:
- generic [ref=f19e4]:
- link " 测试" [ref=f19e6] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f19e7]:
- generic [ref=f19e8]: 测试
- button " 开源HIS改造落地" [ref=f19e10] [cursor=pointer]:
- generic [ref=f19e11]:
- generic "开源HIS改造落地" [ref=f19e12]
- navigation [ref=f19e15]:
- list [ref=f19e16]:
- listitem [ref=f19e17]:
- link "仪表盘" [ref=f19e18] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f19e19]: 仪表盘
- listitem [ref=f19e20]
- listitem [ref=f19e21]:
- link "Bug" [ref=f19e22] [cursor=pointer]:
- /url: /index.php?m=bug&f=browse&productID=4
- generic [ref=f19e23]: Bug
- listitem [ref=f19e24]:
- link "用例" [ref=f19e25] [cursor=pointer]:
- /url: /index.php?m=testcase&f=browse&productID=4
- generic [ref=f19e26]: 用例
- listitem [ref=f19e27]:
- link "套件" [ref=f19e28] [cursor=pointer]:
- /url: /index.php?m=testsuite&f=browse&productID=4
- generic [ref=f19e29]: 套件
- listitem [ref=f19e30]
- listitem [ref=f19e31]:
- link "测试单" [ref=f19e32] [cursor=pointer]:
- /url: /index.php?m=testtask&f=browse&productID=4
- generic [ref=f19e33]: 测试单
- listitem [ref=f19e34]:
- link "测试报告" [ref=f19e35] [cursor=pointer]:
- /url: /index.php?m=testreport&f=browse&productID=4
- generic [ref=f19e36]: 测试报告
- listitem [ref=f19e37]
- listitem [ref=f19e38]:
- link "用例库" [ref=f19e39] [cursor=pointer]:
- /url: /index.php?m=caselib&f=browse&libID=0
- generic [ref=f19e40]: 用例库
- listitem [ref=f19e41]
- listitem [ref=f19e42]:
- link "自动化" [ref=f19e43] [cursor=pointer]:
- /url: /index.php?m=zanode&f=instruction
- generic [ref=f19e44]: 自动化
- generic [ref=f19e46]:
- button "" [ref=f19e47] [cursor=pointer]:
- generic [ref=f19e48]:
- button " 9" [ref=f19e49] [cursor=pointer]:
- generic [ref=f19e50]:
- generic [ref=f19e51]: "9"
- generic [ref=f19e54] [cursor=pointer]: A
- generic [ref=f19e57]:
- generic [ref=f19e58]:
- generic [ref=f19e59]:
- button " 返回" [ref=f19e60] [cursor=pointer]:
- generic [ref=f19e61]:
- generic [ref=f19e62]: 返回
- generic [ref=f19e63]:
- generic [ref=f19e64]: "306"
- generic [ref=f19e65]: 手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单
- link " 提Bug" [ref=f19e68] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extras=projectID=11,executionID=0,moduleID=126
- generic [ref=f19e69]:
- generic [ref=f19e70]: 提Bug
- generic [ref=f19e71]:
- generic [ref=f19e72]:
- generic [ref=f19e74]:
- generic [ref=f19e76]: 重现步骤
- generic [ref=f19e78]:
- paragraph [ref=f19e79]: "[步骤]"
- paragraph [ref=f19e80]:
- link "index.php?m=file&f=read&t=png&fileID=1415" [ref=f19e81] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1415
- img "index.php?m=file&f=read&t=png&fileID=1415" [ref=f19e82]
- paragraph [ref=f19e83]: 图1
- paragraph [ref=f19e84]: 1、如上图1所示手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单。
- paragraph [ref=f19e85]: "[结果]"
- paragraph [ref=f19e86]: 1、手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单。
- paragraph [ref=f19e87]: "[期望]"
- paragraph [ref=f19e88]: 1、手术管理-》门诊手术安排:手术申请查询过滤掉已安排的手术申请单。
- generic [ref=f19e90]:
- generic [ref=f19e94]:
- generic [ref=f19e95]: 历史记录
- navigation [ref=f19e96]:
- button "" [ref=f19e97] [cursor=pointer]:
- generic [ref=f19e98]:
- button " 添加备注" [ref=f19e99] [cursor=pointer]:
- generic [ref=f19e100]:
- generic [ref=f19e101]: 添加备注
- list [ref=f19e103]:
- listitem [ref=f19e104]:
- generic [ref=f19e105]:
- generic [ref=f19e107]: "1"
- generic [ref=f19e110]:
- text: 2026-03-30 17:01:33,
- strong [ref=f19e111]: 陈显精
- text: 创建。
- listitem [ref=f19e112]:
- generic [ref=f19e113]:
- generic [ref=f19e115]: "2"
- generic [ref=f19e118]:
- text: 2026-03-30 17:01:45,
- strong [ref=f19e119]: 陈显精
- text: 指派给
- strong [ref=f19e120]: 王怡哲
- text:
- generic [ref=f19e123]:
- button " 返回" [ref=f19e124] [cursor=pointer]:
- generic [ref=f19e125]:
- generic [ref=f19e126]: 返回
- link " 确认" [ref=f19e128] [cursor=pointer]:
- /url: /index.php?m=bug&f=confirm&bugID=306
- generic [ref=f19e129]:
- generic [ref=f19e130]: 确认
- link " 指派" [ref=f19e131] [cursor=pointer]:
- /url: /index.php?m=bug&f=assignTo&bugID=306
- generic [ref=f19e132]:
- generic [ref=f19e133]: 指派
- link " 解决" [ref=f19e134] [cursor=pointer]:
- /url: /index.php?m=bug&f=resolve&bugID=306
- generic [ref=f19e135]:
- generic [ref=f19e136]: 解决
- button " 转研发需求" [ref=f19e137] [cursor=pointer]:
- generic [ref=f19e138]:
- generic [ref=f19e139]: 转研发需求
- button " 转任务" [ref=f19e140] [cursor=pointer]:
- generic [ref=f19e141]:
- generic [ref=f19e142]: 转任务
- link " 创建用例" [ref=f19e143] [cursor=pointer]:
- /url: /index.php?m=testcase&f=create&productID=4&branch=0&moduleID=0&from=bug&bugID=306
- generic [ref=f19e144]:
- generic [ref=f19e145]: 创建用例
- link "" [ref=f19e147] [cursor=pointer]:
- /url: /index.php?m=bug&f=edit&bugID=306
- generic [ref=f19e148]:
- link "" [ref=f19e149] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extra=bugID=306,projectID=11,executionID=0
- generic [ref=f19e150]:
- link "" [ref=f19e151] [cursor=pointer]:
- /url: /index.php?m=bug&f=delete&bugID=306
- generic [ref=f19e152]:
- generic [ref=f19e153]:
- generic [ref=f19e154]:
- generic [ref=f19e155]:
- list [ref=f19e156]:
- listitem [ref=f19e157]:
- link "基本信息" [ref=f19e158] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane"
- generic [ref=f19e159]: 基本信息
- listitem [ref=f19e160]:
- link "Bug的一生" [ref=f19e161] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_1"
- generic [ref=f19e162]: Bug的一生
- button "" [ref=f19e163] [cursor=pointer]:
- generic [ref=f19e164]:
- generic [ref=f19e167]:
- generic [ref=f19e168]:
- generic "所属模块" [ref=f19e169]
- list [ref=f19e171]:
- listitem [ref=f19e172]: 手术麻醉管理
- generic "所属计划" [ref=f19e174]
- generic "来源用例" [ref=f19e177]
- generic [ref=f19e179]:
- generic "Bug类型" [ref=f19e180]
- generic [ref=f19e181]: 代码错误
- generic [ref=f19e182]:
- generic "严重程度" [ref=f19e183]
- generic [ref=f19e185]: 3 3
- generic [ref=f19e186]:
- generic "优先级" [ref=f19e187]
- generic [ref=f19e189]: "3"
- generic [ref=f19e190]:
- generic "Bug状态" [ref=f19e191]
- generic [ref=f19e193]: 激活
- generic "激活次数" [ref=f19e195]
- generic "激活时间" [ref=f19e198]
- generic [ref=f19e200]:
- generic "是否确认" [ref=f19e201]
- generic [ref=f19e202]: 未确认
- generic [ref=f19e203]:
- generic "指派给" [ref=f19e204]
- generic [ref=f19e205]: 王怡哲 于 2026-03-30 17:01:31
- generic "截止日期" [ref=f19e207]
- generic "反馈者" [ref=f19e210]
- generic "通知邮箱" [ref=f19e213]
- generic "操作系统" [ref=f19e216]
- generic "浏览器" [ref=f19e219]
- generic "关键词" [ref=f19e222]
- generic "抄送给" [ref=f19e225]
- generic [ref=f19e227]:
- generic [ref=f19e228]:
- list [ref=f19e229]:
- listitem [ref=f19e230]:
- link "项目/迭代/研发需求/任务" [ref=f19e231] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_2"
- generic [ref=f19e232]: 项目/迭代/研发需求/任务
- listitem [ref=f19e233]:
- link "其他相关" [ref=f19e234] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_3"
- generic [ref=f19e235]: 其他相关
- button "" [ref=f19e236] [cursor=pointer]:
- generic [ref=f19e237]:
- generic [ref=f19e240]:
- generic [ref=f19e241]:
- generic "所属项目" [ref=f19e242]
- link "开源HIS改造落地" [ref=f19e244] [cursor=pointer]:
- /url: /index.php?m=project&f=view&projectID=11
- generic "所属执行" [ref=f19e246]
- generic "相关需求" [ref=f19e249]
- generic "相关任务" [ref=f19e252]
- button "" [ref=f19e255] [cursor=pointer]:
- generic [ref=f19e256]:
- generic:
- generic:
- link "" [ref=f19e257] [cursor=pointer]:
- /url: /index.php?m=bug&f=view&bugID=307
- generic [ref=f19e258]:
- link "" [ref=f19e259] [cursor=pointer]:
- /url: /index.php?m=bug&f=view&bugID=305
- generic [ref=f19e260]:
- text: "* *"
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list [ref=e90]:
- listitem [ref=e91]:
- generic [ref=e93] [cursor=pointer]: 测试
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

View File

@@ -0,0 +1,91 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,322 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- iframe [ref=e83]:
- generic [active] [ref=f20e1]:
- banner [ref=f20e2]:
- generic [ref=f20e3]:
- generic [ref=f20e4]:
- link " 测试" [ref=f20e6] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f20e7]:
- generic [ref=f20e8]: 测试
- button " 开源HIS改造落地" [ref=f20e10] [cursor=pointer]:
- generic [ref=f20e11]:
- generic "开源HIS改造落地" [ref=f20e12]
- navigation [ref=f20e15]:
- list [ref=f20e16]:
- listitem [ref=f20e17]:
- link "仪表盘" [ref=f20e18] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f20e19]: 仪表盘
- listitem [ref=f20e20]
- listitem [ref=f20e21]:
- link "Bug" [ref=f20e22] [cursor=pointer]:
- /url: /index.php?m=bug&f=browse&productID=4
- generic [ref=f20e23]: Bug
- listitem [ref=f20e24]:
- link "用例" [ref=f20e25] [cursor=pointer]:
- /url: /index.php?m=testcase&f=browse&productID=4
- generic [ref=f20e26]: 用例
- listitem [ref=f20e27]:
- link "套件" [ref=f20e28] [cursor=pointer]:
- /url: /index.php?m=testsuite&f=browse&productID=4
- generic [ref=f20e29]: 套件
- listitem [ref=f20e30]
- listitem [ref=f20e31]:
- link "测试单" [ref=f20e32] [cursor=pointer]:
- /url: /index.php?m=testtask&f=browse&productID=4
- generic [ref=f20e33]: 测试单
- listitem [ref=f20e34]:
- link "测试报告" [ref=f20e35] [cursor=pointer]:
- /url: /index.php?m=testreport&f=browse&productID=4
- generic [ref=f20e36]: 测试报告
- listitem [ref=f20e37]
- listitem [ref=f20e38]:
- link "用例库" [ref=f20e39] [cursor=pointer]:
- /url: /index.php?m=caselib&f=browse&libID=0
- generic [ref=f20e40]: 用例库
- listitem [ref=f20e41]
- listitem [ref=f20e42]:
- link "自动化" [ref=f20e43] [cursor=pointer]:
- /url: /index.php?m=zanode&f=instruction
- generic [ref=f20e44]: 自动化
- generic [ref=f20e46]:
- button "" [ref=f20e47] [cursor=pointer]:
- generic [ref=f20e48]:
- button " 9" [ref=f20e49] [cursor=pointer]:
- generic [ref=f20e50]:
- generic [ref=f20e51]: "9"
- generic [ref=f20e54] [cursor=pointer]: A
- generic [ref=f20e57]:
- generic [ref=f20e58]:
- generic [ref=f20e59]:
- button " 返回" [ref=f20e60] [cursor=pointer]:
- generic [ref=f20e61]:
- generic [ref=f20e62]: 返回
- generic [ref=f20e63]:
- generic [ref=f20e64]: "306"
- generic [ref=f20e65]: 手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单
- link " 提Bug" [ref=f20e68] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extras=projectID=11,executionID=0,moduleID=126
- generic [ref=f20e69]:
- generic [ref=f20e70]: 提Bug
- generic [ref=f20e71]:
- generic [ref=f20e72]:
- generic [ref=f20e74]:
- generic [ref=f20e76]: 重现步骤
- generic [ref=f20e78]:
- paragraph [ref=f20e79]: "[步骤]"
- paragraph [ref=f20e80]:
- link "index.php?m=file&f=read&t=png&fileID=1415" [ref=f20e81] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1415
- img "index.php?m=file&f=read&t=png&fileID=1415" [ref=f20e82]
- paragraph [ref=f20e83]: 图1
- paragraph [ref=f20e84]: 1、如上图1所示手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单。
- paragraph [ref=f20e85]: "[结果]"
- paragraph [ref=f20e86]: 1、手术管理-》门诊手术安排:手术申请查询未过滤掉已安排的手术申请单。
- paragraph [ref=f20e87]: "[期望]"
- paragraph [ref=f20e88]: 1、手术管理-》门诊手术安排:手术申请查询过滤掉已安排的手术申请单。
- generic [ref=f20e90]:
- generic [ref=f20e94]:
- generic [ref=f20e95]: 历史记录
- navigation [ref=f20e96]:
- button "" [ref=f20e97] [cursor=pointer]:
- generic [ref=f20e98]:
- button " 添加备注" [ref=f20e99] [cursor=pointer]:
- generic [ref=f20e100]:
- generic [ref=f20e101]: 添加备注
- list [ref=f20e103]:
- listitem [ref=f20e104]:
- generic [ref=f20e105]:
- generic [ref=f20e107]: "1"
- generic [ref=f20e110]:
- text: 2026-03-30 17:01:33,
- strong [ref=f20e111]: 陈显精
- text: 创建。
- listitem [ref=f20e112]:
- generic [ref=f20e113]:
- generic [ref=f20e115]: "2"
- generic [ref=f20e118]:
- text: 2026-03-30 17:01:45,
- strong [ref=f20e119]: 陈显精
- text: 指派给
- strong [ref=f20e120]: 王怡哲
- text:
- generic [ref=f20e123]:
- button " 返回" [ref=f20e124] [cursor=pointer]:
- generic [ref=f20e125]:
- generic [ref=f20e126]: 返回
- link " 确认" [ref=f20e128] [cursor=pointer]:
- /url: /index.php?m=bug&f=confirm&bugID=306
- generic [ref=f20e129]:
- generic [ref=f20e130]: 确认
- link " 指派" [ref=f20e131] [cursor=pointer]:
- /url: /index.php?m=bug&f=assignTo&bugID=306
- generic [ref=f20e132]:
- generic [ref=f20e133]: 指派
- link " 解决" [ref=f20e134] [cursor=pointer]:
- /url: /index.php?m=bug&f=resolve&bugID=306
- generic [ref=f20e135]:
- generic [ref=f20e136]: 解决
- button " 转研发需求" [ref=f20e137] [cursor=pointer]:
- generic [ref=f20e138]:
- generic [ref=f20e139]: 转研发需求
- button " 转任务" [ref=f20e140] [cursor=pointer]:
- generic [ref=f20e141]:
- generic [ref=f20e142]: 转任务
- link " 创建用例" [ref=f20e143] [cursor=pointer]:
- /url: /index.php?m=testcase&f=create&productID=4&branch=0&moduleID=0&from=bug&bugID=306
- generic [ref=f20e144]:
- generic [ref=f20e145]: 创建用例
- link "" [ref=f20e147] [cursor=pointer]:
- /url: /index.php?m=bug&f=edit&bugID=306
- generic [ref=f20e148]:
- link "" [ref=f20e149] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extra=bugID=306,projectID=11,executionID=0
- generic [ref=f20e150]:
- link "" [ref=f20e151] [cursor=pointer]:
- /url: /index.php?m=bug&f=delete&bugID=306
- generic [ref=f20e152]:
- generic [ref=f20e153]:
- generic [ref=f20e154]:
- generic [ref=f20e155]:
- list [ref=f20e156]:
- listitem [ref=f20e157]:
- link "基本信息" [ref=f20e158] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane"
- generic [ref=f20e159]: 基本信息
- listitem [ref=f20e160]:
- link "Bug的一生" [ref=f20e161] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_1"
- generic [ref=f20e162]: Bug的一生
- button "" [ref=f20e163] [cursor=pointer]:
- generic [ref=f20e164]:
- generic [ref=f20e167]:
- generic [ref=f20e168]:
- generic "所属模块" [ref=f20e169]
- list [ref=f20e171]:
- listitem [ref=f20e172]: 手术麻醉管理
- generic "所属计划" [ref=f20e174]
- generic "来源用例" [ref=f20e177]
- generic [ref=f20e179]:
- generic "Bug类型" [ref=f20e180]
- generic [ref=f20e181]: 代码错误
- generic [ref=f20e182]:
- generic "严重程度" [ref=f20e183]
- generic [ref=f20e185]: 3 3
- generic [ref=f20e186]:
- generic "优先级" [ref=f20e187]
- generic [ref=f20e189]: "3"
- generic [ref=f20e190]:
- generic "Bug状态" [ref=f20e191]
- generic [ref=f20e193]: 激活
- generic "激活次数" [ref=f20e195]
- generic "激活时间" [ref=f20e198]
- generic [ref=f20e200]:
- generic "是否确认" [ref=f20e201]
- generic [ref=f20e202]: 未确认
- generic [ref=f20e203]:
- generic "指派给" [ref=f20e204]
- generic [ref=f20e205]: 王怡哲 于 2026-03-30 17:01:31
- generic "截止日期" [ref=f20e207]
- generic "反馈者" [ref=f20e210]
- generic "通知邮箱" [ref=f20e213]
- generic "操作系统" [ref=f20e216]
- generic "浏览器" [ref=f20e219]
- generic "关键词" [ref=f20e222]
- generic "抄送给" [ref=f20e225]
- generic [ref=f20e227]:
- generic [ref=f20e228]:
- list [ref=f20e229]:
- listitem [ref=f20e230]:
- link "项目/迭代/研发需求/任务" [ref=f20e231] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_2"
- generic [ref=f20e232]: 项目/迭代/研发需求/任务
- listitem [ref=f20e233]:
- link "其他相关" [ref=f20e234] [cursor=pointer]:
- /url: "#zin_bug_view_306_tabPane_3"
- generic [ref=f20e235]: 其他相关
- button "" [ref=f20e236] [cursor=pointer]:
- generic [ref=f20e237]:
- generic [ref=f20e240]:
- generic [ref=f20e241]:
- generic "所属项目" [ref=f20e242]
- link "开源HIS改造落地" [ref=f20e244] [cursor=pointer]:
- /url: /index.php?m=project&f=view&projectID=11
- generic "所属执行" [ref=f20e246]
- generic "相关需求" [ref=f20e249]
- generic "相关任务" [ref=f20e252]
- button "" [ref=f20e255] [cursor=pointer]:
- generic [ref=f20e256]:
- generic:
- generic:
- link "" [ref=f20e257] [cursor=pointer]:
- /url: /index.php?m=bug&f=view&bugID=307
- generic [ref=f20e258]:
- link "" [ref=f20e259] [cursor=pointer]:
- /url: /index.php?m=bug&f=view&bugID=305
- generic [ref=f20e260]:
- text: "* *"
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list [ref=e84]:
- listitem [ref=e85]:
- generic [ref=e87] [cursor=pointer]: 测试
- generic [ref=e71]:
- textbox [ref=e93]:
- /placeholder: 搜索
- button [ref=e73] [cursor=pointer]:
- img [ref=e75]
- link " 开源版21.7" [ref=e76] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e77]:
- generic [ref=e78]: 开源版21.7
- button "升级 " [ref=e79] [cursor=pointer]:
- generic [ref=e80]: 升级
- generic [ref=e81]:

View File

@@ -0,0 +1,93 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

View File

@@ -0,0 +1,337 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- iframe [ref=e89]:
- generic [active] [ref=f1e1]:
- banner [ref=f1e2]:
- generic [ref=f1e3]:
- generic [ref=f1e4]:
- link " 测试" [ref=f1e6] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f1e7]:
- generic [ref=f1e8]: 测试
- button " 开源HIS改造落地" [ref=f1e10] [cursor=pointer]:
- generic [ref=f1e11]:
- generic "开源HIS改造落地" [ref=f1e12]
- navigation [ref=f1e15]:
- list [ref=f1e16]:
- listitem [ref=f1e17]:
- link "仪表盘" [ref=f1e18] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f1e19]: 仪表盘
- listitem [ref=f1e20]
- listitem [ref=f1e21]:
- link "Bug" [ref=f1e22] [cursor=pointer]:
- /url: /index.php?m=bug&f=browse&productID=4
- generic [ref=f1e23]: Bug
- listitem [ref=f1e24]:
- link "用例" [ref=f1e25] [cursor=pointer]:
- /url: /index.php?m=testcase&f=browse&productID=4
- generic [ref=f1e26]: 用例
- listitem [ref=f1e27]:
- link "套件" [ref=f1e28] [cursor=pointer]:
- /url: /index.php?m=testsuite&f=browse&productID=4
- generic [ref=f1e29]: 套件
- listitem [ref=f1e30]
- listitem [ref=f1e31]:
- link "测试单" [ref=f1e32] [cursor=pointer]:
- /url: /index.php?m=testtask&f=browse&productID=4
- generic [ref=f1e33]: 测试单
- listitem [ref=f1e34]:
- link "测试报告" [ref=f1e35] [cursor=pointer]:
- /url: /index.php?m=testreport&f=browse&productID=4
- generic [ref=f1e36]: 测试报告
- listitem [ref=f1e37]
- listitem [ref=f1e38]:
- link "用例库" [ref=f1e39] [cursor=pointer]:
- /url: /index.php?m=caselib&f=browse&libID=0
- generic [ref=f1e40]: 用例库
- listitem [ref=f1e41]
- listitem [ref=f1e42]:
- link "自动化" [ref=f1e43] [cursor=pointer]:
- /url: /index.php?m=zanode&f=instruction
- generic [ref=f1e44]: 自动化
- generic [ref=f1e46]:
- button "" [ref=f1e47] [cursor=pointer]:
- generic [ref=f1e48]:
- button " 9" [ref=f1e49] [cursor=pointer]:
- generic [ref=f1e50]:
- generic [ref=f1e51]: "9"
- generic [ref=f1e54] [cursor=pointer]: A
- generic [ref=f1e57]:
- generic [ref=f1e58]:
- generic [ref=f1e59]:
- button " 返回" [ref=f1e60] [cursor=pointer]:
- generic [ref=f1e61]:
- generic [ref=f1e62]: 返回
- generic [ref=f1e63]:
- generic [ref=f1e64]: "307"
- generic [ref=f1e65]: 门诊医生站:开立的手术申请后未关联生成预手术收费明细记录
- link " 提Bug" [ref=f1e68] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extras=projectID=11,executionID=0,moduleID=126
- generic [ref=f1e69]:
- generic [ref=f1e70]: 提Bug
- generic [ref=f1e71]:
- generic [ref=f1e72]:
- generic [ref=f1e74]:
- generic [ref=f1e76]: 重现步骤
- generic [ref=f1e78]:
- paragraph [ref=f1e79]: "[步骤]"
- paragraph [ref=f1e80]:
- link "index.php?m=file&f=read&t=png&fileID=1416" [ref=f1e81] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1416
- img "index.php?m=file&f=read&t=png&fileID=1416" [ref=f1e82]
- paragraph [ref=f1e83]: 图1门诊医生站手术申请
- paragraph [ref=f1e84]
- paragraph [ref=f1e85]:
- link "index.php?m=file&f=read&t=png&fileID=1417" [ref=f1e86] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1417
- img "index.php?m=file&f=read&t=png&fileID=1417" [ref=f1e87]
- paragraph [ref=f1e88]: 图2手术申请开立成功
- paragraph [ref=f1e89]
- paragraph [ref=f1e90]:
- link "index.php?m=file&f=read&t=png&fileID=1418" [ref=f1e91] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1418
- img "index.php?m=file&f=read&t=png&fileID=1418" [ref=f1e92]
- paragraph [ref=f1e93]: 图3《门诊收费》检索不到待缴费手术费用。
- paragraph [ref=f1e94]: 1、如上图1、2、3所示门诊医生站开立的手术申请后未关联生成预手术收费明细记录。
- paragraph [ref=f1e95]: "[结果]"
- paragraph [ref=f1e96]: 1、门诊医生站:开立的手术申请后未关联生成预手术收费明细记录。
- paragraph [ref=f1e97]: "[期望]"
- paragraph [ref=f1e98]:
- text: 1、门诊医生站:开立的手术申请成功后,
- generic [ref=f1e99]:
- text: 系统应
- strong [ref=f1e100]: 自动将手术收项目明细插入预收费明细表
- text: 确保《门诊收费》处能够实时看见并进行结算如下图4文档所示
- paragraph [ref=f1e101]:
- link "index.php?m=file&f=read&t=png&fileID=1419" [ref=f1e102] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1419
- img "index.php?m=file&f=read&t=png&fileID=1419" [ref=f1e103]
- paragraph [ref=f1e104]: 图4
- paragraph [ref=f1e105]
- generic [ref=f1e107]:
- generic [ref=f1e111]:
- generic [ref=f1e112]: 历史记录
- navigation [ref=f1e113]:
- button "" [ref=f1e114] [cursor=pointer]:
- generic [ref=f1e115]:
- button " 添加备注" [ref=f1e116] [cursor=pointer]:
- generic [ref=f1e117]:
- generic [ref=f1e118]: 添加备注
- list [ref=f1e120]:
- listitem [ref=f1e121]:
- generic [ref=f1e122]:
- generic [ref=f1e124]: "1"
- generic [ref=f1e127]:
- text: 2026-03-30 17:44:22,
- strong [ref=f1e128]: 陈显精
- text: 创建。
- listitem [ref=f1e129]:
- generic [ref=f1e130]:
- generic [ref=f1e132]: "2"
- generic [ref=f1e135]:
- text: 2026-03-30 17:44:26,
- strong [ref=f1e136]: 陈显精
- text: 指派给
- strong [ref=f1e137]: 王怡哲
- text:
- generic [ref=f1e140]:
- button " 返回" [ref=f1e141] [cursor=pointer]:
- generic [ref=f1e142]:
- generic [ref=f1e143]: 返回
- link " 确认" [ref=f1e145] [cursor=pointer]:
- /url: /index.php?m=bug&f=confirm&bugID=307
- generic [ref=f1e146]:
- generic [ref=f1e147]: 确认
- link " 指派" [ref=f1e148] [cursor=pointer]:
- /url: /index.php?m=bug&f=assignTo&bugID=307
- generic [ref=f1e149]:
- generic [ref=f1e150]: 指派
- link " 解决" [ref=f1e151] [cursor=pointer]:
- /url: /index.php?m=bug&f=resolve&bugID=307
- generic [ref=f1e152]:
- generic [ref=f1e153]: 解决
- button " 转研发需求" [ref=f1e154] [cursor=pointer]:
- generic [ref=f1e155]:
- generic [ref=f1e156]: 转研发需求
- button " 转任务" [ref=f1e157] [cursor=pointer]:
- generic [ref=f1e158]:
- generic [ref=f1e159]: 转任务
- link " 创建用例" [ref=f1e160] [cursor=pointer]:
- /url: /index.php?m=testcase&f=create&productID=4&branch=0&moduleID=0&from=bug&bugID=307
- generic [ref=f1e161]:
- generic [ref=f1e162]: 创建用例
- link "" [ref=f1e164] [cursor=pointer]:
- /url: /index.php?m=bug&f=edit&bugID=307
- generic [ref=f1e165]:
- link "" [ref=f1e166] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extra=bugID=307,projectID=11,executionID=0
- generic [ref=f1e167]:
- link "" [ref=f1e168] [cursor=pointer]:
- /url: /index.php?m=bug&f=delete&bugID=307
- generic [ref=f1e169]:
- generic [ref=f1e170]:
- generic [ref=f1e171]:
- generic [ref=f1e172]:
- list [ref=f1e173]:
- listitem [ref=f1e174]:
- link "基本信息" [ref=f1e175] [cursor=pointer]:
- /url: "#zin_bug_view_307_tabPane"
- generic [ref=f1e176]: 基本信息
- listitem [ref=f1e177]:
- link "Bug的一生" [ref=f1e178] [cursor=pointer]:
- /url: "#zin_bug_view_307_tabPane_1"
- generic [ref=f1e179]: Bug的一生
- button "" [ref=f1e180] [cursor=pointer]:
- generic [ref=f1e181]:
- generic [ref=f1e184]:
- generic [ref=f1e185]:
- generic "所属模块" [ref=f1e186]
- list [ref=f1e188]:
- listitem [ref=f1e189]: 手术麻醉管理
- generic "所属计划" [ref=f1e191]
- generic "来源用例" [ref=f1e194]
- generic [ref=f1e196]:
- generic "Bug类型" [ref=f1e197]
- generic [ref=f1e198]: 设计缺陷
- generic [ref=f1e199]:
- generic "严重程度" [ref=f1e200]
- generic [ref=f1e202]: 3 3
- generic [ref=f1e203]:
- generic "优先级" [ref=f1e204]
- generic [ref=f1e206]: "3"
- generic [ref=f1e207]:
- generic "Bug状态" [ref=f1e208]
- generic [ref=f1e210]: 激活
- generic "激活次数" [ref=f1e212]
- generic "激活时间" [ref=f1e215]
- generic [ref=f1e217]:
- generic "是否确认" [ref=f1e218]
- generic [ref=f1e219]: 未确认
- generic [ref=f1e220]:
- generic "指派给" [ref=f1e221]
- generic [ref=f1e222]: 王怡哲 于 2026-03-30 17:44:22
- generic "截止日期" [ref=f1e224]
- generic "反馈者" [ref=f1e227]
- generic "通知邮箱" [ref=f1e230]
- generic "操作系统" [ref=f1e233]
- generic "浏览器" [ref=f1e236]
- generic "关键词" [ref=f1e239]
- generic "抄送给" [ref=f1e242]
- generic [ref=f1e244]:
- generic [ref=f1e245]:
- list [ref=f1e246]:
- listitem [ref=f1e247]:
- link "项目/迭代/研发需求/任务" [ref=f1e248] [cursor=pointer]:
- /url: "#zin_bug_view_307_tabPane_2"
- generic [ref=f1e249]: 项目/迭代/研发需求/任务
- listitem [ref=f1e250]:
- link "其他相关" [ref=f1e251] [cursor=pointer]:
- /url: "#zin_bug_view_307_tabPane_3"
- generic [ref=f1e252]: 其他相关
- button "" [ref=f1e253] [cursor=pointer]:
- generic [ref=f1e254]:
- generic [ref=f1e257]:
- generic [ref=f1e258]:
- generic "所属项目" [ref=f1e259]
- link "开源HIS改造落地" [ref=f1e261] [cursor=pointer]:
- /url: /index.php?m=project&f=view&projectID=11
- generic "所属执行" [ref=f1e263]
- generic "相关需求" [ref=f1e266]
- generic "相关任务" [ref=f1e269]
- button "" [ref=f1e272] [cursor=pointer]:
- generic [ref=f1e273]:
- text: "* *"
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list [ref=e90]:
- listitem [ref=e91]:
- generic [ref=e93] [cursor=pointer]: 测试
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

View File

@@ -0,0 +1,23 @@
- generic [ref=e5]:
- generic [ref=e6]:
- img [ref=e7]
- img [ref=e8]
- generic [ref=e9]:
- generic [ref=e10]:
- heading "经创贺联项目管理系统" [level=2] [ref=e11]
- generic [ref=e12]: 简体
- generic [ref=e13]:
- generic [ref=e14]:
- generic [ref=e16]: 用户名
- textbox [active] [ref=e17]: admin
- generic [ref=e18]:
- generic [ref=e20]: 密码
- textbox [ref=e21]: Jchl1528
- generic [ref=e22]:
- generic [ref=e24]:
- checkbox "保持登录" [checked] [ref=e25]
- generic [ref=e26] [cursor=pointer]: 保持登录
- link "忘记密码" [ref=e27] [cursor=pointer]:
- /url: /index.php?m=user&f=reset
- button "登录" [ref=e29] [cursor=pointer]:
- generic [ref=e30]: 登录

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,93 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

View File

@@ -0,0 +1,328 @@
- generic [active]:
- generic [ref=e1]:
- generic [ref=e2]:
- list [ref=e3]:
- listitem [ref=e4]:
- link " 地盘" [ref=e5] [cursor=pointer]:
- /url: /index.php?m=my&f=index
- generic [ref=e6]:
- generic [ref=e7]: 地盘
- listitem [ref=e8]:
- link " 项目集" [ref=e9] [cursor=pointer]:
- /url: /index.php?m=program&f=browse
- generic [ref=e10]:
- generic [ref=e11]: 项目集
- listitem [ref=e12]:
- link " 产品" [ref=e13] [cursor=pointer]:
- /url: /index.php?m=product&f=all
- generic [ref=e14]:
- generic [ref=e15]: 产品
- listitem [ref=e16]:
- link " 项目" [ref=e17] [cursor=pointer]:
- /url: /index.php?m=project&f=browse
- generic [ref=e18]:
- generic [ref=e19]: 项目
- listitem [ref=e20]:
- link "  执行" [ref=e21] [cursor=pointer]:
- /url: /index.php?m=execution&f=task
- generic [ref=e22]:  
- generic [ref=e23]: 执行
- listitem [ref=e24]:
- link " 测试" [ref=e25] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=e26]:
- generic [ref=e27]: 测试
- listitem [ref=e28]:
- link " DevOps" [ref=e29] [cursor=pointer]:
- /url: /index.php?m=repo&f=maintain
- generic [ref=e30]:
- generic [ref=e31]: DevOps
- listitem [ref=e32]
- listitem [ref=e33]:
- link " AI" [ref=e34] [cursor=pointer]:
- /url: /index.php?m=aiapp&f=square
- generic [ref=e35]:
- generic [ref=e36]: AI
- listitem [ref=e37]:
- link " BI" [ref=e38] [cursor=pointer]:
- /url: /index.php?m=screen&f=browse
- generic [ref=e39]:
- generic [ref=e40]: BI
- listitem [ref=e41]
- listitem [ref=e42]:
- link " 看板" [ref=e43] [cursor=pointer]:
- /url: /index.php?m=kanban&f=space
- generic [ref=e44]:
- generic [ref=e45]: 看板
- listitem [ref=e46]:
- link " 文档" [ref=e47] [cursor=pointer]:
- /url: /index.php?m=doc&f=lastViewedSpace
- generic [ref=e48]:
- generic [ref=e49]: 文档
- listitem [ref=e50]
- listitem [ref=e51]:
- link " 组织" [ref=e52] [cursor=pointer]:
- /url: /index.php?m=my&f=team
- generic [ref=e53]:
- generic [ref=e54]: 组织
- listitem [ref=e55]:
- link " 后台" [ref=e56] [cursor=pointer]:
- /url: /index.php?m=admin&f=index
- generic [ref=e57]:
- generic [ref=e58]: 后台
- text:
- list [ref=e60]:
- listitem [ref=e61]:
- generic [ref=e63] [cursor=pointer]:
- iframe [ref=e89]:
- generic [active] [ref=f3e1]:
- banner [ref=f3e2]:
- generic [ref=f3e3]:
- generic [ref=f3e4]:
- link " 测试" [ref=f3e6] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f3e7]:
- generic [ref=f3e8]: 测试
- button " 开源HIS改造落地" [ref=f3e10] [cursor=pointer]:
- generic [ref=f3e11]:
- generic "开源HIS改造落地" [ref=f3e12]
- navigation [ref=f3e15]:
- list [ref=f3e16]:
- listitem [ref=f3e17]:
- link "仪表盘" [ref=f3e18] [cursor=pointer]:
- /url: /index.php?m=qa&f=index
- generic [ref=f3e19]: 仪表盘
- listitem [ref=f3e20]
- listitem [ref=f3e21]:
- link "Bug" [ref=f3e22] [cursor=pointer]:
- /url: /index.php?m=bug&f=browse&productID=4
- generic [ref=f3e23]: Bug
- listitem [ref=f3e24]:
- link "用例" [ref=f3e25] [cursor=pointer]:
- /url: /index.php?m=testcase&f=browse&productID=4
- generic [ref=f3e26]: 用例
- listitem [ref=f3e27]:
- link "套件" [ref=f3e28] [cursor=pointer]:
- /url: /index.php?m=testsuite&f=browse&productID=4
- generic [ref=f3e29]: 套件
- listitem [ref=f3e30]
- listitem [ref=f3e31]:
- link "测试单" [ref=f3e32] [cursor=pointer]:
- /url: /index.php?m=testtask&f=browse&productID=4
- generic [ref=f3e33]: 测试单
- listitem [ref=f3e34]:
- link "测试报告" [ref=f3e35] [cursor=pointer]:
- /url: /index.php?m=testreport&f=browse&productID=4
- generic [ref=f3e36]: 测试报告
- listitem [ref=f3e37]
- listitem [ref=f3e38]:
- link "用例库" [ref=f3e39] [cursor=pointer]:
- /url: /index.php?m=caselib&f=browse&libID=0
- generic [ref=f3e40]: 用例库
- listitem [ref=f3e41]
- listitem [ref=f3e42]:
- link "自动化" [ref=f3e43] [cursor=pointer]:
- /url: /index.php?m=zanode&f=instruction
- generic [ref=f3e44]: 自动化
- generic [ref=f3e46]:
- button "" [ref=f3e47] [cursor=pointer]:
- generic [ref=f3e48]:
- button " 9" [ref=f3e49] [cursor=pointer]:
- generic [ref=f3e50]:
- generic [ref=f3e51]: "9"
- generic [ref=f3e54] [cursor=pointer]: A
- generic [ref=f3e57]:
- generic [ref=f3e58]:
- generic [ref=f3e59]:
- button " 返回" [ref=f3e60] [cursor=pointer]:
- generic [ref=f3e61]:
- generic [ref=f3e62]: 返回
- generic [ref=f3e63]:
- generic [ref=f3e64]: "320"
- generic [ref=f3e65]: 手术管理-》门诊手术安排:新增手术安排界面的就诊卡号取值错误
- link " 提Bug" [ref=f3e68] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extras=projectID=11,executionID=0,moduleID=126
- generic [ref=f3e69]:
- generic [ref=f3e70]: 提Bug
- generic [ref=f3e71]:
- generic [ref=f3e72]:
- generic [ref=f3e74]:
- generic [ref=f3e76]: 重现步骤
- generic [ref=f3e78]:
- paragraph [ref=f3e79]: "[步骤]"
- paragraph [ref=f3e80]:
- link "index.php?m=file&f=read&t=png&fileID=1450" [ref=f3e81] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1450
- img "index.php?m=file&f=read&t=png&fileID=1450" [ref=f3e82]
- paragraph [ref=f3e83]: 图1门诊手术安排手术申请查询选中手术申请记录点击【确认】
- paragraph [ref=f3e84]:
- link "index.php?m=file&f=read&t=png&fileID=1451" [ref=f3e85] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1451
- img "index.php?m=file&f=read&t=png&fileID=1451" [ref=f3e86]
- paragraph [ref=f3e87]: 图2新增手术安排界面的就诊卡号取值错误
- paragraph [ref=f3e88]: 1、如上图1、2所示手术管理-》门诊手术安排:新增手术安排界面的就诊卡号取值错误。
- paragraph [ref=f3e89]: "[结果]"
- paragraph [ref=f3e90]: 1、手术管理-》门诊手术安排:新增手术安排界面的就诊卡号取值错误。
- paragraph [ref=f3e91]: "[期望]"
- paragraph [ref=f3e92]:
- text: 1、如上图1、2所示手术管理-》门诊手术安排新增手术安排界面的就诊卡号取值于患者档案的就诊卡号字段的值adm_
- link "patient.id" [ref=f3e93] [cursor=pointer]:
- /url: http://patient.id
- text: = adm_patient_identifier.patient_id;adm_patient_identifier.identifier_no 字段就是就诊卡号如下图3所示
- paragraph [ref=f3e94]:
- link "index.php?m=file&f=read&t=png&fileID=1452" [ref=f3e95] [cursor=pointer]:
- /url: /index.php?m=file&f=read&t=png&fileID=1452
- img "index.php?m=file&f=read&t=png&fileID=1452" [ref=f3e96]
- paragraph [ref=f3e97]: 图3
- generic [ref=f3e99]:
- generic [ref=f3e103]:
- generic [ref=f3e104]: 历史记录
- navigation [ref=f3e105]:
- button "" [ref=f3e106] [cursor=pointer]:
- generic [ref=f3e107]:
- button " 添加备注" [ref=f3e108] [cursor=pointer]:
- generic [ref=f3e109]:
- generic [ref=f3e110]: 添加备注
- list [ref=f3e112]:
- listitem [ref=f3e113]:
- generic [ref=f3e114]:
- generic [ref=f3e116]: "1"
- generic [ref=f3e119]:
- text: 2026-03-31 22:53:45,
- strong [ref=f3e120]: 陈显精
- text: 创建。
- listitem [ref=f3e121]:
- generic [ref=f3e122]:
- generic [ref=f3e124]: "2"
- generic [ref=f3e127]:
- text: 2026-03-31 22:53:49,
- strong [ref=f3e128]: 陈显精
- text: 指派给
- strong [ref=f3e129]: 王怡哲
- text:
- generic [ref=f3e132]:
- button " 返回" [ref=f3e133] [cursor=pointer]:
- generic [ref=f3e134]:
- generic [ref=f3e135]: 返回
- link " 确认" [ref=f3e137] [cursor=pointer]:
- /url: /index.php?m=bug&f=confirm&bugID=320
- generic [ref=f3e138]:
- generic [ref=f3e139]: 确认
- link " 指派" [ref=f3e140] [cursor=pointer]:
- /url: /index.php?m=bug&f=assignTo&bugID=320
- generic [ref=f3e141]:
- generic [ref=f3e142]: 指派
- link " 解决" [ref=f3e143] [cursor=pointer]:
- /url: /index.php?m=bug&f=resolve&bugID=320
- generic [ref=f3e144]:
- generic [ref=f3e145]: 解决
- button " 转研发需求" [ref=f3e146] [cursor=pointer]:
- generic [ref=f3e147]:
- generic [ref=f3e148]: 转研发需求
- button " 转任务" [ref=f3e149] [cursor=pointer]:
- generic [ref=f3e150]:
- generic [ref=f3e151]: 转任务
- link " 创建用例" [ref=f3e152] [cursor=pointer]:
- /url: /index.php?m=testcase&f=create&productID=4&branch=0&moduleID=0&from=bug&bugID=320
- generic [ref=f3e153]:
- generic [ref=f3e154]: 创建用例
- link "" [ref=f3e156] [cursor=pointer]:
- /url: /index.php?m=bug&f=edit&bugID=320
- generic [ref=f3e157]:
- link "" [ref=f3e158] [cursor=pointer]:
- /url: /index.php?m=bug&f=create&productID=4&branch=0&extra=bugID=320,projectID=11,executionID=0
- generic [ref=f3e159]:
- link "" [ref=f3e160] [cursor=pointer]:
- /url: /index.php?m=bug&f=delete&bugID=320
- generic [ref=f3e161]:
- generic [ref=f3e162]:
- generic [ref=f3e163]:
- generic [ref=f3e164]:
- list [ref=f3e165]:
- listitem [ref=f3e166]:
- link "基本信息" [ref=f3e167] [cursor=pointer]:
- /url: "#zin_bug_view_320_tabPane"
- generic [ref=f3e168]: 基本信息
- listitem [ref=f3e169]:
- link "Bug的一生" [ref=f3e170] [cursor=pointer]:
- /url: "#zin_bug_view_320_tabPane_1"
- generic [ref=f3e171]: Bug的一生
- button "" [ref=f3e172] [cursor=pointer]:
- generic [ref=f3e173]:
- generic [ref=f3e176]:
- generic [ref=f3e177]:
- generic "所属模块" [ref=f3e178]
- list [ref=f3e180]:
- listitem [ref=f3e181]: 手术麻醉管理
- generic "所属计划" [ref=f3e183]
- generic "来源用例" [ref=f3e186]
- generic [ref=f3e188]:
- generic "Bug类型" [ref=f3e189]
- generic [ref=f3e190]: 代码错误
- generic [ref=f3e191]:
- generic "严重程度" [ref=f3e192]
- generic [ref=f3e194]: 3 3
- generic [ref=f3e195]:
- generic "优先级" [ref=f3e196]
- generic [ref=f3e198]: "3"
- generic [ref=f3e199]:
- generic "Bug状态" [ref=f3e200]
- generic [ref=f3e202]: 激活
- generic "激活次数" [ref=f3e204]
- generic "激活时间" [ref=f3e207]
- generic [ref=f3e209]:
- generic "是否确认" [ref=f3e210]
- generic [ref=f3e211]: 未确认
- generic [ref=f3e212]:
- generic "指派给" [ref=f3e213]
- generic [ref=f3e214]: 王怡哲 于 2026-03-31 22:53:45
- generic "截止日期" [ref=f3e216]
- generic "反馈者" [ref=f3e219]
- generic "通知邮箱" [ref=f3e222]
- generic "操作系统" [ref=f3e225]
- generic "浏览器" [ref=f3e228]
- generic "关键词" [ref=f3e231]
- generic "抄送给" [ref=f3e234]
- generic [ref=f3e236]:
- generic [ref=f3e237]:
- list [ref=f3e238]:
- listitem [ref=f3e239]:
- link "项目/迭代/研发需求/任务" [ref=f3e240] [cursor=pointer]:
- /url: "#zin_bug_view_320_tabPane_2"
- generic [ref=f3e241]: 项目/迭代/研发需求/任务
- listitem [ref=f3e242]:
- link "其他相关" [ref=f3e243] [cursor=pointer]:
- /url: "#zin_bug_view_320_tabPane_3"
- generic [ref=f3e244]: 其他相关
- button "" [ref=f3e245] [cursor=pointer]:
- generic [ref=f3e246]:
- generic [ref=f3e249]:
- generic [ref=f3e250]:
- generic "所属项目" [ref=f3e251]
- link "开源HIS改造落地" [ref=f3e253] [cursor=pointer]:
- /url: /index.php?m=project&f=view&projectID=11
- generic "所属执行" [ref=f3e255]
- generic "相关需求" [ref=f3e258]
- generic "相关任务" [ref=f3e261]
- button "" [ref=f3e264] [cursor=pointer]:
- generic [ref=f3e265]:
- text: "* *"
- generic [ref=e65]:
- button " 研发综合界面" [ref=e67] [cursor=pointer]:
- generic [ref=e68]:
- generic [ref=e69]: 研发综合界面
- list [ref=e90]:
- listitem [ref=e91]:
- generic [ref=e93] [cursor=pointer]: 测试
- generic [ref=e71]:
- textbox [ref=e77]:
- /placeholder: 搜索
- button [ref=e79] [cursor=pointer]:
- img [ref=e81]
- link " 开源版21.7" [ref=e82] [cursor=pointer]:
- /url: https://www.zentao.net
- generic [ref=e83]:
- generic [ref=e84]: 开源版21.7
- button "升级 " [ref=e85] [cursor=pointer]:
- generic [ref=e86]: 升级
- generic [ref=e87]:

91
BUGFIX_ANALYSIS.md Normal file
View File

@@ -0,0 +1,91 @@
# Bug 根因分析与修复方案
## Bug 335 - 门诊医生站开立药品医嘱保存报错
### 问题分析
根据代码分析,`DoctorStationAdviceAppServiceImpl.saveAdvice()` 方法处理药品医嘱保存时可能报错的原因:
1. **patientId/encounterId 为 null** - 删除操作时前端可能未传
2. **accountId 为 null** - 患者账户信息未正确获取
3. **definitionId/definitionDetailId 为 null** - 定价信息缺失
4. **库存校验失败** - 药品库存不足
### 修复方案
✅ 已部分修复(见代码中的 BugFix 注释)
- 已添加 patientId/encounterId 自动补全逻辑
- 已添加 accountId 自动创建逻辑
- 需要进一步验证 definitionId 的处理
---
## Bug 336 - 门诊医生站开立诊疗项目保存报错
### 问题分析
诊疗项目保存与药品类似,但有以下特殊点:
1. **必须选择执行科室** - 代码中有校验 `throw new ServiceException("诊疗项目必须选择执行科室")`
2. **活动绑定设备处理** - 需要处理 `handService()` 中的设备绑定逻辑
3. **库存校验** - 诊疗项目可能关联耗材
### 修复方案
- 确保前端传递 executeDeptId执行科室
- 检查 handService() 方法中的异常处理
- 添加更详细的错误日志
---
## Bug 338 - 门诊划价新增时未校验就诊记录及诊断记录
### 问题分析
**这是患者安全问题!** 未接诊患者也可新增划价项目可能导致:
- 收费错误
- 医疗纠纷
- 数据不一致
当前代码问题:
- `OutpatientPricingAppServiceImpl.getAdviceBaseInfo()` 仅查询医嘱,未校验就诊状态
- 前端划价保存接口未找到(可能在其他地方)
### 修复方案
1. 在划价查询时增加就诊状态校验
2. 在划价保存时增加诊断记录校验
3. 未接诊患者禁止划价
---
## Bug 339 - 药房筛选条件失效
### 问题分析
查询结果中包含非选中药房的数据,可能原因:
- SQL WHERE 条件未正确应用 locationId
- 多表关联时过滤条件丢失
### 修复方案
- 检查 `DoctorStationAdviceAppMapper.getAdviceBaseInfo()` 的 SQL
- 确保 locationId 条件正确应用
---
## 修复优先级
1. **Bug 338** - 患者安全问题,最高优先级
2. **Bug 335/336** - 核心功能阻断,高优先级
3. **Bug 339** - 数据准确性问题,中优先级
---
## 测试用例
### Bug 338 测试
1. 选择未接诊患者,尝试划价 → 应禁止
2. 选择已接诊但无诊断的患者,尝试划价 → 应提示补充诊断
3. 选择正常接诊患者,划价 → 应成功
### Bug 335/336 测试
1. 门诊医生站开立药品医嘱 → 应成功保存
2. 门诊医生站开立诊疗项目 → 应成功保存
3. 签发医嘱 → 应成功
### Bug 339 测试
1. 选择"西药房"筛选 → 结果应仅包含西药房数据
2. 选择"中药房"筛选 → 结果应仅包含中药房数据

84
BUGFIX_PLAN.md Normal file
View File

@@ -0,0 +1,84 @@
# HIS 系统 Bug 修复计划
## 修复负责人
华佗 (AI 团队)
## 修复时间
2026-04-05 开始
---
## Bug 清单与修复优先级
### 🔴 高优先级(核心业务阻断)
#### Bug 335 - 门诊医生站开立药品医嘱保存报错
- **模块**: 医生工作站
- **文件**: `DoctorStationAdviceAppServiceImpl.java`
- **根因分析**: 待分析
- **修复状态**: 🔄 分析中
#### Bug 336 - 门诊医生站开立诊疗项目保存报错
- **模块**: 医生工作站
- **文件**: `DoctorStationAdviceAppServiceImpl.java`
- **根因分析**: 待分析
- **修复状态**: ⏳ 等待 335 修复后验证
#### Bug 338 - 门诊划价新增时未校验就诊记录及诊断记录
- **模块**: 门诊收费
- **问题**: 未接诊患者也可新增划价项目(患者安全问题)
- **修复方案**: 在划价保存前增加就诊状态和诊断记录校验
- **修复状态**: ⏳ 待修复
### 🟡 中优先级(数据准确性/用户体验)
#### Bug 339 - 药房筛选条件失效
- **模块**: 药房药库报表管理
- **问题**: 查询结果中包含非选中药房的数据
- **修复状态**: ⏳ 待分析
#### Bug 333 - 耗材医嘱类型错误
- **模块**: 医生工作站
- **问题**: 类型误转为"中成药"且保存报错
- **修复状态**: ⏳ 待分析
#### Bug 337 - 挂号时间显示异常
- **模块**: 建档挂号管理
- **问题**: 未显示当前实际挂号时间
- **修复状态**: ⏳ 待分析
#### Bug 334 - 检验申请界面布局优化
- **模块**: 门诊医生工作站
- **问题**: 按钮布局需要调整
- **修复状态**: ⏳ 待修复(前端)
### 🟢 低优先级(历史遗留问题)
#### Bug 249/253/280/300 - 3 月份遗留 bug
- **修复状态**: ⏳ 后续处理
---
## 修复流程
1. **分析根因** - 查看代码和日志,定位问题
2. **编写修复** - 修改代码并添加必要校验
3. **本地测试** - 确保修复有效且不引入新问题
4. **提交代码** - commit 并推送到 gitea
5. **验证关闭** - 在禅道更新 Bug 状态
---
## 测试要求
- 修复后必须测试
- 测试不通过继续修
- 确保不影响其他功能
---
## 备注
- 所有修复基于 develop 分支
- 修复完成后统一提交
- 重要修复添加详细注释

61
BUG_FIX_PROGRESS.md Normal file
View File

@@ -0,0 +1,61 @@
# HIS项目 Bug修复与需求开发进度表
## 项目信息
- **项目名称**: 开源HIS改造落地
- **当前分支**: develop
- **代码路径**:
- 前端: openhis-ui-vue3
- 后端: openhis-server-new
- ** Git仓库**: https://gitea.gentronhealth.com/wangyizhe/his
- **禅道地址**: https://zentao.gentronhealth.com
## 当前状态
- ✅ 代码已克隆完成
- ✅ Bug 已重新分配(管理员操作)
- ⏳ 等待修复人员开始工作
- 📋 张飞负责测试验证
## Bug修复任务列表重新分配后
| Bug ID | 严重程度 | 状态 | 模块 | 标题 | 原指派给 | **新指派给** | 进度 |
|--------|----------|------|------|------|----------|--------------|------|
| 339 | 3 | 激活 | 药房药库报表管理 | 药房筛选条件失效 | 王怡哲 | **关羽** | 待处理 |
| 338 | 3 | 激活 | 门诊收费管理 | 未校验就诊记录 | 王怡哲 | **关羽** | 待处理 |
| 337 | 3 | 激活 | 建档挂号管理 | 挂号时间显示异常 | 王怡哲 | **关羽** | 待处理 |
| 336 | 3 | 激活 | 门诊医生工作站 | 开立诊疗项目保存报错 | 王怡哲 | **关羽** | 待处理 |
| 335 | 3 | 激活 | 门诊医生工作站 | 开立药品医嘱保存报错 | 王怡哲 | **关羽** | 待处理 |
| 334 | 3 | 激活 | 门诊医生工作站 | 检验申请界面布局优化 | 王建 | **子龙** | 待处理 |
| 333 | 3 | 激活 | 门诊医生工作站 | 耗材医嘱类型误转 | 陈显精 | **关羽** | 待处理 |
## P0 级别 Bug紧急优先修复
| Bug ID | 标题 | 严重程度 | 负责人 |
|--------|------|----------|--------|
| 335 | 开立药品医嘱保存报错 | 严重 | 关羽 |
| 336 | 开立诊疗项目保存报错 | 严重 | 关羽 |
| 338 | 未校验就诊记录 | 严重 | 关羽 |
## 需求开发任务列表10个全部未关闭
待进一步确认分配情况...
## 工作流程
1. **认领任务** - 在禅道将 Bug 分配给自己
2. **修改代码** - 从 develop 分支创建新分支:`bug/bug-id`
3. **本地测试** - 确保本地 JDK 17 环境编译通过
4. **提交PR** - 提交 Pull Request 到 develop 分支
5. **测试验证** - 张飞进行测试
6. **合并分支** - 测试通过后合并到 develop
## 注意事项
- 所有代码修改必须先创建新分支
- 分支命名:`bug/bug-id``feature/feedback-id`
- 提交信息必须包含禅道Bug/需求ID
- 修改前请先阅读 `AGENTS.md` 了解项目规范
- **JDK 17 配置** - 确保本地开发环境使用 JDK 17
## 今日会议纪要
- 2026-04-05 15:09: 管理员重新分配 Bug 给群内武将
- 2026-04-05 14:58: 确认将王怡哲的 Bug 分配给关羽、张飞、陈琳
- 2026-04-05 13:47: 统一调度分配人员任务
- 2026-04-05 12:45: 初始任务分配完成

89
Bug318_修复总结.md Normal file
View File

@@ -0,0 +1,89 @@
# Bug #318 修复总结 - 手术医嘱类型冲突解决
## 问题描述
手术医嘱的 `adviceType=4` 与耗材类型冲突,导致保存手术医嘱时被错误归类为耗材,进而引发 `device_def_id` 为 null 的数据库错误。
## 解决方案
引入新的手术类型值 **6**避免与耗材类型4冲突。
## 类型映射表
| 类型 | 前端 adviceType | 后端 ItemType | 数据库 category_enum |
|------|----------------|---------------|---------------------|
| 药品 | 1 | MEDICINE(1) | 1 |
| 耗材 | 4 | DEVICE(2) | 2 |
| 诊疗 | 3 | ACTIVITY(3) | 3 |
| 会诊 | 5 | - | 31 |
| **手术** | **6** | **SURGERY(6)** | **6** |
## 修改的文件
### 1. 后端 - 枚举定义
**文件**: `openhis-server-new/openhis-common/src/main/java/com/openhis/common/enums/ItemType.java`
- 添加 `SURGERY(6, "6", "手术")` 枚举值
### 2. 后端 - SQL Mapper医生站
**文件**: `openhis-server-new/openhis-application/src/main/resources/mapper/doctorstation/DoctorStationAdviceAppMapper.xml`
- 修改 SQL`category_enum=4` 映射为 `advice_type=6`
- 修改前: `COALESCE(T1.category_enum, 3) AS advice_type`
- 修改后: `CASE WHEN T1.category_enum = 4 THEN 6 ELSE COALESCE(T1.category_enum, 3) END AS advice_type`
### 3. 后端 - SQL Mapper住院医生站
**文件**: `openhis-server-new/openhis-application/src/main/resources/mapper/regdoctorstation/AdviceManageAppMapper.xml`
- 同上修改
### 4. 后端 - 分类逻辑
**文件**: `openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java`
- 更新 `deviceList` 筛选条件:处理 `adviceType=4`(耗材)
- 更新 `activityList` 筛选条件:处理 `adviceType=6`(手术)
### 5. 前端 - 医嘱类型选项
**文件**: `openhis-ui-vue3/src/views/inpatientDoctor/home/components/order/index.vue`
- 修改手术类型值从 4 改为 6
## 数据迁移
### 历史数据更新脚本
**文件**: `sql/迁移记录-DB变更记录/20260401_update_surgery_advice_type.sql`
```sql
-- 更新历史手术医嘱的 category_enum 从 4 改为 6
UPDATE wor_service_request
SET category_enum = 6
WHERE category_enum = 4
AND delete_flag = '0';
```
### 执行步骤
1. **备份数据库**(重要!)
2. 执行上述 UPDATE 语句
3. 重启后端服务
4. 清除前端缓存
## 验证方法
### 1. 后端日志验证
保存手术申请单后,检查日志:
```
BugFix#219: 医嘱分类完成 - 药品:{}, 耗材:{}, 诊疗:{}
```
手术医嘱应该被归类到"诊疗"中。
### 2. 数据库验证
```sql
-- 检查手术医嘱的 category_enum 是否为 6
SELECT id, bus_no, category_enum, content_json::jsonb->>'surgeryName'
FROM wor_service_request
WHERE category_enum = 6;
```
### 3. 前端验证
- 医嘱列表中手术医嘱显示正常
- 手术医嘱的 adviceType 为 6
- 耗材医嘱的 adviceType 为 4
## 注意事项
1. **部署前必须执行数据迁移脚本**,否则历史手术医嘱无法正确显示
2. 修改后需要重新编译部署后端和前端
3. 建议先在测试环境验证后再部署到生产环境

2
GIT_TEST_GUANYU.md Normal file
View File

@@ -0,0 +1,2 @@
# 关羽 Git 配置测试
测试时间: Mon Apr 6 07:03:56 AM CST 2026

105
analyze_empty_data.js Normal file
View File

@@ -0,0 +1,105 @@
const { Pool } = require('pg');
const pool = new Pool({
host: '47.116.196.11',
port: 15432,
database: 'postgresql',
user: 'postgresql',
password: 'Jchl1528'
});
async function analyze() {
try {
// 1. 检查申请科室ID在adm_organization中是否存在
console.log('=== 分析申请科室ID是否有效 ===');
const deptResult = await pool.query(`
SELECT DISTINCT s.apply_dept_id
FROM hisdev.cli_surgery s
WHERE s.delete_flag = '0'
AND (s.apply_dept_name IS NULL OR s.apply_dept_name = '')
AND s.apply_dept_id IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM hisdev.adm_organization o WHERE o.id = s.apply_dept_id
)
`);
console.log(`申请科室ID无效的记录数: ${deptResult.rows.length}`);
if (deptResult.rows.length > 0) {
console.log('无效的apply_dept_id:', deptResult.rows.map(r => r.apply_dept_id));
}
// 2. 检查主刀医生ID在sys_user中是否存在
console.log('\n=== 分析主刀医生ID是否有效 ===');
const surgeonResult = await pool.query(`
SELECT DISTINCT s.main_surgeon_id
FROM hisdev.cli_surgery s
WHERE s.delete_flag = '0'
AND (s.main_surgeon_name IS NULL OR s.main_surgeon_name = '')
AND s.main_surgeon_id IS NOT NULL
AND NOT EXISTS (
SELECT 1 FROM hisdev.sys_user u WHERE u.user_id = s.main_surgeon_id
)
`);
console.log(`主刀医生ID无效的记录数: ${surgeonResult.rows.length}`);
if (surgeonResult.rows.length > 0) {
console.log('无效的main_surgeon_id:', surgeonResult.rows.map(r => r.main_surgeon_id));
}
// 3. 查看有ID但没有name的记录详情
console.log('\n=== 有ID但Name为空的记录详情 ===');
const detailResult = await pool.query(`
SELECT
s.id,
s.surgery_no,
s.apply_dept_id,
s.main_surgeon_id,
s.create_time,
EXISTS (SELECT 1 FROM hisdev.adm_organization o WHERE o.id = s.apply_dept_id) as dept_exists,
EXISTS (SELECT 1 FROM hisdev.sys_user u WHERE u.user_id = s.main_surgeon_id) as surgeon_exists
FROM hisdev.cli_surgery s
WHERE s.delete_flag = '0'
AND (
((s.apply_dept_name IS NULL OR s.apply_dept_name = '') AND s.apply_dept_id IS NOT NULL)
OR
((s.main_surgeon_name IS NULL OR s.main_surgeon_name = '') AND s.main_surgeon_id IS NOT NULL)
)
ORDER BY s.create_time DESC
LIMIT 10
`);
console.log(JSON.stringify(detailResult.rows, null, 2));
// 4. 检查最近创建的记录为什么name为空
console.log('\n=== 最近10条记录的创建情况 ===');
const recentResult = await pool.query(`
SELECT
s.id,
s.surgery_no,
s.apply_dept_id,
s.apply_dept_name,
s.main_surgeon_id,
s.main_surgeon_name,
s.create_time,
s.create_by,
CASE
WHEN s.apply_dept_id IS NULL THEN 'apply_dept_id为空'
WHEN NOT EXISTS (SELECT 1 FROM hisdev.adm_organization o WHERE o.id = s.apply_dept_id) THEN 'apply_dept_id无效'
ELSE 'apply_dept_id有效'
END as dept_status,
CASE
WHEN s.main_surgeon_id IS NULL THEN 'main_surgeon_id为空'
WHEN NOT EXISTS (SELECT 1 FROM hisdev.sys_user u WHERE u.user_id = s.main_surgeon_id) THEN 'main_surgeon_id无效'
ELSE 'main_surgeon_id有效'
END as surgeon_status
FROM hisdev.cli_surgery s
WHERE s.delete_flag = '0'
ORDER BY s.create_time DESC
LIMIT 10
`);
console.log(JSON.stringify(recentResult.rows, null, 2));
} catch (err) {
console.error('分析失败:', err.message);
} finally {
pool.end();
}
}
analyze();

View File

@@ -0,0 +1,73 @@
const { Pool } = require('pg');
const pool = new Pool({
host: '47.116.196.11',
port: 15432,
database: 'postgresql',
user: 'postgresql',
password: 'Jchl1528'
});
async function analyze() {
try {
// 1. 检查最近的手术安排及其关联的手术申请
console.log('=== 分析手术安排与手术申请的关联 ===\n');
const result = await pool.query(`
SELECT
os.schedule_id,
os.oper_code,
os.apply_id,
os.create_time,
os.creator_id,
cs.id as surgery_id,
cs.surgery_no,
cs.apply_dept_id,
cs.apply_dept_name,
cs.main_surgeon_id,
cs.main_surgeon_name,
cs.status_enum,
CASE
WHEN cs.id IS NULL THEN '手术申请记录不存在'
WHEN cs.apply_dept_name IS NULL THEN '申请科室名称为空'
WHEN cs.main_surgeon_name IS NULL THEN '主刀医生名称为空'
ELSE '正常'
END as status
FROM hisdev.op_schedule os
LEFT JOIN hisdev.cli_surgery cs ON os.apply_id = cs.id
WHERE os.delete_flag = '0'
ORDER BY os.create_time DESC
LIMIT 10
`);
console.table(result.rows);
// 2. 检查手术申请本身的字段情况
console.log('\n=== 最近创建的手术申请 ===');
const surgeryResult = await pool.query(`
SELECT
id,
surgery_no,
patient_name,
apply_dept_id,
apply_dept_name,
main_surgeon_id,
main_surgeon_name,
status_enum,
create_time,
create_by
FROM hisdev.cli_surgery
WHERE delete_flag = '0'
ORDER BY create_time DESC
LIMIT 5
`);
console.table(surgeryResult.rows);
} catch (err) {
console.error('查询失败:', err.message);
} finally {
pool.end();
}
}
analyze();

1
auto-confirm-skill Submodule

Submodule auto-confirm-skill added at 569e5191a5

72
check_id_match.js Normal file
View File

@@ -0,0 +1,72 @@
const { Pool } = require('pg');
const pool = new Pool({
host: '47.116.196.11',
port: 15432,
database: 'postgresql',
user: 'postgresql',
password: 'Jchl1528'
});
async function checkIdMatch() {
try {
// 1. 检查 op_schedule 中的 apply_id
console.log('=== 手术安排中的 apply_id ===');
const scheduleResult = await pool.query(`
SELECT DISTINCT apply_id
FROM hisdev.op_schedule
WHERE delete_flag = '0'
ORDER BY apply_id DESC
LIMIT 10
`);
console.log('apply_id 列表:', scheduleResult.rows.map(r => r.apply_id));
// 2. 检查 cli_surgery 中存在的 id
console.log('\n=== 手术申请中的 id ===');
const surgeryResult = await pool.query(`
SELECT id, surgery_no
FROM hisdev.cli_surgery
WHERE delete_flag = '0'
ORDER BY create_time DESC
LIMIT 10
`);
console.table(surgeryResult.rows);
// 3. 检查 ID 类型
console.log('\n=== 检查 ID 字段类型 ===');
const typeResult = await pool.query(`
SELECT
column_name,
data_type,
character_maximum_length
FROM information_schema.columns
WHERE table_schema = 'hisdev'
AND table_name IN ('op_schedule', 'cli_surgery')
AND column_name IN ('id', 'apply_id')
ORDER BY table_name, column_name
`);
console.table(typeResult.rows);
// 4. 尝试匹配
console.log('\n=== 尝试匹配 ===');
const matchResult = await pool.query(`
SELECT
os.schedule_id,
os.apply_id,
cs.id as surgery_id,
CASE WHEN cs.id IS NULL THEN '未找到' ELSE '已找到' END as match_status
FROM hisdev.op_schedule os
LEFT JOIN hisdev.cli_surgery cs ON os.apply_id = cs.id
WHERE os.delete_flag = '0'
ORDER BY os.create_time DESC
LIMIT 5
`);
console.table(matchResult.rows);
} catch (err) {
console.error('查询失败:', err.message);
} finally {
pool.end();
}
}
checkIdMatch();

31
check_nulls.js Normal file
View File

@@ -0,0 +1,31 @@
const { Pool } = require('pg');
const pool = new Pool({
host: '47.116.196.11',
port: 15432,
database: 'postgresql',
user: 'postgresql',
password: 'Jchl1528'
});
const query = `
SELECT
COUNT(*) as total_count,
COUNT(apply_dept_id) as has_apply_dept_id_count,
COUNT(apply_dept_name) as has_apply_dept_name_count,
COUNT(*) - COUNT(apply_dept_name) as apply_dept_name_null_count,
COUNT(main_surgeon_id) as has_main_surgeon_id_count,
COUNT(main_surgeon_name) as has_main_surgeon_name_count,
COUNT(*) - COUNT(main_surgeon_name) as main_surgeon_name_null_count
FROM hisdev.cli_surgery
WHERE delete_flag = '0'
`;
pool.query(query, (err, res) => {
if (err) {
console.error('Error:', err.message);
} else {
console.log('=== 当前 cli_surgery 表空值统计 ===');
console.log(JSON.stringify(res.rows[0], null, 2));
}
pool.end();
});

67
check_surgery_save.js Normal file
View File

@@ -0,0 +1,67 @@
const { Pool } = require('pg');
const pool = new Pool({
host: '47.116.196.11',
port: 15432,
database: 'postgresql',
user: 'postgresql',
password: 'Jchl1528'
});
async function checkLatestSurgery() {
try {
console.log('=== 检查最近创建的手术安排 ===\n');
// 1. 查询最近创建的手术安排
const latestSchedule = await pool.query(`
SELECT
os.schedule_id,
os.oper_code,
os.oper_name,
os.apply_id,
os.create_time,
cs.apply_dept_id,
cs.apply_dept_name,
cs.main_surgeon_id,
cs.main_surgeon_name,
cs.surgery_no
FROM hisdev.op_schedule os
LEFT JOIN hisdev.cli_surgery cs ON os.apply_id = cs.id
WHERE os.delete_flag = '0'
ORDER BY os.create_time DESC
LIMIT 5
`);
console.log('最近5条手术安排');
console.table(latestSchedule.rows);
// 2. 检查是否有空值
const nullCheck = await pool.query(`
SELECT
COUNT(*) as total,
COUNT(CASE WHEN cs.apply_dept_name IS NULL OR cs.apply_dept_name = '' THEN 1 END) as null_apply_dept,
COUNT(CASE WHEN cs.main_surgeon_name IS NULL OR cs.main_surgeon_name = '' THEN 1 END) as null_surgeon
FROM hisdev.op_schedule os
LEFT JOIN hisdev.cli_surgery cs ON os.apply_id = cs.id
WHERE os.delete_flag = '0'
AND os.create_time > NOW() - INTERVAL '1 hour'
`);
console.log('\n=== 最近1小时内创建的手术安排 ===');
console.log(`总计: ${nullCheck.rows[0].total}`);
console.log(`申请科室为空的: ${nullCheck.rows[0].null_apply_dept}`);
console.log(`主刀医生为空的: ${nullCheck.rows[0].null_surgeon}`);
if (parseInt(nullCheck.rows[0].null_apply_dept) === 0 && parseInt(nullCheck.rows[0].null_surgeon) === 0) {
console.log('\n✅ 所有字段都已正确保存!');
} else {
console.log('\n⚠ 仍有部分字段为空,请检查后端代码是否已部署');
}
} catch (err) {
console.error('查询失败:', err.message);
} finally {
pool.end();
}
}
checkLatestSurgery();

76
find_missing_ids.js Normal file
View File

@@ -0,0 +1,76 @@
const { Pool } = require('pg');
const pool = new Pool({
host: '47.116.196.11',
port: 15432,
database: 'postgresql',
user: 'postgresql',
password: 'Jchl1528'
});
async function findMissingIds() {
try {
// 1. 查找 op_schedule 中存在的 apply_id但在 cli_surgery 中不存在的
console.log('=== 查找不匹配的 apply_id ===\n');
const result = await pool.query(`
SELECT DISTINCT os.apply_id
FROM hisdev.op_schedule os
LEFT JOIN hisdev.cli_surgery cs ON os.apply_id = cs.id
WHERE os.delete_flag = '0'
AND cs.id IS NULL
ORDER BY os.apply_id DESC
LIMIT 10
`);
console.log('在 op_schedule 中存在,但在 cli_surgery 中不存在的 apply_id:');
console.table(result.rows);
// 2. 尝试用这些 ID 直接查询 cli_surgery
if (result.rows.length > 0) {
console.log('\n=== 尝试直接查询这些 ID ===');
for (const row of result.rows) {
const id = row.apply_id;
const checkResult = await pool.query(`
SELECT id, surgery_no, patient_name, status_enum, delete_flag
FROM hisdev.cli_surgery
WHERE id = $1
`, [id]);
if (checkResult.rows.length === 0) {
console.log(`ID ${id}: 在 cli_surgery 表中不存在`);
} else {
console.log(`ID ${id}: 找到记录`, checkResult.rows[0]);
}
}
}
// 3. 检查是否有可能是手术单号匹配而不是 ID 匹配
console.log('\n=== 检查手术单号关联 ===');
const operCodeResult = await pool.query(`
SELECT
os.schedule_id,
os.oper_code,
os.apply_id,
cs.id as surgery_id_by_apply_id,
cs2.id as surgery_id_by_oper_code,
cs2.surgery_no,
cs2.apply_dept_name,
cs2.main_surgeon_name
FROM hisdev.op_schedule os
LEFT JOIN hisdev.cli_surgery cs ON os.apply_id = cs.id
LEFT JOIN hisdev.cli_surgery cs2 ON os.oper_code = cs2.surgery_no
WHERE os.delete_flag = '0'
ORDER BY os.create_time DESC
LIMIT 5
`);
console.table(operCodeResult.rows);
} catch (err) {
console.error('查询失败:', err.message);
} finally {
pool.end();
}
}
findMissingIds();

105
fix_surgery_data.js Normal file
View File

@@ -0,0 +1,105 @@
const { Pool } = require('pg');
const pool = new Pool({
host: '47.116.196.11',
port: 15432,
database: 'postgresql',
user: 'postgresql',
password: 'Jchl1528'
});
async function fixData() {
const client = await pool.connect();
try {
await client.query('BEGIN');
// 1. 修复申请科室名称
console.log('步骤1: 修复申请科室名称...');
const fixDeptResult = await client.query(`
UPDATE hisdev.cli_surgery s
SET apply_dept_name = o.name
FROM hisdev.adm_organization o
WHERE s.apply_dept_id = o.id
AND (s.apply_dept_name IS NULL OR s.apply_dept_name = '')
AND s.delete_flag = '0'
`);
console.log(` 修复了 ${fixDeptResult.rowCount} 条申请科室记录`);
// 2. 修复主刀医生姓名
console.log('步骤2: 修复主刀医生姓名...');
const fixSurgeonResult = await client.query(`
UPDATE hisdev.cli_surgery s
SET main_surgeon_name = u.nick_name
FROM hisdev.sys_user u
WHERE s.main_surgeon_id = u.user_id
AND (s.main_surgeon_name IS NULL OR s.main_surgeon_name = '')
AND s.delete_flag = '0'
`);
console.log(` 修复了 ${fixSurgeonResult.rowCount} 条主刀医生记录`);
// 3. 对于 apply_dept_id 为空但有 org_id 的记录,使用 org_name
console.log('步骤3: 使用 org_name 填充剩余空申请科室...');
const fixOrgResult = await client.query(`
UPDATE hisdev.cli_surgery s
SET apply_dept_name = o.name,
apply_dept_id = s.org_id
FROM hisdev.adm_organization o
WHERE s.org_id = o.id
AND (s.apply_dept_name IS NULL OR s.apply_dept_name = '')
AND s.delete_flag = '0'
`);
console.log(` 修复了 ${fixOrgResult.rowCount} 条使用org_name的记录`);
// 4. 验证修复结果
console.log('步骤4: 验证修复结果...');
const checkResult = await client.query(`
SELECT
COUNT(*) as total_count,
COUNT(apply_dept_name) as has_apply_dept_name_count,
COUNT(*) - COUNT(apply_dept_name) as apply_dept_name_null_count,
COUNT(main_surgeon_name) as has_main_surgeon_name_count,
COUNT(*) - COUNT(main_surgeon_name) as main_surgeon_name_null_count
FROM hisdev.cli_surgery
WHERE delete_flag = '0'
`);
console.log('\n=== 修复后统计 ===');
console.log(JSON.stringify(checkResult.rows[0], null, 2));
// 5. 查看仍有空值的记录
const nullRecords = await client.query(`
SELECT
id,
surgery_no,
patient_name,
apply_dept_id,
apply_dept_name,
main_surgeon_id,
main_surgeon_name
FROM hisdev.cli_surgery
WHERE delete_flag = '0'
AND (apply_dept_name IS NULL OR apply_dept_name = '' OR main_surgeon_name IS NULL OR main_surgeon_name = '')
ORDER BY create_time DESC
LIMIT 10
`);
if (nullRecords.rows.length > 0) {
console.log('\n=== 仍有空值的记录 ===');
console.log(JSON.stringify(nullRecords.rows, null, 2));
} else {
console.log('\n✅ 所有记录的申请科室和主刀医生姓名已修复完毕!');
}
await client.query('COMMIT');
console.log('\n修复完成');
} catch (err) {
await client.query('ROLLBACK');
console.error('修复失败:', err.message);
} finally {
client.release();
pool.end();
}
}
fixData();

70
md/BUG_ANALYSIS.md Normal file
View File

@@ -0,0 +1,70 @@
# HIS项目 Bug 分析与修复日志
## 2026-04-05 23:55 - 子龙开始工作
### Bug 334 分析:门诊医生站-检验申请界面按钮布局优化
**文件位置**
- `/openhis-ui-vue3/src/views/doctorstation/components/inspection/inspectionApplication.vue`
**当前布局问题**
1. 顶部操作按钮区高度 60px可能有优化空间
2. 表单区域 padding 较大
3. 需要优化垂直空间利用率
**修复方案**
- 减少不必要的 padding 和 margin
- 优化表单字段布局
- 调整按钮区域高度
---
### Bug 335 分析:门诊医生站开立药品医嘱点击【保存】时报错
**文件位置**
- `/openhis-server-new/openhis-application/src/main/java/com/openhis/web/doctorstation/appservice/impl/DoctorStationAdviceAppServiceImpl.java`
**问题定位**
- 方法:`saveAdvice()` -> `handMedication()`
- 可能原因:
1. encounterId 或 patientId 为 null
2. 库存校验失败
3. 账户ID缺失
**代码已修复**
- 行 488-588已添加 encounterId 和 patientId 校验
- 行 497-588自动补全逻辑
---
### Bug 336 分析:门诊医生站开立诊疗项目后点击【保存】报错
**文件位置**
- 同上文件
**问题定位**
- 方法:`saveAdvice()` -> `handService()`
- 可能原因:
1. effectiveOrgId执行科室为 null
2. accountId 为 null
**代码已修复**
- 行 1290-1390已添加 accountId 自动补全
- 行 1338-1343诊疗项目执行科室非空校验
---
## 工作分工
| Bug ID | 负责人 | 状态 |
|--------|--------|------|
| 334 | 子龙 | 分析中 |
| 335 | 关羽 | 待修复 |
| 336 | 关羽 | 待修复 |
| 338 | 关羽 | 待修复 |
## 下一步行动
1. 子龙修复 Bug 334检验申请界面布局优化
2. 关羽修复 Bug 335、336、338
3. 张飞测试验证

10
md/test.html Normal file
View File

@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试合并11111</title>
</head>
<body>
</body>
</html>

193
null_key_error_analysis.md Normal file
View File

@@ -0,0 +1,193 @@
# "element cannot be mapped to a null key" 错误分析报告
## 错误根本原因
该错误发生在 Java Stream 使用 `Collectors.groupingBy``Collectors.toMap` 时,**key 为 null** 导致的。
Java 的 `HashMap` 不允许 null key`HashMap` 的实现有关),当试图将元素映射到 null key 时,就会抛出此异常。
## 问题定位
### 1. 数据层问题 - SQL 查询返回 null
#### 位置1: ChargeItemMapper.xml (第71行)
**文件**: `openhis-server-new/openhis-domain/src/main/resources/mapper/administration/ChargeItemMapper.xml`
```sql
SELECT
...
contract.bus_no as contract_no, -- 第71行
...
FROM adm_charge_item a
...
LEFT JOIN adm_account acc ON a.account_id = acc.id
LEFT JOIN fin_contract contract ON acc.contract_no = contract.bus_no -- LEFT JOIN
```
**问题**: 使用 LEFT JOIN 关联 `fin_contract` 表,当 `acc.contract_no` 为 null 或没有匹配的合同记录时,`contract.bus_no` 会返回 null。
#### 位置2: PaymentRecDetailMapper.xml (第37行)
**文件**: `openhis-server-new/openhis-domain/src/main/resources/mapper/financial/PaymentRecDetailMapper.xml`
```sql
SELECT
...
T2.contract_no, -- 第37行
...
FROM fin_payment_rec_detail T1
LEFT JOIN adm_account T2 ON T1.account_id = T2."id" -- LEFT JOIN
```
**问题**: 使用 LEFT JOIN 关联 `adm_account` 表,当 `T1.account_id` 为 null 或没有匹配的账户记录时,`T2.contract_no` 会返回 null。
---
### 2. 业务层问题 - 使用 groupingBy 时 key 可能为 null
#### 位置1: PaymentRecServiceImpl.java (第2334行)
**文件**: `openhis-server-new/openhis-application/src/main/java/com/openhis/web/paymentmanage/appservice/impl/PaymentRecServiceImpl.java`
```java
// 2333-2334行
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
= chargeItemBaseInfoByIds.stream().collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
```
**风险**: 如果 `ChargeItemBaseInfoDto.contractNo` 为 null来自上述 SQL 查询),将抛出异常。
#### 位置2: PaymentRecServiceImpl.java (第2462行)
**文件**: `openhis-server-new/openhis-application/src/main/java/com/openhis/web/paymentmanage/appservice/impl/PaymentRecServiceImpl.java`
```java
// 2461-2462行
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
= chargeItemBaseInfoByIds.stream().collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
```
**风险**: 同上,如果 `contractNo` 为 null将抛出异常。
#### 位置3: PaymentRecServiceImpl.java (第2478行)
**文件**: `openhis-server-new/openhis-application/src/main/java/com/openhis/web/paymentmanage/appservice/impl/PaymentRecServiceImpl.java`
```java
// 2477-2478行
Map<Long, List<PaymentRecDetail>> payTransNoMap
= paymentRecDetails.stream().collect(Collectors.groupingBy(PaymentRecDetail::getAccountId));
```
**风险**: 如果 `PaymentRecDetail.accountId` 为 null将抛出异常。
#### 位置4: IChargeBillServiceImpl.java (第936行)
**文件**: `openhis-server-new/openhis-application/src/main/java/com/openhis/web/paymentmanage/appservice/impl/IChargeBillServiceImpl.java`
```java
// 935-936行
Map<String, List<PaymentRecDetailAccountResult>> paymentDetailsMapByContract = PaymentRecDetailAccountResultList
.stream().collect(Collectors.groupingBy(PaymentRecDetailAccountResult::getContractNo));
```
**风险**: 如果 `PaymentRecDetailAccountResult.contractNo` 为 null来自上述 SQL 查询),将抛出异常。
#### 位置5: IChargeBillServiceImpl.java (第1485行)
**文件**: `openhis-server-new/openhis-application/src/main/java/com/openhis/web/paymentmanage/appservice/impl/IChargeBillServiceImpl.java`
```java
// 1484-1485行
Map<String, List<PaymentRecDetailAccountResult>> paymentDetailsMapByContract = PaymentRecDetailAccountResultList
.stream().collect(Collectors.groupingBy(PaymentRecDetailAccountResult::getContractNo));
```
**风险**: 同上,如果 `contractNo` 为 null将抛出异常。
---
## 修复建议
### 方案1: 修改 SQL 查询,使用 COALESCE 处理 null (推荐)
修改 `ChargeItemMapper.xml` 第71行
```sql
-- 修改前
contract.bus_no as contract_no,
-- 修改后
COALESCE(contract.bus_no, 'DEFAULT') as contract_no,
```
修改 `PaymentRecDetailMapper.xml` 第37行
```sql
-- 修改前
T2.contract_no,
-- 修改后
COALESCE(T2.contract_no, 'DEFAULT') as contract_no,
```
### 方案2: 修改 Java 代码,过滤 null key
在使用 `groupingBy` 之前过滤掉 key 为 null 的数据:
```java
// 修改前
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
= chargeItemBaseInfoByIds.stream().collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
// 修改后
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
= chargeItemBaseInfoByIds.stream()
.filter(dto -> dto.getContractNo() != null)
.collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
```
### 方案3: 使用 null-safe 的收集器
自定义一个处理 null key 的收集器:
```java
public static <T, K> Collector<T, ?, Map<K, List<T>>> groupingByNullSafe(
Function<? super T, ? extends K> classifier) {
return Collectors.groupingBy(
classifier,
HashMap::new,
Collectors.toList()
);
}
```
---
## 建议修复优先级
1. **高优先级**: 修改 `ChargeItemMapper.xml``PaymentRecDetailMapper.xml` 的 SQL 查询
- 这是根本原因,修复后可以防止 null 值传播到 Java 层
2. **中优先级**: 修改 `PaymentRecServiceImpl.java` 第2334行和第2462行
- 这是门诊收费和住院结算的关键路径
3. **低优先级**: 修改 `IChargeBillServiceImpl.java` 第936行和第1485行
- 这是收费账单相关功能
---
## 与最近修改的关系
用户提到最近修改了 `OutpatientChargeAppMapper.xml`,增加了 `cli_surgery` 表关联。
虽然这个修改本身不会直接导致 `contract_no` 为 null但可能触发了某些收费流程使得原本不会执行的代码路径被执行从而暴露了这个潜在问题。
根本原因还是 `ChargeItemMapper.xml` 中的 SQL 查询使用了 LEFT JOIN 导致 `contract_no` 可能为 null。
---
## 验证方法
1. 检查数据库中是否存在 `account_id` 为 null 的 `adm_charge_item` 记录
2. 检查数据库中是否存在 `contract_no` 为 null 的 `adm_account` 记录
3. 在出现错误的收费操作中,打印相关 DTO 对象的 `contractNo` 字段值
```java
// 调试代码示例
chargeItemBaseInfoByIds.forEach(dto -> {
System.out.println("ChargeItem ID: " + dto.getId() + ", contractNo: " + dto.getContractNo());
});
```

View File

@@ -1,11 +1,15 @@
package com.core.framework.config;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;
/**
@@ -24,6 +28,14 @@ public class ApplicationConfig {
*/
@Bean
public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization() {
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
return builder -> {
// 设置默认时区
builder.timeZone(TimeZone.getDefault());
// 设置日期格式为 yyyy/M/d HH:mm:ss支持多种格式反序列化
builder.simpleDateFormat("yyyy/M/d HH:mm:ss");
// 添加JavaTimeModule支持用于LocalDateTime
builder.modules(new JavaTimeModule());
builder.serializerByType(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy/M/d HH:mm:ss")));
};
}
}

View File

@@ -1,8 +1,10 @@
package com.openhis.web.appointmentmanage.appservice.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.core.common.core.domain.R;
import com.core.common.utils.SecurityUtils;
import com.openhis.common.constant.CommonConstants;
import com.openhis.appointmentmanage.domain.DoctorSchedule;
import com.openhis.appointmentmanage.domain.DoctorScheduleWithDateDto;
import com.openhis.appointmentmanage.domain.SchedulePool;
@@ -497,6 +499,15 @@ public class DoctorScheduleAppServiceImpl implements IDoctorScheduleAppService {
if (ObjectUtil.isNotEmpty(pools)) {
List<Long> poolIds = pools.stream().map(SchedulePool::getId).collect(java.util.stream.Collectors.toList());
// 该排班下存在有效患者预约(号源槽:已预约/已锁定/已取号)则禁止删除;已退号、仅可用/已取消槽位不计入
long appointmentCount = scheduleSlotService.count(new QueryWrapper<ScheduleSlot>()
.in("pool_id", poolIds)
.in("status", CommonConstants.SlotStatus.BOOKED, CommonConstants.SlotStatus.LOCKED,
CommonConstants.SlotStatus.CHECKED_IN));
if (appointmentCount > 0) {
return R.fail("该排班已有患者预约,禁止删除!如需取消请先处理患者退预约或使用'停诊'功能。");
}
// 2. 根据号源池ID找到所有关联的号源槽
List<ScheduleSlot> slots = scheduleSlotService.list(
new com.baomidou.mybatisplus.core.conditions.query.QueryWrapper<ScheduleSlot>()

View File

@@ -16,6 +16,7 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -123,6 +124,7 @@ public class TicketAppServiceImpl implements ITicketAppService {
if (query == null) {
query = new com.openhis.appointmentmanage.dto.TicketQueryDTO();
}
normalizeQueryStatus(query);
// 2. 构造 MyBatis 的分页对象 (传入前端给的当前页和每页条数)
com.baomidou.mybatisplus.extension.plugins.pagination.Page<com.openhis.appointmentmanage.domain.TicketSlotDTO> pageParam = new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(
@@ -140,42 +142,67 @@ public class TicketAppServiceImpl implements ITicketAppService {
// 基础字段映射
dto.setSlot_id(raw.getSlotId());
dto.setSeqNo(raw.getSeqNo());
dto.setBusNo(String.valueOf(raw.getSlotId()));
dto.setDoctor(raw.getDoctor());
dto.setDepartment(raw.getDepartmentName()); // 注意以前这里传成了ID导致前端出Bug现在修复成了真正的科室名
dto.setFee(raw.getFee());
dto.setPatientName(raw.getPatientName());
dto.setPatientId(raw.getPatientId() != null ? String.valueOf(raw.getPatientId()) : null);
dto.setPatientId(raw.getMedicalCard());
dto.setPhone(raw.getPhone());
dto.setIdCard(raw.getIdCard());
dto.setDoctorId(raw.getDoctorId());
dto.setDepartmentId(raw.getDepartmentId());
dto.setRealPatientId(raw.getPatientId());
// 性别处理:直接读取优先级最高的订单性别字段 (SQL 已处理优先级)
if (raw.getPatientGender() != null) {
String pg = raw.getPatientGender().trim();
dto.setGender("1".equals(pg) ? "" : ("2".equals(pg) ? "" : "未知"));
} else {
dto.setGender("未知");
}
// 号源类型处理 (底层是1前端要的是expert)
if (raw.getRegType() != null && raw.getRegType() == 1) {
dto.setTicketType("expert");
} else {
dto.setTicketType("general");
}
// 拼接就诊时间
if (raw.getScheduleDate() != null && raw.getExpectTime() != null) {
dto.setDateTime(raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
try {
dto.setAppointmentDate(
new java.text.SimpleDateFormat("yyyy-MM-dd").parse(raw.getScheduleDate().toString()));
String timeStr = raw.getAppointmentTime() != null ? raw.getAppointmentTime() : (raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(timeStr.length() > 10 ? "yyyy-MM-dd HH:mm" : "yyyy-MM-dd");
java.util.Date date = sdf.parse(timeStr);
dto.setAppointmentDate(date);
dto.setAppointmentTime(date);
} catch (Exception e) {
dto.setAppointmentDate(new java.util.Date());
}
}
// 精准状态翻译把底层的1和2翻译回前端能懂的中文
if (Boolean.TRUE.equals(raw.getIsStopped())) {
dto.setStatus("已停诊");
} else {
Integer slotStatus = raw.getSlotStatus();
if (slotStatus != null) {
if (SlotStatus.BOOKED.equals(slotStatus)) {
dto.setStatus(AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus()) ? "已取号" : "已预约");
} else if (SlotStatus.STOPPED.equals(slotStatus)) {
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
dto.setStatus("已取号");
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
if (AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus())) {
dto.setStatus("已取号");
} else if (AppointmentOrderStatus.RETURNED.equals(raw.getOrderStatus())) {
dto.setStatus("已退号");
} else {
dto.setStatus("已预约");
}
} else if (SlotStatus.RETURNED.equals(slotStatus)) {
dto.setStatus("已退号");
} else if (SlotStatus.CANCELLED.equals(slotStatus)) {
dto.setStatus("已停诊");
} else if (SlotStatus.LOCKED.equals(slotStatus)) {
dto.setStatus("已锁定");
} else {
dto.setStatus("未预约");
}
@@ -198,6 +225,62 @@ public class TicketAppServiceImpl implements ITicketAppService {
return R.ok(result);
}
/**
* 统一状态入参,避免前端状态值大小写/中文/数字差异导致 SQL 条件失效后回全量数据
*/
private void normalizeQueryStatus(com.openhis.appointmentmanage.dto.TicketQueryDTO query) {
String rawStatus = query.getStatus();
if (rawStatus == null) {
return;
}
String normalized = rawStatus.trim();
if (normalized.isEmpty()) {
query.setStatus(null);
return;
}
String lower = normalized.toLowerCase(Locale.ROOT);
switch (lower) {
case "all":
case "全部":
query.setStatus("all");
break;
case "unbooked":
case "0":
case "未预约":
query.setStatus("unbooked");
break;
case "booked":
case "1":
case "已预约":
query.setStatus("booked");
break;
case "checked":
case "checkin":
case "checkedin":
case "2":
case "已取号":
query.setStatus("checked");
break;
case "cancelled":
case "canceled":
case "3":
case "已停诊":
case "已取消":
query.setStatus("cancelled");
break;
case "returned":
case "4":
case "5":
case "已退号":
query.setStatus("returned");
break;
default:
// 设置为 impossible 值,配合 mapper 的 otherwise 分支直接返回空
query.setStatus("__invalid__");
break;
}
}
@Override
public R<?> listDoctorAvailability(com.openhis.appointmentmanage.dto.TicketQueryDTO query) {
if (query == null) {
@@ -237,12 +320,13 @@ public class TicketAppServiceImpl implements ITicketAppService {
// --- 基础字段处理 ---
// 注意:这里已经变成了极其舒服的 .getSlotId() 方法调用,告别魔鬼字符串!
dto.setSlot_id(raw.getSlotId());
dto.setSeqNo(raw.getSeqNo());
dto.setBusNo(String.valueOf(raw.getSlotId())); // 暂时借用真实槽位ID做唯一流水号
dto.setDoctor(raw.getDoctor());
dto.setDepartment(raw.getDepartmentName());
dto.setFee(raw.getFee());
dto.setPatientName(raw.getPatientName());
dto.setPatientId(raw.getPatientId() != null ? String.valueOf(raw.getPatientId()) : null);
dto.setPatientId(raw.getMedicalCard());
dto.setPhone(raw.getPhone());
// --- 号源类型处理 (普通/专家) ---
@@ -258,9 +342,13 @@ public class TicketAppServiceImpl implements ITicketAppService {
if (raw.getScheduleDate() != null && raw.getExpectTime() != null) {
dto.setDateTime(raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
try {
dto.setAppointmentDate(
new java.text.SimpleDateFormat("yyyy-MM-dd").parse(raw.getScheduleDate().toString()));
String timeStr = raw.getAppointmentTime() != null ? raw.getAppointmentTime() : (raw.getScheduleDate().toString() + " " + raw.getExpectTime().toString());
java.text.SimpleDateFormat sdf = new java.text.SimpleDateFormat(timeStr.length() > 10 ? "yyyy-MM-dd HH:mm" : "yyyy-MM-dd");
java.util.Date date = sdf.parse(timeStr);
dto.setAppointmentDate(date);
dto.setAppointmentTime(date);
} catch (Exception e) {
log.error("时间解析失败", e);
dto.setAppointmentDate(new java.util.Date());
}
}
@@ -273,10 +361,22 @@ public class TicketAppServiceImpl implements ITicketAppService {
// 第二关:看独立的细分槽位状态 (0: 可用, 1: 已预约, 2: 已取消...)
Integer slotStatus = raw.getSlotStatus();
if (slotStatus != null) {
if (SlotStatus.BOOKED.equals(slotStatus)) {
dto.setStatus(AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus()) ? "已取号" : "已预约");
} else if (SlotStatus.STOPPED.equals(slotStatus)) {
dto.setStatus("已停诊"); // 视业务可改回已取消
if (SlotStatus.CHECKED_IN.equals(slotStatus)) {
dto.setStatus("已取号");
} else if (SlotStatus.BOOKED.equals(slotStatus)) {
if (AppointmentOrderStatus.CHECKED_IN.equals(raw.getOrderStatus())) {
dto.setStatus("已取号");
} else if (AppointmentOrderStatus.RETURNED.equals(raw.getOrderStatus())) {
dto.setStatus("已退号");
} else {
dto.setStatus("已预约");
}
} else if (SlotStatus.RETURNED.equals(slotStatus)) {
dto.setStatus("已退号");
} else if (SlotStatus.CANCELLED.equals(slotStatus)) {
dto.setStatus("已停诊");
} else if (SlotStatus.LOCKED.equals(slotStatus)) {
dto.setStatus("已锁定");
} else {
dto.setStatus("未预约");
}
@@ -355,15 +455,12 @@ public class TicketAppServiceImpl implements ITicketAppService {
if (patient != null) {
Integer genderEnum = patient.getGenderEnum();
if (genderEnum != null) {
switch (genderEnum) {
case 1:
dto.setGender("");
break;
case 2:
dto.setGender("");
break;
default:
dto.setGender("未知");
if (Integer.valueOf(1).equals(genderEnum)) {
dto.setGender("");
} else if (Integer.valueOf(2).equals(genderEnum)) {
dto.setGender("");
} else {
dto.setGender("未知");
}
}
}

View File

@@ -23,6 +23,11 @@ public class TicketDto {
@JsonSerialize(using = ToStringSerializer.class)
private Long slot_id;
/**
* 号源序号(对应 adm_schedule_slot.seq_no
*/
private Integer seqNo;
/**
* 号源编码
*/
@@ -99,4 +104,15 @@ public class TicketDto {
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long doctorId;
/**
* 真实患者ID数据库主键区别于 patientId 存的就诊卡号)
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long realPatientId;
/**
* 身份证号
*/
private String idCard;
}

View File

@@ -73,11 +73,10 @@ public class OutpatientPricingAppServiceImpl implements IOutpatientPricingAppSer
} else {
adviceTypes = List.of(1, 2, 3);
}
// 门诊划价:不要强制 pricingFlag=1 参与过滤wor_activity_definition.pricing_flag 可能为 0
// 否则会导致诊疗项目(adviceType=3)查询结果为空 records=[]
String categoryCode = adviceBaseDto != null ? adviceBaseDto.getCategoryCode() : null;
// 门诊划价:仅返回划价标记为“是”的项目
return iDoctorStationAdviceAppService.getAdviceBaseInfo(adviceBaseDto, searchKey, locationId, null,
organizationId, pageNo, pageSize, null, adviceTypes, null, categoryCode);
organizationId, pageNo, pageSize, Whether.YES.getValue(), adviceTypes, null, categoryCode);
}
}

View File

@@ -22,6 +22,10 @@ import com.openhis.common.enums.ybenums.YbPayment;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisPageUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.appointmentmanage.mapper.SchedulePoolMapper;
import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper;
import com.openhis.clinical.domain.Order;
import com.openhis.clinical.service.IOrderService;
import com.openhis.financial.domain.PaymentReconciliation;
import com.openhis.financial.domain.RefundLog;
import com.openhis.financial.service.IRefundLogService;
@@ -48,6 +52,7 @@ import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
@@ -97,6 +102,15 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
@Resource
IRefundLogService iRefundLogService;
@Resource
IOrderService orderService;
@Resource
ScheduleSlotMapper scheduleSlotMapper;
@Resource
SchedulePoolMapper schedulePoolMapper;
/**
* 门诊挂号 - 查询患者信息
*
@@ -291,6 +305,11 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
}
}
// 如果本次门诊挂号来自预约签到,同步把预约订单与号源槽位状态改为已退号
if (result != null && result.getCode() == 200) {
syncAppointmentReturnStatus(byId, cancelRegPaymentDto.getReason());
}
// 记录退号日志
recordRefundLog(cancelRegPaymentDto, byId, result, paymentRecon);
@@ -399,6 +418,74 @@ public class OutpatientRegistrationAppServiceImpl implements IOutpatientRegistra
return R.ok("已取消挂号");
}
/**
* 同步预约号源状态为已退号。
* 说明:
* 1) 门诊退号主流程不依赖该步骤成功与否,因此此方法内部异常仅记录日志,不向上抛出。
* 2) 通过患者、科室、日期以及状态筛选最近一条预约订单,尽量避免误匹配。
*/
private void syncAppointmentReturnStatus(Encounter encounter, String reason) {
if (encounter == null || encounter.getPatientId() == null) {
return;
}
try {
LambdaQueryWrapper<Order> queryWrapper = new LambdaQueryWrapper<Order>()
.eq(Order::getPatientId, encounter.getPatientId())
.in(Order::getStatus, CommonConstants.AppointmentOrderStatus.BOOKED,
CommonConstants.AppointmentOrderStatus.CHECKED_IN)
.orderByDesc(Order::getUpdateTime)
.orderByDesc(Order::getCreateTime)
.last("LIMIT 1");
if (encounter.getOrganizationId() != null) {
queryWrapper.eq(Order::getDepartmentId, encounter.getOrganizationId());
}
if (encounter.getTenantId() != null) {
queryWrapper.eq(Order::getTenantId, encounter.getTenantId());
}
if (encounter.getCreateTime() != null) {
LocalDate encounterDate = encounter.getCreateTime().toInstant()
.atZone(ZoneId.systemDefault()).toLocalDate();
Date startOfDay = Date.from(encounterDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
Date nextDayStart = Date.from(encounterDate.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant());
queryWrapper.ge(Order::getAppointmentDate, startOfDay)
.lt(Order::getAppointmentDate, nextDayStart);
}
Order appointmentOrder = orderService.getOne(queryWrapper, false);
if (appointmentOrder == null) {
return;
}
Date now = new Date();
if (!CommonConstants.AppointmentOrderStatus.RETURNED.equals(appointmentOrder.getStatus())) {
Order updateOrder = new Order();
updateOrder.setId(appointmentOrder.getId());
updateOrder.setStatus(CommonConstants.AppointmentOrderStatus.RETURNED);
updateOrder.setCancelTime(now);
updateOrder.setCancelReason(
StringUtils.isNotEmpty(reason) ? reason : "门诊退号");
updateOrder.setUpdateTime(now);
orderService.updateById(updateOrder);
}
Long slotId = appointmentOrder.getSlotId();
if (slotId == null) {
return;
}
int slotRows = scheduleSlotMapper.updateSlotStatus(slotId, CommonConstants.SlotStatus.RETURNED);
if (slotRows > 0) {
Long poolId = scheduleSlotMapper.selectPoolIdBySlotId(slotId);
if (poolId != null) {
schedulePoolMapper.refreshPoolStats(poolId);
}
}
} catch (Exception e) {
log.warn("同步预约号源已退号状态失败, encounterId={}", encounter.getId(), e);
}
}
/**
* 补打挂号
* 补打挂号不需要修改数据库,只需要返回成功即可,前端已有所有需要的数据用于打印

View File

@@ -343,7 +343,24 @@ public class SurgeryAppServiceImpl implements ISurgeryAppService {
serviceRequest.setEncounterId(surgeryDto.getEncounterId()); // 就诊id
serviceRequest.setAuthoredTime(curDate); // 请求签发时间
serviceRequest.setOrgId(orgId); // 执行科室
// 🔧 BugFix#318: 设置 contentJson包含手术名称
Map<String, String> serviceContentMap = new HashMap<>();
String surgeryNameFromDto = surgeryDto.getSurgeryName();
String surgeryCodeFromDto = surgeryDto.getSurgeryCode();
log.info("【DEBUG】surgeryName from DTO: {}", surgeryNameFromDto);
log.info("【DEBUG】surgeryCode from DTO: {}", surgeryCodeFromDto);
serviceContentMap.put("surgeryName", surgeryNameFromDto != null ? surgeryNameFromDto : "");
serviceContentMap.put("surgeryCode", surgeryCodeFromDto != null ? surgeryCodeFromDto : "");
try {
String contentJson = new ObjectMapper().writeValueAsString(serviceContentMap);
log.info("【DEBUG】Setting contentJson: {}", contentJson);
serviceRequest.setContentJson(contentJson);
} catch (JsonProcessingException e) {
log.error("【DEBUG】设置手术医嘱 contentJson 失败", e);
}
serviceRequestService.save(serviceRequest);
log.info("【DEBUG】Saved serviceRequest with ID: {}, contentJson: {}",
serviceRequest.getId(), serviceRequest.getContentJson());
// 生成收费项目
ChargeItem chargeItem = new ChargeItem();

View File

@@ -371,7 +371,7 @@ public class SurgicalScheduleAppServiceImpl implements ISurgicalScheduleAppServi
index, // 序号从1开始
schedule.getOrgName() != null ? schedule.getOrgName() : "",
schedule.getPatientName() != null ? schedule.getPatientName() : "",
schedule.getVisitId() != null ? schedule.getVisitId().toString() : "",
schedule.getIdentifierNo() != null ? schedule.getIdentifierNo() : "",
schedule.getOperCode() != null ? schedule.getOperCode() : "",
schedule.getOperName() != null ? schedule.getOperName() : "",
schedule.getApplyDeptName() != null ? schedule.getApplyDeptName() : "",

View File

@@ -24,6 +24,11 @@ public class OpCreateScheduleDto {
*/
private Long visitId;
/**
* 就诊卡号
*/
private String identifierNo;
/**
* 手术编码
*/

View File

@@ -43,6 +43,11 @@ public class OpScheduleDto extends OpSchedule {
*/
private Long encounterId;
/**
* 就诊卡号
*/
private String patientCardNo;
/**
* 性别
*/

View File

@@ -2,6 +2,7 @@ package com.openhis.web.clinicalmanage.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.openhis.common.annotation.Dict;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -45,6 +46,9 @@ public class SurgeryDto {
/** 就诊流水号 */
private String encounterNo;
/** 就诊卡号 */
private String patientCardNo;
/** 申请医生ID */
@JsonSerialize(using = ToStringSerializer.class)
private Long applyDoctorId;
@@ -84,6 +88,7 @@ public class SurgeryDto {
private String statusEnum_dictText;
/** 计划手术时间 */
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss", timezone = "GMT+8")
private Date plannedTime;
/** 实际开始时间 */

View File

@@ -421,6 +421,20 @@ public class ConsultationAppServiceImpl implements IConsultationAppService {
// 新增:更新门诊医嘱表状态为已提交
updateServiceRequestStatus(entity.getOrderId(), RequestStatus.ACTIVE.getValue());
// 🎯 更新会诊关联费用项状态为"待收费",提交后即可在收费界面看到
if (entity.getOrderId() != null) {
LambdaQueryWrapper<ChargeItem> chargeItemWrapper = new LambdaQueryWrapper<>();
chargeItemWrapper.eq(ChargeItem::getServiceId, entity.getOrderId())
.eq(ChargeItem::getServiceTable, "wor_service_request");
List<ChargeItem> chargeItems = iChargeItemService.list(chargeItemWrapper);
for (ChargeItem chargeItem : chargeItems) {
chargeItem.setStatusEnum(ChargeItemStatus.PLANNED.getValue());
iChargeItemService.updateById(chargeItem);
}
log.info("会诊提交,更新关联费用项状态为待收费,更新数量: {}", chargeItems.size());
}
return true;
} catch (Exception e) {
log.error("提交会诊申请失败", e);
@@ -464,6 +478,18 @@ public class ConsultationAppServiceImpl implements IConsultationAppService {
// 更新门诊医嘱表状态为新开
updateServiceRequestStatus(entity.getOrderId(), RequestStatus.DRAFT.getValue());
// 更新关联费用项状态为草稿
if (entity.getOrderId() != null) {
LambdaQueryWrapper<ChargeItem> chargeItemWrapper = new LambdaQueryWrapper<>();
chargeItemWrapper.eq(ChargeItem::getServiceId, entity.getOrderId())
.eq(ChargeItem::getServiceTable, "wor_service_request");
List<ChargeItem> chargeItems = iChargeItemService.list(chargeItemWrapper);
for (ChargeItem chargeItem : chargeItems) {
chargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
iChargeItemService.updateById(chargeItem);
}
}
} else {
// 作废:状态校验 - 已确认(20)、已签名(30)、已完成(40) 状态禁止作废
ConsultationStatusEnum currentStatus = ConsultationStatusEnum.getByCode(entity.getConsultationStatus());
@@ -480,6 +506,18 @@ public class ConsultationAppServiceImpl implements IConsultationAppService {
// 更新门诊医嘱表状态为已作废
updateServiceRequestStatus(entity.getOrderId(), RequestStatus.CANCELLED.getValue());
// 更新关联费用项状态为终止
if (entity.getOrderId() != null) {
LambdaQueryWrapper<ChargeItem> chargeItemWrapper = new LambdaQueryWrapper<>();
chargeItemWrapper.eq(ChargeItem::getServiceId, entity.getOrderId())
.eq(ChargeItem::getServiceTable, "wor_service_request");
List<ChargeItem> chargeItems = iChargeItemService.list(chargeItemWrapper);
for (ChargeItem chargeItem : chargeItems) {
chargeItem.setStatusEnum(ChargeItemStatus.ABORTED.getValue());
iChargeItemService.updateById(chargeItem);
}
}
}
return true;
@@ -668,12 +706,14 @@ public class ConsultationAppServiceImpl implements IConsultationAppService {
@Override
public List<ConsultationRequestDto> getMyInvitations() {
try {
// 获取当前登录医生ID
// 获取当前登录医生ID和租户ID
Long currentPhysicianId = SecurityUtils.getLoginUser().getPractitionerId();
Long tenantId = SecurityUtils.getLoginUser().getTenantId().longValue();
// 查询邀请我的会诊申请
LambdaQueryWrapper<ConsultationInvited> invitedWrapper = new LambdaQueryWrapper<>();
invitedWrapper.eq(ConsultationInvited::getInvitedPhysicianId, currentPhysicianId)
invitedWrapper.eq(ConsultationInvited::getTenantId, tenantId)
.eq(ConsultationInvited::getInvitedPhysicianId, currentPhysicianId)
.orderByDesc(ConsultationInvited::getCreateTime);
List<ConsultationInvited> invitedList = consultationInvitedMapper.selectList(invitedWrapper);
@@ -1201,14 +1241,16 @@ public class ConsultationAppServiceImpl implements IConsultationAppService {
@Override
public List<ConsultationConfirmationDto> getPendingConfirmationList() {
try {
// 获取当前登录医生ID
// 获取当前登录医生ID和租户ID
Long currentPhysicianId = SecurityUtils.getLoginUser().getPractitionerId();
Long tenantId = SecurityUtils.getLoginUser().getTenantId().longValue();
log.info("获取待确认会诊列表当前医生ID: {}", currentPhysicianId);
// 🎯 关键修改:查询当前医生个人状态为"待确认"、"已确认"或"已签名"的邀请记录
// 10=已提交待确认、20=已确认待签名、30=已签名排除40=已完成
LambdaQueryWrapper<ConsultationInvited> invitedWrapper = new LambdaQueryWrapper<>();
invitedWrapper.eq(ConsultationInvited::getInvitedPhysicianId, currentPhysicianId)
invitedWrapper.eq(ConsultationInvited::getTenantId, tenantId)
.eq(ConsultationInvited::getInvitedPhysicianId, currentPhysicianId)
.in(ConsultationInvited::getInvitedStatus,
ConsultationStatusEnum.SUBMITTED.getCode(), // 10-待确认
ConsultationStatusEnum.CONFIRMED.getCode(), // 20-已确认(待签名)
@@ -1233,7 +1275,8 @@ public class ConsultationAppServiceImpl implements IConsultationAppService {
// 🎯 查询会诊申请详情(白名单:只查询正在进行中的会诊,明确业务范围)
// 查询已提交、已确认、已签名状态的会诊排除已完成40
LambdaQueryWrapper<ConsultationRequest> requestWrapper = new LambdaQueryWrapper<>();
requestWrapper.in(ConsultationRequest::getId, requestIds)
requestWrapper.eq(ConsultationRequest::getTenantId, tenantId)
.in(ConsultationRequest::getId, requestIds)
.in(ConsultationRequest::getConsultationStatus,
ConsultationStatusEnum.SUBMITTED.getCode(), // 10-已提交
ConsultationStatusEnum.CONFIRMED.getCode(), // 20-已确认
@@ -1322,10 +1365,13 @@ public class ConsultationAppServiceImpl implements IConsultationAppService {
}
// 4. 更新邀请记录(存储会诊意见)
// 格式:科室-医生:意见内容
// 格式:科室-会诊确认参加医师:意见内容
// 兼容:若前端未填写“会诊确认参加医师”,则回退为当前医生姓名
String confirmingPhysicianText =
StringUtils.hasText(dto.getConfirmingPhysician()) ? dto.getConfirmingPhysician().trim() : currentPhysicianName;
String formattedOpinion = String.format("%s-%s%s",
currentDeptName,
currentPhysicianName,
confirmingPhysicianText,
dto.getConsultationOpinion());
invited.setInvitedStatus(ConsultationStatusEnum.CONFIRMED.getCode()); // 已确认
@@ -1634,6 +1680,19 @@ public class ConsultationAppServiceImpl implements IConsultationAppService {
// 更新医嘱状态为"已完成"
updateServiceRequestStatus(request.getOrderId(), RequestStatus.COMPLETED.getValue());
// 🎯 更新会诊关联费用项状态为"待收费",这样收费界面就能看到了
if (request.getOrderId() != null) {
LambdaQueryWrapper<ChargeItem> chargeItemWrapper = new LambdaQueryWrapper<>();
chargeItemWrapper.eq(ChargeItem::getServiceId, request.getOrderId())
.eq(ChargeItem::getServiceTable, "wor_service_request");
List<ChargeItem> chargeItems = iChargeItemService.list(chargeItemWrapper);
for (ChargeItem chargeItem : chargeItems) {
chargeItem.setStatusEnum(ChargeItemStatus.PLANNED.getValue());
iChargeItemService.updateById(chargeItem);
}
log.info("会诊完成,更新关联费用项状态为待收费,更新数量: {}", chargeItems.size());
}
log.info("所有医生都已签名,会诊申请状态更新为:已签名(30)");
} else {
// 🎯 关键修改部分医生签名整体状态不变保持为10或20

View File

@@ -78,7 +78,6 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
private IOperationRecordService operationRecordService;
@Resource
private IServiceRequestService serviceRequestService;
/**
* 诊疗目录初期查询
*
@@ -240,9 +239,8 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
DiagnosisTreatmentSelParam.setPricingFlag(pricingFlagValue);
}
// 分页查询
IPage<DiagnosisTreatmentDto> diseaseTreatmentPage
= activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page<DiagnosisTreatmentDto>(pageNo, pageSize), queryWrapper);
= activityDefinitionManageMapper.getDiseaseTreatmentPage(new Page<>(pageNo, pageSize), queryWrapper);
diseaseTreatmentPage.getRecords().forEach(e -> {
// 医保标记枚举类回显赋值
@@ -447,24 +445,17 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
*/
@Override
public R<?> editDiseaseTreatmentStop(List<Long> ids) {
List<ActivityDefinition> ActivityDefinitionList = new CopyOnWriteArrayList<>();
// 取得更新值
for (Long detail : ids) {
ActivityDefinition ActivityDefinition = new ActivityDefinition();
ActivityDefinition.setId(detail);
ActivityDefinition.setStatusEnum(PublicationStatus.RETIRED.getValue());
ActivityDefinitionList.add(ActivityDefinition);
List<ActivityDefinition> actList = new CopyOnWriteArrayList<>();
for (Long id : ids) {
ActivityDefinition act = new ActivityDefinition();
act.setId(id);
act.setStatusEnum(PublicationStatus.RETIRED.getValue());
actList.add(act);
}
// 插入操作记录
operationRecordService.addIdsOperationRecord(DbOpType.STOP.getCode(),
CommonConstants.TableName.WOR_ACTIVITY_DEFINITION, ids);
// 更新诊疗信息
return activityDefinitionService.updateBatchById(ActivityDefinitionList)
? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"诊疗目录"}))
: R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
activityDefinitionService.updateBatchById(actList);
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"\u8bca\u7597\u76ee\u5f55"}));
}
/**
@@ -475,24 +466,17 @@ public class DiagTreatMAppServiceImpl implements IDiagTreatMAppService {
*/
@Override
public R<?> editDiseaseTreatmentStart(List<Long> ids) {
List<ActivityDefinition> ActivityDefinitionList = new CopyOnWriteArrayList<>();
// 取得更新值
for (Long detail : ids) {
ActivityDefinition ActivityDefinition = new ActivityDefinition();
ActivityDefinition.setId(detail);
ActivityDefinition.setStatusEnum(PublicationStatus.ACTIVE.getValue());
ActivityDefinitionList.add(ActivityDefinition);
List<ActivityDefinition> actList = new CopyOnWriteArrayList<>();
for (Long id : ids) {
ActivityDefinition act = new ActivityDefinition();
act.setId(id);
act.setStatusEnum(PublicationStatus.ACTIVE.getValue());
actList.add(act);
}
// 插入操作记录
operationRecordService.addIdsOperationRecord(DbOpType.START.getCode(),
CommonConstants.TableName.WOR_ACTIVITY_DEFINITION, ids);
// 更新诊疗信息
return activityDefinitionService.updateBatchById(ActivityDefinitionList)
? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"诊疗目录"}))
: R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
activityDefinitionService.updateBatchById(actList);
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"诊疗目录"}));
}
/**

View File

@@ -0,0 +1,51 @@
package com.openhis.web.datadictionary.mapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* 检验项目定义管理 Mapper操作 lab_activity_definition 表)
*/
@Repository
public interface LabActivityDefinitionManageMapper {
/**
* 检验项目分页查询
*
* @param page 分页参数
* @param queryWrapper 查询条件
* @return 分页结果
*/
IPage<DiagnosisTreatmentDto> getLabActivityDefinitionPage(
@Param("page") Page<DiagnosisTreatmentDto> page,
@Param(Constants.WRAPPER) QueryWrapper<DiagnosisTreatmentDto> queryWrapper);
/**
* 检验项目详情
*
* @param id 项目ID
* @param tenantId 租户ID
* @return 详情
*/
DiagnosisTreatmentDto getLabActivityDefinitionOne(@Param("id") Long id, @Param("tenantId") Integer tenantId);
/**
* 检验项目下拉列表(轻量级)
*
* @param statusEnum 状态
* @param tenantId 租户ID
* @param searchKey 搜索关键词(可选)
* @return 列表
*/
List<DiagnosisTreatmentDto> getLabActivityDefinitionSimpleList(
@Param("statusEnum") Integer statusEnum,
@Param("tenantId") Integer tenantId,
@Param("searchKey") String searchKey);
}

View File

@@ -205,6 +205,11 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
// 构建查询条件
QueryWrapper<AdviceBaseDto> queryWrapper = HisQueryUtils.buildQueryWrapper(adviceBaseDto, searchKey,
new HashSet<>(Arrays.asList("advice_name", "py_str", "wb_str")), null);
// 🔧 BugFix#339: 药房筛选条件失效 - 添加 locationId 过滤条件
if (locationId != null) {
queryWrapper.eq("location_id", locationId);
log.info("BugFix#339: 添加药房筛选条件 locationId={}", locationId);
}
IPage<AdviceBaseDto> adviceBaseInfo = doctorStationAdviceAppMapper.getAdviceBaseInfo(
new Page<>(pageNo, pageSize), PublicationStatus.ACTIVE.getValue(), organizationId,
CommonConstants.TableName.MED_MEDICATION_DEFINITION, CommonConstants.TableName.ADM_DEVICE_DEFINITION,
@@ -561,6 +566,25 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
return R.fail(null, "无法获取患者信息,请重新选择患者");
}
}
// 🔧 BugFix#338: 门诊划价新增时校验就诊状态和诊断记录(患者安全)
// 仅对新增/修改操作进行校验,删除操作不需要
if (!DbOpType.DELETE.getCode().equals(adviceSaveDto.getDbOpType())) {
// 1. 校验就诊状态:必须是已接诊状态
Encounter encounterCheck = iEncounterService.getById(adviceSaveDto.getEncounterId());
if (encounterCheck != null) {
// 就诊状态1=待诊(PLANNED),允许保存的状态 = 2(IN_PROGRESS在诊)、3(ON_HOLD暂离)、4(DISCHARGED诊毕)、5(COMPLETED完成)
if (encounterCheck.getStatusEnum() != null &&
encounterCheck.getStatusEnum() != EncounterStatus.IN_PROGRESS.getValue() &&
encounterCheck.getStatusEnum() != EncounterStatus.ON_HOLD.getValue() &&
encounterCheck.getStatusEnum() != EncounterStatus.DISCHARGED.getValue() &&
encounterCheck.getStatusEnum() != EncounterStatus.COMPLETED.getValue()) {
log.error("BugFix#338: 患者未接诊,禁止划价/保存医嘱encounterId={}, status={}",
adviceSaveDto.getEncounterId(), encounterCheck.getStatusEnum());
return R.fail(null, "患者尚未接诊,无法保存医嘱。请先完成接诊操作!");
}
}
}
}
// 药品前端adviceType=1
@@ -570,13 +594,15 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
// 耗材前端adviceType=4后端ItemType.DEVICE=2
List<AdviceSaveDto> deviceList = adviceSaveList.stream()
.filter(e -> ItemType.DEVICE.getValue().equals(e.getAdviceType())
|| e.getAdviceType() == 4) // 🔧 BugFix: 前端耗材类型值为4
|| e.getAdviceType() == 4) // 前端耗材类型值为4
.collect(Collectors.toList());
// 诊疗活动包括普通诊疗前端adviceType=3会诊前端adviceType=5
// 诊疗活动前端adviceType=3诊疗、adviceType=5会诊、adviceType=6手术
List<AdviceSaveDto> activityList = adviceSaveList.stream()
.filter(e -> ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
|| e.getAdviceType() == 3 // 🔧 BugFix: 前端诊疗类型值为3
|| e.getAdviceType() == 5) // 🔧 BugFix: 前端会诊类型值为5
|| e.getAdviceType() == 3 // 前端诊疗类型值为3
|| e.getAdviceType() == 5 // 前端会诊类型值为5
|| ItemType.SURGERY.getValue().equals(e.getAdviceType())) // 🔧 BugFix#318: 手术类型值为6
.collect(Collectors.toList());
// 🔍 Debug日志: 记录分类结果
@@ -605,11 +631,12 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
iDeviceDispenseService.deleteDeviceDispense(adviceSaveDto.getRequestId());
}
// 🔧 Bug Fix: 跳过耗材的库存校验(耗材的库存校验逻辑不同)
// 🔧 Bug Fix: 跳过耗材、诊疗、手术的库存校验
List<AdviceSaveDto> needCheckList = adviceSaveList.stream()
.filter(e -> !DbOpType.DELETE.getCode().equals(e.getDbOpType())
&& !ItemType.ACTIVITY.getValue().equals(e.getAdviceType())
&& !ItemType.DEVICE.getValue().equals(e.getAdviceType())) // 排除耗材
&& !ItemType.DEVICE.getValue().equals(e.getAdviceType())
&& !ItemType.SURGERY.getValue().equals(e.getAdviceType())) // 🔧 BugFix#318: 排除手术类型
.collect(Collectors.toList());
// 校验库存
String tipRes = adviceUtils.checkInventory(needCheckList);
@@ -767,6 +794,18 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
}
}
// 🔧 Bug Fix: 确保practitionerId不为null
if (adviceSaveDto.getPractitionerId() == null) {
adviceSaveDto.setPractitionerId(SecurityUtils.getLoginUser().getPractitionerId());
log.info("handMedication - 自动补全practitionerId: practitionerId={}", adviceSaveDto.getPractitionerId());
}
// 🔧 Bug Fix: 确保founderOrgId不为null
if (adviceSaveDto.getFounderOrgId() == null) {
adviceSaveDto.setFounderOrgId(SecurityUtils.getLoginUser().getOrgId());
log.info("handMedication - 自动补全founderOrgId: founderOrgId={}", adviceSaveDto.getFounderOrgId());
}
boolean firstTimeSave = false;// 第一次保存
medicationRequest = new MedicationRequest();
medicationRequest.setId(adviceSaveDto.getRequestId()); // 主键id
@@ -929,13 +968,20 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
// 处理耗材发放
Long dispenseId = iDeviceDispenseService.handleDeviceDispense(deviceRequest, DbOpType.INSERT.getCode());
// 查询耗材定价信息
AdviceBaseDto deviceAdviceDto = new AdviceBaseDto();
deviceAdviceDto.setAdviceDefinitionId(boundDevice.getDevActId());
deviceAdviceDto.setAdviceTableName(CommonConstants.TableName.ADM_DEVICE_DEFINITION);
IPage<AdviceBaseDto> devicePage = getAdviceBaseInfo(deviceAdviceDto, null, null, null,
adviceSaveDto.getFounderOrgId(), 1, 1, Whether.NO.getValue(),
List.of(ItemType.DEVICE.getValue()), null, null);
// 查询耗材定价信息 - 直接使用mapper查询避免递归调用getAdviceBaseInfo导致栈溢出
IPage<AdviceBaseDto> devicePage = doctorStationAdviceAppMapper.getAdviceBaseInfo(
new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(1, 1),
PublicationStatus.ACTIVE.getValue(),
adviceSaveDto.getFounderOrgId(),
null,
CommonConstants.TableName.ADM_DEVICE_DEFINITION,
null,
null,
List.of(boundDevice.getDevActId()),
null,
null,
null,
null);
if (devicePage == null || devicePage.getRecords().isEmpty()) {
log.warn("无法找到耗材定价信息: deviceDefId={}", boundDevice.getDevActId());
@@ -943,12 +989,19 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
}
AdviceBaseDto deviceBaseInfo = devicePage.getRecords().get(0);
if (deviceBaseInfo.getPriceList() == null || deviceBaseInfo.getPriceList().isEmpty()) {
// 查询价格信息 - 直接查询定价主表
List<AdvicePriceDto> mainCharge = doctorStationAdviceAppMapper.getMainCharge(
List.of(deviceBaseInfo.getChargeItemDefinitionId()), PublicationStatus.ACTIVE.getValue());
if (mainCharge == null || mainCharge.isEmpty()) {
log.warn("耗材没有定价信息: deviceDefId={}", boundDevice.getDevActId());
continue;
}
AdvicePriceDto devicePrice = deviceBaseInfo.getPriceList().get(0);
AdvicePriceDto devicePrice = mainCharge.get(0);
devicePrice.setDefinitionId(deviceBaseInfo.getChargeItemDefinitionId());
// 如果需要定价子表ID可以从mainCharge中获取
// 创建耗材费用项
ChargeItem deviceChargeItem = new ChargeItem();
@@ -1134,6 +1187,18 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
}
}
// 🔧 Bug Fix: 确保practitionerId不为null
if (adviceSaveDto.getPractitionerId() == null) {
adviceSaveDto.setPractitionerId(SecurityUtils.getLoginUser().getPractitionerId());
log.info("自动补全practitionerId: practitionerId={}", adviceSaveDto.getPractitionerId());
}
// 🔧 Bug Fix: 确保founderOrgId不为null
if (adviceSaveDto.getFounderOrgId() == null) {
adviceSaveDto.setFounderOrgId(SecurityUtils.getLoginUser().getOrgId());
log.info("自动补全founderOrgId: founderOrgId={}", adviceSaveDto.getFounderOrgId());
}
deviceRequest = new DeviceRequest();
deviceRequest.setId(adviceSaveDto.getRequestId()); // 主键id
deviceRequest.setStatusEnum(is_save ? RequestStatus.DRAFT.getValue() : RequestStatus.ACTIVE.getValue()); // 请求状态
@@ -1198,6 +1263,47 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
chargeItem.setServiceId(deviceRequest.getId()); // 医疗服务ID
chargeItem.setProductTable(adviceSaveDto.getAdviceTableName());// 产品所在表
chargeItem.setProductId(adviceSaveDto.getAdviceDefinitionId());// 收费项id
// 🔧 Bug Fix: 如果 definitionId 或 definitionDetailId 为 null从定价信息中获取
if (chargeItem.getDefinitionId() == null || chargeItem.getDefDetailId() == null) {
log.warn("耗材的 definitionId 或 definitionDetailId 为 null尝试从定价信息中获取: deviceDefId={}",
adviceSaveDto.getAdviceDefinitionId());
// 查询耗材定价信息
IPage<AdviceBaseDto> devicePage = doctorStationAdviceAppMapper.getAdviceBaseInfo(
new Page<>(1, 1),
PublicationStatus.ACTIVE.getValue(),
orgId,
CommonConstants.TableName.ADM_DEVICE_DEFINITION,
null,
null,
null,
Arrays.asList(adviceSaveDto.getAdviceDefinitionId()),
null,
null,
null,
null);
if (devicePage != null && !devicePage.getRecords().isEmpty()) {
AdviceBaseDto deviceBaseInfo = devicePage.getRecords().get(0);
if (deviceBaseInfo.getPriceList() != null && !deviceBaseInfo.getPriceList().isEmpty()) {
AdvicePriceDto devicePrice = deviceBaseInfo.getPriceList().get(0);
if (chargeItem.getDefinitionId() == null) {
chargeItem.setDefinitionId(devicePrice.getDefinitionId());
log.info("从定价信息中获取 definitionId: {}", devicePrice.getDefinitionId());
}
if (chargeItem.getDefDetailId() == null) {
chargeItem.setDefDetailId(devicePrice.getDefinitionDetailId());
log.info("从定价信息中获取 definitionDetailId: {}", devicePrice.getDefinitionDetailId());
}
}
}
}
// 🔧 Bug Fix: 确保定义ID不为null
if (chargeItem.getDefinitionId() == null) {
log.error("无法获取耗材的 definitionId: deviceDefId={}", adviceSaveDto.getAdviceDefinitionId());
throw new ServiceException("无法获取耗材的定价信息,请联系管理员");
}
// 🔧 Bug Fix: 如果accountId为null从就诊中获取账户ID如果没有则自动创建
Long accountId = adviceSaveDto.getAccountId();
if (accountId == null) {
@@ -1320,6 +1426,18 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
}
}
// 🔧 Bug Fix: 确保practitionerId不为null
if (adviceSaveDto.getPractitionerId() == null) {
adviceSaveDto.setPractitionerId(SecurityUtils.getLoginUser().getPractitionerId());
log.info("handService - 自动补全practitionerId: practitionerId={}", adviceSaveDto.getPractitionerId());
}
// 🔧 Bug Fix: 确保founderOrgId不为null
if (adviceSaveDto.getFounderOrgId() == null) {
adviceSaveDto.setFounderOrgId(SecurityUtils.getLoginUser().getOrgId());
log.info("handService - 自动补全founderOrgId: founderOrgId={}", adviceSaveDto.getFounderOrgId());
}
// 🔧 Bug Fix #238: 诊疗项目执行科室非空校验
if (adviceSaveDto.getAdviceType() != null && adviceSaveDto.getAdviceType() == 3) {
Long effectiveOrgId = adviceSaveDto.getEffectiveOrgId();
@@ -1451,6 +1569,15 @@ public class DoctorStationAdviceAppServiceImpl implements IDoctorStationAdviceAp
// }
// log.error(e.getMessage(), e);
// }
// 签发时将收费项目状态从草稿改为待收费
Long chargeItemId = adviceSaveDto.getChargeItemId();
if (chargeItemId != null) {
ChargeItem existingChargeItem = iChargeItemService.getById(chargeItemId);
if (existingChargeItem != null) {
existingChargeItem.setStatusEnum(ChargeItemStatus.PLANNED.getValue());
iChargeItemService.updateById(existingChargeItem);
}
}
}
}
}

View File

@@ -273,12 +273,28 @@ public class DoctorStationDiagnosisAppServiceImpl implements IDoctorStationDiagn
*/
@Override
public R<?> saveDoctorDiagnosisNew(SaveDiagnosisParam saveDiagnosisParam) {
// 参数校验:确保诊断列表不为空
if (saveDiagnosisParam == null) {
return R.fail(MessageUtils.message(PromptMsgConstant.Common.M00009, new Object[] { "保存诊断参数" }));
}
// 患者id
Long patientId = saveDiagnosisParam.getPatientId();
// 就诊ID
Long encounterId = saveDiagnosisParam.getEncounterId();
// 诊断定义集合
List<SaveDiagnosisChildParam> diagnosisChildList = saveDiagnosisParam.getDiagnosisChildList();
// 校验患者ID和就诊ID
if (patientId == null || encounterId == null) {
return R.fail(MessageUtils.message(PromptMsgConstant.Common.M00009, new Object[] { "患者ID或就诊ID" }));
}
// 校验诊断列表不为空
if (diagnosisChildList == null || diagnosisChildList.isEmpty()) {
return R.fail(MessageUtils.message(PromptMsgConstant.Common.M00009, new Object[] { "诊断列表" }));
}
// 先删除再保存
// iEncounterDiagnosisService.deleteEncounterDiagnosisInfos(encounterId);

View File

@@ -374,11 +374,11 @@ public class DoctorStationLabApplyServiceImpl implements IDoctorStationInspectio
// 查询检验申请单列表
log.debug("查询申请单数据前");
List<InspectionLabApply> list = doctorStationLabApplyMapper.getInspectionApplyListPage(encounterId);
List<DoctorStationLabApplyDto> list = doctorStationLabApplyMapper.getInspectionApplyListPage(encounterId);
log.debug("查询申请单数据后");
// 使用 PageInfo 包装查询结果
PageInfo<InspectionLabApply> pageInfo = new PageInfo<>(list);
PageInfo<DoctorStationLabApplyDto> pageInfo = new PageInfo<>(list);
// 构建返回结果
Map<String, Object> result = new HashMap<>();

View File

@@ -1,6 +1,7 @@
package com.openhis.web.doctorstation.appservice.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -16,21 +17,23 @@ import com.openhis.common.constant.CommonConstants;
import com.openhis.common.enums.*;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.triageandqueuemanage.domain.TriageQueueItem;
import com.openhis.triageandqueuemanage.service.TriageQueueItemService;
import com.openhis.web.doctorstation.appservice.*;
import com.openhis.web.doctorstation.dto.PatientInfoDto;
import com.openhis.web.doctorstation.dto.PrescriptionInfoBaseDto;
import com.openhis.web.doctorstation.dto.PrescriptionInfoDetailDto;
import com.openhis.web.doctorstation.dto.ReceptionStatisticsDto;
import com.openhis.web.doctorstation.mapper.DoctorStationMainAppMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
@@ -64,6 +67,9 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
@Resource
private JdbcTemplate jdbcTemplate;
@Resource
private TriageQueueItemService triageQueueItemService;
/**
* 查询就诊患者信息
*
@@ -124,14 +130,40 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
* @return 结果
*/
@Override
@Transactional(rollbackFor = Exception.class)
public R<?> receiveEncounter(Long encounterId) {
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
String currentUsername = SecurityUtils.getUsername();
// 检查就诊记录是否存在
Encounter encounter = encounterMapper.selectById(encounterId);
if (encounter == null) {
return R.fail("就诊记录不存在");
}
// 检查患者状态,防止重复接诊
Integer currentStatus = encounter.getStatusEnum();
if (EncounterStatus.IN_PROGRESS.getValue().equals(currentStatus)) {
return R.fail("已接诊,请勿重复点击,已为您刷新");
}
int update = encounterMapper.update(null,
new LambdaUpdateWrapper<Encounter>().eq(Encounter::getId, encounterId)
.eq(Encounter::getStatusEnum, EncounterStatus.PLANNED.getValue()) // 只更新待诊状态的患者
.set(Encounter::getReceptionTime, new Date())
.set(Encounter::getStatusEnum, EncounterStatus.IN_PROGRESS.getValue())
.set(Encounter::getSubjectStatusEnum, EncounterSubjectStatus.RECEIVING_CARE.getValue()));
// 如果更新失败,说明状态已被其他医生修改
if (update <= 0) {
// 重新查询当前状态
encounter = encounterMapper.selectById(encounterId);
if (EncounterStatus.IN_PROGRESS.getValue().equals(encounter.getStatusEnum())) {
return R.fail("已接诊,请勿重复接诊");
}
return R.fail("接诊失败,请刷新后重试");
}
// 先把之前的接诊记录更新为已完成
iEncounterParticipantService.update(new LambdaUpdateWrapper<EncounterParticipant>()
.eq(EncounterParticipant::getTypeCode, ParticipantType.ADMITTER.getCode())
@@ -148,7 +180,28 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
encounterParticipant.setCreateBy(currentUsername);
encounterParticipant.setCreateTime(new Date());
iEncounterParticipantService.save(encounterParticipant);
return update > 0 ? R.ok() : R.fail();
// 更新 triage_queue_item 队列记录状态为 CALLING
try {
TriageQueueItem queueItem = triageQueueItemService.getOne(
new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getEncounterId, encounterId)
.eq(TriageQueueItem::getDeleteFlag, "0")
);
if (queueItem != null) {
queueItem.setStatus("CALLING");
queueItem.setUpdateTime(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
triageQueueItemService.updateById(queueItem);
log.info("接诊时更新队列状态为CALLINGencounterId={}, queueItemId={}", encounterId, queueItem.getId());
} else {
log.warn("接诊时未找到队列记录encounterId={}", encounterId);
}
} catch (Exception e) {
log.error("接诊时更新队列状态失败encounterId={}", encounterId, e);
}
return R.ok();
}
/**
@@ -181,11 +234,54 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
return R.fail("就诊记录不存在");
}
if (!EncounterStatus.IN_PROGRESS.getValue().equals(encounter.getStatusEnum())) {
return R.fail("当前患者不在就诊中状态");
// 检查患者状态,防止重复完诊
Integer currentStatus = encounter.getStatusEnum();
if (EncounterStatus.DISCHARGED.getValue().equals(currentStatus) ||
EncounterStatus.COMPLETED.getValue().equals(currentStatus)) {
// 患者已完成就诊,返回特定提示
return R.fail("患者已完成就诊,已为您自动刷新患者列表");
}
// 2. 更新状态、完成时间以及初复诊标识
if (!EncounterStatus.IN_PROGRESS.getValue().equals(currentStatus)) {
return R.fail("非就诊中患者不能完诊");
}
// 2. 查找队列项
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
TriageQueueItem queueItem = triageQueueItemService.getOne(
new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getEncounterId, encounterId)
.eq(TriageQueueItem::getDeleteFlag, "0")
);
// 如果队列项存在,检查状态并更新
if (queueItem != null && "CALLING".equals(queueItem.getStatus())) {
// 更新队列状态为已完成
java.time.LocalDateTime nowLocal = java.time.LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS);
queueItem.setStatus("COMPLETED");
queueItem.setUpdateTime(nowLocal);
triageQueueItemService.updateById(queueItem);
// 写入 div_log 审计日志
try {
Long userId = SecurityUtils.getLoginUser().getUserId();
String divLogSql = "INSERT INTO hisdev.div_log "
+ "(pool_id, slot_id, queue_no, op_user_id, action, create_time) "
+ "VALUES (?, ?, ?, ?, 'COMPLETE', NOW()::timestamp(0))";
jdbcTemplate.update(divLogSql,
queueItem.getOrganizationId(), // pool_id: 候选池ID科室
queueItem.getPractitionerId(), // slot_id: 槽位ID医生
queueItem.getQueueOrder(), // queue_no: 队列号
userId); // op_user_id: 操作用户ID
} catch (Exception e) {
log.error("写入div_log审计日志失败", e);
// 审计日志失败不影响主流程
}
}
// 3. 更新状态、完成时间以及初复诊标识
Date now = new Date();
int update = encounterMapper.update(null,
new LambdaUpdateWrapper<Encounter>()
@@ -198,7 +294,7 @@ public class DoctorStationMainAppServiceImpl implements IDoctorStationMainAppSer
if (update <= 0) return R.fail("完诊失败");
// 3. 审计日志
// 4. 审计日志sys_oper_log
try {
String username = SecurityUtils.getUsernameSafe();
String sql = "INSERT INTO sys_oper_log "

View File

@@ -17,6 +17,10 @@ import java.util.List;
@Data
@Accessors(chain = true)
public class DoctorStationLabApplyDto {
/**
* 申请单ID数据库自增主键
*/
private Long applicationId;
/**
* 申请单编号
*/

View File

@@ -161,6 +161,11 @@ public class RequestBaseDto {
private String doseUnitCode;
private String doseUnitCode_dictText;
/**
* 单价
*/
private BigDecimal unitPrice;
/**
* 总价
*/
@@ -215,4 +220,16 @@ public class RequestBaseDto {
@JsonSerialize(using = ToStringSerializer.class)
private Long basedOnId;
/**
* 就诊id
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long encounterId;
/**
* 患者id
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long patientId;
}

View File

@@ -2,6 +2,7 @@ package com.openhis.web.doctorstation.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -73,12 +74,16 @@ public class SaveDiagnosisChildParam {
/**
* 诊断时间
* 添加 pattern 以支持前端传来的 "yyyy/M/d HH:mm:ss" 格式
*/
@JsonFormat(pattern = "yyyy/M/d HH:mm:ss", timezone = "GMT+8")
private Date diagnosisTime;
/**
* 发病时间
* 同样添加 pattern 以防前端传来相同格式的发病时间
*/
@JsonFormat(pattern = "yyyy/M/d HH:mm:ss", timezone = "GMT+8")
private Date onsetDate;
/** 患者疾病诊断类型代码 */

View File

@@ -1,6 +1,6 @@
package com.openhis.web.doctorstation.mapper;
import com.openhis.lab.domain.InspectionLabApply;
import com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@@ -23,5 +23,5 @@ public interface DoctorStationLabApplyMapper {
* @param encounterId 就诊 ID
* @return 检验申请单列表
*/
List<InspectionLabApply> getInspectionApplyListPage(@Param("encounterId") Long encounterId);
List<DoctorStationLabApplyDto> getInspectionApplyListPage(@Param("encounterId") Long encounterId);
}

View File

@@ -115,6 +115,15 @@ public class AdviceUtils {
matched = true;
// 检查库存是否充足
BigDecimal minUnitQuantity = saveDto.getMinUnitQuantity();
// 🔧 Bug Fix: 对于耗材类型如果没有设置minUnitQuantity则使用quantity作为默认值
if (minUnitQuantity == null) {
if (CommonConstants.TableName.ADM_DEVICE_DEFINITION.equals(inventoryDto.getItemTable())) {
// 耗材只有一个单位minUnitQuantity等于quantity
minUnitQuantity = saveDto.getQuantity();
} else {
return saveDto.getAdviceName() + "的小单位数量不能为空";
}
}
BigDecimal chineseHerbsDoseQuantity = saveDto.getChineseHerbsDoseQuantity(); // 中药付数
// 中草药医嘱的情况
if (chineseHerbsDoseQuantity != null && chineseHerbsDoseQuantity.compareTo(BigDecimal.ZERO) > 0) {

View File

@@ -0,0 +1,45 @@
package com.openhis.web.lab.appservice;
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentSelParam;
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentUpDto;
import com.core.common.core.domain.R;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* 检验项目 AppService 接口(独立操作 lab_activity_definition 表)
*/
public interface ILabActivityDefinitionAppService {
/**
* 分页查询检验项目列表
*/
R<?> getLabActivityDefinitionPage(DiagnosisTreatmentSelParam selParam, String searchKey,
Integer pageNo, Integer pageSize, HttpServletRequest request);
/**
* 根据id查询检验项目详情
*/
R<?> getLabActivityDefinitionOne(Long id);
/**
* 新增检验项目
*/
R<?> addLabActivityDefinition(DiagnosisTreatmentUpDto dto);
/**
* 编辑检验项目
*/
R<?> editLabActivityDefinition(DiagnosisTreatmentUpDto dto);
/**
* 停用检验项目
*/
R<?> stopLabActivityDefinition(List<Long> ids);
/**
* 启用检验项目
*/
R<?> startLabActivityDefinition(List<Long> ids);
}

View File

@@ -0,0 +1,189 @@
package com.openhis.web.lab.appservice.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.core.domain.model.LoginUser;
import com.core.common.utils.*;
import com.core.common.utils.bean.BeanUtils;
import com.openhis.common.constant.PromptMsgConstant;
import com.openhis.common.enums.ActivityType;
import com.openhis.common.enums.PublicationStatus;
import com.openhis.common.enums.Whether;
import com.core.common.utils.ChineseConvertUtils;
import com.openhis.common.utils.EnumUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.common.enums.AssignSeqEnum;
import com.openhis.lab.domain.LabActivityDefinition;
import com.openhis.lab.service.ILabActivityDefinitionService;
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto;
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentSelParam;
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentUpDto;
import com.openhis.web.lab.appservice.ILabActivityDefinitionAppService;
import com.openhis.web.datadictionary.mapper.LabActivityDefinitionManageMapper;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 检验项目 AppService 实现(独立操作 lab_activity_definition 表)
*/
@Service
public class LabActivityDefinitionAppServiceImpl implements ILabActivityDefinitionAppService {
@Resource
private ILabActivityDefinitionService labActivityDefinitionService;
@Resource
private LabActivityDefinitionManageMapper labActivityDefinitionManageMapper;
@Resource
private AssignSeqUtil assignSeqUtil;
@Override
public R<?> getLabActivityDefinitionPage(DiagnosisTreatmentSelParam selParam, String searchKey,
Integer pageNo, Integer pageSize, HttpServletRequest request) {
if (selParam == null) {
selParam = new DiagnosisTreatmentSelParam();
}
if (selParam.getStatusEnum() == null) {
selParam.setStatusEnum(PublicationStatus.ACTIVE.getValue());
}
// 临时移除需要手动拼别名条件的字段
Long inspectionTypeIdValue = null;
if (selParam.getInspectionTypeId() != null) {
inspectionTypeIdValue = selParam.getInspectionTypeId();
selParam.setInspectionTypeId(null);
}
Integer pricingFlagValue = null;
if (selParam.getPricingFlag() != null) {
pricingFlagValue = selParam.getPricingFlag();
selParam.setPricingFlag(null);
}
QueryWrapper<DiagnosisTreatmentDto> queryWrapper = HisQueryUtils.buildQueryWrapper(selParam,
searchKey, new HashSet<>(Arrays.asList("T1.bus_no", "T1.name", "T1.py_str", "T1.wb_str")), request);
if (inspectionTypeIdValue != null) {
queryWrapper.eq("T1.inspection_type_id", inspectionTypeIdValue);
selParam.setInspectionTypeId(inspectionTypeIdValue);
}
if (pricingFlagValue != null) {
queryWrapper.eq("T1.pricing_flag", pricingFlagValue);
selParam.setPricingFlag(pricingFlagValue);
}
IPage<DiagnosisTreatmentDto> page = labActivityDefinitionManageMapper
.getLabActivityDefinitionPage(new Page<>(pageNo, pageSize), queryWrapper);
page.getRecords().forEach(e -> {
e.setYbFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getYbFlag()));
e.setYbMatchFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getYbMatchFlag()));
e.setTypeEnum_enumText(EnumUtils.getInfoByValue(ActivityType.class, e.getTypeEnum()));
e.setStatusEnum_enumText(EnumUtils.getInfoByValue(PublicationStatus.class, e.getStatusEnum()));
e.setPricingFlag_enumText(EnumUtils.getInfoByValue(Whether.class, e.getPricingFlag()));
});
return R.ok(page);
}
@Override
public R<?> getLabActivityDefinitionOne(Long id) {
Integer tenantId = SecurityUtils.getLoginUser().getTenantId();
DiagnosisTreatmentDto dto = labActivityDefinitionManageMapper.getLabActivityDefinitionOne(id, tenantId);
return R.ok(dto);
}
@Override
public R<?> addLabActivityDefinition(DiagnosisTreatmentUpDto dto) {
if (dto.getOrgId() == null) {
dto.setOrgId(SecurityUtils.getLoginUser().getHospitalId());
}
LabActivityDefinition lab = new LabActivityDefinition();
BeanUtils.copyProperties(dto, lab);
lab.setSortOrder(dto.getSortOrder())
.setServiceRange(dto.getServiceRange())
.setInspectionTypeId(dto.getInspectionTypeId())
.setFeePackageId(dto.getFeePackageId())
.setSubItemId(dto.getSubItemId());
if (StringUtils.isEmpty(lab.getBusNo())) {
lab.setBusNo(assignSeqUtil.getSeq(AssignSeqEnum.ACTIVITY_DEFINITION_NUM.getPrefix(), 10));
}
lab.setPyStr(ChineseConvertUtils.toPinyinFirstLetter(lab.getName()));
lab.setWbStr(ChineseConvertUtils.toWBFirstLetter(lab.getName()));
lab.setStatusEnum(PublicationStatus.ACTIVE.getValue());
// 设置创建者和租户ID
String createBy = "system";
Integer tenantId = null;
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
createBy = loginUser.getUsername();
tenantId = loginUser.getTenantId();
}
} catch (Exception e) {
// 使用默认值
}
lab.setCreateBy(createBy);
lab.setTenantId(tenantId != null ? tenantId : 1);
if (lab.getCreateTime() == null) {
lab.setCreateTime(new java.util.Date());
}
return labActivityDefinitionService.addLabActivityDefinition(lab)
? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"检验项目"}))
: R.fail(null, "检验编码已存在:" + lab.getBusNo());
}
@Override
public R<?> editLabActivityDefinition(DiagnosisTreatmentUpDto dto) {
LabActivityDefinition lab = new LabActivityDefinition();
BeanUtils.copyProperties(dto, lab);
lab.setSortOrder(dto.getSortOrder())
.setServiceRange(dto.getServiceRange())
.setInspectionTypeId(dto.getInspectionTypeId())
.setFeePackageId(dto.getFeePackageId())
.setSubItemId(dto.getSubItemId())
.setPricingFlag(dto.getPricingFlag());
lab.setPyStr(ChineseConvertUtils.toPinyinFirstLetter(lab.getName()));
lab.setWbStr(ChineseConvertUtils.toWBFirstLetter(lab.getName()));
return labActivityDefinitionService.updateById(lab)
? R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"检验项目"}))
: R.fail(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00007, null));
}
@Override
public R<?> stopLabActivityDefinition(List<Long> ids) {
List<LabActivityDefinition> labList = new CopyOnWriteArrayList<>();
for (Long id : ids) {
LabActivityDefinition lab = new LabActivityDefinition();
lab.setId(id).setStatusEnum(PublicationStatus.RETIRED.getValue());
labList.add(lab);
}
labActivityDefinitionService.updateBatchById(labList);
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"检验项目"}));
}
@Override
public R<?> startLabActivityDefinition(List<Long> ids) {
List<LabActivityDefinition> labList = new CopyOnWriteArrayList<>();
for (Long id : ids) {
LabActivityDefinition lab = new LabActivityDefinition();
lab.setId(id).setStatusEnum(PublicationStatus.ACTIVE.getValue());
labList.add(lab);
}
labActivityDefinitionService.updateBatchById(labList);
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[]{"检验项目"}));
}
}

View File

@@ -94,7 +94,6 @@ public class InspectionTypeController extends BaseController {
// 查询是否存在相同编码的记录
List<InspectionType> existingRecords = inspectionTypeService.list(queryWrapper);
log.debug("检查编码唯一性code={}, 数据库中存在记录数={}", inspectionType.getCode(), existingRecords.size());
if (!existingRecords.isEmpty()) {
return AjaxResult.error("检验类型编码已存在");
@@ -119,8 +118,6 @@ public class InspectionTypeController extends BaseController {
return toAjax(result);
});
} catch (Exception e) {
log.error("新增检验类型失败code={}, 错误信息:{}", inspectionType.getCode(), e.getMessage(), e);
// 捕获唯一性约束冲突异常
if (e.getMessage().contains("uk_inspection_type_code") ||
e.getMessage().contains("duplicate key value") ||

View File

@@ -0,0 +1,78 @@
package com.openhis.web.lab.controller;
import com.core.common.core.domain.R;
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentSelParam;
import com.openhis.web.datadictionary.dto.DiagnosisTreatmentUpDto;
import com.openhis.web.lab.appservice.ILabActivityDefinitionAppService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* 检验项目维护 Controller独立操作 lab_activity_definition 表)
* 路径前缀:/lab/activity-definition
*/
@RestController
@RequestMapping("/lab/activity-definition")
@Slf4j
public class LabActivityDefinitionController {
@Resource
private ILabActivityDefinitionAppService labActivityDefinitionAppService;
/**
* 分页查询检验项目列表
*/
@GetMapping("/page")
public R<?> getPage(DiagnosisTreatmentSelParam selParam,
@RequestParam(value = "searchKey", defaultValue = "") String searchKey,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest request) {
return labActivityDefinitionAppService.getLabActivityDefinitionPage(selParam, searchKey, pageNo, pageSize, request);
}
/**
* 根据id查询检验项目详情
*/
@GetMapping("/one")
public R<?> getOne(@RequestParam Long id) {
return labActivityDefinitionAppService.getLabActivityDefinitionOne(id);
}
/**
* 新增检验项目
*/
@PostMapping("/add")
public R<?> add(@Validated @RequestBody DiagnosisTreatmentUpDto dto) {
return labActivityDefinitionAppService.addLabActivityDefinition(dto);
}
/**
* 编辑检验项目
*/
@PutMapping("/edit")
public R<?> edit(@RequestBody DiagnosisTreatmentUpDto dto) {
return labActivityDefinitionAppService.editLabActivityDefinition(dto);
}
/**
* 停用检验项目
*/
@PutMapping("/stop")
public R<?> stop(@RequestBody List<Long> ids) {
return labActivityDefinitionAppService.stopLabActivityDefinition(ids);
}
/**
* 启用检验项目
*/
@PutMapping("/start")
public R<?> start(@RequestBody List<Long> ids) {
return labActivityDefinitionAppService.startLabActivityDefinition(ids);
}
}

View File

@@ -55,6 +55,8 @@ import com.openhis.web.paymentmanage.dto.CancelPaymentDto;
import com.openhis.web.paymentmanage.dto.Clinic2207OrderResultDto;
import com.openhis.web.paymentmanage.mapper.PaymentMapper;
import com.openhis.web.personalization.dto.ActivityDeviceDto;
import com.openhis.triageandqueuemanage.domain.TriageQueueItem;
import com.openhis.triageandqueuemanage.service.TriageQueueItemService;
import com.openhis.workflow.domain.ServiceRequest;
import com.openhis.workflow.service.IDeviceDispenseService;
import com.openhis.workflow.service.IDeviceRequestService;
@@ -81,9 +83,11 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
@@ -149,6 +153,8 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
@Resource
private OutpatientRegistrationAppMapper outpatientRegistrationAppMapper;
@Resource
private TriageQueueItemService triageQueueItemService;
@Resource
private IRegService iRegService;
@Resource
private IPatientService iPatientService;
@@ -255,7 +261,9 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
// 账户id对应的账单列表
Map<Long, List<ChargeItem>> chargeItemMapByAccountId
= chargeItemList.stream().collect(Collectors.groupingBy(ChargeItem::getAccountId));
= chargeItemList.stream()
.filter(item -> item.getAccountId() != null)
.collect(Collectors.groupingBy(ChargeItem::getAccountId));
// 查询合同信息
List<Contract> contractList = contractService.list();
@@ -1928,6 +1936,80 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
// 就诊ID
Long encounterId = iEncounterService.saveEncounterByRegister(encounter);
// 创建 triage_queue_item 队列记录
try {
Integer tenantId = encounter.getTenantId() != null ? encounter.getTenantId() : SecurityUtils.getLoginUser().getTenantId();
LocalDate queueDate = LocalDate.now();
// 查询当前科室当天的最大排队序号
Integer maxOrder = triageQueueItemService.list(
new LambdaQueryWrapper<TriageQueueItem>()
.eq(TriageQueueItem::getTenantId, tenantId)
.eq(TriageQueueItem::getOrganizationId, encounter.getOrganizationId())
.eq(TriageQueueItem::getQueueDate, queueDate)
.eq(TriageQueueItem::getDeleteFlag, "0")
.ne(TriageQueueItem::getStatus, "COMPLETED")
).stream()
.map(TriageQueueItem::getQueueOrder)
.filter(Objects::nonNull)
.max(Integer::compareTo)
.orElse(0);
// 获取患者信息
Patient patient = iPatientService.getById(encounter.getPatientId());
String patientName = patient != null ? patient.getName() : null;
// 获取挂号医生信息
String practitionerName = null;
Long queuePractitionerId = null;
if (encounterParticipantFormData.getPractitionerId() != null) {
Practitioner practitioner = iPractitionerService.getById(encounterParticipantFormData.getPractitionerId());
if (practitioner != null) {
practitionerName = practitioner.getName();
queuePractitionerId = practitioner.getId();
}
}
// 获取科室信息
Organization organization = iOrganizationService.getById(encounter.getOrganizationId());
String organizationName = organization != null ? organization.getName() : null;
// 获取服务项目信息(挂号类型)
String healthcareName = null;
if (encounter.getServiceTypeId() != null) {
HealthcareService healthcareService = healthcareServiceService.getById(encounter.getServiceTypeId());
if (healthcareService != null) {
healthcareName = healthcareService.getName();
}
}
// 创建队列项
TriageQueueItem queueItem = new TriageQueueItem()
.setTenantId(tenantId)
.setQueueDate(queueDate)
.setOrganizationId(encounter.getOrganizationId())
.setOrganizationName(organizationName)
.setEncounterId(encounterId)
.setPatientId(encounter.getPatientId())
.setPatientName(patientName)
.setHealthcareName(healthcareName)
.setPractitionerId(queuePractitionerId)
.setPractitionerName(practitionerName)
.setRoomNo(null)
.setStatus("WAITING")
.setQueueOrder(maxOrder + 1)
.setDeleteFlag("0")
.setCreateTime(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS))
.setUpdateTime(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
triageQueueItemService.save(queueItem);
logger.info("挂号时创建队列记录成功encounterId={}, queueItemId={}", encounterId, queueItem.getId());
} catch (Exception e) {
logger.error("挂号时创建队列记录失败encounterId={}", encounterId, e);
// 队列记录创建失败不影响挂号流程
}
// 保存就诊位置信息
// 挂号时不选Location了
// encounterLocationFormData.setEncounterId(encounterId);
@@ -2251,7 +2333,9 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
= iChargeItemService.getChargeItemBaseInfoByIds(prePaymentDto.getChargeItemIds());
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
= chargeItemBaseInfoByIds.stream().collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
= chargeItemBaseInfoByIds.stream()
.filter(dto -> dto.getContractNo() != null && !dto.getContractNo().isEmpty())
.collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
List<InpatientPreSettleDto> yb2303OutputSetInfos = new ArrayList<>();
Yb2303OutputSetInfo yb2303OutputSetInfo;
@@ -2379,13 +2463,17 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
List<ChargeItemBaseInfoDto> chargeItemBaseInfoByIds
= iChargeItemService.getChargeItemBaseInfoByIds(paymentDto.getChargeItemIds());
Map<String, List<ChargeItemBaseInfoDto>> chargeItemKVByContractNo
= chargeItemBaseInfoByIds.stream().collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
= chargeItemBaseInfoByIds.stream()
.filter(dto -> dto.getContractNo() != null && !dto.getContractNo().isEmpty())
.collect(Collectors.groupingBy(ChargeItemBaseInfoDto::getContractNo));
List<Account> accountList = iAccountService.getAccountListByEncounter(paymentDto.getEncounterId());
if (accountList.isEmpty()) {
throw new ServiceException("未查询到账户信息");
}
Map<Long, List<Account>> accountKVById = accountList.stream().collect(Collectors.groupingBy(Account::getId));
Map<Long, List<Account>> accountKVById = accountList.stream()
.filter(acc -> acc.getId() != null)
.collect(Collectors.groupingBy(Account::getId));
com.openhis.financial.model.PaymentResult paymentResult;
List<com.openhis.financial.model.PaymentResult> paymentResultList = new ArrayList<>();
@@ -2395,7 +2483,9 @@ public class PaymentRecServiceImpl implements IPaymentRecService {
// <3>收费详情按照收费批次进行分组后结算
Map<Long, List<PaymentRecDetail>> payTransNoMap
= paymentRecDetails.stream().collect(Collectors.groupingBy(PaymentRecDetail::getAccountId));
= paymentRecDetails.stream()
.filter(detail -> detail.getAccountId() != null)
.collect(Collectors.groupingBy(PaymentRecDetail::getAccountId));
for (Map.Entry<Long, List<PaymentRecDetail>> stringListEntry : payTransNoMap.entrySet()) {
// paymentResult = new PaymentResult();

View File

@@ -216,136 +216,186 @@ public class RequestFormManageAppServiceImpl implements IRequestFormManageAppSer
}
// 如果是手术申请单,需要额外生成手术医嘱
if (ActivityDefCategory.PROCEDURE.getCode().equals(typeCode)) {
log.info("开始生成手术医嘱encounterId={}, patientId={}, typeCode={}", encounterId, patientId, typeCode);
// 从 descJson 中解析手术信息
String descJson = requestFormSaveDto.getDescJson();
Map<String, Object> descMap = null;
if (descJson != null && !descJson.isEmpty()) {
try {
ObjectMapper objectMapper = new ObjectMapper();
descMap = objectMapper.readValue(descJson, Map.class);
} catch (Exception e) {
log.error("解析手术申请单 descJson 失败", e);
}
}
// 获取手术信息
String surgeryName = descMap != null ? (String) descMap.get("surgeryName") : null;
String surgeryCode = descMap != null ? (String) descMap.get("surgeryCode") : null;
String surgeryFee = descMap != null ? (String) descMap.get("surgeryFee") : null;
String anesthesiaFee = descMap != null ? (String) descMap.get("anesthesiaFee") : null;
String plannedTime = descMap != null ? (String) descMap.get("plannedTime") : null;
String surgeryIndication = descMap != null ? (String) descMap.get("surgeryIndication") : null;
String preoperativeDiagnosis = descMap != null ? (String) descMap.get("preoperativeDiagnosis") : null;
// 生成手术医嘱
ServiceRequest surgeryServiceRequest = new ServiceRequest();
surgeryServiceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());
surgeryServiceRequest.setBusNo(String.format("%04d", (int) (Math.random() * 10000)));
surgeryServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
surgeryServiceRequest.setPrescriptionNo(prescriptionNo);
surgeryServiceRequest.setTherapyEnum(TherapyTimeType.TEMPORARY.getValue());
surgeryServiceRequest.setQuantity(BigDecimal.valueOf(1));
surgeryServiceRequest.setUnitCode("");
surgeryServiceRequest.setCategoryEnum(4); // 4-手术
// 优先从 activityList 获取手术 ID如果为空则从 descJson 获取
if (!activityList.isEmpty()) {
surgeryServiceRequest.setActivityId(activityList.get(0).getAdviceDefinitionId());
}
surgeryServiceRequest.setPatientId(patientId);
surgeryServiceRequest.setRequesterId(practitionerId);
surgeryServiceRequest.setEncounterId(encounterId);
surgeryServiceRequest.setAuthoredTime(curDate);
surgeryServiceRequest.setOrgId(orgId);
// 设置手术相关信息到 contentJson 字段
Map<String, String> contentMap = new java.util.HashMap<>();
if (surgeryName != null && !surgeryName.isEmpty()) {
contentMap.put("surgeryName", surgeryName);
}
if (surgeryCode != null && !surgeryCode.isEmpty()) {
contentMap.put("surgeryCode", surgeryCode);
}
if (plannedTime != null && !plannedTime.isEmpty()) {
contentMap.put("plannedTime", plannedTime);
}
if (surgeryIndication != null && !surgeryIndication.isEmpty()) {
contentMap.put("surgeryIndication", surgeryIndication);
}
if (preoperativeDiagnosis != null && !preoperativeDiagnosis.isEmpty()) {
contentMap.put("preoperativeDiagnosis", preoperativeDiagnosis);
}
if (!contentMap.isEmpty()) {
try {
ObjectMapper objectMapper = new ObjectMapper();
surgeryServiceRequest.setContentJson(objectMapper.writeValueAsString(contentMap));
} catch (Exception e) {
log.error("序列化手术信息失败", e);
}
}
iServiceRequestService.save(surgeryServiceRequest);
log.info("手术医嘱生成成功serviceRequestId={}, prescriptionNo={}", surgeryServiceRequest.getId(), prescriptionNo);
// 生成手术收费项目
ChargeItem surgeryChargeItem = new ChargeItem();
surgeryChargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
surgeryChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
surgeryChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
surgeryChargeItem.setPatientId(patientId);
surgeryChargeItem.setContextEnum(3); // 3-诊疗
surgeryChargeItem.setEncounterId(encounterId);
surgeryChargeItem.setEntererId(practitionerId);
surgeryChargeItem.setEnteredDate(curDate);
surgeryChargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
surgeryChargeItem.setServiceId(surgeryServiceRequest.getId());
surgeryChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
// 优先从 activityList 获取 productId如果为空则不设置
if (!activityList.isEmpty()) {
surgeryChargeItem.setProductId(activityList.get(0).getAdviceDefinitionId());
}
surgeryChargeItem.setAccountId(activityList.isEmpty() ? null : activityList.get(0).getAccountId());
surgeryChargeItem.setRequestingOrgId(orgId);
surgeryChargeItem.setQuantityValue(BigDecimal.valueOf(1));
surgeryChargeItem.setQuantityUnit("");
// 设置手术费用
if (surgeryFee != null && !surgeryFee.isEmpty()) {
try {
surgeryChargeItem.setUnitPrice(new BigDecimal(surgeryFee));
surgeryChargeItem.setTotalPrice(new BigDecimal(surgeryFee));
} catch (NumberFormatException e) {
log.warn("手术费用格式不正确:{}", surgeryFee);
}
}
iChargeItemService.save(surgeryChargeItem);
// 如果存在麻醉费用,生成麻醉收费项目
if (anesthesiaFee != null && !anesthesiaFee.isEmpty()) {
try {
BigDecimal anesthesiaFeeAmount = new BigDecimal(anesthesiaFee);
if (anesthesiaFeeAmount.compareTo(BigDecimal.ZERO) > 0) {
ChargeItem anesthesiaChargeItem = new ChargeItem();
anesthesiaChargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
anesthesiaChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
anesthesiaChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
anesthesiaChargeItem.setPatientId(patientId);
anesthesiaChargeItem.setContextEnum(3); // 3-诊疗
anesthesiaChargeItem.setEncounterId(encounterId);
anesthesiaChargeItem.setEntererId(practitionerId);
anesthesiaChargeItem.setEnteredDate(curDate);
anesthesiaChargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
anesthesiaChargeItem.setServiceId(surgeryServiceRequest.getId());
anesthesiaChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
anesthesiaChargeItem.setRequestingOrgId(orgId);
anesthesiaChargeItem.setQuantityValue(BigDecimal.valueOf(1));
anesthesiaChargeItem.setQuantityUnit("");
anesthesiaChargeItem.setUnitPrice(anesthesiaFeeAmount);
anesthesiaChargeItem.setTotalPrice(anesthesiaFeeAmount);
iChargeItemService.save(anesthesiaChargeItem);
log.info("【调试】判断手术医嘱生成条件: typeCode={}, PROCEDURE.code={}, typeCode类型={}, PROCEDURE.code类型={}",
typeCode, ActivityDefCategory.PROCEDURE.getCode(),
typeCode != null ? typeCode.getClass().getName() : "null",
ActivityDefCategory.PROCEDURE.getCode().getClass().getName());
boolean isProcedure = ActivityDefCategory.PROCEDURE.getCode().equals(typeCode);
log.info("【调试】判断结果: isProcedure={}, typeCode字符串={}, PROCEDURE.code字符串={}",
isProcedure,
typeCode != null ? "'" + typeCode + "'" : "null",
"'" + ActivityDefCategory.PROCEDURE.getCode() + "'");
if (isProcedure) {
log.info("开始生成手术医嘱encounterId={}, patientId={}, typeCode={}, activityListSize={}",
encounterId, patientId, typeCode, activityList != null ? activityList.size() : 0);
try {
// 从 descJson 中解析手术信息
String descJson = requestFormSaveDto.getDescJson();
Map<String, Object> descMap = null;
if (descJson != null && !descJson.isEmpty()) {
try {
ObjectMapper objectMapper = new ObjectMapper();
descMap = objectMapper.readValue(descJson, Map.class);
log.info("解析手术申请单 descJson 成功: {}", descMap);
} catch (Exception e) {
log.error("解析手术申请单 descJson 失败: {}", descJson, e);
}
} catch (NumberFormatException e) {
log.warn("麻醉费用格式不正确:{}", anesthesiaFee);
} else {
log.warn("手术申请单 descJson 为空");
}
// 获取手术信息
String surgeryName = descMap != null ? (String) descMap.get("surgeryName") : null;
String surgeryCode = descMap != null ? (String) descMap.get("surgeryCode") : null;
String surgeryFee = descMap != null ? (String) descMap.get("surgeryFee") : null;
String anesthesiaFee = descMap != null ? (String) descMap.get("anesthesiaFee") : null;
String plannedTime = descMap != null ? (String) descMap.get("plannedTime") : null;
String surgeryIndication = descMap != null ? (String) descMap.get("surgeryIndication") : null;
String preoperativeDiagnosis = descMap != null ? (String) descMap.get("preoperativeDiagnosis") : null;
// 🔧 BugFix#318: 从 activityList 获取手术项目名称
String adviceDefinitionName = null;
if (activityList != null && !activityList.isEmpty()) {
adviceDefinitionName = activityList.get(0).getAdviceDefinitionName();
log.info("从 activityList 获取手术项目名称: {}", adviceDefinitionName);
}
log.info("手术信息: surgeryName={}, surgeryCode={}, surgeryFee={}, anesthesiaFee={}, adviceDefinitionName={}",
surgeryName, surgeryCode, surgeryFee, anesthesiaFee, adviceDefinitionName);
// 生成手术医嘱
ServiceRequest surgeryServiceRequest = new ServiceRequest();
surgeryServiceRequest.setStatusEnum(RequestStatus.DRAFT.getValue());
surgeryServiceRequest.setBusNo(String.format("%04d", (int) (Math.random() * 10000)));
surgeryServiceRequest.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
surgeryServiceRequest.setPrescriptionNo(prescriptionNo);
surgeryServiceRequest.setTherapyEnum(TherapyTimeType.TEMPORARY.getValue());
surgeryServiceRequest.setQuantity(BigDecimal.valueOf(1));
surgeryServiceRequest.setUnitCode("");
surgeryServiceRequest.setCategoryEnum(4); // 4-手术
// 优先从 activityList 获取手术 ID
if (activityList != null && !activityList.isEmpty()) {
Long activityId = activityList.get(0).getAdviceDefinitionId();
surgeryServiceRequest.setActivityId(activityId);
log.info("从 activityList 获取手术ID: {}", activityId);
} else {
log.warn("activityList 为空无法获取手术ID");
}
surgeryServiceRequest.setPatientId(patientId);
surgeryServiceRequest.setRequesterId(practitionerId);
surgeryServiceRequest.setEncounterId(encounterId);
surgeryServiceRequest.setAuthoredTime(curDate);
surgeryServiceRequest.setOrgId(orgId);
// 设置手术相关信息到 contentJson 字段
Map<String, String> contentMap = new java.util.HashMap<>();
// 🔧 BugFix#318: 优先使用 activityList 中的手术项目名称
if (adviceDefinitionName != null && !adviceDefinitionName.isEmpty()) {
contentMap.put("surgeryName", adviceDefinitionName);
} else if (surgeryName != null && !surgeryName.isEmpty()) {
contentMap.put("surgeryName", surgeryName);
}
if (surgeryCode != null && !surgeryCode.isEmpty()) {
contentMap.put("surgeryCode", surgeryCode);
}
if (plannedTime != null && !plannedTime.isEmpty()) {
contentMap.put("plannedTime", plannedTime);
}
if (surgeryIndication != null && !surgeryIndication.isEmpty()) {
contentMap.put("surgeryIndication", surgeryIndication);
}
if (preoperativeDiagnosis != null && !preoperativeDiagnosis.isEmpty()) {
contentMap.put("preoperativeDiagnosis", preoperativeDiagnosis);
}
if (!contentMap.isEmpty()) {
try {
ObjectMapper objectMapper = new ObjectMapper();
surgeryServiceRequest.setContentJson(objectMapper.writeValueAsString(contentMap));
} catch (Exception e) {
log.error("序列化手术信息失败", e);
}
}
try {
iServiceRequestService.save(surgeryServiceRequest);
log.info("手术医嘱生成成功serviceRequestId={}, prescriptionNo={}", surgeryServiceRequest.getId(), prescriptionNo);
} catch (Exception e) {
log.error("保存手术医嘱失败", e);
throw new ServiceException("保存手术医嘱失败: " + e.getMessage());
}
// 生成手术收费项目
try {
ChargeItem surgeryChargeItem = new ChargeItem();
surgeryChargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
surgeryChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
surgeryChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
surgeryChargeItem.setPatientId(patientId);
surgeryChargeItem.setContextEnum(6); // 6-手术
surgeryChargeItem.setEncounterId(encounterId);
surgeryChargeItem.setEntererId(practitionerId);
surgeryChargeItem.setEnteredDate(curDate);
surgeryChargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
surgeryChargeItem.setServiceId(surgeryServiceRequest.getId());
surgeryChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
// 优先从 activityList 获取 productId
if (activityList != null && !activityList.isEmpty()) {
surgeryChargeItem.setProductId(activityList.get(0).getAdviceDefinitionId());
surgeryChargeItem.setAccountId(activityList.get(0).getAccountId());
}
surgeryChargeItem.setRequestingOrgId(orgId);
surgeryChargeItem.setQuantityValue(BigDecimal.valueOf(1));
surgeryChargeItem.setQuantityUnit("");
// 设置手术费用
if (surgeryFee != null && !surgeryFee.isEmpty()) {
try {
surgeryChargeItem.setUnitPrice(new BigDecimal(surgeryFee));
surgeryChargeItem.setTotalPrice(new BigDecimal(surgeryFee));
} catch (NumberFormatException e) {
log.warn("手术费用格式不正确:{}", surgeryFee);
}
}
iChargeItemService.save(surgeryChargeItem);
log.info("手术收费项目生成成功chargeItemId={}", surgeryChargeItem.getId());
} catch (Exception e) {
log.error("生成手术收费项目失败", e);
throw new ServiceException("生成手术收费项目失败: " + e.getMessage());
}
// 如果存在麻醉费用,生成麻醉收费项目
if (anesthesiaFee != null && !anesthesiaFee.isEmpty()) {
try {
BigDecimal anesthesiaFeeAmount = new BigDecimal(anesthesiaFee);
if (anesthesiaFeeAmount.compareTo(BigDecimal.ZERO) > 0) {
ChargeItem anesthesiaChargeItem = new ChargeItem();
anesthesiaChargeItem.setStatusEnum(ChargeItemStatus.DRAFT.getValue());
anesthesiaChargeItem.setBusNo(AssignSeqEnum.CHARGE_ITEM_NO.getPrefix().concat(surgeryServiceRequest.getBusNo()));
anesthesiaChargeItem.setGenerateSourceEnum(GenerateSource.DOCTOR_PRESCRIPTION.getValue());
anesthesiaChargeItem.setPatientId(patientId);
anesthesiaChargeItem.setContextEnum(3); // 3-诊疗
anesthesiaChargeItem.setEncounterId(encounterId);
anesthesiaChargeItem.setEntererId(practitionerId);
anesthesiaChargeItem.setEnteredDate(curDate);
anesthesiaChargeItem.setServiceTable(CommonConstants.TableName.WOR_SERVICE_REQUEST);
anesthesiaChargeItem.setServiceId(surgeryServiceRequest.getId());
anesthesiaChargeItem.setProductTable(CommonConstants.TableName.WOR_ACTIVITY_DEFINITION);
anesthesiaChargeItem.setRequestingOrgId(orgId);
anesthesiaChargeItem.setQuantityValue(BigDecimal.valueOf(1));
anesthesiaChargeItem.setQuantityUnit("");
anesthesiaChargeItem.setUnitPrice(anesthesiaFeeAmount);
anesthesiaChargeItem.setTotalPrice(anesthesiaFeeAmount);
iChargeItemService.save(anesthesiaChargeItem);
log.info("麻醉收费项目生成成功");
}
} catch (NumberFormatException e) {
log.warn("麻醉费用格式不正确:{}", anesthesiaFee);
}
}
} catch (Exception e) {
log.error("生成手术医嘱过程中发生异常", e);
throw e;
}
} else {
log.info("不是手术申请单跳过手术医嘱生成typeCode={}", typeCode);
}
return R.ok(null, MessageUtils.createMessage(PromptMsgConstant.Common.M00002, new Object[] {"申请单"}));

View File

@@ -72,6 +72,7 @@ public class RequestFormManageController {
*/
@PostMapping(value = "/save-surgery")
public R<?> saveSurgeryRequestForm(@RequestBody RequestFormSaveDto requestFormSaveDto) {
log.info("【Controller】保存手术申请单typeCode={}", ActivityDefCategory.PROCEDURE.getCode());
return iRequestFormManageAppService.saveRequestForm(requestFormSaveDto,
ActivityDefCategory.PROCEDURE.getCode());
}

View File

@@ -93,4 +93,9 @@ public class RequestFormPageDto {
* 手术等级
*/
private Integer surgeryLevel;
/**
* 就诊卡号
*/
private String identifierNo;
}

View File

@@ -59,7 +59,7 @@
T9.gender_enum AS genderEnum,
T9.id_card AS idCard,
T9.status_enum AS statusEnum,
T9.register_time AS registerTime,
T9.register_time AS register_time,
T9.total_price AS totalPrice,
T9.account_name AS accountName,
T9.enterer_name AS entererName,
@@ -84,7 +84,7 @@
T8.gender_enum AS gender_enum,
T8.id_card AS id_card,
T1.status_enum AS status_enum,
T1.create_time AS register_time,
T1.create_time AS "register_time",
T10.total_price,
T11."name" AS account_name,
T12."name" AS enterer_name,

View File

@@ -13,6 +13,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="patientAge" column="patient_age" />
<result property="encounterId" column="encounter_id" />
<result property="encounterNo" column="encounter_no" />
<result property="patientCardNo" column="patient_card_no" />
<result property="applyDoctorId" column="apply_doctor_id" />
<result property="applyDoctorName" column="apply_doctor_name" />
<result property="applyDeptId" column="apply_dept_id" />
@@ -79,6 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
EXTRACT(YEAR FROM AGE(p.birth_date)) as patient_age,
s.encounter_id,
e.bus_no as encounter_no,
pi.identifier_no as patient_card_no,
s.apply_doctor_id,
COALESCE(s.apply_doctor_name, apply_doc.name) as apply_doctor_name,
s.apply_dept_id,
@@ -177,6 +179,18 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
FROM cli_surgery s
LEFT JOIN adm_patient p ON s.patient_id = p.id
LEFT JOIN adm_encounter e ON s.encounter_id = e.id
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON s.patient_id = pi.patient_id
LEFT JOIN adm_operating_room r ON s.operating_room_id = r.id
LEFT JOIN adm_organization ro ON r.organization_id = ro.id
LEFT JOIN adm_organization o ON s.org_id = o.id
@@ -248,6 +262,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
p.birth_date,
<!-- 就诊编号 -->
e.bus_no as encounter_no,
<!-- 就诊卡号 -->
pi.identifier_no as patient_card_no,
<!-- 字典文本使用CASE WHEN避免额外JOIN -->
CASE s.surgery_type_enum
WHEN 1 THEN '门诊手术'
@@ -302,6 +318,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<!-- 只JOIN必要的表患者和就诊 -->
LEFT JOIN adm_patient p ON s.patient_id = p.id
LEFT JOIN adm_encounter e ON s.encounter_id = e.id
<!-- 关联患者标识表获取就诊卡号 -->
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON s.patient_id = pi.patient_id
<where>
s.delete_flag = '0'
<if test="ew.sqlSegment != null and ew.sqlSegment != ''">

View File

@@ -30,13 +30,26 @@
cs.apply_dept_name,
cs.org_id,
o.name AS org_name,
cs.main_surgeon_name AS surgeon_name
cs.main_surgeon_name AS surgeon_name,
COALESCE(pi.identifier_no, ap.bus_no, '') AS identifierNo
FROM op_schedule os
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
LEFT JOIN adm_organization o ON cs.org_id = o.id
LEFT JOIN sys_tenant st ON st.id = os.tenant_id
LEFT JOIN sys_user su ON su.user_id = os.creator_id
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON os.patient_id = pi.patient_id
<where>
<if test="dto.tenantId != null">
AND os.tenant_id = #{dto.tenantId}
@@ -75,12 +88,25 @@
cs.main_surgeon_name AS surgeon_name,
cs.apply_doctor_name AS apply_doctor_name,
drf.create_time AS apply_time,
os.surgery_nature AS surgeryType
os.surgery_nature AS surgeryType,
COALESCE(pi.identifier_no, ap.bus_no, '') AS identifierNo
FROM op_schedule os
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
LEFT JOIN adm_organization o ON cs.org_id = o.id
LEFT JOIN doc_request_form drf ON drf.prescription_no=cs.surgery_no
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON os.patient_id = pi.patient_id
WHERE os.schedule_id = #{scheduleId}
LIMIT 1
</select>
@@ -123,13 +149,26 @@
cs.apply_dept_name,
cs.org_id,
o.name AS org_name,
cs.main_surgeon_name AS surgeon_name
cs.main_surgeon_name AS surgeon_name,
COALESCE(pi.identifier_no, ap.bus_no, '') AS identifierNo
FROM op_schedule os
LEFT JOIN adm_patient ap ON os.patient_id = ap.id
LEFT JOIN cli_surgery cs ON os.oper_code = cs.surgery_no AND cs.delete_flag = '0'
LEFT JOIN adm_organization o ON cs.org_id = o.id
LEFT JOIN sys_tenant st ON st.id = os.tenant_id
LEFT JOIN sys_user su ON su.user_id = os.creator_id
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0'
AND identifier_no IS NOT NULL
AND identifier_no != ''
) t
WHERE rn = 1
) pi ON os.patient_id = pi.patient_id
<where>
AND os.delete_flag = '0'
<if test="dto.patientId != null"> AND os.patient_id = #{dto.patientId}</if>

View File

@@ -0,0 +1,149 @@
<?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.openhis.web.datadictionary.mapper.LabActivityDefinitionManageMapper">
<!-- 检验项目分页查询(操作 lab_activity_definition 表,无物理外键) -->
<select id="getLabActivityDefinitionPage" parameterType="java.util.Map"
resultType="com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto">
SELECT
T1.id,
T1.category_code,
T1.bus_no,
T1.name,
T1.py_str,
T1.wb_str,
T1.type_enum,
T1.permitted_unit_code,
T1.org_id,
T1.location_id,
T1.yb_flag,
T1.yb_no,
T1.yb_match_flag,
T1.status_enum,
T1.body_site_code,
T1.specimen_code,
T1.description_text,
T1.rule_id,
T1.tenant_id,
T1.chrgitm_lv,
T1.children_json,
T1.pricing_flag,
T1.sort_order,
T1.service_range,
T1.inspection_type_id,
T1.fee_package_id,
T1.sub_item_id,
T3.name AS test_type,
T5.package_name,
T6.name AS sub_item_name
FROM lab_activity_definition T1
/* 检验类型关联(逻辑关联,无外键) */
LEFT JOIN inspection_type T3
ON T1.inspection_type_id = T3.id
AND T3.valid_flag = 1
/* 费用套餐关联(逻辑关联,无外键) */
LEFT JOIN inspection_basic_information T5
ON T1.fee_package_id = T5.basic_information_id
AND T5.del_flag = false
/* 下级医技类型关联(逻辑关联,无外键) */
LEFT JOIN inspection_type T6
ON T1.sub_item_id = T6.id
AND T6.valid_flag = 1
<where>
T1.delete_flag = '0'
<if test="ew.customSqlSegment != null and ew.customSqlSegment != ''">
<choose>
<when test="ew.customSqlSegment.contains('tenant_id')">
${ew.customSqlSegment.replaceFirst('tenant_id', 'T1.tenant_id').replaceFirst('status_enum', 'T1.status_enum').replaceFirst('WHERE', 'AND')}
</when>
<otherwise>
${ew.customSqlSegment.replaceFirst('status_enum', 'T1.status_enum').replaceFirst('WHERE', 'AND')}
</otherwise>
</choose>
</if>
</where>
ORDER BY T1.id DESC
</select>
<!-- 检验项目详情 -->
<select id="getLabActivityDefinitionOne" resultType="com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto">
SELECT
T1.id,
T1.category_code,
T1.bus_no,
T1.name,
T1.py_str,
T1.wb_str,
T1.type_enum,
T1.permitted_unit_code,
T1.org_id,
T1.location_id,
T1.yb_flag,
T1.yb_no,
T1.yb_match_flag,
T1.status_enum,
T1.body_site_code,
T1.specimen_code,
T1.description_text,
T1.rule_id,
T1.tenant_id,
T1.chrgitm_lv,
T1.children_json,
T1.pricing_flag,
T1.sort_order,
T1.service_range,
T1.inspection_type_id,
T1.fee_package_id,
T1.sub_item_id,
T3.name AS test_type,
T5.package_name,
T6.name AS sub_item_name
FROM lab_activity_definition T1
LEFT JOIN inspection_type T3
ON T1.inspection_type_id = T3.id
AND T3.valid_flag = 1
LEFT JOIN inspection_basic_information T5
ON T1.fee_package_id = T5.basic_information_id
AND T5.del_flag = false
LEFT JOIN inspection_type T6
ON T1.sub_item_id = T6.id
AND T6.valid_flag = 1
<where>
T1.delete_flag = '0'
<if test="id != null">
AND T1.id = #{id}
</if>
<if test="tenantId != null">
AND T1.tenant_id = #{tenantId}
</if>
</where>
</select>
<!-- 检验项目下拉列表(轻量级) -->
<select id="getLabActivityDefinitionSimpleList" resultType="com.openhis.web.datadictionary.dto.DiagnosisTreatmentDto">
SELECT
T1.id,
T1.bus_no,
T1.name,
T1.permitted_unit_code
FROM lab_activity_definition T1
WHERE T1.delete_flag = '0'
AND T1.status_enum = #{statusEnum}
AND T1.tenant_id = #{tenantId}
<if test="searchKey != null and searchKey != ''">
AND (
T1.name LIKE CONCAT('%', #{searchKey}, '%')
OR T1.bus_no LIKE CONCAT('%', #{searchKey}, '%')
OR T1.py_str LIKE CONCAT('%', #{searchKey}, '%')
)
</if>
ORDER BY T1.id DESC
<if test="searchKey != null and searchKey != ''">
LIMIT 1500
</if>
<if test="searchKey == null or searchKey == ''">
LIMIT 500
</if>
</select>
</mapper>

View File

@@ -471,6 +471,7 @@
T1.dose AS dose,
T1.dose_unit_code AS dose_unit_code,
T4.id AS charge_item_id,
T4.unit_price AS unit_price,
T4.total_price AS total_price,
T4.status_enum AS charge_status,
al.id AS position_id,
@@ -480,7 +481,9 @@
ccd.name AS condition_definition_name,
T1.sort_number AS sort_number,
T1.based_on_id AS based_on_id,
T1.category_enum AS category_enum
T1.category_enum AS category_enum,
T1.encounter_id AS encounter_id,
T1.patient_id AS patient_id
FROM med_medication_request AS T1
LEFT JOIN med_medication_definition AS T2 ON T2.ID = T1.medication_id
AND T2.delete_flag = '0'
@@ -523,6 +526,7 @@
NULL AS dose,
'' AS dose_unit_code,
T3.id AS charge_item_id,
T3.unit_price AS unit_price,
T3.total_price AS total_price,
T3.status_enum AS charge_status,
al.id AS position_id,
@@ -532,7 +536,9 @@
'' AS condition_definition_name,
99 AS sort_number,
T1.based_on_id AS based_on_id,
T1.category_enum AS category_enum
T1.category_enum AS category_enum,
T1.encounter_id AS encounter_id,
T1.patient_id AS patient_id
FROM wor_device_request AS T1
LEFT JOIN adm_device_definition AS T2 ON T2.ID = T1.device_def_id
AND T2.delete_flag = '0'
@@ -550,7 +556,7 @@
AND T1.refund_device_id IS NULL
ORDER BY T1.status_enum)
UNION ALL
(SELECT 3 AS advice_type,
(SELECT CASE WHEN T1.category_enum = 4 THEN 6 ELSE COALESCE(T1.category_enum, 3) END AS advice_type,
T1.id AS request_id,
T1.id || '-3' AS unique_key,
'' AS prescription_no,
@@ -561,18 +567,19 @@
null AS skin_test_flag,
null AS inject_flag,
null AS group_id,
COALESCE(T2.NAME, CASE WHEN T1.content_json IS NOT NULL AND T1.content_json != '' THEN T1.content_json::json->>'adviceName' ELSE NULL END) AS advice_name,
COALESCE(T2.NAME, T1.content_json::jsonb->>'surgeryName', T1.content_json::jsonb->>'adviceName') AS advice_name,
'' AS volume,
'' AS lot_number,
T1.quantity AS quantity,
T1.unit_code AS unit_code,
T1.status_enum AS status_enum,
'' AS method_code,
'' AS rate_code,
NULL AS dose,
'' AS dose_unit_code,
T3.id AS charge_item_id,
T3.total_price AS total_price,
T1.quantity AS quantity,
T1.unit_code AS unit_code,
T1.status_enum AS status_enum,
'' AS method_code,
'' AS rate_code,
NULL AS dose,
'' AS dose_unit_code,
T3.id AS charge_item_id,
T3.unit_price AS unit_price,
T3.total_price AS total_price,
T3.status_enum AS charge_status,
ao.id AS position_id,
ao.name AS position_name,
@@ -580,9 +587,11 @@
1 AS part_percent,
'' AS condition_definition_name,
99 AS sort_number,
T1.based_on_id AS based_on_id,
T1.category_enum AS category_enum
FROM wor_service_request AS T1
T1.based_on_id AS based_on_id,
T1.category_enum AS category_enum,
T1.encounter_id AS encounter_id,
T1.patient_id AS patient_id
FROM wor_service_request AS T1
LEFT JOIN wor_activity_definition AS T2
ON T2.ID = T1.activity_id
AND T2.delete_flag = '0'

View File

@@ -7,6 +7,7 @@
<!-- 根据申请单号查询检验申请单(返回完整字段) -->
<select id="getInspectionApplyByApplyNo" resultType="com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto">
SELECT
id AS applicationId,
apply_no AS applyNo,
patient_id AS patientId,
patient_name AS patientName,
@@ -40,20 +41,17 @@
</select>
<!-- 分页查询检验申请单列表根据就诊ID查询按申请时间降序
encounterId: 就诊ID作为查询条件查出患者idpatient_id再以患者id对申请单进行查询
对申请单表(lab_apply)、申请单明细表(lab_apply_item)和就诊表(adm_encounter)进行联合查询(申请单号,检验项目,申请医生,申请单优先级码,申请单状态,金额)-->
直接查询申请单表,不关联明细表,避免重复记录-->
<select id="getInspectionApplyListPage" resultType="com.openhis.web.doctorstation.dto.DoctorStationLabApplyDto">
SELECT t1.apply_no AS applyNo,
t1.inspection_item AS inspectionItem,
SELECT t1.id AS applicationId,
t1.apply_no AS applyNo,
t1.inspection_item AS itemName,
t1.apply_doc_name AS applyDocName,
t1.priority_code AS priorityCode,
t2.item_name AS itemName,
t1.apply_status AS applyStatus,
t2.item_amount AS itemAmount
t1.apply_remark AS applyRemark
FROM lab_apply AS t1
INNER JOIN adm_encounter AS t3 ON t1.patient_id::bigint = t3.patient_id
LEFT JOIN lab_apply_item AS t2
ON t1.apply_no = t2.apply_no
WHERE t1.delete_flag = '0'
AND t3.id = #{encounterId}
ORDER BY t1.apply_time DESC

View File

@@ -49,7 +49,7 @@
T8.phone AS phone,
T8.birth_date AS birth_date,
T1.status_enum AS status_enum,
T1.create_time AS register_time,
T1.create_time AS "register_time",
T1.reception_time AS reception_time,
T1.organization_id AS org_id,
T8.bus_no AS bus_no,

View File

@@ -203,6 +203,7 @@
T1.dose AS dose,
T1.dose_unit_code AS dose_unit_code,
T4.id AS charge_item_id,
T4.unit_price AS unit_price,
T4.total_price AS total_price,
T4.status_enum AS charge_status,
al.id AS position_id,
@@ -254,6 +255,7 @@
NULL AS dose,
'' AS dose_unit_code,
T3.id AS charge_item_id,
T3.unit_price AS unit_price,
T3.total_price AS total_price,
T3.status_enum AS charge_status,
al.id AS position_id,
@@ -281,7 +283,7 @@
AND T1.refund_device_id IS NULL
ORDER BY T1.status_enum)
UNION ALL
(SELECT 3 AS advice_type,
(SELECT CASE WHEN T1.category_enum = 4 THEN 6 ELSE COALESCE(T1.category_enum, 3) END AS advice_type,
T1.id AS request_id,
T1.id || '-3' AS unique_key,
T1.requester_id AS requester_id,
@@ -291,7 +293,7 @@
null AS skin_test_flag,
null AS inject_flag,
null AS group_id,
T2.NAME AS advice_name,
COALESCE(T2.NAME, T1.content_json::jsonb->>'surgeryName') AS advice_name,
'' AS volume,
'' AS lot_number,
T1.quantity AS quantity,
@@ -302,6 +304,7 @@
NULL AS dose,
'' AS dose_unit_code,
T3.id AS charge_item_id,
T3.unit_price AS unit_price,
T3.total_price AS total_price,
T3.status_enum AS charge_status,
ao.id AS position_id,
@@ -309,7 +312,7 @@
null AS dispense_per_duration,
1 AS part_percent,
'' AS condition_definition_name,
T1.therapy_enum AS therapyEnum,
COALESCE(T1.therapy_enum, 2) AS therapyEnum,
99 AS sort_number,
T1.based_on_id AS based_on_id
FROM wor_service_request AS T1

View File

@@ -26,12 +26,13 @@
<select id="getRequestFormDetail" resultType="com.openhis.web.regdoctorstation.dto.RequestFormDetailQueryDto">
SELECT wsr.quantity,
wsr.unit_code,
wad.NAME AS advice_name,
COALESCE(wad.NAME, wsr.content_json::jsonb->>'surgeryName') AS advice_name,
aci.total_price
FROM wor_service_request AS wsr
LEFT JOIN wor_activity_definition AS wad ON wad.ID = wsr.activity_id
AND wad.delete_flag = '0'
LEFT JOIN adm_charge_item AS aci ON aci.service_id = wsr.ID
AND aci.service_table = 'wor_service_request'
AND aci.delete_flag = '0'
WHERE wsr.delete_flag = '0'
AND wsr.prescription_no = #{prescriptionNo}
@@ -67,6 +68,7 @@
<result column="anesthesia_type_enum" property="anesthesiaTypeEnum"/>
<result column="incision_level" property="incisionLevel"/>
<result column="surgery_level" property="surgeryLevel"/>
<result column="identifier_no" property="identifierNo"/>
</resultMap>
<!-- 分页查询申请单 -->
@@ -91,7 +93,8 @@
cs.anesthesia_type_enum,
cs.incision_level,
cs.surgery_level,
fc.contract_name AS fee_type
fc.contract_name AS fee_type,
COALESCE(pi.identifier_no, ap.bus_no, '') AS identifier_no
FROM doc_request_form drf
LEFT JOIN cli_surgery cs ON cs.surgery_no = drf.prescription_no
LEFT JOIN adm_patient ap ON ap.id = cs.patient_id
@@ -99,6 +102,16 @@
LEFT JOIN adm_account aa ON aa.encounter_id = ae.id AND aa.delete_flag = '0'
LEFT JOIN fin_contract fc ON fc.bus_no = aa.contract_no AND fc.delete_flag = '0'
LEFT JOIN op_schedule os ON os.apply_id = drf.id AND os.delete_flag = '0'
LEFT JOIN (
SELECT patient_id, identifier_no
FROM (
SELECT patient_id, identifier_no,
ROW_NUMBER() OVER (PARTITION BY patient_id ORDER BY create_time ASC) AS rn
FROM adm_patient_identifier
WHERE delete_flag = '0' AND identifier_no IS NOT NULL AND identifier_no != ''
) t
WHERE rn = 1
) pi ON ap.id = pi.patient_id
<where>
<if test="requestFormDto.surgeryNo != null and requestFormDto.surgeryNo != ''">
AND drf.prescription_no LIKE CONCAT('%', #{requestFormDto.surgeryNo}, '%')

View File

@@ -43,7 +43,7 @@
T8.gender_enum AS gender_enum,
T8.id_card AS id_card,
T1.status_enum AS status_enum,
T1.create_time AS register_time,
T1.create_time AS "register_time",
T10.total_price,
T11."name" AS account_name,
T12."name" AS enterer_name,
@@ -140,7 +140,7 @@
T8.phone AS phone,
T8.birth_date AS birth_date,
T1.status_enum AS status_enum,
T1.create_time AS register_time,
T1.create_time AS "register_time",
T1.reception_time AS reception_time,
T1.organization_id AS org_id,
T8.bus_no AS bus_no,

View File

@@ -769,15 +769,21 @@ public class CommonConstants {
}
/**
* 号源槽位状态 (adm_schedule_slot.slot_status)
* 号源槽位状态 (adm_schedule_slot.status)
*/
public interface SlotStatus {
/** 可用 / 待预约 */
Integer AVAILABLE = 0;
/** 已预约 */
Integer BOOKED = 1;
/** 已停诊 / 已失效 */
Integer STOPPED = 2;
/** 已取消 / 已停诊 */
Integer CANCELLED = 2;
/** 已锁定 */
Integer LOCKED = 3;
/** 已签到 / 已取号 */
Integer CHECKED_IN = 4;
/** 已退号 */
Integer RETURNED = 5;
}
/**
@@ -790,6 +796,8 @@ public class CommonConstants {
Integer CHECKED_IN = 2;
/** 已取消 */
Integer CANCELLED = 3;
/** 已退号 */
Integer RETURNED = 4;
}
}

View File

@@ -23,14 +23,19 @@ public enum ItemType implements HisEnumInterface {
MEDICINE(1, "1", "药品"),
/**
* 耗材
* 医疗活动
*/
ACTIVITY(3, "3", "医疗活动"),
/**
* 耗材前端使用值2
*/
DEVICE(2, "2", "耗材"),
/**
* 医疗活动
* 手术前端使用值6避免与耗材冲突
*/
ACTIVITY(3, "3", "医疗活动");
SURGERY(6, "6", "手术");
@EnumValue
private Integer value;

View File

@@ -9,6 +9,8 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.time.LocalTime;
import java.util.Date;
/**
* 号源池明细Entity
*
@@ -29,7 +31,7 @@ public class ScheduleSlot extends HisBaseEntity {
/** 序号 */
private Integer seqNo;
/** 序号状态: 0-可用,1-已预约,2-已取消,3-已过期等 */
/** 序号状态: 0-可用,1-已预约,2-已取消/已停诊,3-已锁定,4-已签到,5-已退号 */
private Integer status;
/** 预约订单ID */
@@ -37,4 +39,7 @@ public class ScheduleSlot extends HisBaseEntity {
/** 预计叫号时间 */
private LocalTime expectTime;
/** 签到时间 */
private Date checkInTime;
}

View File

@@ -11,6 +11,7 @@ import java.time.LocalTime;
public class TicketSlotDTO {
// 基础信息
private Long slotId;
private Integer seqNo;
private Long scheduleId;
private String doctor;
private Long doctorId;
@@ -22,6 +23,13 @@ public class TicketSlotDTO {
private Long patientId;
private String phone;
private Integer orderStatus;
private Long orderId;
private String orderNo;
private String patientGender;
private Integer genderEnum;
private String idCard;
private String encounterId;
private String appointmentTime;
// 底层逻辑判断专属字段
private Integer slotStatus;

View File

@@ -37,4 +37,21 @@ public interface SchedulePoolMapper extends BaseMapper<SchedulePool> {
AND p.delete_flag = '0'
""")
int refreshPoolStats(@Param("poolId") Long poolId);
/**
* 签到时更新号源池统计:锁定数-1已预约数+1
*
* @param poolId 号源池ID
* @return 结果
*/
@Update("""
UPDATE adm_schedule_pool
SET locked_num = locked_num - 1,
booked_num = booked_num + 1,
update_time = NOW()
WHERE id = #{poolId}
AND locked_num > 0
AND delete_flag = '0'
""")
int updatePoolStatsOnCheckIn(@Param("poolId") Integer poolId);
}

View File

@@ -6,6 +6,7 @@ import com.openhis.appointmentmanage.domain.ScheduleSlot;
import com.openhis.appointmentmanage.domain.TicketSlotDTO;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.openhis.appointmentmanage.dto.TicketQueryDTO;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Repository;
import org.apache.ibatis.annotations.Param;
@@ -30,6 +31,16 @@ public interface ScheduleSlotMapper extends BaseMapper<ScheduleSlot> {
*/
int updateSlotStatus(@Param("slotId") Long slotId, @Param("status") Integer status);
/**
* 更新槽位状态并记录签到时间
*
* @param slotId 槽位ID
* @param status 状态
* @param checkInTime 签到时间
* @return 结果
*/
int updateSlotStatusAndCheckInTime(@Param("slotId") Long slotId, @Param("status") Integer status, @Param("checkInTime") Date checkInTime);
/**
* 根据槽位ID查询所属号源池ID。
*/

View File

@@ -20,7 +20,7 @@ import lombok.experimental.Accessors;
@EqualsAndHashCode(callSuper = false)
public class Order extends HisBaseEntity {
@TableId(type = IdType.ASSIGN_ID)
@TableId(type = IdType.AUTO)
@JsonSerialize(using = ToStringSerializer.class)
private Long id;

View File

@@ -32,4 +32,30 @@ public interface OrderMapper extends BaseMapper<Order> {
int updateOrderStatusById(Long id, Integer status);
int updateOrderCancelInfoById(Long id, Date cancelTime, String cancelReason);
/**
* 更新订单支付状态
*
* @param orderId 订单ID
* @param payStatus 支付状态0-未支付1-已支付
* @param payTime 支付时间
* @return 结果
*/
int updatePayStatus(@Param("orderId") Long orderId, @Param("payStatus") Integer payStatus, @Param("payTime") Date payTime);
/**
* 统计同一患者在同一科室、同一时段(上午/下午)内的有效预约订单数量
*
* @param patientId 患者ID
* @param departmentId 科室ID
* @param startTime 时段起始时间(含)
* @param endTime 时段结束时间(不含)
* @param statuses 订单状态集合(如 1=已预约,2=已取号)
* @return 数量
*/
int countPatientDeptOrdersInPeriod(@Param("patientId") Long patientId,
@Param("departmentId") Long departmentId,
@Param("startTime") Date startTime,
@Param("endTime") Date endTime,
@Param("statuses") List<Integer> statuses);
}

View File

@@ -88,6 +88,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
}
Order order = new Order();
order.setId(null); // 显式置空,确保触发数据库自增,避免 MP 预分配雪花 ID 的干扰
String orderNo = assignSeqUtil.getSeq(AssignSeqEnum.ORDER_NUM.getPrefix(), 18);
order.setOrderNo(orderNo);

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.openhis.appointmentmanage.domain.AppointmentConfig;
import com.openhis.appointmentmanage.service.IAppointmentConfigService;
import com.openhis.appointmentmanage.domain.TicketSlotDTO;
import com.openhis.appointmentmanage.domain.ScheduleSlot;
import com.openhis.appointmentmanage.mapper.SchedulePoolMapper;
import com.openhis.appointmentmanage.mapper.ScheduleSlotMapper;
import com.openhis.clinical.domain.Order;
@@ -27,6 +28,7 @@ import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -52,6 +54,9 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
@Resource
private SchedulePoolMapper schedulePoolMapper;
@Resource
private com.openhis.clinical.mapper.OrderMapper orderMapper;
@Resource
private IAppointmentConfigService appointmentConfigService;
@@ -146,7 +151,25 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
logger.debug("开始执行纯净打单路线slotId: {}, patientName: {}", slotId, dto.getPatientName());
// 1. 直查物理大底座!
// 1. 检查患者取消预约次数限制(应在预约挂号时限制,而非取消预约时)
Integer tenantId = dto.getTenant_id();
Long patientId = dto.getPatientId();
if (tenantId != null && patientId != null) {
AppointmentConfig config = appointmentConfigService.getConfigByTenantId(tenantId);
if (config != null && config.getCancelAppointmentCount() != null
&& config.getCancelAppointmentCount() > 0) {
// 计算当前周期的起始时间
LocalDateTime startTime = calculatePeriodStartTime(config.getCancelAppointmentType());
// 统计已取消次数
long cancelledCount = orderService.countPatientCancellations(patientId, tenantId, startTime);
if (cancelledCount >= config.getCancelAppointmentCount()) {
String periodName = getPeriodName(config.getCancelAppointmentType());
throw new RuntimeException("由于您在" + periodName + "内累计取消预约已达" + cancelledCount + "次,触发系统限制,暂时无法在线预约,请联系分诊台或咨询客服。");
}
}
}
// 2. 直查物理大底座!
TicketSlotDTO slot = scheduleSlotMapper.selectTicketSlotById(slotId);
if (slot == null) {
@@ -160,6 +183,28 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
throw new RuntimeException("该排班医生已停诊");
}
// 2.1 同一患者同一天/同一科室/同一时段(上午/下午)不可重复预约
if (dto.getPatientId() != null && slot.getDepartmentId() != null && slot.getScheduleDate() != null && slot.getExpectTime() != null) {
boolean isMorning = slot.getExpectTime().isBefore(LocalTime.NOON);
LocalDate scheduleDateForCheck = slot.getScheduleDate();
LocalDateTime periodStart = isMorning
? LocalDateTime.of(scheduleDateForCheck, LocalTime.MIN)
: LocalDateTime.of(scheduleDateForCheck, LocalTime.NOON);
LocalDateTime periodEnd = isMorning
? LocalDateTime.of(scheduleDateForCheck, LocalTime.NOON)
: LocalDateTime.of(scheduleDateForCheck.plusDays(1), LocalTime.MIN);
Date startTime = Date.from(periodStart.atZone(ZoneId.systemDefault()).toInstant());
Date endTime = Date.from(periodEnd.atZone(ZoneId.systemDefault()).toInstant());
// 预约去重以订单为准order_main因为预约成功会先落订单clinical_ticket 不一定在此链路写入
List<Integer> effectiveOrderStatuses = Arrays.asList(AppointmentOrderStatus.BOOKED, AppointmentOrderStatus.CHECKED_IN);
int exists = orderMapper.countPatientDeptOrdersInPeriod(dto.getPatientId(), slot.getDepartmentId(), startTime, endTime, effectiveOrderStatuses);
if (exists > 0) {
throw new RuntimeException("该患者已在当前科室该时段存在预约记录,不可重复预约");
}
}
// 原子抢占:避免并发下同一槽位被重复预约
int lockRows = scheduleSlotMapper.lockSlotForBooking(slotId);
if (lockRows <= 0) {
@@ -242,26 +287,8 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
throw new RuntimeException("当前号源没有可取消的预约订单");
}
// 核心逻辑:获取订单信息并检查机构取消限制
Order latestOrder = orders.get(0);
Integer tenantId = latestOrder.getTenantId();
Long patientId = latestOrder.getPatientId();
if (tenantId != null && patientId != null) {
AppointmentConfig config = appointmentConfigService.getConfigByTenantId(tenantId);
if (config != null && config.getCancelAppointmentCount() != null
&& config.getCancelAppointmentCount() > 0) {
// 计算当前周期的起始时间
LocalDateTime startTime = calculatePeriodStartTime(config.getCancelAppointmentType());
// 统计已取消次数
long cancelledCount = orderService.countPatientCancellations(patientId, tenantId, startTime);
if (cancelledCount >= config.getCancelAppointmentCount()) {
String periodName = getPeriodName(config.getCancelAppointmentType());
throw new RuntimeException("您在" + periodName + "内已达到该机构取消预约次数上限(" + config.getCancelAppointmentCount() + "次),禁止取消");
}
}
}
// 直接执行取消,不再检查取消限制
// 根据需求,取消限制应在预约挂号时检查,而非取消预约时
for (Order order : orders) {
orderService.cancelAppointmentOrder(order.getId(), "患者取消预约");
}
@@ -274,7 +301,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
}
/**
* 取号
* 取号(签到)
*
* @param slotId 槽位ID
* @return 结果
@@ -287,7 +314,24 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
throw new RuntimeException("当前号源没有可取号的预约订单");
}
Order latestOrder = orders.get(0);
return orderService.updateOrderStatusById(latestOrder.getId(), AppointmentOrderStatus.CHECKED_IN);
// 1. 更新订单状态为已取号,并更新支付状态和支付时间
orderService.updateOrderStatusById(latestOrder.getId(), AppointmentOrderStatus.CHECKED_IN);
// 更新支付状态为已支付,记录支付时间
orderMapper.updatePayStatus(latestOrder.getId(), 1, new Date());
// 2. 查询号源槽位信息
ScheduleSlot slot = scheduleSlotMapper.selectById(slotId);
// 3. 更新号源槽位状态为已签到,记录签到时间
scheduleSlotMapper.updateSlotStatusAndCheckInTime(slotId, SlotStatus.CHECKED_IN, new Date());
// 4. 更新号源池统计:锁定数-1已预约数+1
if (slot != null && slot.getPoolId() != null) {
schedulePoolMapper.updatePoolStatsOnCheckIn(slot.getPoolId());
}
return 1;
}
/**
@@ -309,7 +353,7 @@ public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> impleme
orderService.cancelAppointmentOrder(order.getId(), "医生停诊");
}
int updated = scheduleSlotMapper.updateSlotStatus(slotId, SlotStatus.STOPPED);
int updated = scheduleSlotMapper.updateSlotStatus(slotId, SlotStatus.CANCELLED);
if (updated > 0) {
refreshPoolStatsBySlotId(slotId);
}

View File

@@ -17,7 +17,7 @@ import java.util.Date;
* @date 2025-06-03
*/
@Data
@TableName("doc_ital_signs")
@TableName("doc_vital_signs")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class VitalSigns extends HisBaseEntity {

View File

@@ -46,16 +46,24 @@ public class PaymentRecStaticServiceImpl extends ServiceImpl<PaymentRecStaticMap
Map<String, List<ChargeItemDefInfo>> collect;
List<PaymentRecStatic> paymentRecStatics = new ArrayList<>();
if (paymentStatisticalMethod == PaymentStatisticalMethod.FIN_TYPE_CODE) {
collect = chargeItemDefInfoList.stream().collect(Collectors.groupingBy(ChargeItemDefInfo::getTypeCode));
collect = chargeItemDefInfoList.stream()
.filter(info -> info.getTypeCode() != null)
.collect(Collectors.groupingBy(ChargeItemDefInfo::getTypeCode));
getPaymentRecStaticList(paymentId, paymentType, paymentStatisticalMethod, collect, paymentRecStatics);
} else if (paymentStatisticalMethod == PaymentStatisticalMethod.MED_CHRGITM_TYPE) {
collect = chargeItemDefInfoList.stream().collect(Collectors.groupingBy(ChargeItemDefInfo::getYbType));
collect = chargeItemDefInfoList.stream()
.filter(info -> info.getYbType() != null)
.collect(Collectors.groupingBy(ChargeItemDefInfo::getYbType));
getPaymentRecStaticList(paymentId, paymentType, paymentStatisticalMethod, collect, paymentRecStatics);
} else {
collect = chargeItemDefInfoList.stream().collect(Collectors.groupingBy(ChargeItemDefInfo::getTypeCode));
collect = chargeItemDefInfoList.stream()
.filter(info -> info.getTypeCode() != null)
.collect(Collectors.groupingBy(ChargeItemDefInfo::getTypeCode));
getPaymentRecStaticList(paymentId, paymentType, PaymentStatisticalMethod.FIN_TYPE_CODE, collect,
paymentRecStatics);
collect = chargeItemDefInfoList.stream().collect(Collectors.groupingBy(ChargeItemDefInfo::getYbType));
collect = chargeItemDefInfoList.stream()
.filter(info -> info.getYbType() != null)
.collect(Collectors.groupingBy(ChargeItemDefInfo::getYbType));
getPaymentRecStaticList(paymentId, paymentType, PaymentStatisticalMethod.MED_CHRGITM_TYPE, collect,
paymentRecStatics);
}

View File

@@ -24,9 +24,14 @@ import java.util.Date;
public class InspectionLabApply extends HisBaseEntity {
/**
* 主键ID,申请单编号
* 主键ID(自增)
*/
@TableId(type = IdType.AUTO)
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/**
* 申请单编号
*/
@TableId(type = IdType.NONE)
private String applyNo;
/**
* 患者主索引

View File

@@ -55,7 +55,10 @@ public class InspectionPackageDetail {
/** 单位 */
private String unit;
/** 单价 */
/** 原始单价(未折扣前的价格,用于折扣变更时恢复原价) */
private BigDecimal originalPrice;
/** 单价(折后单价 = 原始单价 × 折扣比例) */
private BigDecimal unitPrice;
/** 金额 */

View File

@@ -0,0 +1,106 @@
package com.openhis.lab.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.core.common.core.domain.HisBaseEntity;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 检验项目定义实体(独立表 lab_activity_definition不依赖 wor_activity_definition
*/
@Data
@TableName("lab_activity_definition")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
public class LabActivityDefinition extends HisBaseEntity {
/** 主键ID */
@TableId(type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
/** 目录类别 */
private String categoryCode;
/** 编码 */
private String busNo;
/** 项目名称 */
private String name;
/** 项目名称拼音 */
private String pyStr;
/** 五笔拼音 */
private String wbStr;
/** 类型 */
private Integer typeEnum;
/** 使用单位 */
private String permittedUnitCode;
/** 所属科室 */
@JsonSerialize(using = ToStringSerializer.class)
private Long orgId;
/** 所在位置 */
@JsonSerialize(using = ToStringSerializer.class)
private Long locationId;
/** 医保标记 */
private Integer ybFlag;
/** 医保编码 */
private String ybNo;
/** 医保对码标记 */
private Integer ybMatchFlag;
/** 状态 */
private Integer statusEnum;
/** 身体部位 */
private String bodySiteCode;
/** 所需标本 */
private String specimenCode;
/** 说明 */
private String descriptionText;
/** 规则id */
private Integer ruleId;
/** 医保等级 */
private Integer chrgitmLv;
/** 子项json */
private String childrenJson;
/** 划价标记 */
private Integer pricingFlag;
/** 序号 */
private Integer sortOrder;
/** 服务范围 */
private String serviceRange;
/** 检验类型ID关联 inspection_type 大类,逻辑关联无外键) */
@JsonSerialize(using = ToStringSerializer.class)
private Long inspectionTypeId;
/** 费用套餐ID关联 inspection_basic_information逻辑关联无外键 */
@JsonSerialize(using = ToStringSerializer.class)
private Long feePackageId;
/** 下级医技类型ID关联 inspection_type 子类,逻辑关联无外键) */
@JsonSerialize(using = ToStringSerializer.class)
private Long subItemId;
}

View File

@@ -0,0 +1,13 @@
package com.openhis.lab.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.openhis.lab.domain.LabActivityDefinition;
import org.springframework.stereotype.Repository;
/**
* 检验项目定义 Mapper 接口
*/
@Repository
public interface LabActivityDefinitionMapper extends BaseMapper<LabActivityDefinition> {
}

View File

@@ -0,0 +1,18 @@
package com.openhis.lab.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.openhis.lab.domain.LabActivityDefinition;
/**
* 检验项目定义 Service 接口
*/
public interface ILabActivityDefinitionService extends IService<LabActivityDefinition> {
/**
* 新增检验项目
*
* @param labActivityDefinition 检验项目实体
* @return 是否成功
*/
boolean addLabActivityDefinition(LabActivityDefinition labActivityDefinition);
}

View File

@@ -0,0 +1,63 @@
package com.openhis.lab.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.core.common.utils.SecurityUtils;
import com.core.common.core.domain.model.LoginUser;
import com.openhis.lab.domain.LabActivityDefinition;
import com.openhis.lab.mapper.LabActivityDefinitionMapper;
import com.openhis.lab.service.ILabActivityDefinitionService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
/**
* 检验项目定义 Service 实现类
*/
@Slf4j
@Service
public class LabActivityDefinitionServiceImpl
extends ServiceImpl<LabActivityDefinitionMapper, LabActivityDefinition>
implements ILabActivityDefinitionService {
/**
* 新增检验项目(检查编码唯一性)
*/
@Override
@Transactional(rollbackFor = Exception.class)
public boolean addLabActivityDefinition(LabActivityDefinition labActivityDefinition) {
// 根据编码判断是否已存在
List<LabActivityDefinition> existing = baseMapper.selectList(
new LambdaQueryWrapper<LabActivityDefinition>()
.eq(LabActivityDefinition::getBusNo, labActivityDefinition.getBusNo()));
if (!existing.isEmpty()) {
return false;
}
setRequiredFields(labActivityDefinition);
return baseMapper.insert(labActivityDefinition) == 1;
}
/**
* 补全必填字段create_by、tenant_id、create_time
*/
private void setRequiredFields(LabActivityDefinition entity) {
String createBy = "system";
Integer tenantId = 1;
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
createBy = loginUser.getUsername();
tenantId = loginUser.getTenantId() != null ? loginUser.getTenantId() : 1;
}
} catch (Exception ignored) {
}
entity.setCreateBy(createBy);
entity.setTenantId(tenantId);
if (entity.getCreateTime() == null) {
entity.setCreateTime(new Date());
}
}
}

View File

@@ -37,6 +37,10 @@ public class OpSchedule extends HisBaseEntity {
/** 就诊ID */
private Long visitId;
/** 就诊卡号 */
@TableField(exist = false)
private String identifierNo;
/** 手术编码 */
private String operCode;

Some files were not shown because too many files have changed in this diff Show More