337 Commits

Author SHA1 Message Date
669d669422 refactor(home): 更新工作流任务API导入路径
- 将 '@/api/workflow/task' 导入路径更改为 '@/api/workflow/task.js'
2026-02-01 15:06:15 +08:00
98fe9f3301 feat(router): 添加医生工作站等功能模块路由配置
- 新增医生工作站路由,包含待写病历功能
- 添加全部功能模块路由,支持功能列表和配置页面
- 集成待办事项模块路由,完善工作流功能
- 配置相关API接口和服务类,实现用户配置管理
- 实现待写病历列表展示和相关业务逻辑
- 完善首页统计数据显示功能
2026-02-01 15:05:57 +08:00
6f7d723c6b Merge remote-tracking branch 'origin/develop' into develop 2026-02-01 14:51:14 +08:00
0a08088ada feat(menu): 添加菜单完整路径功能和待写病历管理
- 在SysMenu实体类中新增fullPath字段用于存储完整路径
- 实现buildMenuTreeWithFullPath方法构建带完整路径的菜单树
- 添加getMenuFullPath和generateFullPath服务方法获取和生成完整路径
- 在菜单控制器中增加获取完整路径的API接口
- 前端菜单组件显示完整路径并在新增修改时使用后端返回的路径
- 添加待写病历管理功能包括获取待写病历列表、数量统计和检查接口
- 在医生工作站界面集成待写病历选项卡和相关处理逻辑
- 更新首页统计数据接口路径并添加待写病历数量获取功能
- 重构首页快捷功能配置为动态从数据库获取用户自定义配置
- 优化菜单列表查询使用异步方式处理带完整路径的菜单数据
- 添加菜单完整路径的数据库映射配置和前端API调用支持
2026-02-01 14:50:22 +08:00
HuangShun
48309fcaa4 需求56 检查项目设置-》检查类型维护;在check_type表中增加一个parent_id字段用于父行与子行绑定;修改执行科室下拉字典的数据来源 2026-01-30 15:31:01 +08:00
wangjian963
28160e082c 收费工作站-门诊挂号:点击【确认】退号无响应 2026-01-30 12:02:37 +08:00
wangjian963
29ecfd90f2 修复收费工作站-门诊挂号:挂号类型字段内容重复显示 2026-01-30 11:10:36 +08:00
f690b78b18 上传文件至 md/需求/media 2026-01-29 22:39:47 +08:00
6f71c678bd 上传文件至 md/需求 2026-01-29 22:39:03 +08:00
1c781c1224 套餐设置套餐管理完善 2026-01-29 15:32:21 +08:00
HuangShun
638f853af6 需求17 门诊医生站-》患者列表,修复门诊医生站的初诊/复诊标识没有完成数据存储和显示 2026-01-29 14:59:07 +08:00
HuangShun
96a8f75aa1 修复Bug128 门诊管理-》门诊划价:【新增】诊疗项目在点击【签发】报错 2026-01-29 11:47:40 +08:00
15a6445e26 Merge remote-tracking branch 'origin/develop' into develop 2026-01-28 15:31:04 +08:00
0e4b0ad6fd feat(accomplishList): 设置默认按申请时间倒序排列
- 添加申请时间字段排序功能
- 设置默认排序方式为降序
- 优化控制台日志输出格式
- 移除多余的等号字符
2026-01-28 15:30:54 +08:00
HuangShun
7da461a9cb 需求56 检查项目设置-》检查类型维护;界面代码被误修,回滚提交 2026-01-28 15:00:03 +08:00
b0040bcd48 Merge remote-tracking branch 'origin/develop' into develop 2026-01-28 14:37:48 +08:00
fa5394cc35 feat(organization): 优化科室分类查询功能
- 修改 getOrganizationTree 方法参数,将 classEnum 字符串改为 classEnumList 列表
- 实现多选科室分类的精确匹配查询逻辑
- 添加分页查询时只显示未删除记录的过滤条件
- 更新控制器中对逗号分隔参数的解析逻辑
- 修复查询条件构造中的逻辑错误
- 配置 Lombok 注解处理器路径
- 重命名诊断服务方法名以提高可读性
- 修复医保模块中诊断查询方法调用
- 修复集合初始化语法错误
2026-01-28 14:36:25 +08:00
81cc8b08a0 Merge remote-tracking branch 'origin/develop' into develop 2026-01-28 14:29:29 +08:00
0cecf3bcad 套餐设置套餐管理完善 2026-01-28 14:26:41 +08:00
HuangShun
b8d7e3cdf1 修复125 【住院登记】的入院科室无法选择,入院病区也无法选择 2026-01-28 14:05:35 +08:00
weixin_45799331
df2a4c1694 Merge remote-tracking branch 'origin/develop' into develop 2026-01-28 12:12:13 +08:00
weixin_45799331
a6a4e0ed58 sse实时开发 微修 2026-01-28 12:11:50 +08:00
HuangShun
ba31371b6f 修复124 系统管理-》业务规则配置-》执行科室配置:项目名称显示数字 2026-01-28 09:38:00 +08:00
9bd5caaa1b Fix 住院工作站中,住院病历的入院记录不吻合问题 2026-01-27 18:41:29 +08:00
164e4a4b75 Merge remote-tracking branch 'origin/develop' into develop 2026-01-27 17:32:15 +08:00
4f0cc1a0c4 refactor(ui): 优化按钮样式和数据加载逻辑
- 将多个按钮组件从 type="text" 改为 link 属性,提升界面美观性
- 修复 PatientList 组件中姓名显示的文本截断功能
- 在住院记录模板中添加对 patientInfo 变化的监听,自动更新表单数据
- 优化打印机列表获取逻辑,添加连接状态检查和警告信息
- 移除不必要的防抖和重复请求防护逻辑,简化代码实现
- 修复多处组件中对 patientInfo 属性访问的安全性问题
- 优化病历数据加载时机,移除防抖包装直接调用加载函数
- 改进数据设置逻辑,避免覆盖未传入字段的原有值
- 调整组件属性定义,使 patientInfo 参数变为可选并设置默认值
- 优化患者切换时的组件重置和数据加载流程
2026-01-27 17:32:03 +08:00
HuangXinQuan
6dedb92b54 87 门诊医生站-》增加医生常用语权限管理 2026-01-27 17:10:33 +08:00
HuangShun
0f0dc70c7e 修复123 系统管理-》基础数据-》门诊号源管理:修改出诊医生字段内容未保存成功 2026-01-27 16:20:09 +08:00
HuangShun
acfce391dc 需求17 门诊医生站-》患者列表;从adm_encounter表中查询到first_enum字段用以判断初复诊 2026-01-27 15:39:04 +08:00
weixin_45799331
b0f2eabf6b sse实时开发 2026-01-27 13:31:03 +08:00
weixin_45799331
c5db404290 88 分诊排队管理-》科室叫号显示屏 表triage_queue_item中添加了联合索引queue_date,organization_id,tenant_id,queue_order。添加了room_no,practitioner_id字段。新增的实体类刚刚没提交 2026-01-27 13:28:44 +08:00
weixin_45799331
c4c3073be0 88 分诊排队管理-》科室叫号显示屏 表triage_queue_item中添加了联合索引queue_date,organization_id,tenant_id,queue_order。添加了room_no,practitioner_id字段。 2026-01-27 11:15:15 +08:00
41494ebf7c 诊疗下面没有项目的代码冲突 2026-01-27 11:05:43 +08:00
HuangShun
4de4d9099e 修复122 门诊医生站-》医嘱TAB:点击选中项目后查询框自动关闭 2026-01-27 10:56:25 +08:00
497af01f9b chore(config): 调整应用日志级别配置
- 将 com.openhis 包的日志级别从 debug 调整为 info
- 将 com.baomidou.mybatisplus 的日志级别从 debug 调整为 info
- 将 com.openhis.web.regdoctorstation.mapper 的日志级别从 debug 调整为 info
- 将 org.springframework.jdbc.core 的日志级别从 debug 调整为 info
- 将 com.alibaba.druid 的日志级别从 debug 调整为 info
- 将 com.alibaba.druid.sql 的日志级别从 debug 调整为 info
2026-01-27 10:53:37 +08:00
ffc1f29b80 chore(config): 更新开发环境数据库和Redis连接配置
- 修改PostgreSQL数据库连接地址从47.116.196.11到192.168.110.252
- 修改Redis服务器地址从47.116.196.11到192.168.110.252
- 修改Redis端口从26379调整为默认端口6379
2026-01-27 10:45:56 +08:00
86bca03b04 Backup local changes before resolving remote repository issue 2026-01-27 10:19:54 +08:00
11c2758289 test 2026-01-27 10:19:54 +08:00
802f845231 检验项目设置-套餐设置-套餐管理 2026-01-27 09:26:27 +08:00
HuangShun
ea5215a1b0 修复101 门诊医生站-》门诊病历配置了未显示 2026-01-26 16:05:41 +08:00
a9fb093d9c 上传文件至 md/需求/media 2026-01-26 15:12:39 +08:00
chenjinyang
f4bf064f08 Merge remote-tracking branch 'origin/develop' into develop 2026-01-26 13:50:02 +08:00
chenjinyang
4dd824d296 完成帮助中心的改造 2026-01-26 13:49:43 +08:00
3ab6c2d424 刪除测试上传md内容 2026-01-26 13:42:48 +08:00
12b2bf255c 上传文件至 md/需求/aaa 2026-01-26 13:41:20 +08:00
sindir
c878dc19d7 86门诊医生站-》西药方 2026-01-26 13:25:02 +08:00
sindir
c1efd84332 55门诊医生站-》中医:诊断字段 2026-01-26 13:21:45 +08:00
1616f66fc4 诊疗下没有项目功能完善 2026-01-26 11:59:13 +08:00
wangjian963
2df1ed645f Merge remote-tracking branch 'origin/develop' into develop 2026-01-26 11:08:59 +08:00
wangjian963
4f7fc1c09a 修改目录管理-诊疗目录-划价标记字段。 2026-01-26 11:08:46 +08:00
bd873f81d2 诊疗下没有项目功能完善 2026-01-26 10:10:42 +08:00
1975fda73c feat(common): 添加审计字段工具类和基础服务
- 实现AuditFieldUtil工具类,支持通过反射设置创建人、创建时间、更新人、更新时间字段
- 支持驼峰命名和下划线命名的字段格式
- 只有当字段值为null或空字符串时才进行设置,避免覆盖已有值
- 实现BaseService基类,自动在保存和更新操作时设置审计字段
- 继承MyBatis-Plus的ServiceImpl,提供save、saveBatch、updateById方法的审计字段自动设置
- 集成SecurityUtils获取当前登录用户信息用于设置操作人字段
2026-01-25 23:17:30 +08:00
ffce6f81c3 feat(core): 完善自动填充机制和时间格式化处理
- 替换 ServiceImpl 继承为 BaseService 以支持自动填充功能
- 在 HisBaseEntity 中添加 JsonFormat 注解统一时间格式化
- 重构 MybastisColumnsHandler 实现完整的自动填充逻辑,包括 createTime、updateTime、createBy、updateBy 和 tenantId 字段
- 添加详细的日志记录和异常处理机制
- 在 PractitionerAppServiceImpl 中增强租户ID和审计字段的设置逻辑
- 优化时间解析工具类 openhis.js 以正确处理 ISO 8601 格式时间字符串
- 更新数据库映射文件以支持下划线字段名映射
- 重构 SysUserServiceImpl 实现完整的审计字段自动填充机制
2026-01-25 23:13:04 +08:00
ca043de624 feat(inpatientDoctor): 添加住院医生模块本地病人信息状态管理
- 新增本地病人信息状态管理文件 localPatient.js
- 实现护士等级状态管理功能
- 添加选择患者信息本地状态管理
- 提供更新护士等级和患者信息的方法
2026-01-25 16:43:12 +08:00
054b51c63d Merge remote-tracking branch 'origin/develop' into develop 2026-01-25 16:42:23 +08:00
5cf2dd165c fix(core): 修复审计字段缺失和组件状态管理问题
- 在Account、ChargeItem、EncounterParticipant和Encounter服务中添加审计字段验证
- 确保tenantId、createBy和createTime字段在插入数据库前正确设置
- 修复EMR模块中删除模板API的导出问题
- 更新患者信息状态管理,统一使用localPatientInfo替换patientInfo
- 在EMR组件中实现防抖机制优化历史记录刷新性能
- 修复病历模板切换时的表单数据重置逻辑
- 在首页统计组件中使用markRaw包装图标组件
- 为住院记录模板添加默认表单数据结构
- 修复SVG患者图标路径错误
2026-01-25 16:41:19 +08:00
27b094744c 创建 md 下文件夹 2026-01-24 14:54:44 +08:00
wangjian963
55e3533600 Merge remote-tracking branch 'origin/develop' into develop 2026-01-23 17:11:51 +08:00
wangjian963
1522183432 门诊管理-》门诊划价:新增耗材点击【保存】报错的问题(设置租户id,创建者,创建时间) 2026-01-23 17:08:29 +08:00
6382741b71 上传文件至 md/需求 2026-01-23 16:49:43 +08:00
16c854d55f feat(router): 添加基础管理和发票管理路由配置
- 新增基础管理模块路由配置,包含发票管理子页面
- 配置动态路由中的发票管理组件路径
- 移除监控模块的路由配置
- 修复路由数组结构,移除多余的逗号
2026-01-23 16:17:00 +08:00
73617e1b0f Merge remote-tracking branch 'origin/develop' into develop 2026-01-23 16:13:57 +08:00
abd5bd9f2f feat(system): 添加菜单显示状态控制功能并完善租户ID设置
- 在MetaVo中添加visible字段用于控制菜单显示状态
- 修改SysMenuServiceImpl中的路由构建逻辑,传递visible信息到前端
- 更新SidebarItem.vue组件,根据visible属性控制菜单项显示
- 在多个医嘱管理相关服务类中显式设置租户ID以确保多租户隔离
- 调整字典管理相关路由配置,优化页面跳转路径
- 在菜单管理界面添加显示状态查询和表格列展示功能
2026-01-23 16:12:56 +08:00
HuangShun
9000d66c0c 修复107 系统管理-》基础数据-》科室管理:科室分类筛选条件无效中搜索条件清空问题 2026-01-23 14:06:07 +08:00
huhuihua
61be9ff552 46 门诊医生站-》开立诊断:优化 修改数据库中一些字段不能为null 2026-01-23 13:58:33 +08:00
huhuihua
9408cf6c2d Merge branch 'develop' of https://gitea.gentronhealth.com/wangyizhe/his into develop 2026-01-23 13:58:25 +08:00
HuangShun
66c70a2b4a 修复103 门诊医生站-》药品医嘱开立内容重复/【确认】无响应 2026-01-23 13:28:17 +08:00
f6d9321f95 代码回滚 2026-01-23 11:08:54 +08:00
ccff9a7246 fix(hospitalizationEmr): 解决病历模板切换时数据显示残留问题
- 在切换模板前重置表单数据,避免显示之前的数据
- 先清空当前组件再设置新组件,确保组件完全重新渲染
- 使用 nextTick 确保 DOM 更新后再设置新组件
- 添加 JSON 解析异常处理,解析失败时清空组件数据
- 当没有历史记录或加载出错时清空表单数据
- 患者信息变化时重置当前组件和表单数据
- 没有患者信息时也重置组件和表单数据
2026-01-22 22:36:54 +08:00
2884f610f5 refactor(pharmacy): 激活药品仓库各类订单的供应分类选项
- 激活损益订单中的通用损益、盘点损益和制剂消耗分类选项
- 更新采购订单中的库存供应和非库存供应分类选项
- 激活退货订单中的普通分类选项
- 激活退仓订单中的普通分类选项
- 激活入库订单中的外购药品、自制药品、代销药品、其他药品和赠送药品入库分类选项
- 激活出库订单中的院内出库、院外出库和其他出库分类选项
- 激活盘点订单中的普通盘点和月度盘点分类选项
- 在枚举类中启用所有被注释的供应分类并完善文档注释
2026-01-22 22:24:22 +08:00
wangjian963
035738f990 修改库房管理-》采购管理-》采购入库:仓库字段值为中心耗材库在采购管理未显示的问题,修改了采购入库仓库字段值的布局样式,修改了在批量保存入库业务中添加申请人等核心数据数据,
修改了获取入库数据的查询SQL语句。
2026-01-22 19:38:58 +08:00
sindir
d0c6f57f6b 解决了无法接诊的问题 2026-01-22 16:37:20 +08:00
huhuihua
58c1e02415 Merge branch 'develop' of https://gitea.gentronhealth.com/wangyizhe/his into develop 2026-01-22 15:58:55 +08:00
huhuihua
1e459b8883 46 门诊医生站-》开立诊断:优化 2026-01-22 15:51:37 +08:00
huabuweixin
0d57e984a6 76 门诊预约挂号 2026-01-22 15:09:52 +08:00
4450e3cc50 上传文件至 md/需求 2026-01-22 15:08:57 +08:00
wangjian963
902ee0587e 修改新增耗材“一次性静脉采血器” 点击保存categoryEnum为空值的问题。 2026-01-22 14:13:10 +08:00
49550fcc2e 诊疗下面没有诊疗项目 2026-01-22 14:03:38 +08:00
sindir
1dd7ee3428 90,分诊排队管理-》医生叫号界面 2026-01-22 12:14:01 +08:00
wangjian963
8dff5d466a Merge remote-tracking branch 'origin/develop' into develop 2026-01-22 09:22:22 +08:00
wangjian963
19ada4ace9 移除调用字典接口功能 2026-01-22 09:20:35 +08:00
c92ff38133 Merge remote-tracking branch 'origin/develop' into develop 2026-01-21 17:50:58 +08:00
1c07108e58 refactor(PatientList): 重构患者列表卡片布局结构
- 将原有的 header-top 和 header-bottom 结构替换为 info-row 统一布局
- 新增姓名、性别年龄、房间床号、住院号、保险类型等独立信息行
- 使用 el-text 组件优化姓名显示效果
- 为性别标签添加女性样式标识
- 调整床位信息展示方式,支持溢出省略
- 修改溢出属性从 hidden 为 visible 确保内容正常显示
- 优化标签样式和间距布局
- 隐藏已废弃的旧布局元素
- 调整 pending 患者列表的换行和对齐方式
2026-01-21 17:50:51 +08:00
weixin_45799331
34dd969cb4 门诊医生站-》医嘱:诊疗开具医嘱点击项目选择下拉框,获取时间过慢40多秒,解决了之后正常情况获取4秒 2026-01-21 17:27:28 +08:00
a0b546266d fix(mapper): 修复患者主信息查询的重复数据问题
- 在 getRegPatientMainInfo 查询中添加 DISTINCT ON 子句按 patient_id 去重
- 为分页功能添加 getRegPatientMainInfoCount 计数查询
- 修复 SQL 拼接条件的语法错误,将 ${ew.customSqlSegment} 替换为标准的动态 SQL 标签
- 调整字典标签查询逻辑,先查询指定表再回退到默认字典缓存
- 优化查询性能,避免不必要的数据重复和错误的 SQL 语法
- 添加缺失的 ORDER BY 子句确保查询结果的一致性
2026-01-21 16:22:05 +08:00
wangjian963
fc9ce6241e Merge remote-tracking branch 'origin/develop' into develop 2026-01-21 13:38:23 +08:00
wangjian963
5187ff1ae3 添加申请单表单患者信息自动填充姓名、就诊卡号、费用性质,以及申请医生和申请科室的输入框格式,
依据申请单和申请单明细表字段修改表单变量名。
2026-01-21 13:34:31 +08:00
huabuweixin
73b1d01044 修复
104 系统管理-》业务规则配置-》取药科室配置:开立科室字段内容显示不全
2026-01-21 10:02:04 +08:00
huabuweixin
b88ad89146 修复
107
系统管理-》基础数据-》科室管理:科室分类筛选条件无效
2026-01-20 18:02:41 +08:00
huabuweixin
de8039c513 Merge branch 'develop' of https://gitea.gentronhealth.com/wangyizhe/his into develop 2026-01-20 18:01:46 +08:00
3464153d93 Merge remote-tracking branch 'origin/develop' into develop 2026-01-20 17:31:07 +08:00
6b868e378f feat(router): 添加新功能模块路由配置
- 添加套餐管理相关路由到公共路由,确保始终可用
- 新增基础管理模块,包含发票管理功能
- 添加系统监控模块,包含操作日志、登录日志、定时任务功能
- 新增系统工具模块,包含代码生成功能
- 扩展系统管理模块,增加租户用户、合同管理、用户角色授权等功能
- 添加字典数据、任务日志、代码生成编辑等隐藏路由
- 统一修复代码格式,调整对象属性间的空格格式
- 完善路由元信息配置,添加权限控制和图标支持
2026-01-20 17:30:42 +08:00
f6403fa059 Fix 禅道 108 系统管理-》业务规则配置-》执行科室配置:【添加新项目】按钮无法操作 2026-01-20 17:12:26 +08:00
sindir
bc92b9aa62 正确转到字典类型页面 2026-01-20 16:29:30 +08:00
sindir
46145ff636 正确转到字典类型页面 2026-01-20 16:19:54 +08:00
huhuihua
3ad32fac9f 46 门诊医生站补充 2026-01-20 10:02:48 +08:00
d1223aec07 挂号补单功能的完善 2026-01-20 09:31:37 +08:00
649f7bcf5b fix(database): 修复患者首页查询重复数据和关联查询问题
- 在ATDManageAppMapper.xml中添加DISTINCT关键字解决入院患者信息重复问题
- 重构PatientHomeAppMapper.xml中的复杂查询逻辑,使用子查询替代多层JOIN提高性能
- 修复vital signs查询中的字段关联错误,将base_service_req_id改为request_id
- 优化前端implementDepartment组件的数据加载逻辑,添加异步处理和错误捕获
- 为诊疗项目下拉框添加数据加载状态检查,防止空数据导致的界面异常
- 实现防抖机制和数据量限制,提升大数据量下的响应性能
- 添加并行数据加载,减少页面初始化时间
2026-01-20 08:24:07 +08:00
a3dce8de60 fix(inhospitalnurse): 优化住院护士站患者管理和床位分配功能
- 移除住院参与者更新失败时的异常返回,改为静默处理
- 更新床位分配提示信息,为用户提供更清晰的操作指导
- 实现实施科室下拉选择器的远程搜索功能,提升大数据量下的用户体验
- 添加节点切换时的未保存数据确认提醒,防止数据丢失
- 优化实施科室管理页面的选项过滤和加载状态管理
2026-01-19 23:18:38 +08:00
f81dd54f0c Merge remote-tracking branch 'origin/develop' into develop 2026-01-19 22:36:12 +08:00
803e4d0bb5 refactor(inhospitalnursestation): 优化入院护士站应用的数据库查询性能
- 将CTE查询重构为子查询以提高执行效率
- 为位置和医生查询添加LIMIT 1约束以减少数据量
- 移除不必要的GROUP BY子句以简化查询逻辑
- 在前端组件中实现异步数据加载和错误处理机制
- 使用可选链操作符处理空值情况避免报错
- 添加防抖机制解决单击双击冲突问题
- 优化患者列表和床位列表的并行加载逻辑
- 清理调试用的console.log语句并替换为有意义的信息
2026-01-19 22:36:04 +08:00
deebcde41f 依赖标记更新 2026-01-19 21:48:43 +08:00
095c43bbf3 修复医嘱下获取读取慢问题,同时解决系列字典表读取慢问题 2026-01-19 21:48:11 +08:00
aa3beb848b fix(patient): 修复患者信息新增和更新逻辑
- 修改handlePatientInfo方法中的患者对象初始化逻辑
- 添加患者ID存在时的查询验证机制
- 区分新增和更新操作分别调用不同的服务方法
- 移除重复的身份证号查询条件优化性能
- 统一患者信息保存和更新的操作流程
2026-01-19 21:41:05 +08:00
sindir
ae96bbd0bb 医生常用语管理 - 行内编辑改为弹窗编辑,优化编辑体验。新增编辑弹窗,点击编辑按钮弹窗回显数据,修改更便捷 2026-01-19 17:25:37 +08:00
sindir
1a2c444269 Merge branch 'develop' of https://gitea.gentronhealth.com/wangyizhe/his into develop 2026-01-19 15:47:38 +08:00
sindir
9cba8fea12 完善医生常用语管理功能
### 后端修改
1. 实体类DoctorPhrase:字段/注解调整
2. 枚举完善:新增DoctorPhraseAppTypeEnum/DoctorPhraseBizTypeEnum,统一业务分类
3. 服务实现类:修正类名拼写(DoctorPhraesAppS → DoctorPhraseAppServiceImpl
### 前端修改
1. 常用语管理页面(doctorphrase/index.vue):
   业务分类硬编码替换为枚举(主诉/现病史/术前/术后/既往史)
2026-01-19 15:43:34 +08:00
huabuweixin
f11b7380a4 Merge remote-tracking branch 'origin/develop' into develop 2026-01-19 15:01:28 +08:00
da17b2b89c fix(inpatient): 修复就诊位置更新逻辑
- 修改就诊位置表更新方式,直接更新指定ID的记录
- 添加位置ID设置功能
- 使用updateById方法替代saveOrUpdate方法提高准确性
2026-01-19 14:22:39 +08:00
9e4a010a8d Merge remote-tracking branch 'origin/develop' into develop 2026-01-19 11:39:58 +08:00
7e76083c37 feat(doctorstation): 优化医生工作站处方列表功能
- 调整诊疗定义表结构,添加序号和服务范围字段
- 修改费用项目查询逻辑,使用INNER JOIN替代LEFT JOIN并优化排序
- 增加批处理批次大小从500到1000,提升查询性能
- 修复处方类型筛选中的诊疗和耗材顺序错误
- 优化处方行数据重置逻辑,避免残留数据问题
- 移除不必要的README标题元素
2026-01-19 11:39:29 +08:00
de105adbdc 上传文件至 md/需求 2026-01-19 11:28:29 +08:00
f3eeee7405 refactor(doctorstation): 优化医嘱基础列表组件性能和数据处理
- 实现虚拟滚动表格以提升大数据量渲染性能
- 添加数据缓存机制减少重复API请求
- 增强节流防抖功能优化搜索响应
- 重构数据过滤逻辑支持本地快速检索
- 添加加载状态提示改善用户体验
- 优化表格列宽度设置提升界面美观度
- 修复医保等级显示和价格获取逻辑
- 后端服务增加分批处理避免大量参数问题
- 添加空值安全检查防止运行时错误
- 统一数据结构处理药品耗材诊疗不同类型
2026-01-19 10:37:46 +08:00
97f04d0b15 fix(inpatient): 修复就诊位置更新逻辑
- 修改就诊位置表更新方式,直接更新指定ID的记录
- 添加位置ID设置功能
- 使用updateById方法替代saveOrUpdate方法提高准确性
2026-01-18 19:44:32 +08:00
5667e04d12 fix(organization): 修复组织查询中class_enum字段的多值匹配逻辑
- 将FIND_IN_SET函数替换为LIKE操作符组合,提高PostgreSQL兼容性
- 添加子查询包装器支持多种匹配模式
- 实现精确匹配、前缀匹配、后缀匹配和中间匹配四种查询方式
- 确保逗号分隔的枚举值能够正确匹配查询条件
- 优化查询性能并提升代码可读性
2026-01-18 14:06:44 +08:00
59157fda56 feat(organization): 支持科室分类多选功能
- 修改前端界面组件支持科室分类多选下拉框
- 更新后端接口参数类型从Integer改为String以支持多选值
- 实现FIND_IN_SET查询方式处理多选分类条件
- 添加parseClassEnumValues函数处理字符串或数组格式转换
- 在医院住院对话框中扩展筛选条件支持多选分类
- 优化错误信息显示逻辑提供更详细的错误提示
- 在患者列表组件中添加入院日期和主治医生信息展示
- 修复多个服务调用中科室分类参数传递的数据类型问题
2026-01-18 13:39:57 +08:00
2fe6d45ad4 fix(doctorstation): 修复诊断组件和住院办理功能的数据处理问题
- 修复诊断组件中el-popover模板语法错误,添加template标签
- 优化患者历史数据处理逻辑,确保数组类型安全并正确构建树形结构
- 完善住院办理流程中的组织机构数据获取和筛选逻辑
- 添加详细的控制台日志用于调试住院办理功能
- 修复办理住院按钮的禁用状态计算逻辑
- 优化患者卡片点击事件处理,确保就诊ID正确传递
- 添加诊断信息完整性检查并提供用户引导
- 修复检验申请组件中的监听器和暴露方法逻辑
2026-01-18 00:37:54 +08:00
982ee316f7 fix(doctorstation): 解决参数验证和数据获取问题
- 在前端api.js中添加encounterId参数验证,避免无效参数导致的错误
- 在后端服务层添加参数检查,当encounterId为空时返回空数据而非报错
- 修改控制器参数注解,将required设置为false以允许空值传递
- 优化住院办理流程中的错误处理和参数验证
- 改进检验申请单获取时的数据验证和错误提示
- 更新maven编译器插件版本并添加必要的模块参数
- 统一错误处理机制,提供更友好的用户提示信息
2026-01-17 16:07:57 +08:00
64c7db68e8 上传文件至 md/需求 2026-01-17 00:03:51 +08:00
cb6b6ced67 上传文件至 md/需求 2026-01-16 18:54:27 +08:00
itcast
8fcfb481c9 门诊医生站-》开立诊断 页面调整 2026-01-16 16:32:36 +08:00
itcast
be0514bc08 门诊医生站-》开立诊断 页面调整 2026-01-16 15:46:43 +08:00
ljj
2b3add4808 91 分诊排队管理-》门诊医生站:【完诊】患者队列状态的变化
68 检验项目设置-检验类型 / 检验项目设置-检验项目
2026-01-16 11:31:40 +08:00
b33cb6f9a1 测试合并v13 2026-01-15 17:04:46 +08:00
072e71b025 测试合并v12 2026-01-15 16:58:14 +08:00
47394de43c Merge pull request 'document' (#2) from document into develop
Reviewed-on: #2
2026-01-15 07:37:39 +00:00
f0f1dde6b6 测试合并 2026-01-15 07:37:39 +00:00
1ab1165697 测试合并 2026-01-15 07:37:39 +00:00
a8f1b1fdfa feat(doctorstation): 添加医嘱类型对应的药品分类筛选功能
- 在处方列表组件中根据医嘱类型自动设置categoryCode筛选条件
- 为西药类型设置categoryCode为'2'
- 为中成药类型设置categoryCode为'1'
- 为耗材和诊疗类型清空categoryCode筛选条件
- 更新基础医嘱列表组件以接收并应用categoryCode查询参数
- 实现医嘱类型改变时的联动筛选逻辑
2026-01-15 15:34:34 +08:00
3b94d19199 Merge remote-tracking branch 'origin/develop' into develop 2026-01-15 15:13:20 +08:00
db1139a14f fix(prescription): 解决处方列表中价格显示的空值异常问题
- 在处方列表组件中添加对unitPrice和totalPrice的空值检查,防止NaN显示
- 优化价格计算逻辑,确保无效价格值被正确处理并显示为默认值
- 更新数据库查询中的条件判断,改进UNION查询的逻辑结构
- 添加对adviceTypes参数的有效性验证,确保查询条件的正确执行
2026-01-15 15:13:09 +08:00
chenjinyang
bea74aeac2 使用element-plus进行提示替换HTML原生弹窗 2026-01-15 15:01:05 +08:00
chenjinyang
634a1f45f9 根据LIS分组开发手册完成功能 2026-01-15 14:36:54 +08:00
8f1ad3307c refactor(doctorstation): 优化医生站医嘱查询SQL逻辑
- 将原有的条件判断逻辑重构为更清晰的choose/when/otherwise结构
- 修复了adviceTypes参数为空或未指定时的SQL执行问题
- 通过trim标签处理UNION ALL连接避免多余关键字
- 添加otherwise分支确保无adviceTypes时返回正确空结果集
- 保持了原有的所有功能逻辑和数据映射关系不变
- 提高了SQL查询的可读性和维护性
2026-01-15 13:42:36 +08:00
d8080fa22d 挂号补单功能的完善 2026-01-14 12:56:39 +08:00
chenjinyang
e8783d9f8f 修复叫号显示屏跳转异常问题 2026-01-14 10:44:35 +08:00
d8c4348341 挂号补单功能的完善 2026-01-14 10:12:25 +08:00
wangjian963
8e61490005 修复门诊医生站检验申请单的就诊卡号无法获取到对应的值的问题 2026-01-13 17:47:51 +08:00
f5f4e3c48e fix(charge): 修复收费模块中的数值计算和空指针异常问题
- 修复金额计算精度问题,使用Number转换和toFixed(2)确保数值准确性
- 添加安全访问操作符(?.)避免空指针异常导致页面崩溃
- 修复数组过滤和查找操作的空值处理逻辑
- 优化错误消息显示,提供更友好的用户提示
- 修复模板文件路径引用问题,确保打印功能正常工作
- 统一金额计算逻辑,避免因数据类型不一致导致的计算错误
2026-01-13 17:30:17 +08:00
0f013715b8 fix(charge): 修复合同列表空值访问导致的门诊登记页面异常 2026-01-13 17:06:52 +08:00
fb9722d328 fix(charge): 修复合同列表空值访问导致的门诊登记页面异常 2026-01-13 17:06:43 +08:00
6f9192d30d fix(charge): 修复医保支付金额计算的安全访问问题
- 在 cliniccharge 组件中为所有金额查询添加可选链操作符防止空指针异常
- 在住院管理收费结算组件中修复金额格式化导致的显示问题
- 统一处理患者信息字段的空值情况避免页面渲染错误
- 修正金额计算逻辑确保数值精度和显示准确性
2026-01-13 17:02:27 +08:00
f2b5b90f34 Merge remote-tracking branch 'origin/develop' into develop 2026-01-13 17:01:29 +08:00
py
a2cbd5e583 测试:科室预约工作时间维护 2026-01-13 17:00:31 +08:00
d3df46858b fix(charge): 修复医保支付计算中的潜在空指针异常
- 在 chargeDialog.vue 中为所有 param.detail.find() 调用添加可选链操作符
- 修复了基金支付总额、个人负担总金额和其他支付类型的空指针风险
- 解决了基本医保统筹基金支出等各项支付类型的潜在运行时错误
- 在微信刷卡支付逻辑中同样应用可选链操作符保护
- 修复了 FULAMT_OWNPAY_AMT 计算中的运算符优先级问题

feat(hospitalRecord): 动态替换打印模板中的医院名称

- 在 MedicationDetails.vue 中引入并使用 userStore 获取医院名称
- 修改处置模板打印逻辑以动态替换 {{HOSPITAL_NAME}} 占位符
- 更新处方模板打印功能以支持医院名称的动态替换
- 激活之前被注释掉的模板文件导入语句
- 移除硬编码的医院名称,实现模板的动态化配置
2026-01-13 16:58:43 +08:00
47a7a945bc Merge remote-tracking branch 'origin/develop' into develop 2026-01-13 15:27:01 +08:00
0a56c0dcf0 feat(store): 更新用户模块状态管理以支持租户配置
- 调整导入语句顺序以符合代码风格规范
- 添加tenantName字段用于存储租户名称
- 添加optionMap字段用于存储租户配置项映射
- 修改getInfo方法以从optionMap优先获取医院名称配置
- 添加tenantName赋值逻辑以支持租户名称显示
- 移除已废弃的用户个人资料相关组件文件
2026-01-13 15:26:46 +08:00
15d32134e2 挂号补单功能的完善 2026-01-13 14:48:18 +08:00
eff98ea5eb Merge remote-tracking branch 'origin/develop' into develop 2026-01-13 14:41:36 +08:00
a47306825a docs(requirement): 添加手术室维护界面需求文档
- 创建手术室维护界面PRD文档
- 定义页面概述、核心功能和用户价值
- 设计整体布局和页面区域详细描述
- 规范交互功能和数据结构说明
- 说明开发实现要点和注意事项
- 移除中医诊断主诊断功能实现说明文档
- 移除公告通知弹窗功能说明文档
- 移除手术人员字段不显示问题解决方案文档
- 移除手术和麻醉信息Redis缓存实现说明文档
- 移除手术室管理添加类型和所属科室字段说明文档
2026-01-13 14:41:27 +08:00
sindir
9b35fec931 诊室页面新增卫生机构、操作人列展示 2026-01-13 14:26:51 +08:00
e20e2b637f 挂号补单功能的完善 2026-01-13 13:26:09 +08:00
ebd2e8aa75 迁移:将DB变更记录SQL文件移动到sql目录下 2026-01-13 10:05:32 +08:00
cb268fe26d feat(operating-room): 添加手术室类型和所属科室字段
- 新增手术室类型字段支持急诊、择期、日间、复合手术室四种类型
- 添加所属科室字段实现科室级别资源管理
- 前端列表页面新增类型和所属科室显示列
- 新增类型选择器和科室选择器组件
- 后端实体类和服务类添加对应字段处理逻辑
- 数据库添加room_type_enum字段和相关索引
- 创建手术室类型字典数据和字典项配置
- 生成手术室管理功能说明文档
2026-01-13 10:03:57 +08:00
23bd49d940 挂号单补打功能完善 2026-01-12 18:14:54 +08:00
32adb984e2 实现科室护士管理患者排队叫号队列,实现患者智能分诊、队列调整、叫号控制等功能 2026-01-12 17:36:55 +08:00
py
c1d453600b 测试:科室预约工作时间维护 2026-01-12 15:49:10 +08:00
py
02eab2d932 测试:科室预约工作时间维护1 2026-01-12 15:36:58 +08:00
py
d5c8b7a1ad 测试:科室预约工作时间维护1 2026-01-12 15:32:41 +08:00
wangjian963
4053064a22 Merge remote-tracking branch 'origin/develop' into develop 2026-01-09 17:38:19 +08:00
wangjian963
089e28f913 修复门诊工作站医生开医嘱的表单标题与内容无法对应的问题 2026-01-09 17:36:36 +08:00
cf9ab03b17 feat(operatingroom): 添加手术室类型和所属科室字段支持
- 在手术室管理界面添加类型和所属科室表格列显示
- 添加手术室类型下拉选择功能,支持急诊、择期、日间、复合四种类型
- 添加手术室详情查看页面中的类型字段展示
- 在后端服务中实现手术室类型的字典转换和文本显示
- 添加手术室实体类中的类型和所属机构名称字段
- 更新路由配置注释掉废弃的系统管理相关路径配置
2026-01-09 17:18:07 +08:00
d332650bfa feat(patient): 实现门诊挂号页面跳转到患者档案页面的精确定位功能
- 在门诊挂号页面添加患者ID和姓名查询参数传递到患者档案页面
- 在患者档案页面实现路由参数接收和按数据库ID精确查询功能
- 新增searchType字段支持按姓名和病人ID两种查询方式
- 优化患者档案页面初始化逻辑,分离字典数据加载和列表查询
- 修改后端服务实现,对精确ID查询跳过医生患者过滤条件以确保跳转查询成功
2026-01-09 16:15:36 +08:00
840983ac94 修复了中医诊断保存时主诊断标记不唯一的问题,并优化了诊断保存逻辑 2026-01-09 15:33:06 +08:00
April
86673d7be3 Merge remote-tracking branch 'origin/develop' into develop 2026-01-09 15:10:05 +08:00
April
3753a916f5 修复了门诊医生站重新调入该患者的本次就诊记录,点击中医诊断发现诊断详情是空的问题 2026-01-09 15:08:19 +08:00
chenjinyang
0556f77870 Merge branch 'develop' of https://gitea.gentronhealth.com/wangyizhe/his into develop
# Conflicts:
#	openhis-ui-vue3/src/router/index.js
2026-01-09 14:07:02 +08:00
chenjinyang
b185c156ca 新增了系统操作手册实例,后续可以加入md文件 2026-01-09 14:01:35 +08:00
ljj
a48308dcbf Merge branch 'develop' of https://gitea.gentronhealth.com/Yajentine/his into develop 2026-01-09 13:28:45 +08:00
e37f6a70f9 revert 28629ccd35
revert Merge remote-tracking branch 'origin/develop' into develop
2026-01-09 04:05:51 +00:00
April
28629ccd35 Merge remote-tracking branch 'origin/develop' into develop 2026-01-09 12:02:45 +08:00
April
fbd7f0be78 修复了在新建患者信息时就诊卡号无法录入的问题,并且修改了前端页面添加中医诊断表单宽度过大的问题。 2026-01-09 11:47:39 +08:00
ljj
763f05da84 Merge remote-tracking branch 'origin/develop' into develop 2026-01-09 11:38:35 +08:00
ljj
8c74d45332 76 门诊预约挂号 2026-01-09 11:33:03 +08:00
8d62c0461b 挂号单补打功能的实现 2026-01-09 10:03:21 +08:00
58936c957d fix(doctorstation): 解决医嘱开具和报告查询中的问题
- 修复医嘱开具时诊断验证警告显示逻辑,支持可选的警告提示
- 修复中医医嘱库存检查条件判断逻辑
- 修复中医医嘱表单验证后数据处理逻辑,添加剂量单位字典值设置
- 优化报告查询处理,独立处理检查和检验报告查询,避免相互影响
- 修复LIS和PACS报告地址配置缺失时的处理逻辑,改为警告而非异常抛出
2026-01-08 16:32:45 +08:00
062c4a92b8 chore(router): 添加患者档案管理路由配置
- 添加患者档案管理路由配置代码
- 注释掉租户用户设置路由部分代码
- 新增patientmgr路由项配置
- 配置路由组件和元信息
- 设置路由隐藏属性
- 完善路由路径和名称定义
2026-01-08 14:52:28 +08:00
fb9f85e967 chore(router): 添加患者档案管理路由配置
- 添加患者档案管理路由配置代码
- 注释掉租户用户设置路由部分代码
- 新增patientmgr路由项配置
- 配置路由组件和元信息
- 设置路由隐藏属性
- 完善路由路径和名称定义
2026-01-08 14:52:22 +08:00
38ef377cbd 手术管理->优化字典数据获取逻辑 2026-01-07 22:56:48 +08:00
240d5dc3f7 手术管理->更改部分组件数据来源,改为从字典中获取。 2026-01-07 17:28:56 +08:00
82702f16e0 Merge remote-tracking branch 'origin/develop' into develop 2026-01-07 17:00:19 +08:00
0b4b63dfbe feat(surgery): 增加手术室确认信息和次要手术功能
- 添加手术室确认时间和确认人字段显示
- 实现次要手术的添加、编辑和删除功能
- 增加急诊标志和植入高值耗材开关选项
- 添加手术费用和麻醉费用计算功能
- 实现手术和麻醉项目的远程搜索功能
- 增加第一助手和第二助手选择功能
- 优化医生列表加载逻辑,支持多接口获取
- 添加按钮图标提升界面体验
- 修复encounterId为空时的接口调用问题
2026-01-07 17:00:06 +08:00
b4422a0dca 收费工作站:合并后按钮重复问题,档案按钮跳转无反应问题。 2026-01-07 13:51:30 +08:00
d8627df2dd 检验项目->套餐设置->部分组件、布局问题 2026-01-07 11:01:49 +08:00
09ca077559 refactor(surgery): 优化手术服务中医生信息查询逻辑
- 引入 IPractitionerService 服务替代 SysUserService 查询医生信息
- 修改手术列表查询中主刀医生、麻醉医生、助手和护士的姓名填充逻辑
- 使用 Practitioner 实体的 name 字段替代 SysUser 的 nickName 字段
- 更新 SQL 查询使用 COALESCE 函数合并数据库中存储的姓名和实时查询结果
- 添加多个 LEFT JOIN 查询以支持手术相关医生和科室信息的实时获取
- 优化申请医生和申请科室名称的查询机制,支持数据回退逻辑
2026-01-06 16:40:57 +08:00
py
3091fc7337 新增科室预约工作时间维护页面 2026-01-06 16:31:08 +08:00
b0850257c8 feat(surgery): 完善手术管理功能模块
- 添加手术申请相关API接口,包括根据患者ID查询就诊列表功能
- 在医生工作站界面集成手术申请功能选项卡
- 实现手术管理页面的完整功能,包括手术申请的增删改查
- 添加手术排期、开始、完成等状态流转功能
- 优化手术管理页面表格展示,增加手术类型、等级、计划时间等字段
- 实现手术申请表单的完整编辑和查看模式
- 集成患者信息和就诊记录关联功能
- 添加手术室、医生、护士等资源选择功能
- 更新系统依赖配置,添加core-common模块
- 优化图标资源和manifest配置文件
- 调整患者档案和门诊记录相关状态枚举
2026-01-06 16:23:15 +08:00
fa2884b320 实现科室护士管理患者排队叫号队列,实现患者智能分诊、队列调整、叫号控制等功能 2026-01-06 15:34:16 +08:00
941054734f 实现科室护士管理患者排队叫号队列,实现患者智能分诊、队列调整、叫号控制等功能 2026-01-06 14:48:45 +08:00
8d69dc3c00 患者档案(现为患者列表)->修改和查看按钮调出窗口与新建患者保持一致 2026-01-05 14:22:57 +08:00
2157806ba5 系统管理->基础数据->字典管理->添加字典数据异常 2026-01-05 11:10:14 +08:00
2236cbea36 门诊挂号->下方列表获取挂号记录-SQL报错。 2026-01-04 16:31:02 +08:00
2128e717e7 门诊挂号->医生字段无数据问题。 2026-01-04 15:59:49 +08:00
1311e87e13 叫号显示屏页面开发,诊疗目录新增或修改时添加医保编码唯一性校验。 2026-01-04 14:24:33 +08:00
ddf1553846 检验项目设置-检验类型的实现 2026-01-04 13:50:05 +08:00
5d82800976 refactor(patientmanage): 为门诊记录服务添加日志功能
- 引入 lombok 的 Slf4j 注解用于日志记录
- 为 OutpatientRecordServiceImpl 添加日志支持
- 为后续调试和监控提供日志输出能力
2026-01-03 23:52:45 +08:00
0c35044231 feat(menu): 优化菜单路径唯一性校验并更新前端界面
- 在SysLoginController中添加optionMap数据返回
- 添加JSQLParser依赖支持MyBatis Plus功能
- 实现selectMenuByPathExcludeId方法用于排除当前菜单的路径唯一性校验
- 在SysMenuServiceImpl中添加日志记录并优化路径唯一性判断逻辑
- 在SysMenuMapper.xml中添加LIMIT 1限制并实现排除ID查询
- 在前端路由中注释患者管理相关路由配置
- 在用户store中添加optionMap配置项并优先从optionMap获取医院名称
- 重构检查项目设置页面的操作按钮样式为统一的圆形按钮设计
- 更新检查项目设置页面的导航栏样式和交互体验
- 优化门诊记录页面的搜索条件和表格展示功能
- 添加性别和状态筛选条件并改进数据加载逻辑
2026-01-03 23:47:09 +08:00
61f4020487 新增患者:监护人信息限制 2025-12-31 13:43:24 +08:00
aeb6b95970 Merge branch 'develop' of https://gitea.gentronhealth.com/py/his into develop 2025-12-31 13:37:29 +08:00
b5ce854eb6 fix(login): 修复登录页面invokeYb默认值设置问题
- 修正了localStorage中invokeYb的默认值从true改为false
- 添加了loginForm.value.invokeYb的默认值设置
- 更新了注释内容以反映正确的默认行为
2025-12-31 11:00:17 +08:00
4d4828ea71 feat(login): 添加租户名称获取功能并优化前端布局
- 在登录控制器中注入租户服务并获取租户名称信息
- 添加租户名称到登录响应结果中
- 更新样式变量定义侧边栏宽度和Logo高度
- 重构公告面板组件统一公告通知显示逻辑
- 简化公告类型图标和样式映射关系
- 更新侧边栏为垂直菜单布局并添加折叠功能
- 优化Logo组件显示租户名称和系统标题
- 调整导航栏布局结构和响应式样式
- 重构主应用容器样式和标签页显示逻辑
2025-12-31 10:28:52 +08:00
10e738edd9 feat(notice): 新增公告优先级和未读状态功能,优化公告展示逻辑 2025-12-30 22:49:14 +08:00
88a4e58130 feat(notice): 新增公告优先级和未读状态功能,优化公告展示逻辑 2025-12-30 22:49:03 +08:00
76c324b0df feat(organization): 添加科室管理查询过滤功能
- 修复api.js中params参数拼写错误
- 添加科室名称、类型、分类的查询表单
- 实现搜索和重置功能
- 集成分页组件并修正页码参数映射
- 在后端服务中添加查询条件过滤逻辑
- 支持按科室名称、类型、分类进行条件查询
- 实现动态排序功能并修复分页查询逻辑
2025-12-30 17:01:37 +08:00
a65e8dd2cc feat(organization): 添加科室管理查询过滤功能
- 修复api.js中params参数拼写错误
- 添加科室名称、类型、分类的查询表单
- 实现搜索和重置功能
- 集成分页组件并修正页码参数映射
- 在后端服务中添加查询条件过滤逻辑
- 支持按科室名称、类型、分类进行条件查询
- 实现动态排序功能并修复分页查询逻辑
2025-12-30 17:01:34 +08:00
1ac9b5ae0b feat(organization): 添加科室管理查询过滤功能
- 修复api.js中params参数拼写错误
- 添加科室名称、类型、分类的查询表单
- 实现搜索和重置功能
- 集成分页组件并修正页码参数映射
- 在后端服务中添加查询条件过滤逻辑
- 支持按科室名称、类型、分类进行条件查询
- 实现动态排序功能并修复分页查询逻辑
2025-12-30 16:52:01 +08:00
8f77fe8bc9 Merge remote-tracking branch 'origin/develop' into develop 2025-12-30 16:13:52 +08:00
b567747901 style(flowable): 优化流程相关代码的import顺序和代码结构 2025-12-30 16:12:16 +08:00
ed7004ae85 style(flowable): 优化流程相关代码的import顺序和代码结构 2025-12-30 15:34:43 +08:00
d1670b79a0 style(flowable): 优化流程相关代码的import顺序和代码结构 2025-12-30 15:11:32 +08:00
54cde91aac style(ui): 统一界面样式标准并优化组件布局
- 引入 ui-standard.scss 样式文件以统一界面标准
- 为查询表单添加 query-form 样式类
- 为搜索按钮组添加 search-buttons 样式类
- 为按钮组容器添加 button-group 样式类
- 为字典标签添加 dict-tag 样式类以统一样式
- 为操作按钮添加 action-button 样式类
- 为分页组件添加 pagination-container 容器
- 优化患者管理页面表格列的字典标签显示
- 调整公告页面布局结构并添加容器样式
- 优化表格单元格间距和样式显示
2025-12-30 14:57:20 +08:00
7974bdc51c feat(ui): 添加OpenHIS UI统一风格规范和样式
- 创建ui-standard.scss样式文件,定义全局组件样式规范
- 添加容器、表格、表单、按钮、对话框等统一UI样式
- 实现响应式设计和动画效果
- 编写完整的UI风格规范文档
- 定义颜色、间距、圆角、阴影等设计规范
- 提供组件使用示例和命名规范指导
2025-12-30 14:56:29 +08:00
91cb465962 医生常用语维护->名称字数限制、前端名称唯一性校验等 2025-12-30 14:26:14 +08:00
1b2c248fa2 Merge remote-tracking branch 'origin/develop' into develop 2025-12-30 14:10:01 +08:00
1c16d6ba0f feat(invoice): 完善发票管理权限控制和检验申请功能
- 超级管理员可以编辑操作员字段,普通用户不可编辑
- 修改权限判断逻辑,只有用户名等于 'admin' 的用户才是超级管理员
- 非超级管理员用户只能查询自己的发票数据
- 添加根据员工ID更新操作员名称功能
- 新增行时根据用户权限填充信息
- 严格检查权限,超级管理员可以删除所有记录,普通用户只能删除自己维护的记录
- 在 bargain 组件中验证患者选择
- 添加检验申请单相关API接口
- 在医生工作站中添加检验申请tab页
- 实现检验申请单的增删改查功能
- 添加公告通知已读记录相关功能
- 实现用户未读公告数量统计和标记已读功能
2025-12-30 14:09:37 +08:00
49b8a975a8 feat(invoice): 完善发票管理权限控制和检验申请功能
- 超级管理员可以编辑操作员字段,普通用户不可编辑
- 修改权限判断逻辑,只有用户名等于 'admin' 的用户才是超级管理员
- 非超级管理员用户只能查询自己的发票数据
- 添加根据员工ID更新操作员名称功能
- 新增行时根据用户权限填充信息
- 严格检查权限,超级管理员可以删除所有记录,普通用户只能删除自己维护的记录
- 在 bargain 组件中验证患者选择
- 添加检验申请单相关API接口
- 在医生工作站中添加检验申请tab页
- 实现检验申请单的增删改查功能
- 添加公告通知已读记录相关功能
- 实现用户未读公告数量统计和标记已读功能
2025-12-30 13:52:06 +08:00
d17a502da1 Merge remote-tracking branch 'origin/develop' into develop 2025-12-30 13:43:54 +08:00
430adc2112 feat(system): 添加公告通知已读记录功能
- 新增 SysNoticeRead 实体类用于存储公告/通知已读记录
- 实现 SysNoticeReadMapper 数据访问层接口及 XML 映射文件
- 创建 ISysNoticeReadService 服务接口及实现类
- 添加数据库表 sys_notice_read 存储用户阅读状态
- 添加发布状态字段到公告表支持公告发布控制
- 实现前端 NoticePanel 组件支持未读标记和阅读状态显示
- 提供标记已读、批量标记、未读数量统计等功能
- 优化公告列表按已读状态和时间排序显示
2025-12-30 13:43:28 +08:00
5f5c47f528 新增门诊医生开立检验申请单前端页面样式、模板初步完成 2025-12-30 13:30:06 +08:00
92d74c47ce 增加发票号码维护界面bug修复和新增门诊医生开立检验申请单前端页面样式、模板初步完成 2025-12-30 13:25:55 +08:00
5d8e7b667f 门诊划价->新增按钮报错BUG,叫号语音设置页面开发。 2025-12-30 13:19:01 +08:00
58449fc2f9 Merge remote-tracking branch 'origin/develop' into develop 2025-12-30 10:24:44 +08:00
4c541f43b9 `` refactor(doctorstation): 修正处方列表组件导入路径大小写问题并删除废弃的体温单组件`` 2025-12-30 10:24:25 +08:00
9a037ae446 Merge remote-tracking branch 'origin/develop' into develop 2025-12-30 10:11:25 +08:00
bb0eb60eae Merge branch 'merge_1.3' into develop 2025-12-30 10:10:40 +08:00
cf5dbc6133 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	openhis-ui-vue3/src/views/doctorstation/components/diagnosis/addDiagnosisDialog.vue
#	openhis-ui-vue3/src/views/doctorstation/components/tcm/tcmAdvice.vue
2025-12-30 10:04:25 +08:00
5f6fa50000 修复了作废的中医诊断也显示出来的问题, 2025-12-30 10:03:46 +08:00
08b2e76d47 修复了作废的中医诊断也显示出来的问题, 2025-12-30 09:59:58 +08:00
5ffeab8999 修复了作废的中医诊断也显示出来的问题, 2025-12-30 09:56:39 +08:00
fc6640b846 Merge branch 'merge_1.3' into develop 2025-12-30 09:38:57 +08:00
8e11dde7c0 feat(deptManage): 添加医生排班管理API接口
- 实现添加医生排班功能接口
- 实现删除医生排班功能接口
- 实现批量保存医生排班功能接口
- 集成统一请求处理工具
- 添加详细的函数注释说明
- 完善参数类型和返回值定义
2025-12-30 09:31:43 +08:00
e8f24ee290 `` refactor(config): 更新开发环境数据库和Redis配置为内网地址`` 2025-12-30 09:27:12 +08:00
a1e07a204b ``` refactor(db): 移除SQL语句中的public schema前缀 2025-12-30 00:02:59 +08:00
a080b4294c ```
feat(invoice): 添加发票分页查询权限过滤功能

- 移除未使用的Supplier导入
- 新增selectInvoicePage方法支持用户角色权限过滤
- 非管理员用户只能查看自己创建的发票
- 优化发票新增逻辑,使用count查询替代list查询提升性能
- 添加事务注解确保数据一致性
- 异常处理改进,抛出ServiceException替代返回null
```
2025-12-27 22:53:39 +08:00
0827ce2908 ```
refactor(invoice): 移除发票服务中的权限过滤功能

移除发票服务接口中的分页查询权限过滤方法,简化发票新增逻辑,
移除异常抛出改为返回null,更新分页查询方法实现

- 移除 IInvoiceService 中的 selectInvoicePage 方法
- 移除 InvoiceServiceImpl 中的权限过滤逻辑
- 移除发票新增时的异常抛出,改为返回null
- 移除多余的import和注释
- 简化发票编码存在性检查逻辑

refactor(outpatient): 修复门诊记录服务中的方法注解

为门诊记录服务中的 getDoctorNames 方法添加 @Override 注解,
移除多余的空行

- 在 OutpatientRecordServiceImpl 中添加 @Override 注解
- 移除 PatientManageMapper 导入前的多余空行
```
2025-12-27 22:53:32 +08:00
5f600209b8 ```
refactor(core): 优化DelFlag枚举值比较逻辑

- 修改DelFlag.getValue()调用为直接访问value字段
- 提升代码性能和可读性
```
2025-12-27 22:45:20 +08:00
79ea4ed4f7 提交merge1.3 2025-12-27 15:31:06 +08:00
cbd3e7f981 提交merge1.3 2025-12-27 15:30:48 +08:00
3c497417dc 提交merge1.3 2025-12-27 15:30:40 +08:00
088861f66e 提交merge1.3 2025-12-27 15:30:25 +08:00
8914c8b143 ```
chore(app): 更新应用启动横幅

更新了应用启动时显示的横幅,替换了原有的ASCII艺术样式,
使用了新的样式以提升视觉效果和品牌识别度。
```
2025-12-27 14:21:00 +08:00
8c607c8749 ```
feat(common): 添加core-common依赖

新增core-common依赖项,用于提供通用功能支持,
移除core-admin的版本号配置
```
2025-12-26 22:45:08 +08:00
3115e38cc4 Revert "```"
This reverts commit abc0674531.
2025-12-26 22:21:21 +08:00
ae6c486114 Revert "```"
This reverts commit 85fcb7c2e2.
2025-12-26 22:20:01 +08:00
a41ffa4cfc pgsql脚本 2025-12-25 14:28:44 +08:00
b1f74161f8 检验项目设置-套餐设置前后端及数据库基本完成 2025-12-25 14:25:35 +08:00
3bab56a19b Merge branch 'develop' of https://gitea.gentronhealth.com/Yajentine/his into develop 2025-12-25 14:13:37 +08:00
abc0674531 ```
docs(release-notes): 添加住院护士站划价功能说明和发版记录

- 新增住院护士站划价服务流程说明文档,详细描述了从参数预处理到结果响应的五大阶段流程
- 包含耗材类医嘱和诊疗活动类医嘱的差异化处理逻辑
- 添加完整的发版内容记录,涵盖新增菜单功能和各模块优化点
- 记录了住院相关功能的新增和门诊业务流程的修复
```
2025-12-25 14:13:14 +08:00
85fcb7c2e2 ```
docs(release-notes): 添加住院护士站划价功能说明和发版记录

- 新增住院护士站划价服务流程说明文档,详细描述了从参数预处理到结果响应的五大阶段流程
- 包含耗材类医嘱和诊疗活动类医嘱的差异化处理逻辑
- 添加完整的发版内容记录,涵盖新增
2025-12-25 14:12:53 +08:00
fc6a7437a3 门诊医生站->医嘱定价来源未配置bug,叫号语音设置后端框架基本接口开发。 2025-12-25 14:09:32 +08:00
999a0992e7 门诊医生预约科室管理功能的完善 2025-12-25 13:49:30 +08:00
55b3dfc077 套餐设置功能前后端内容基本完成(细节未处理) 2025-12-25 11:12:56 +08:00
ljj
32d1673667 84 系统管理-》易用性配置-》病历模板定义:新建模板点击【确认】报错 2025-12-24 16:55:56 +08:00
17c7cc70ed 药品出货单按钮被隐藏bug修复 2025-12-24 15:59:56 +08:00
44be570ffa ```
chore(deps): 更新项目依赖版本

- 将 area-data 依赖的版本从 5.0.6 的固定版本更新为 ^5.0.6
- 将 vue-plugin-hiprint 依赖版本从 ^0.0.60 降级至 ^0.0.19
- 升级 sass 依赖版本从 ^1.97.0 至 ^1.97.1
- 升级 vite 依赖版本从 ^5.0.4 至 ^7.3.0
- 移除重复的 area-data 依赖声明
```
2025-12-24 15:38:19 +08:00
c6f4996ba7 Merge remote-tracking branch 'origin/develop' into develop 2025-12-24 14:25:43 +08:00
6c20b15339 套餐设置页面完成 2025-12-24 14:25:06 +08:00
c297072b36 ```
feat(index): 优化index.html页面结构和加载体验

- 添加基础meta标签、SEO描述信息和安全相关meta标签
- 配置移动端和PWA支持,更新图标和manifest配置
- 优化CSS样式,包括box-sizing重置和加载动画样式
- 改进加载器动画效果,添加无障碍属性和noscript提示
- 修复viewport配置,移除过时的IE兼容性代码
- 统一CSS单位格式,优化margin和padding设置
```
2025-12-24 14:15:08 +08:00
4c6886be6a ```
build(pom): 更新lombok版本并配置编译插件版本

- 将lombok版本从1.18.26升级到1.18.42
- 添加maven-compiler-plugin.version属性配置为3.13.0
- 为lombok依赖添加provided作用域配置
```
2025-12-24 10:11:35 +08:00
8beb7f3d3d 医生常用语页面开发,接口实现. 2025-12-23 17:01:24 +08:00
91968530b4 调整套餐设置布局 2025-12-23 16:37:31 +08:00
0833f82fb4 耗材目录包装单位的拼音搜索 2025-12-23 15:05:26 +08:00
cce71f324b Merge remote-tracking branch 'origin/develop' into develop 2025-12-23 12:45:24 +08:00
ee6efafde4 第一次提交 2025-12-23 12:45:15 +08:00
2051807ecf 第一次提交 2025-12-23 12:44:27 +08:00
0a4de15599 医生常用语模板维护->后端接口优化,页面开发;检查方法,部位新增编辑按钮。 2025-12-23 10:56:38 +08:00
25b3c26ec2 医生常用语模板维护->后端接口开发、数据库建表。 2025-12-22 16:45:40 +08:00
91d673de77 检验项目设置-检验类型功能完成 2025-12-22 16:28:05 +08:00
0bfa7183f9 Merge branch 'develop' of https://gitea.gentronhealth.com/Yajentine/his into develop 2025-12-22 12:10:59 +08:00
79d451931d ```
feat(core-admin): 添加 Lombok 依赖并升级版本

在 core-admin 模块中显式添加了 Lombok 依赖,并将 Lombok 版本从 1.18.26 升级至 1.18.38。
同时,将 Lombok 依赖统一管理到父 pom 的 dependencyManagement 中,并配置 Maven 编译插件以支持注解处理器。
此外,引入 core-common 通用工具模块依赖,移除了冗余的 Maven 构建配置注释。
```
2025-12-22 12:10:55 +08:00
ae5f1c795b 检验项目设置-检验类型功能完成 2025-12-22 11:45:16 +08:00
c1074fc4fb 修改检验项目设置的样式风格 2025-12-22 10:33:14 +08:00
e832b6d38e Merge branch 'develop' of https://gitea.gentronhealth.com/Yajentine/his into develop 2025-12-19 14:33:17 +08:00
5043466e84 ```
feat(package): 添加 area-data、next、react 和 react-dom 依赖

新增 area-data 用于地区数据处理,添加 next、react 和 react-dom 以支持 React 相关功能。
同时升级 sass 版本并添加 sass-loader 以优化样式构建流程。
```
2025-12-19 14:33:15 +08:00
fcaeedb543 ```
fix(openhis-ui-vue3): 修复 package.json 文件格式问题

修正了 package.json 文件末尾缺少的换行符,确保文件格式符合标准要求
```
2025-12-19 14:33:04 +08:00
8cf434a46f 系统管理->诊疗目录->添加新项目报错BUG。 2025-12-19 13:53:00 +08:00
bfbc061b0b 根据您提供的代码差异信息为空的情况,我将提供一个通用的commit message模板:
```
docs(changelog): 更新版本变更记录

更新项目的变更日志文件,添加最新的功能改进和修复内容,
确保文档与当前版本保持同步。
```

如果您有具体的代码变更内容,请提供详细的差异信息,我可以为您生成更准确的commit message。
2025-12-19 13:13:36 +08:00
f92cd830e9 库房管理-采购管理-采购入库->经手人设置默认值(当前登录用户) 2025-12-18 16:20:38 +08:00
a7a1a18445 检查项目设置-》检查类型维护 2025-12-18 15:28:32 +08:00
d1331cd4e1 Merge remote-tracking branch 'origin/develop' into develop 2025-12-18 14:57:34 +08:00
37d08b8545 菜单管理修改接口优化 2025-12-18 14:56:15 +08:00
e69f499ac0 Merge branch 'develop' of https://gitea.gentronhealth.com/Yajentine/his into develop 2025-12-18 14:49:40 +08:00
3baf7161f1 feat(router): 注释掉部分路由配置并调整租户相关路由
注释掉了预约管理、基础管理、维护系统及系统管理等模块的路由配置,
同时修改了租户用户设置与租户合同管理的路由路径和对应组件,
使其更符合当前业务需求。此外,移除了重复或不再使用的路由注释块,
优化了路由结构的可读性与维护性。
2025-12-18 14:49:35 +08:00
85188651ca 门诊出诊医生诊室设置维护 2025-12-18 14:43:17 +08:00
d6fbfb1427 router-index.js中注释掉系统管理的路由配置,系统管理的相关页面均能访问,药品目录添加新项目时医保等级默认值设置完成。 2025-12-18 13:53:38 +08:00
966847499a 菜单管理-根据Path进行唯一性校验-优化修改接口 2025-12-18 13:19:27 +08:00
1e91171001 router-index.js部分路径注释。 2025-12-18 11:01:45 +08:00
51f495f81e 页面最上面导航栏取消居中显示。 2025-12-18 10:32:49 +08:00
1e6a5972b9 菜单管理->修改、新增时路由地址唯一性检验 2025-12-18 10:20:52 +08:00
515f03a5cd 页面上导航栏搜索栏显示不全bug 2025-12-17 17:23:31 +08:00
b27542ba6d feat(router): 删除预约管理路由模块并注释部分系统路由
移除了独立的预约管理路由文件,该模块功能已整合至其他模块。
同时注释掉了系统监控、系统工具等相关路由配置,便于后续按需启用。
2025-12-17 16:25:54 +08:00
4790855079 Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	openhis-ui-vue3/src/views/maintainSystem/Inspection/index.vue
2025-12-17 13:31:05 +08:00
72cf9c6f2d 检验项目前端页面更新 2025-12-17 13:30:21 +08:00
19ecb65183 增加发票号码维护界面 2025-12-17 10:39:19 +08:00
d85a8684a6 feat(router): 注释掉部分路由配置以优化初始加载性能
注释掉了门诊医生站、套餐管理、预约管理、基础管理、维护系统及系统管理等模块的路由配置,\
便于后续按需加载或调试。此举可减少初次加载时不必要的资源请求,提升页面初始化效率。
2025-12-17 10:32:10 +08:00
574a9267bf 医生工作站->患者信息中医页面无法打开bug 2025-12-17 09:58:28 +08:00
py
27a7396c78 挂号收费系统参数页面的完善 2025-12-17 09:40:44 +08:00
633cf2c17f 门诊医生站患者病历打不开 不显示数据问题 2025-12-16 17:12:21 +08:00
3188ca5752 build(openhis-ui-vue3): 更新 sass 依赖版本并注释部分路由配置
更新 sass 依赖从 ^1.70.0 到 ^1.77.8,并注释掉 router 中暂时未使用的路由配置项,
包括门诊医生站、套餐管理、预约管理、基础管理、维护系统及系统管理等相关路由。
2025-12-16 13:49:06 +08:00
py
c79e4c2623 需求27:增加挂号收费系统参数维护界面-》挂号处理相关参数 2025-12-16 13:33:50 +08:00
f3c451d0a1 解决首页和门诊挂号保存报错问题 2025-12-15 17:06:25 +08:00
a077bd57d4 预约管理->相关文件转移、号源后端接口实现、前端页面逻辑、数据处理修改。 2025-12-15 16:50:16 +08:00
cf16c497bd 修改路由配置 2025-12-15 16:05:16 +08:00
fd1ab239a9 门诊出诊医生诊室设置 2025-12-15 15:37:23 +08:00
caf65e3113 ```
feat(router): 优化路由配置与注释说明

- 重构 constantRoutes 和 dynamicRoutes 中的路由结构,提升可读性
- 补充详细的路由配置项注释,便于后续维护
- 添加路由名称检查避免重复添加相同路由
- 更新数据库连接地址及 Redis 配置信息
- 完善 .gitignore 忽略文件列表,排除临时文件和日志
```
2025-12-15 14:24:45 +08:00
c18c21ff4c ```
build(openhis-ui-vue3): 更新 package-lock.json 文件

添加 resolutions 字段以解决依赖版本冲突问题,包含 stable、source-map-url、
urix、resolve-url、source-map-resolve 和 sourcemap-codec 等依赖包的版本
锁定,确保项目构建稳定性。
```
2025-12-14 15:01:10 +08:00
ab6849c9eb 根据您提供的信息,没有实际的代码差异内容。但我可以为您提供一个符合Angular规范的commit message模板示例:
```
docs(changelog): 更新版本发布说明

添加新功能描述和bug修复记录到更新日志中,
确保所有重要的变更都已正确记录以便用户查阅。
```

如果您有具体的代码差异信息,请提供详细内容,我将为您生成更准确的commit message。
2025-12-14 14:53:10 +08:00
6b555f2563 fix(openhis-ui-vue3): 降级 element-plus-icons-vue 版本
将 @element-plus/icons-vue 从版本 2.5.0 降级到 2.3.2,以解决可能存在的兼容性问题或回退到稳定版本。
2025-12-14 14:53:02 +08:00
7645405c5b 更新组件 2025-12-14 14:44:43 +08:00
5bfadb9174 fix(login): 修复获取用户绑定租户列表时用户名为空导致的URL错误
确保username参数存在,避免因为空值造成接口调用失败

feat(editor): 重构富文本编辑器组件并优化图片上传逻辑
- 使用 Composition API 重构代码结构,提升可维护性
- 改进图片上传功能,增强对 quill 实例的安全访问
- 更新样式排版,提高组件可读性和一致性

refactor(file-upload): 移除旧代理引用,使用 modern Vue API
替换 `proxy` 调用为 `modal` 插件直接调用,提升代码清晰度与健壮性

refactor(image-upload): 替换旧实例调用方式,强化错误提示机制
统一使用 `modal` 进行消息提示和加载状态控制,改善用户体验

refactor(tree-select): 引入 Composition API 优化节点操作逻辑
移除 `getCurrentInstance` 的不必要使用,改为明确的模板引用管理

chore(main): 添加 util._extend 补丁以消除 Node.js 环境警告
解决开发环境下由于 Node.js 内建模块缺失造成的运行时警告问题

feat(template): 完善跌倒/坠床评估护理记录单模板
- 增加详细注释说明各部分作用,便于后续维护
- 明确组件名称为中文,利于业务识别
- 丰富表单交互细节及数据处理逻辑,支持动态打分、措施选择等功能

refactor(template-index): 加强模板组件自动注册逻辑
增加组件 name 属性校验,防止无效或匿名组件被注册到全局
2025-12-14 14:22:55 +08:00
e1b9d36153 feat(template): 添加股骨头坏死门诊病历模板
新增了一个名为“股骨头坏死(模板1)”的门诊病历模板文件,包含完整的主诉、现病史、既往史、体格检查、辅助检查、诊断和治疗方案等内容,便于医生快速调用和填写。

该模板位于 `src/template/股骨头坏死(模板1).vue`,采用 Vue 单文件组件格式编写,并定义了相应的结构与样式。
2025-12-13 22:23:58 +08:00
fdb8d6c934 更新模板注释测试中文名 2025-12-13 22:18:56 +08:00
22a1ac57b2 改回配置IP地址 2025-12-13 16:06:13 +08:00
4d243815a6 修正格式 2025-12-13 16:03:06 +08:00
882e8c9199 修正问题 2025-12-12 17:06:14 +08:00
a0c87f6335 问题关键 2025-12-12 17:01:24 +08:00
538dde55f7 还原门诊医生站 2025-12-12 15:57:03 +08:00
f33e3c6f15 首页报错和门诊医生站报错 2025-12-12 15:48:07 +08:00
0794782505 TypeScript Vue Plugi 2025-12-12 15:43:58 +08:00
d37fa46b5f 删除rabbitmq 2025-12-12 15:07:27 +08:00
8fcc229ad8 关联套餐设置页面对应字段 2025-12-12 10:59:22 +08:00
39aa710fd3 医生排班后端接口异常修复 2025-12-12 09:12:40 +08:00
49f95b40ea Merge branch 'develop' of https://gitea.gentronhealth.com/Yajentine/his into develop 2025-12-12 09:11:50 +08:00
eb2d7302b7 添加文件 2025-12-11 22:04:00 +08:00
eb26f9db34 添加文件 2025-12-11 22:03:51 +08:00
bd6f3ca587 医生排班页面修复,新增组件间交互功能。 2025-12-11 17:14:48 +08:00
a58e02f2cb 预约管理 2025-12-11 16:23:59 +08:00
8c8ef13021 预约管理需求 2025-12-11 16:06:09 +08:00
d9a0a98f52 预约管理需求 2025-12-11 15:53:00 +08:00
8c84b6eb46 修正可以显示出主页 2025-12-11 15:23:16 +08:00
3d797cc0e0 修正前端问题 2025-12-11 14:47:17 +08:00
df7281a2d4 INDEX.JS修正 2025-12-10 16:33:41 +08:00
f83d7ae520 修改index.js 2025-12-10 16:29:00 +08:00
d9c8525b94 修正问题 2025-12-10 16:04:18 +08:00
bcc5cbb2fb 删除miniapp相关 2025-12-10 15:48:35 +08:00
67a8351d70 Merge remote-tracking branch 'origin/develop' into develop 2025-12-10 15:45:19 +08:00
391506e423 医生排班 2025-12-10 15:44:36 +08:00
3533 changed files with 288497 additions and 119679 deletions

7
.gitignore vendored
View File

@@ -57,4 +57,9 @@
# 忽略设计书
PostgreSQL/openHis_DB设计书.xlsx
public.sql
public.sql
发版记录/2025-11-12/~$发版日志.docx
发版记录/2025-11-12/~$S-管理系统-调价管理.docx
发版记录/2025-11-12/发版日志.docx
.gitignore
openhis-server-new/openhis-application/src/main/resources/application-dev.yml

View File

@@ -0,0 +1,29 @@
---
name: full-stack-developer
description: Use this agent when you need comprehensive full-stack development assistance including frontend, backend, database design, API integration, deployment planning, and architectural decisions. This agent excels at analyzing complex technical requirements, designing scalable solutions, implementing clean code across multiple technologies, and providing expert guidance on best practices for modern web applications.
color: Blue
---
You are an elite full-stack software engineer with extensive experience across all layers of modern web application development. You possess deep expertise in frontend technologies (React, Vue, Angular, HTML/CSS, JavaScript/TypeScript), backend systems (Node.js, Python, Java, .NET, Ruby), databases (SQL and NoSQL), cloud platforms (AWS, Azure, GCP), and DevOps practices.
Your primary responsibilities include:
- Analyzing complex technical requirements and proposing optimal architectural solutions
- Writing clean, efficient, maintainable code across frontend and backend systems
- Designing robust APIs and data models
- Optimizing performance and ensuring security best practices
- Providing guidance on scalability, testing, and deployment strategies
- Troubleshooting complex issues spanning multiple technology stacks
When working on projects, you will:
1. First understand the complete scope and requirements before proposing solutions
2. Consider scalability, maintainability, and security implications of your designs
3. Follow industry best practices for code organization, documentation, and testing
4. Suggest appropriate technologies based on project requirements and constraints
5. Provide implementation details with proper error handling and edge case considerations
6. Recommend optimization strategies for performance and resource utilization
For frontend development, focus on responsive design, accessibility, state management, and user experience. For backend work, emphasize proper architecture patterns, database design, authentication/authorization, and API design principles. When addressing databases, consider normalization, indexing, query optimization, and data consistency.
Always prioritize clean code principles, proper separation of concerns, and modular design. When uncertain about requirements, ask clarifying questions to ensure your solution meets the actual needs. Provide code examples that demonstrate best practices and include comments where necessary for understanding.
In your responses, balance technical depth with practical applicability. Consider trade-offs between different approaches and explain your recommendations. When reviewing existing code, identify potential improvements related to performance, security, maintainability, and adherence to best practices.

View File

@@ -0,0 +1,32 @@
---
name: his-architect-developer
description: Use this agent when designing, developing, reviewing, or troubleshooting Hospital Information System (HIS) applications. This agent specializes in full-stack development for healthcare systems including database design, backend APIs, frontend interfaces, security compliance, and integration with medical devices or third-party systems.
color: Blue
---
You are an elite Healthcare Information System (HIS) Development Architect and Full-Stack Engineer with extensive experience in designing and implementing comprehensive hospital management solutions. You possess deep expertise in healthcare software architecture, regulatory compliance (HIPAA, FDA, etc.), medical data standards (HL7, FHIR), and secure system integration.
Your responsibilities include:
- Designing scalable, secure, and compliant HIS architectures
- Developing robust backend services and APIs
- Creating intuitive frontend interfaces for healthcare professionals
- Ensuring patient data security and privacy compliance
- Integrating with medical devices and external healthcare systems
- Optimizing system performance for high-availability environments
- Troubleshooting complex technical issues in healthcare IT infrastructure
When working on HIS projects, you will:
1. Prioritize patient safety and data security above all other considerations
2. Follow healthcare industry standards and regulations (HIPAA, HITECH, FDA guidelines)
3. Implement proper audit trails and logging for all patient-related operations
4. Design fail-safe mechanisms and disaster recovery procedures
5. Ensure accessibility compliance for users with varying technical expertise
6. Plan for high availability and minimal downtime in critical systems
For database design, focus on normalized schemas that support medical record integrity, implement proper indexing for fast queries, and ensure backup/recovery procedures meet healthcare requirements. When developing APIs, follow RESTful principles while incorporating OAuth 2.0 or similar authentication methods suitable for healthcare environments.
For frontend development, prioritize usability for healthcare workers who may be operating under stress, ensuring clear workflows and minimizing cognitive load. Implement responsive designs that work across various devices commonly used in healthcare settings.
Always consider scalability requirements for growing healthcare institutions and plan for future expansion. When troubleshooting, approach problems systematically considering the potential impact on patient care.
In your responses, provide detailed explanations of your architectural decisions, code implementations, and recommendations. Include relevant healthcare industry best practices and explain how your solutions address specific regulatory requirements.

View File

@@ -0,0 +1,33 @@
---
name: his-developer-architect
description: Use this agent when developing or architecting Hospital Information System (HIS) solutions using Vue3, Spring Boot, and MyBatis technologies. This agent specializes in healthcare system development, understanding medical workflows, patient management systems, and hospital operational processes. Ideal for designing secure, scalable, and compliant healthcare applications.
color: Blue
---
You are an elite Healthcare Information System (HIS) developer and architect with deep expertise in Vue3, Spring Boot, and MyBatis technologies. You specialize in building robust, secure, and scalable hospital management systems that handle critical healthcare operations including patient records, medical workflows, billing, pharmacy management, and administrative processes.
Your responsibilities include:
- Designing and implementing full-stack HIS solutions using Vue3 for modern, responsive frontends and Spring Boot with MyBatis for secure, efficient backends
- Ensuring compliance with healthcare industry standards such as HIPAA, HL7, FHIR, and local health data protection regulations
- Creating secure authentication and authorization systems for healthcare staff with role-based access controls
- Optimizing database designs for handling large volumes of sensitive patient data efficiently
- Implementing audit trails and logging systems required for healthcare environments
- Building integration capabilities between different hospital systems and external healthcare providers
Technical Guidelines:
- Follow Vue3 best practices using Composition API, TypeScript, and state management with Pinia
- Implement Spring Boot microservices architecture with proper security configurations (Spring Security)
- Use MyBatis effectively with proper transaction management and connection pooling
- Apply healthcare-specific design patterns and architectural principles
- Prioritize data integrity, security, and system reliability over performance optimizations when there's a conflict
- Implement comprehensive error handling and logging for healthcare regulatory compliance
When designing solutions, consider:
- Patient privacy and data security requirements
- High availability and disaster recovery needs for critical healthcare systems
- Scalability to handle varying loads during peak times
- Integration with existing hospital infrastructure and legacy systems
- User experience for healthcare professionals who need quick, reliable access to information
- Regulatory compliance and audit requirements specific to healthcare systems
You will provide detailed technical recommendations, code implementations, architectural diagrams, and best practices tailored specifically to healthcare information systems. Always prioritize patient safety and data security in your solutions.

6
.qwen/settings.json Normal file
View File

@@ -0,0 +1,6 @@
{
"tools": {
"approvalMode": "yolo"
},
"$version": 2
}

View File

@@ -0,0 +1,26 @@
# 修复门诊预约界面专家号查询结果显示问题
## 问题分析
1. 前端传递的参数正确:`type=expert`,后端正确转换为`ticketType=专家`
2. 实际查询返回了5条记录但COUNT查询只返回了1条记录
3. 这导致前端只显示了1条记录而不是全部5条
4. 原因MyBatis-Plus自动生成的COUNT查询和实际查询使用了不同的条件特别是逻辑删除条件
## 解决方案
1. 修改TicketMapper.xml中的自定义COUNT查询显式添加`delete_flag = '0'`条件
2. 在selectTicketPage和selectTicketPage_mpCount查询中都添加逻辑删除条件
3. 确保两个查询使用完全相同的WHERE条件
## 修复步骤
1. 修改`selectTicketPage`查询,添加逻辑删除条件`and delete_flag = '0'`
2. 修改`selectTicketPage_mpCount`查询,添加逻辑删除条件`and delete_flag = '0'`
3. 确保两个查询的WHERE条件完全一致
4. 测试修复后的功能确保专家号能正确显示全部5条记录
## 代码修改点
- 文件:`d:/work/openhis-server-new/openhis-domain/src/main/resources/mapper/clinical/TicketMapper.xml`
- 查询:`selectTicketPage``selectTicketPage_mpCount`
- 修改内容:添加逻辑删除条件`and delete_flag = '0'`
## 预期效果
修复后COUNT查询和实际查询将使用完全相同的条件包括逻辑删除条件从而确保COUNT查询返回正确的总记录数前端能显示所有5条专家号记录。

View File

@@ -0,0 +1,30 @@
# 修复门诊预约界面专家号查询COUNT结果不正确问题
## 问题分析
1. 前端传递的参数正确:`type=expert`,后端正确转换为`ticketType=专家`
2. COUNT查询和实际查询的WHERE条件完全相同`WHERE delete_flag = '0' AND ticket_type = '专家'`
3. 但COUNT查询只返回1条记录而实际查询返回5条记录
4. 原因MyBatis-Plus的分页插件在处理自定义COUNT查询时存在bug导致COUNT查询结果不正确
## 解决方案
修改`TicketAppServiceImpl.java`中的`listTicket`方法不使用MyBatis-Plus的自动分页功能而是手动实现分页查询
1. 直接调用`ticketService.countTickets`方法获取总记录数
2. 手动构建查询条件
3. 确保COUNT查询和实际查询使用完全相同的条件
## 修复步骤
1. 修改`TicketAppServiceImpl.java`中的`listTicket`方法
2. 手动实现分页查询,包括:
- 构建查询条件
- 调用`countTickets`获取总记录数
- 调用`selectTicketList`获取分页数据
- 手动组装分页结果
3. 测试修复后的功能确保专家号能正确显示全部5条记录
## 代码修改点
- 文件:`d:/work/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java`
- 方法:`listTicket`
- 修改内容替换MyBatis-Plus的自动分页改为手动分页实现
## 预期效果
修复后COUNT查询和实际查询将使用完全相同的条件COUNT查询将返回正确的总记录数5条前端能显示所有5条专家号记录。

View File

@@ -0,0 +1,32 @@
## 问题分析
根据日志和代码分析,发现号源列表显示"没有更多数据了"的问题原因:
1. **后端查询正常**成功查询到5条符合条件的专家号源记录
2. **数据转换失败**:在`convertToDto`方法中,`fee`字段类型转换错误
3. **响应返回空列表**:由于转换异常,最终返回给前端的号源列表为空
## 问题根源
- `Ticket`实体类的`fee`字段为**BigDecimal类型**(数据库存储)
- `TicketDto`类的`fee`字段为**String类型**(前端展示)
-`convertToDto`方法中直接将BigDecimal类型的`fee`赋值给String类型的`fee`,导致**ClassCastException**
## 修复方案
修改`TicketAppServiceImpl.java`文件中的`convertToDto`方法将BigDecimal类型的`fee`转换为String类型
```java
// 原代码
dto.setFee(ticket.getFee());
// 修复后代码
dto.setFee(ticket.getFee().toString());
```
## 预期效果
1. 修复后,后端能成功将`Ticket`实体转换为`TicketDto`
2. 前端能接收到包含5条专家号源的完整列表
3. 页面显示正常,不再出现"没有更多数据了"的提示
## 验证方法
1. 重新启动项目,访问号源管理页面
2. 选择"专家号"类型查看是否能正确显示5条号源记录
3. 检查日志,确认没有类型转换异常

View File

@@ -0,0 +1,23 @@
# 修复门诊预约界面专家号查询问题
## 问题分析
从日志中发现关键问题:
- 前端传递的ticket_type值是英文`general` (普通号) 和 `expert` (专家号)
- 数据库中存储的ticket_type值是中文`普通``专家`
- 导致查询条件不匹配,无法查询到数据
## 解决方案
需要在后端添加类型映射转换,将前端传递的英文类型转换为数据库中存储的中文类型。
## 修复步骤
1. 修改 `TicketAppServiceImpl.java` 文件在处理type参数时添加映射转换逻辑
2. 添加从英文类型到中文类型的映射关系
3. 测试修复后的功能,确保普通号和专家号都能正确查询
## 代码修改点
- 文件:`d:/work/openhis-server-new/openhis-application/src/main/java/com/openhis/web/appointmentmanage/appservice/impl/TicketAppServiceImpl.java`
- 方法:`listTicket` 中的type参数处理部分
- 修改内容:添加类型映射转换,将 "general" 转换为 "普通""expert" 转换为 "专家"
## 预期效果
修复后,前端选择"普通号"或"专家号"时,系统能正确查询到对应的号源数据,不再出现"没有更多数据了"的提示。

View File

@@ -0,0 +1,23 @@
**问题分析**
后端返回的响应格式是`{code: 200, msg: "操作成功", data: {total: 5, limit: 20, page: 1, list: [5条记录]}}`,而前端可能期望直接访问`list`属性导致只能显示1条数据。
**修复方案**
1. 修改`TicketAppServiceImpl.java``listTicket`方法,确保返回的分页数据格式正确
2. 调整响应结构,使其更符合前端期望
3. 保持与现有代码的兼容性
**修改点**
* `TicketAppServiceImpl.java`:优化`listTicket`方法的响应格式
* 确保分页信息和列表数据都能正确返回给前端
**预期效果**
* 后端返回正确格式的响应数据
* 前端能够正确显示所有5条专家号数据
* 保持与现有代码的兼容性

View File

376
CODEBUDDY.md Normal file
View File

@@ -0,0 +1,376 @@
# CODEBUDDY.md
This file provides guidance to CodeBuddy Code when working with code in this repository.
## Project Overview
This is a comprehensive Hospital Information System (HIS) built with a Java Spring Boot backend and Vue 3 frontend.
- **Backend**: Java 17, Spring Boot 2.5.15, multi-module Maven architecture
- **Frontend**: Vue 3, Vite, Element Plus, Pinia state management
- **Database**: PostgreSQL (recommended v16.2)
- **Cache**: Redis
## Repository Structure
```
.
├── openhis-server-new/ # Backend multi-module Maven project
│ ├── openhis-application/ # Main application module with startup class
│ ├── openhis-domain/ # Business domain modules (administration, clinical, financial, etc.)
│ ├── openhis-common/ # Shared utilities and common code
│ ├── core-admin/ # Core administration module
│ ├── core-framework/ # Framework configuration and security
│ ├── core-system/ # System management module
│ ├── core-quartz/ # Scheduled tasks
│ ├── core-generator/ # Code generation utilities
│ ├── core-common/ # Core utilities
│ └── core-flowable/ # Workflow engine integration
└── openhis-ui-vue3/ # Vue 3 frontend
├── src/
│ ├── api/ # API service layer
│ ├── components/ # Reusable components
│ ├── router/ # Vue Router configuration
│ ├── store/ # Pinia state management
│ ├── utils/ # Utility functions
│ └── views/ # Page components
└── vite/ # Vite plugins configuration
```
## Build and Development Commands
### Backend (Java)
**Build the entire backend:**
```bash
cd openhis-server-new
mvn clean package -DskipTests
```
**Run the backend application (development):**
```bash
cd openhis-server-new/openhis-application
mvn spring-boot:run
```
**Alternative: Run directly from IDE:**
- Run the main method in `openhis-server-new/openhis-application/src/main/java/com/openhis/OpenHisApplication.java`
**Start scripts:**
- Linux/Mac: `openhis-server-new/start.sh`
- Windows: `openhis-server-new/start.bat`
### Frontend (Vue 3)
**Install dependencies:**
```bash
cd openhis-ui-vue3
npm install
```
**Development server (with hot reload):**
```bash
npm run dev
```
- Runs on port 81 by default
- Proxies `/dev-api` requests to `http://localhost:18080/openhis`
**Build for production:**
```bash
npm run build:prod # Production build
npm run build:stage # Staging build
npm run build:test # Test environment build
npm run build:dev # Development build
npm run build:spug # Spug environment build
```
**Preview production build:**
```bash
npm run preview
```
## Architecture Overview
### Backend Architecture
The backend uses a multi-module Maven architecture with clear separation of concerns:
1. **openhis-application**: Entry point with `OpenHisApplication.java` (d:\his\openhis-server-new\openhis-application\src\main\java\com\openhis\OpenHisApplication.java:20)
- Scans `com.core` and `com.openhis` packages
- Configures async processing and YAML service configuration
- Runs on port 18080 with context path `/openhis`
2. **openhis-domain**: Business domain modules organized by medical functionality:
- `administration`: Administrative functions
- `appointmentmanage`: Appointment management
- `check`: Medical examination/checkup
- `clinical`: Clinical workflows
- `crosssystem`: Cross-system integration
- `document`: Document management
- `financial`: Financial/billing
- `lab`: Laboratory operations
- `medication`: Medication management
- `triageandqueuemanage`: Patient triage and queue management
- `yb`, `ybcatalog`, `ybelep`: Insurance (Yi Bao) integration
- `workflow`: Workflow management
- `jlau`, `nenu`: Additional domain modules
- `template`: Template management
3. **Core Modules** (com.core package):
- `core-system`: User, role, menu, and permission management
- `core-framework`: Security, exception handling, and framework configurations
- `core-common`: Shared utilities and base classes
- `core-quartz`: Scheduled task management
- `core-generator`: Code generation tools
- `core-flowable`: Workflow engine integration
- `core-admin`: Administrative functions
4. **openhis-common**: Domain-specific shared code and utilities under `com.openhis.common` package
**Key Technologies:**
- MyBatis-Plus 3.5.5 for ORM with enhanced CRUD operations
- Druid 1.2.27 connection pool with monitoring at `/druid/*`
- Flowable 6.8.0 for workflow management
- LiteFlow 2.12.4.1 for business rule orchestration
- Swagger 3.0.0 for API documentation
- JWT 0.9.1 for authentication
- Hutool 5.3.8 utility library
- Fastjson2 2.0.58 for JSON processing
- Pinyin4j 2.5.1 for Chinese character to Pinyin conversion
### Frontend Architecture
The frontend uses Vue 3 with composition API and modern tooling:
**Key Files:**
- Entry point: `openhis-ui-vue3/src/main.js`
- Router configuration: `openhis-ui-vue3/src/router/index.js`
- Store initialization: `openhis-ui-vue3/src/store/store.js`
- Vite configuration: `openhis-ui-vue3/vite.config.js`
**State Management:**
- Pinia for global state (replaces Vuex)
- Store modules: `app`, `dict`, `permission`, `settings`, `tagsView`, `user`
- Modules located in `openhis-ui-vue3/src/store/modules/`
**Routing:**
- Vue Router 4.3.0
- Two types of routes:
- `constantRoutes`: Public routes (login, 404, etc.)
- `dynamicRoutes`: Permission-based routes loaded dynamically
- Route meta fields: `title`, `icon`, `permissions`, `noCache`, `activeMenu`
**API Integration:**
- Axios 0.27.2 for HTTP requests
- Base API URL configured via environment variables (`VITE_APP_BASE_API`)
- Proxy configuration in vite.config.js for development
- `/dev-api``http://localhost:18080/openhis`
- `/ybplugin``http://localhost:5000` (insurance plugin)
- Request/response interceptors in `openhis-ui-vue3/src/utils/request.js`
- API service files organized by module in `openhis-ui-vue3/src/api/`
- `administration`, `appoinmentmanage`, `monitor`, `system`, `tool`
- Shared APIs: `home.js`, `login.js`, `menu.js`, `public.js`
**Component Architecture:**
- Element Plus as the UI framework
- Custom components in `openhis-ui-vue3/src/components/`
- Global components registered in main.js:
- Pagination, TreeSelect, FileUpload, ImageUpload, ImagePreview
- RightToolbar, Editor, DictTag
## Configuration
### Backend Configuration
**Main configuration file:** `openhis-server-new/openhis-application/src/main/resources/application.yml`
**Environment-specific profiles:**
- `application-dev.yml` - Development environment
- `application-test.yml` - Test environment
- `application-prd.yml` - Production environment
**Key configuration sections:**
- Database: PostgreSQL connection (URL, username, password, pool settings)
- Redis: Cache configuration (host, port, database index)
- Server: Port (18080), context path (/openhis), thread pool
- MyBatis-Plus: Mapper scanning (`com.core.**.domain,com.openhis.**.domain`), type aliases, logical delete
- Logging: Debug levels for com.openhis and com.baomidou.mybatisplus
- Swagger: API documentation at `/swagger-ui/index.html`
- Druid: Database monitoring at `/druid/*` (credentials: openhis/123456)
- Flowable: Workflow engine settings (schema update disabled)
- LiteFlow: Business rule configuration at `config/flow.el.xml`
- Token: JWT configuration (secret, expire time, header)
- File upload: Max file size (10MB), max request size (20MB)
### Frontend Configuration
**Environment files** (in `openhis-ui-vue3/`):
- `.env.dev` - Dev environment
- `.env.development` - Development environment variables
- `.env.staging` - Staging environment variables
- `.env.production` - Production environment variables
- `.env.test` - Test environment variables
- `.env.spug` - Spug environment variables
**Key environment variables:**
- `VITE_APP_TITLE`: Application title (e.g., "医院信息管理系统")
- `VITE_APP_BASE_API`: Backend API base URL (e.g., `/dev-api`)
- `VITE_APP_ENV`: Environment identifier
**Vite configuration:**
- Development server: Port 81, host true, auto-open
- Proxy: `/dev-api``http://localhost:18080/openhis`
- Path aliases: `@``./src`, `~``./`
## Database
**Initialization script:** `数据库初始话脚本请使用navicat16版本导入.sql` (located at repository root)
- Use Navicat version 16 to import
- Contains schema and initial demonstration data
**Database connection (dev environment):**
- Type: PostgreSQL
- URL: `jdbc:postgresql://47.116.196.11:15432/postgresql?currentSchema=hisdev`
- Driver: `org.postgresql.Driver`
- Schema: `hisdev`
## Common Development Tasks
### Running Full Stack Locally
**Terminal 1 - Start backend:**
```bash
cd openhis-server-new/openhis-application
mvn spring-boot:run
```
**Terminal 2 - Start frontend:**
```bash
cd openhis-ui-vue3
npm run dev
```
Access the application at:
- Frontend: http://localhost:81
- Backend API: http://localhost:18080/openhis
- Swagger UI: http://localhost:18080/openhis/swagger-ui/index.html
- Druid monitoring: http://localhost:18080/openhis/druid/login.html
### Adding a New Backend Feature
1. Create domain entity in appropriate module under `openhis-domain/[module]/domain/`
2. Create mapper interface in `openhis-domain/[module]/mapper/`
3. Create mapper XML in `openhis-domain/[module]/resources/mapper/` (if custom SQL needed)
4. Create service interface and implementation in `openhis-domain/[module]/service/`
5. Create controller in `openhis-application/src/main/java/com/openhis/web/[module]/`
6. Add MyBatis-Plus annotations if using enhanced features
7. Test endpoints via Swagger UI at `http://localhost:18080/openhis/swagger-ui/index.html`
**Note:** Controllers are organized under `com.openhis.web` by business module (e.g., `web.administration`, `web.clinicalmanage`, `web.patientmanage`, etc.)
### Adding a New Frontend Page
1. Create Vue component in `openhis-ui-vue3/src/views/[module]/`
2. Add API service methods in `openhis-ui-vue3/src/api/`
3. Add route to `openhis-ui-vue3/src/router/index.js` (constantRoutes or dynamicRoutes)
4. Add Pinia store module if state management needed
5. Register global components if reusable
### Testing
**Backend:**
```bash
cd openhis-server-new
mvn test
```
**Frontend:**
- Run unit tests (if configured):
```bash
cd openhis-ui-vue3
npm test
```
## Key Patterns and Conventions
### Backend
- Package structure follows domain-driven design
- Service layer uses `@Service` annotation
- Controllers use `@RestController` with request mapping
- MyBatis-Plus base mapper: `BaseMapper<T>`
- Logical delete field: `validFlag` (1 = active, 0 = deleted)
- Use `@EnableAsync` for async processing
- JWT token stored in `Authorization` header
### Frontend
- Use Vue 3 Composition API (`<script setup>`)
- Element Plus components with Chinese locale (zhCn)
- API calls through centralized request utility in `src/utils/request.js`
- Route-based permission control
- Dictionary data through `useDict()` composable
- Global properties: `$download`, `$downloadGet`, `$parseTime`, `$resetForm`, `$handleTree`, `$formatDateStr`
- CSS in SCSS with global styles in `src/assets/styles/index.scss`
- Registered global components: DictTag, Pagination, TreeSelect, FileUpload, ImageUpload, ImagePreview, RightToolbar, Editor
- Hiprint plugin for printing functionality (window.hiprint)
## Important Files
### Backend
- Startup class: `openhis-server-new/openhis-application/src/main/java/com/openhis/OpenHisApplication.java`
- Main config: `openhis-server-new/openhis-application/src/main/resources/application.yml`
- MyBatis config: `openhis-server-new/openhis-application/src/main/resources/mybatis/mybatis-config.xml`
- Parent POM: `openhis-server-new/pom.xml`
### Frontend
- Entry point: `openhis-ui-vue3/src/main.js`
- Router: `openhis-ui-vue3/src/router/index.js`
- Request utils: `openhis-ui-vue3/src/utils/request.js`
- Vite config: `openhis-ui-vue3/vite.config.js`
- Environment files: `openhis-ui-vue3/.env.*`
## External Integrations
- **PostgreSQL 42.2.27**: Primary database
- **MySQL Connector 9.4.0**: MySQL database support (alternative)
- **Redis**: Caching and session management
- **Flowable 6.8.0**: Workflow engine
- **LiteFlow 2.12.4.1**: Business rule engine
- **Swagger 3.0.0**: API documentation
- **Druid 1.2.27**: Database connection pool and monitoring
- **Element Plus 2.12.0**: Vue 3 UI component library
- **Pinia 2.2.0**: State management
- **Vite 5.0.4**: Build tool and dev server
- **Hutool 5.3.8**: Java utility library
- **Fastjson2 2.0.58**: JSON processing
- **Pinyin4j 2.5.1**: Chinese character to Pinyin conversion
- **iText 5.5.12**: PDF generation
- **Apache POI 4.1.2**: Excel file processing
## Additional Notes
### WebView Integration
- Frontend supports WebView environment (e.g., embedded in desktop applications)
- Chrome WebView integration with C# accessor (`chrome.webview.hostObjects.CSharpAccessor`)
- Mounted to Vue instance as `csAccessor` global property
### File Upload
- Backend upload path: Configured in `core.profile` property (default: `D:/home/uploadPath`)
- Max file size: 10MB per file, 20MB total request
- File upload component: `FileUpload` (global component)
### Authentication
- JWT token stored in `Authorization` header
- Token configuration: `token.secret`, `token.expireTime`, `token.header`
- Password lockout: 5 failed attempts, 10-minute lock time
### Logging
- Backend logs: Configured in `logback.xml`
- Debug logging enabled for: `com.openhis`, `com.baomidou.mybatisplus`, `com.alibaba.druid`
- Druid slow SQL threshold: 1000ms
### Code Generation
- Backend code generator: `core-generator` module
- Access via Swagger or `/tool/gen` route
- Uses Velocity templates in `openhis-application/src/main/resources/vm/`

View File

@@ -1,4 +1,4 @@
GNU GENERAL PUBLIC LICENSE
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>

View File

@@ -0,0 +1,223 @@
# MyBatis-Plus 自动填充处理器优化指南
## 概述
本文档说明如何优化 `MybastisColumnsHandler` 以确保所有实体的审计字段create_by、create_time、update_by、update_time能够正确自动填充。
## 问题背景
在 OpenHIS 系统中,当保存实体时可能会遇到以下错误:
```
org.postgresql.util.PSQLException: ERROR: null value in column "create_by" of relation "adm_practitioner" violates not-null constraint
```
这是因为数据库表中的审计字段设置了 NOT NULL 约束,但在某些情况下自动填充机制未能正确设置这些字段。
## 解决方案
通过优化 `MybastisColumnsHandler` 来确保总是使用当前登录用户的用户名填充 `create_by` 字段,使用当前时间填充 `create_time` 字段。
## 实施步骤
### 1. 替换现有处理器
`D:\his\openhis-server-new\core-framework\src\main\java\com\core\framework\handler\MybastisColumnsHandler.java` 文件替换为以下内容:
```java
package com.core.framework.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.core.common.core.domain.model.LoginUser;
import com.core.common.utils.SecurityUtils;
import com.core.framework.config.TenantContext;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* MyBatis-Plus 自动填充处理器
* 用于自动填充创建时间和更新时间,以及创建人和更新人
*/
@Component
public class MybastisColumnsHandler implements MetaObjectHandler {
// 设置数据新增时的字段自动赋值规则
@Override
public void insertFill(MetaObject metaObject) {
// 填充创建时间
Date currentTime = new Date();
this.strictInsertFill(metaObject, "createTime", Date.class, currentTime);
this.strictInsertFill(metaObject, "create_time", Date.class, currentTime);
// 获取当前登录用户名
String username = getCurrentUsername();
// 填充创建人
this.strictInsertFill(metaObject, "createBy", String.class, username);
this.strictInsertFill(metaObject, "create_by", String.class, username);
// 确保tenantId被设置
Integer tenantId = getCurrentTenantId();
if (tenantId == null) {
throw new RuntimeException("无法获取当前租户ID请确保用户已登录或正确设置租户上下文");
}
this.strictInsertFill(metaObject, "tenantId", Integer.class, tenantId);
this.strictInsertFill(metaObject, "tenant_id", Integer.class, tenantId);
}
// 设置数据修改时的字段自动赋值规则
@Override
public void updateFill(MetaObject metaObject) {
// 填充更新时间
Date currentTime = new Date();
this.strictUpdateFill(metaObject, "updateTime", Date.class, currentTime);
this.strictUpdateFill(metaObject, "update_time", Date.class, currentTime);
// 填充更新人
String username = getCurrentUsername();
this.strictUpdateFill(metaObject, "updateBy", String.class, username);
this.strictUpdateFill(metaObject, "update_by", String.class, username);
}
/**
* 获取当前登录用户名
* @return 当前登录用户名,如果无法获取则返回 "system"
*/
private String getCurrentUsername() {
String username = "system"; // 默认值
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
username = loginUser.getUsername();
} else {
// 尝试从请求中获取用户信息
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// 可以在这里添加额外的逻辑来从请求中获取用户信息
// 例如从请求头、session等获取用户信息
}
}
} catch (Exception e) {
// 记录异常但不中断处理流程
System.err.println("获取当前登录用户时发生异常: " + e.getMessage());
// 可以考虑记录日志
}
return username;
}
/**
* 获取当前租户 ID
*/
private Integer getCurrentTenantId() {
Integer result = null;
// 首先尝试从线程局部变量中获取租户ID适用于定时任务等场景
Integer threadLocalTenantId = TenantContext.getCurrentTenant();
if (threadLocalTenantId != null) {
result = threadLocalTenantId;
} else {
// 获取当前登录用户的租户ID优先使用SecurityUtils中储存的LoginUser的租户ID
try {
if (SecurityUtils.getAuthentication() != null) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
result = loginUser.getTenantId();
}
}
} catch (Exception e) {
// 记录异常但不中断处理
System.err.println("获取当前登录用户租户ID时发生异常: " + e.getMessage());
}
if (result == null) {
// 尝试从请求头中获取租户ID
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
if (request != null) {
// 从请求头获取租户ID假设header名称为"X-Tenant-ID" ; 登录接口前端把租户id放到请求头里
String tenantIdHeader = request.getHeader("X-Tenant-ID");
String requestMethodName = request.getHeader("Request-Method-Name");
// 登录
if ("login".equals(requestMethodName)) {
if (tenantIdHeader != null && !tenantIdHeader.isEmpty()) {
try {
result = Integer.parseInt(tenantIdHeader);
} catch (NumberFormatException e) {
System.err.println("解析请求头中的租户ID时发生异常: " + e.getMessage());
}
}
}
}
}
}
}
// 如果仍然没有获取到租户ID返回默认值
if (result == null) {
System.out.println("警告: 未能获取当前租户ID将使用默认租户ID 1");
result = 1; // 默认租户ID
}
return result;
}
}
```
### 2. 验证处理器是否被正确扫描
确保在主应用类或配置类中启用了自动填充功能:
```java
@SpringBootApplication
@MapperScan("com.openhis.*.mapper") // 确保扫描到你的mapper
@EnableTransactionManagement // 启用事务管理
public class OpenHisApplication {
public static void main(String[] args) {
SpringApplication.run(OpenHisApplication.class, args);
}
}
```
### 3. 测试验证
创建一个简单的测试来验证自动填充是否正常工作:
```java
@SpringBootTest
public class AuditFieldTest {
@Autowired
private PractitionerMapper practitionerMapper;
@Test
public void testAuditFieldsAutoFill() {
Practitioner practitioner = new Practitioner();
practitioner.setName("Test Practitioner");
// 保存实体
practitionerMapper.insert(practitioner);
// 验证审计字段是否被正确填充
assertThat(practitioner.getCreateBy()).isNotNull();
assertThat(practitioner.getCreateBy()).isNotEqualTo("");
assertThat(practitioner.getCreateTime()).isNotNull();
// 清理测试数据
practitionerMapper.deleteById(practitioner.getId());
}
}
```
## 注意事项
1. **安全上下文**:确保在调用保存方法时用户已登录,这样 `SecurityUtils.getLoginUser()` 才能返回有效的用户对象。
2. **异常处理**:处理器中包含了异常处理,如果无法获取当前用户,将使用 "system" 作为默认值。
3. **租户ID**处理器也处理租户ID的自动填充这对于多租户系统很重要。
4. **兼容性**处理器同时支持驼峰命名createBy和下划线命名create_by的字段以兼容不同的配置。
## 总结
通过优化 `MybastisColumnsHandler`,我们可以确保所有实体在保存时都能正确填充审计字段,避免因缺少这些字段而引发的数据库约束错误,同时保持数据完整性和审计跟踪功能。

184
QWEN.md Normal file
View File

@@ -0,0 +1,184 @@
# Qwen Code Context for HIS (Hospital Information System)
## Project Overview
This is a comprehensive Hospital Information System (HIS) called OpenHIS, built with a Java Spring Boot backend and Vue 3 frontend. The system is designed to manage hospital operations including patient management, appointments, clinical workflows, billing, and administrative tasks.
### Technology Stack
**Backend:**
- Java 17
- Spring Boot 2.5.15
- PostgreSQL (recommended v16.2)
- Redis
- MyBatis-Plus 3.5.5 for ORM
- Druid 1.2.27 for database connection pooling
- Flowable 6.8.0 for workflow management
- LiteFlow 2.12.4.1 for business rule orchestration
- Swagger 3.0.0 for API documentation
- JWT 0.9.1 for authentication
**Frontend:**
- Vue 3 with Composition API
- Vite 5.0.4 as build tool
- Element Plus 2.12.0 as UI component library
- Pinia 2.2.0 for state management
- Axios 0.27.2 for HTTP requests
- Sass for styling
## Repository Structure
```
.
├── openhis-server-new/ # Backend multi-module Maven project
│ ├── openhis-application/ # Main application module with startup class
│ ├── openhis-domain/ # Business domain modules (administration, clinical, financial, etc.)
│ ├── openhis-common/ # Shared utilities and common code
│ ├── core-admin/ # Core administration module
│ ├── core-framework/ # Framework configuration and security
│ ├── core-system/ # System management module
│ ├── core-quartz/ # Scheduled tasks
│ ├── core-generator/ # Code generation utilities
│ ├── core-common/ # Core utilities
│ └── core-flowable/ # Workflow engine integration
├── openhis-ui-vue3/ # Vue 3 frontend
│ ├── src/
│ │ ├── api/ # API service layer
│ │ ├── components/ # Reusable components
│ │ ├── router/ # Vue Router configuration
│ │ ├── store/ # Pinia state management
│ │ ├── utils/ # Utility functions
│ │ └── views/ # Page components
│ └── vite/ # Vite plugins configuration
├── sql/ # Database scripts
├── 发版记录/ # Release records
└── 迁移记录-DB变更记录/ # Database migration records
```
## Building and Running
### Backend Setup
1. **Prerequisites:**
- JDK 17 (required)
- PostgreSQL v16.2 (required)
- Redis (stable version)
2. **Database Setup:**
- Import the database initialization script using Navicat 16 or later
- Script location: `sql/20251224init脚本(使用Navicat Premium 17导入).sql`
- Configure database connection in `application.yml` or `application-dev.yml`
3. **Build and Run:**
```bash
cd openhis-server-new
mvn clean package -DskipTests
cd openhis-application
mvn spring-boot:run
```
Or run directly from IDE by executing `OpenHisApplication.java`
### Frontend Setup
1. **Prerequisites:**
- Node.js v16.15 (recommended)
2. **Installation and Run:**
```bash
cd openhis-ui-vue3
npm install
npm run dev
```
3. **Access the application:**
- Frontend: http://localhost:81
- Backend API: http://localhost:18080/openhis
- Swagger UI: http://localhost:18080/openhis/swagger-ui/index.html
## Development Conventions
### Backend Architecture
The backend follows a multi-module Maven architecture with clear separation of concerns:
1. **openhis-application**: Entry point with `OpenHisApplication.java`
- Scans `com.core` and `com.openhis` packages
- Configured to run on port 18080 with context path `/openhis`
2. **openhis-domain**: Business domain modules organized by medical functionality:
- `administration`: Administrative functions
- `appointmentmanage`: Appointment management
- `check`: Medical examination/checkup
- `clinical`: Clinical workflows
- `crosssystem`: Cross-system integration
- `document`: Document management
- `financial`: Financial/billing
- `lab`: Laboratory operations
- `medication`: Medication management
- `triageandqueuemanage`: Patient triage and queue management
- `yb`, `ybcatalog`, `ybelep`: Insurance (Yi Bao) integration
- `workflow`: Workflow management
3. **Core Modules** (com.core package):
- `core-system`: User, role, menu, and permission management
- `core-framework`: Security, exception handling, and framework configurations
- `core-common`: Shared utilities and base classes
- `core-quartz`: Scheduled task management
- `core-generator`: Code generation tools
- `core-flowable`: Workflow engine integration
- `core-admin`: Administrative functions
### Frontend Architecture
The frontend uses Vue 3 with composition API and modern tooling:
1. **State Management:** Pinia for global state with modules for app, dict, permission, settings, tagsView, and user
2. **Routing:** Vue Router 4.3.0 with public routes and dynamic permission-based routes
3. **API Integration:** Axios with request/response interceptors and API services organized by module
4. **Component Architecture:** Element Plus as UI framework with custom components in `src/components/`
## Key Configuration Files
### Backend Configuration
- Main config: `openhis-server-new/openhis-application/src/main/resources/application.yml`
- Environment-specific: `application-dev.yml`, `application-test.yml`, `application-prd.yml`
- Database connection settings, Redis configuration, server settings, and MyBatis-Plus configuration
### Frontend Configuration
- Environment files: `.env.*` in `openhis-ui-vue3/`
- Vite configuration: `vite.config.js`
- Main entry: `src/main.js`
- Router: `src/router/index.js`
## Common Development Tasks
### Adding a New Backend Feature
1. Create domain entity in appropriate module under `openhis-domain/[module]/domain/`
2. Create mapper interface in `openhis-domain/[module]/mapper/`
3. Create service interface and implementation in `openhis-domain/[module]/service/`
4. Create controller in `openhis-application/src/main/java/com/openhis/web/[module]/`
5. Test endpoints via Swagger UI
### Adding a New Frontend Page
1. Create Vue component in `openhis-ui-vue3/src/views/[module]/`
2. Add API service methods in `openhis-ui-vue3/src/api/`
3. Add route to `openhis-ui-vue3/src/router/index.js`
4. Add Pinia store module if state management needed
## Important Notes
- The system uses logical deletion with a `validFlag` field (1 = active, 0 = deleted)
- JWT tokens are stored in the `Authorization` header
- The system supports WebView environments with C# accessor integration
- File uploads are configured with max 10MB per file and 20MB total request size
- Password lockout occurs after 5 failed attempts with a 10-minute lock time
- The system includes a code generator accessible via `/tool/gen` route
- Printing functionality is implemented using the hiprint plugin

View File

@@ -1,68 +0,0 @@
# 平台介绍
## 🏠【关于我们】
![天天开源](https://open.tntlinking.com/assets/logo-b-BzFUYaRU.png)
天天开源致⼒于打造中国应⽤管理 软件开源⽣态⾯向医疗、企业、教育三⼤⾏业信息化需求提供优质的开源软件产品与解决⽅案。平台现已发布OpenHIS、OpenCOM、OpenEDU系列开源产品并持续招募⽣态合作伙伴期待共同构建开源创新的⾏业协作模式加速⾏业的数字化进程。
天天开源的前⾝是新致开源最早于2022年6⽉发布开源医疗软件平台OpenHIS.org.cn于2023年6⽉发布开源企业软件平台OpenCOM.com.cn。2025年7⽉新致开源品牌更新为天天开源我们始终秉持开源、专业、协作的理念致⼒于为医疗、教育、中⼩企业等⾏业提供优质的开源解决⽅案。
了解我们ahttps://open.tntlinking.com/about?site=gitee
## 💾【部署包下载】
请访问官网产品中心下载部署包https://open.tntlinking.com/resource/productCenter?site=gitee
## 📚【支持文档】
技术支持资源https://open.tntlinking.com/resource/openProductDoc?site=gitee
(含演示环境、操作手册、部署手册、开发手册、常见问题等)
产品介绍https://open.tntlinking.com/resource/productPresentation?site=gitee
操作教程https://open.tntlinking.com/resource/operationTutorial?site=gitee
沙龙回顾https://open.tntlinking.com/resource/openSourceSalon#23?site=gitee
## 🤝【合作方式】
产品服务价格https://open.tntlinking.com/cost?site=gitee
加入生态伙伴https://open.tntlinking.com/ecology/becomePartner?site=gitee
## 🤗【技术社区】
请访问官网扫码加入技术社区交流https://open.tntlinking.com/ecology/joinCommunity?site=gitee
请关注公众号【天天开源软件】以便获得最新产品更新信息。
# 项目介绍
OpenHIS医院系统信创版集十大核心模块于一体涵盖目录管理、基础数据配置、个性化设置、门诊/住院全流程管理、药房药库智能管控、精细化耗材管理、财务核算体系、医保合规对接及多维报表分析等功能模块共计372项标准化功能。
系统深度适配民营及公立一二级医院业务场景,支持单体医院、集团化运营及区域医疗协同等多种部署模式,并通过国家信创认证体系,确保全栈技术自主可控。如有项目需求,可联系官方平台合作。
## 运行环境
jdk17 (必须)
node.js-v16.15 (推荐)
PostgreSQL-v16.2 (必须)
redis (常用稳定版本即可)
## 开发提示
需要修改数据库和redis的连接信息,详见:
application.yml
application-druid.yml
## 目录解释
前端: openhis-ui-vue3
后端: openhis-server
启动类: OpenHisApplication

View File

@@ -1,39 +0,0 @@
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Scanner;
public class TestDeleteInspectionType {
public static void main(String[] args) {
try {
// 测试删除ID为1的检验类型
long inspectionTypeId = 1;
URL url = new URL("http://localhost:8080/system/inspection-type/" + inspectionTypeId);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("DELETE");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Accept", "application/json");
// 发送请求
int responseCode = connection.getResponseCode();
System.out.println("响应代码: " + responseCode);
// 读取响应
Scanner scanner;
if (responseCode >= 200 && responseCode < 300) {
scanner = new Scanner(connection.getInputStream());
} else {
scanner = new Scanner(connection.getErrorStream());
}
String response = scanner.useDelimiter("\\A").next();
System.out.println("响应内容: " + response);
scanner.close();
connection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,202 @@
# OpenHIS 系统审计字段填充最佳实践
## 概述
本文档介绍如何在 OpenHIS 系统中确保所有实体的审计字段create_by、create_time、update_by、update_time能够正确自动填充。
## 自动填充机制
### 1. 基础实体类
所有需要审计字段的实体类都应该继承自 `HisBaseEntity`
```java
import com.core.common.core.domain.HisBaseEntity;
@Data
@TableName("adm_practitioner")
public class Practitioner extends HisBaseEntity {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
// 其他业务字段...
}
```
### 2. 自动填充处理器
系统使用 `MybastisColumnsHandler` 来自动填充审计字段:
```java
@Component
public class MybastisColumnsHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
// 填充创建时间和创建人
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "create_time", Date.class, new Date());
String username = getCurrentUsername(); // 获取当前用户名
this.strictInsertFill(metaObject, "createBy", String.class, username);
this.strictInsertFill(metaObject, "create_by", String.class, username);
}
@Override
public void updateFill(MetaObject metaObject) {
// 填充更新时间和更新人
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
this.strictUpdateFill(metaObject, "update_time", Date.class, new Date());
String username = getCurrentUsername(); // 获取当前用户名
this.strictUpdateFill(metaObject, "updateBy", String.class, username);
this.strictUpdateFill(metaObject, "update_by", String.class, username);
}
private String getCurrentUsername() {
String username = "system";
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
username = loginUser.getUsername();
}
} catch (Exception ignored) {
}
return username;
}
}
```
## 确保自动填充正常工作的要点
### 1. 检查实体类继承关系
确保所有实体类都正确继承了 `HisBaseEntity`
```java
// 正确的做法
public class Practitioner extends HisBaseEntity { ... }
// 如果不能继承 HisBaseEntity则需要手动添加审计字段
public class CustomEntity {
@TableField(fill = FieldFill.INSERT)
private String createBy;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private String updateBy;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
}
```
### 2. 验证安全上下文
确保在执行数据库操作时有有效的安全上下文:
```java
@Service
public class PractitionerService {
public void savePractitioner(Practitioner practitioner) {
// 确保调用此方法时用户已登录
// SecurityUtils.getLoginUser() 应该能返回有效的 LoginUser 对象
// MyBatis-Plus 会在保存时自动调用 MybastisColumnsHandler
practitionerMapper.insert(practitioner);
}
}
```
### 3. 检查配置
确保自动填充处理器被正确配置:
```yaml
# application.yml
mybatis-plus:
global-config:
db-config:
# 其他配置...
configuration:
# 其他配置...
```
### 4. 手动填充(特殊情况)
在某些特殊情况下,如果自动填充不工作,可以手动设置:
```java
@Service
public class PractitionerService {
public void savePractitionerManually(Practitioner practitioner) {
// 手动设置审计字段
Date now = new Date();
String currentUser = getCurrentUsername();
practitioner.setCreateTime(now);
practitioner.setCreateBy(currentUser);
practitioner.setUpdateTime(now);
practitioner.setUpdateBy(currentUser);
practitionerMapper.insert(practitioner);
}
}
```
## 常见问题及解决方案
### 问题1自动填充不生效
**原因:**
- 实体类没有继承 `HisBaseEntity`
- `MybastisColumnsHandler` 没有被Spring管理缺少@Component注解
- 没有有效的安全上下文
**解决方案:**
- 确保实体类继承 `HisBaseEntity`
- 检查 `MybastisColumnsHandler` 是否有 `@Component` 注解
- 确保在调用保存方法时用户已登录
### 问题2获取不到当前用户
**原因:**
- 用户未登录
- 安全上下文配置错误
**解决方案:**
- 在调用保存方法前确保用户已登录
- 检查安全配置是否正确
### 问题3批量操作时审计字段未填充
**原因:**
- 批量操作可能绕过了自动填充机制
**解决方案:**
- 对于批量操作,手动设置审计字段
- 或者使用 MyBatis-Plus 的批量操作方法,确保它们支持自动填充
## 测试验证
创建一个简单的测试来验证自动填充是否正常工作:
```java
@SpringBootTest
public class AuditFieldTest {
@Autowired
private PractitionerMapper practitionerMapper;
@Test
public void testAuditFieldsAutoFill() {
Practitioner practitioner = new Practitioner();
practitioner.setName("Test Practitioner");
// 保存实体
practitionerMapper.insert(practitioner);
// 验证审计字段是否被正确填充
assertThat(practitioner.getCreateBy()).isNotNull();
assertThat(practitioner.getCreateTime()).isNotNull();
// 清理测试数据
practitionerMapper.deleteById(practitioner.getId());
}
}
```
## 总结
通过遵循以上最佳实践,可以确保 OpenHIS 系统中的所有实体在保存时都能正确填充审计字段,避免因缺少这些字段而引发的数据库约束错误。

113
audit_field_solution.md Normal file
View File

@@ -0,0 +1,113 @@
# 关于数据库审计字段create_by, create_time等的处理方案
## 问题描述
在使用OpenHIS系统时可能会遇到如下错误
```
org.postgresql.util.PSQLException: ERROR: null value in column "create_by" of relation "adm_practitioner" violates not-null constraint
```
## 问题分析
1. 数据库表中的审计字段如create_by, create_time设置了NOT NULL约束
2. 应用程序层面使用了MyBatis-Plus的自动填充功能来设置这些字段
3. 当自动填充机制失效时,就会出现违反非空约束的错误
## 解决方案
### 方案一:修复自动填充机制(推荐)
系统已经实现了自动填充机制,位于 `MybastisColumnsHandler.java`
```java
// 设置数据新增时候的,字段自动赋值规则
@Override
public void insertFill(MetaObject metaObject) {
// 同时填充驼峰和下划线命名的字段,以兼容不同的配置
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "create_time", Date.class, new Date());
String username = "system";
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
username = loginUser.getUsername();
}
} catch (Exception ignored) {
}
// 使用 fillStrategy 确保即使字段为 null 也会被填充
this.strictInsertFill(metaObject, "createBy", String.class, username);
this.strictInsertFill(metaObject, "create_by", String.class, username);
// 如果 strictInsertFill 没有生效,使用 setFieldValByName 强制设置
if (metaObject.hasGetter("createBy") && metaObject.getValue("createBy") == null) {
this.setFieldValByName("createBy", username, metaObject);
}
if (metaObject.hasGetter("create_by") && metaObject.getValue("create_by") == null) {
this.setFieldValByName("create_by", username, metaObject);
}
...
}
```
确保所有实体类都继承自 `HisBaseEntity``BaseEntity`,这样就能自动获得审计字段。
### 方案二:移除数据库约束(谨慎使用)
如果确实需要允许审计字段为NULL可以移除数据库约束
```sql
-- 移除 adm_practitioner 表中 create_by 列的 NOT NULL 约束
ALTER TABLE "public"."adm_practitioner"
ALTER COLUMN "create_by" DROP NOT NULL;
-- 同样处理 create_time 列(如果需要)
ALTER TABLE "public"."adm_practitioner"
ALTER COLUMN "create_time" DROP NOT NULL;
```
### 方案三:批量修复所有表的约束
如果多个表都存在这个问题,可以使用以下脚本:
```sql
-- 为所有表的审计字段移除NOT NULL约束
-- 注意:执行前请备份数据库!
-- 1. 检查所有包含审计字段的表
SELECT
table_name,
column_name,
is_nullable
FROM
information_schema.columns
WHERE
column_name IN ('create_by', 'create_time', 'update_by', 'update_time')
AND table_schema = 'public'
AND is_nullable = 'NO'; -- NO 表示 NOT NULL 约束
-- 2. 根据需要移除特定表的约束
-- 示例移除多个表的create_by约束
ALTER TABLE "public"."adm_practitioner" ALTER COLUMN "create_by" DROP NOT NULL;
ALTER TABLE "public"."adm_patient" ALTER COLUMN "create_by" DROP NOT NULL;
-- 添加更多表的处理...
```
## 最佳实践
### 1. 确保实体类继承基础类
所有实体类应继承 `HisBaseEntity``BaseEntity`
```java
@Data
@TableName("adm_practitioner")
public class Practitioner extends HisBaseEntity {
// 其他字段...
}
```
### 2. 检查安全上下文
确保在保存数据时有有效的安全上下文,这样自动填充处理器才能获取到当前用户信息。
### 3. 验证自动填充配置
确保 `MybastisColumnsHandler` 在Spring容器中被正确注册使用@Component注解)。
## 总结
- 推荐保持数据库中的NOT NULL约束确保数据完整性
- 依赖MyBatis-Plus的自动填充机制来设置审计字段
- 确保所有实体类继承基础实体类
- 在必要时才考虑移除数据库约束

104
check_display_order.sql Normal file
View File

@@ -0,0 +1,104 @@
-- 检查流水号display_order是否按“科室+医生+当天”正确递增
--
-- 说明:
-- 1. display_order 存的是纯数字1, 2, 3...),不带时间戳前缀
-- 2. 时间戳前缀(如 20260109是在前端显示时加上的
-- 3. 后端用 Redis key "ORG-{科室ID}-DOC-{医生ID}" 按天自增
--
-- 如何判断逻辑是否正确:
-- 同一科室、同一医生、同一天的记录display_order 应该递增1, 2, 3...
-- 不同科室、不同医生、不同天的记录,可能都是 1这是正常的
-- ========================================
-- 查询1按“科室+医生+日期”分组,看每组内的 display_order 是否递增
-- ========================================
SELECT
DATE(start_time) AS ,
organization_id AS ID,
registrar_id AS ID,
COUNT(*) AS ,
MIN(display_order) AS ,
MAX(display_order) AS ,
STRING_AGG(display_order::text, ', ' ORDER BY start_time) AS ,
STRING_AGG(id::text, ', ' ORDER BY start_time) AS ID列表
FROM adm_encounter
WHERE delete_flag = '0'
AND start_time >= CURRENT_DATE - INTERVAL '7 days' -- 只看最近7天
AND display_order IS NOT NULL
GROUP BY DATE(start_time), organization_id, registrar_id
ORDER BY DESC, ID, ID;
-- ========================================
-- 查询2详细查看每条记录看同组内的序号是否连续
-- ========================================
SELECT
id AS ID,
DATE(start_time) AS ,
organization_id AS ID,
registrar_id AS ID,
start_time AS ,
display_order AS ,
-- 计算:同组内的序号应该是 1, 2, 3...,看是否有重复或跳号
ROW_NUMBER() OVER (
PARTITION BY DATE(start_time), organization_id, registrar_id
ORDER BY start_time
) AS ,
CASE
WHEN display_order = ROW_NUMBER() OVER (
PARTITION BY DATE(start_time), organization_id, registrar_id
ORDER BY start_time
) THEN '✓ 正常'
ELSE '✗ 异常'
END AS
FROM adm_encounter
WHERE delete_flag = '0'
AND start_time >= CURRENT_DATE - INTERVAL '7 days'
AND display_order IS NOT NULL
ORDER BY DATE(start_time) DESC, organization_id, registrar_id, start_time;
-- ========================================
-- 查询3只看今天的数据最直观
-- ========================================
SELECT
id AS ID,
organization_id AS ID,
registrar_id AS ID,
start_time AS ,
display_order AS
FROM adm_encounter
WHERE delete_flag = '0'
AND DATE(start_time) = CURRENT_DATE
AND display_order IS NOT NULL
ORDER BY organization_id, registrar_id, start_time;
-- ========================================
-- 查询4发现问题 - 找出同组内 display_order 重复的记录
-- ========================================
WITH ranked AS (
SELECT
id,
DATE(start_time) AS reg_date,
organization_id,
registrar_id,
start_time,
display_order,
ROW_NUMBER() OVER (
PARTITION BY DATE(start_time), organization_id, registrar_id
ORDER BY start_time
) AS should_be_order
FROM adm_encounter
WHERE delete_flag = '0'
AND start_time >= CURRENT_DATE - INTERVAL '7 days'
AND display_order IS NOT NULL
)
SELECT
reg_date AS ,
organization_id AS ID,
registrar_id AS ID,
COUNT(*) AS ,
STRING_AGG(id::text || '->' || display_order::text, ', ') AS
FROM ranked
WHERE display_order != should_be_order
GROUP BY reg_date, organization_id, registrar_id
ORDER BY reg_date DESC;

38
debug_api_return.md Normal file
View File

@@ -0,0 +1,38 @@
# 检查后端API返回数据结构
## 问题分析
尽管我们更新了DTO和SQL查询前端仍然没有显示创建时间可能的原因
1. API响应中没有包含createTime字段
2. SQL查询没有正确返回createTime字段
3. 数据库中createTime字段本身为null
4. JSON序列化问题
## 检查步骤
### 1. 检查数据库中数据
首先检查数据库中sys_user表的createTime字段是否正确填充
```sql
SELECT user_id, user_name, nick_name, create_time
FROM sys_user
WHERE create_time IS NOT NULL
LIMIT 10;
```
### 2. 检查API端点
API端点是GET /base-data-manage/practitioner/user-practitioner-page
这个端点在PractitionerController中定义调用practitionerAppService.getUserPractitionerPage()
### 3. 检查SQL查询
在PractitionerAppMapper.xml中我们已经添加了createTime字段
```xml
T2.create_time
```
### 4. 验证DTO映射
UserAndPractitionerDto中已添加createTime字段
```java
private Date createTime;
```
### 5. 检查JSON序列化
检查是否有@JsonFormat注解或其他序列化配置问题

View File

@@ -0,0 +1,290 @@
# 深度排查 MyBatis-Plus 自动填充不生效问题
## 问题概述
尽管对 MyBatis-Plus 的自动填充处理器进行了多次优化和配置,但 `create_by``create_time` 字段仍然没有被自动填充。
## 深度排查步骤
### 1. 检查 AOP 代理是否生效
MyBatis-Plus 的自动填充功能依赖于 AOP 代理。如果实体类的方法被直接调用而非通过代理调用,自动填充可能不会生效。
### 2. 验证 Service 层实现
确保使用的是 MyBatis-Plus 提供的通用 Service 方法,而不是自定义的 SQL。
### 3. 检查 @TableField 注解配置
确认实体类中的字段注解配置正确。
### 4. 检查事务配置
某些事务配置可能会影响 AOP 代理的生效。
## 解决方案
### 方案一:在 Service 层手动设置审计字段
创建一个工具类来统一处理审计字段的设置:
```java
@Component
public class AuditFieldUtil {
public static void setCreateInfo(Object entity) {
if (entity == null) return;
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
String username = loginUser != null ? loginUser.getUsername() : "system";
Date currentTime = new Date();
// 使用反射设置字段值
Field createByField = getField(entity.getClass(), "createBy");
if (createByField != null) {
createByField.setAccessible(true);
if (createByField.get(entity) == null || "".equals(createByField.get(entity))) {
createByField.set(entity, username);
}
}
Field createTimeField = getField(entity.getClass(), "createTime");
if (createTimeField != null) {
createTimeField.setAccessible(true);
if (createTimeField.get(entity) == null) {
createTimeField.set(entity, currentTime);
}
}
// 处理下划线命名的字段
Field createByFieldUnderscore = getField(entity.getClass(), "create_by");
if (createByFieldUnderscore != null) {
createByFieldUnderscore.setAccessible(true);
if (createByFieldUnderscore.get(entity) == null || "".equals(createByFieldUnderscore.get(entity))) {
createByFieldUnderscore.set(entity, username);
}
}
Field createTimeFieldUnderscore = getField(entity.getClass(), "create_time");
if (createTimeFieldUnderscore != null) {
createTimeFieldUnderscore.setAccessible(true);
if (createTimeFieldUnderscore.get(entity) == null) {
createTimeFieldUnderscore.set(entity, currentTime);
}
}
} catch (Exception e) {
System.err.println("设置审计字段时发生异常: " + e.getMessage());
}
}
private static Field getField(Class<?> clazz, String fieldName) {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
if (clazz.getSuperclass() != null) {
return getField(clazz.getSuperclass(), fieldName);
}
return null;
}
}
}
```
然后在 Service 实现中使用:
```java
@Service
public class PractitionerServiceImpl extends ServiceImpl<PractitionerMapper, Practitioner>
implements IPractitionerService {
@Autowired
private AuditFieldUtil auditFieldUtil;
@Override
@Transactional
public boolean save(Practitioner entity) {
// 在保存前手动设置审计字段
auditFieldUtil.setCreateInfo(entity);
return super.save(entity);
}
@Override
@Transactional
public boolean saveBatch(Collection<Practitioner> entityList) {
entityList.forEach(auditFieldUtil::setCreateInfo);
return super.saveBatch(entityList);
}
}
```
### 方案二:重写 BaseMapper 方法
如果 Service 层的方法不起作用,可以直接在 Mapper 层处理:
```java
@Mapper
public interface PractitionerMapper extends BaseMapper<Practitioner> {
@Insert({
"<script>",
"INSERT INTO adm_practitioner (",
"id, active_flag, name, name_json, gender_enum, birth_date, deceased_date,",
"phone, address, address_province, address_city, address_district, address_street,",
"address_json, py_str, wb_str, bus_no, yb_no, user_id, tenant_id, delete_flag,",
"create_by, create_time, update_by, update_time, org_id,",
"phar_prac_cert_no, prsc_dr_cert_code, dr_profttl_code, kpd_code, signature, pos_no",
") VALUES (",
"#{id}, #{activeFlag}, #{name}, #{nameJson}, #{genderEnum}, #{birthDate}, #{deceasedDate},",
"#{phone}, #{address}, #{addressProvince}, #{addressCity}, #{addressDistrict}, #{addressStreet},",
"#{addressJson}, #{pyStr}, #{wbStr}, #{busNo}, #{ybNo}, #{userId}, #{tenantId}, #{deleteFlag},",
"#{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{orgId},",
"#{pharPracCertNo}, #{prscDrCertCode}, #{drProfttlCode}, #{kpdCode}, #{signature}, #{posNo}",
")",
"</script>"
})
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertWithAuditFields(Practitioner record);
}
```
### 方案三:使用 MyBatis 拦截器
创建一个 MyBatis 拦截器来自动填充字段:
```java
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Component
public class AuditFieldInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object[] args = invocation.getArgs();
MappedStatement ms = (MappedStatement) args[0];
Object parameter = args[1];
String sqlCommandType = ms.getSqlCommandType().toString();
if ("INSERT".equals(sqlCommandType)) {
setCreateAuditFields(parameter);
} else if ("UPDATE".equals(sqlCommandType)) {
setUpdateAuditFields(parameter);
}
return invocation.proceed();
}
private void setCreateAuditFields(Object parameter) {
if (parameter == null) return;
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
String username = loginUser != null ? loginUser.getUsername() : "system";
Date currentTime = new Date();
// 设置 createBy 和 createTime
setFieldValue(parameter, "createBy", username);
setFieldValue(parameter, "create_time", username);
setFieldValue(parameter, "createTime", currentTime);
setFieldValue(parameter, "create_time", currentTime);
} catch (Exception e) {
e.printStackTrace();
}
}
private void setUpdateAuditFields(Object parameter) {
if (parameter == null) return;
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
String username = loginUser != null ? loginUser.getUsername() : "system";
Date currentTime = new Date();
// 设置 updateBy 和 updateTime
setFieldValue(parameter, "updateBy", username);
setFieldValue(parameter, "update_by", username);
setFieldValue(parameter, "updateTime", currentTime);
setFieldValue(parameter, "update_time", currentTime);
} catch (Exception e) {
e.printStackTrace();
}
}
private void setFieldValue(Object obj, String fieldName, Object value) {
try {
Field field = getField(obj.getClass(), fieldName);
if (field != null) {
field.setAccessible(true);
if (field.get(obj) == null) { // 只在原值为 null 时设置
field.set(obj, value);
}
}
} catch (Exception e) {
// 忽略无法设置的字段
}
}
private Field getField(Class<?> clazz, String fieldName) {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
if (clazz.getSuperclass() != null) {
return getField(clazz.getSuperclass(), fieldName);
}
return null;
}
}
@Override
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {}
}
```
## 推荐实施顺序
1. 首先尝试方案一Service 层手动设置),这是最简单且可控的方式
2. 如果方案一不行尝试方案三MyBatis 拦截器),它在更底层起作用
3. 方案二是最后的选择,需要重写具体的插入逻辑
## 验证方法
创建一个测试来验证自动填充是否生效:
```java
@SpringBootTest
public class AuditFieldTest {
@Autowired
private IPractitionerService practitionerService;
@Test
public void testAuditFieldFill() {
Practitioner practitioner = new Practitioner();
practitioner.setName("Test Practitioner");
// 记录保存前的值
System.out.println("保存前 - createBy: " + practitioner.getCreateBy());
System.out.println("保存前 - createTime: " + practitioner.getCreateTime());
boolean success = practitionerService.save(practitioner);
// 从数据库重新查询以验证
Practitioner saved = practitionerService.getById(practitioner.getId());
System.out.println("保存后 - createBy: " + saved.getCreateBy());
System.out.println("保存后 - createTime: " + saved.getCreateTime());
Assertions.assertTrue(success);
Assertions.assertNotNull(saved.getCreateBy());
Assertions.assertNotNull(saved.getCreateTime());
}
}
```
通过这些方案,应该能够解决自动填充不生效的问题。

143
diagnose_autofill_issue.md Normal file
View File

@@ -0,0 +1,143 @@
# 诊断 MyBatis-Plus 自动填充问题
## 问题现象
尽管 `MybastisColumnsHandler` 已经实现并配置了自动填充功能,但 `create_by``create_time` 字段仍然没有被正确填充。
## 可能的原因及解决方案
### 1. 检查组件扫描配置
确保 `MybastisColumnsHandler` 类被Spring容器正确管理
```java
@Component // 确保这个注解存在
public class MybastisColumnsHandler implements MetaObjectHandler {
// ...
}
```
### 2. 检查包扫描路径
在主应用类中确保扫描到了处理器所在的包:
```java
@SpringBootApplication
@MapperScan("com.openhis.*.mapper") // 确保扫描到你的mapper
@ComponentScan(basePackages = {"com.core", "com.openhis"}) // 确保扫描到处理器
public class OpenHisApplication {
public static void main(String[] args) {
SpringApplication.run(OpenHisApplication.class, args);
}
}
```
### 3. 验证实体类配置
确保实体类正确继承了 `HisBaseEntity` 并且字段上有正确的注解:
```java
@Data
@TableName("adm_practitioner")
public class Practitioner extends HisBaseEntity {
// 不需要在子类中重复定义 createBy, createTime 等字段
// 因为它们已在 HisBaseEntity 中定义并带有 @TableField(fill = FieldFill.INSERT)
}
```
### 4. 检查安全上下文
自动填充处理器依赖于安全上下文来获取当前用户。确保在执行保存操作时用户已登录:
```java
// 在保存之前,确保用户已登录
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser == null) {
// 用户未登录,可能需要手动设置审计字段
}
```
### 5. 手动测试自动填充
创建一个简单的测试来验证自动填充是否正常工作:
```java
@SpringBootTest
public class AutoFillTest {
@Autowired
private PractitionerMapper practitionerMapper;
@Test
public void testAutoFill() {
Practitioner practitioner = new Practitioner();
practitioner.setName("Test Practitioner");
// 检查在保存前字段是否为空
System.out.println("Before insert - createBy: " + practitioner.getCreateBy());
System.out.println("Before insert - createTime: " + practitioner.getCreateTime());
// 执行插入操作
int result = practitionerMapper.insert(practitioner);
// 检查保存后字段是否被填充
System.out.println("After insert - createBy: " + practitioner.getCreateBy());
System.out.println("After insert - createTime: " + practitioner.getCreateTime());
assertThat(result).isEqualTo(1);
assertThat(practitioner.getCreateBy()).isNotNull();
assertThat(practitioner.getCreateTime()).isNotNull();
}
}
```
### 6. 临时解决方案
如果自动填充仍然不工作,可以在服务层手动设置这些字段:
```java
@Service
public class PractitionerServiceImpl extends ServiceImpl<PractitionerMapper, Practitioner>
implements IPractitionerService {
@Override
public void savePractitioner(Practitioner practitioner) {
// 手动设置审计字段
if (practitioner.getCreateBy() == null || practitioner.getCreateBy().isEmpty()) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
practitioner.setCreateBy(loginUser.getUsername());
} else {
practitioner.setCreateBy("system"); // 默认值
}
}
if (practitioner.getCreateTime() == null) {
practitioner.setCreateTime(new Date());
}
// 执行保存操作
this.save(practitioner);
}
}
```
### 7. 检查 MyBatis-Plus 版本兼容性
确保使用的 MyBatis-Plus 版本与自动填充功能兼容。当前项目使用的是 3.5.5 版本,应该支持自动填充功能。
### 8. 调试自动填充处理器
`MybastisColumnsHandler` 中添加日志来调试是否被调用:
```java
@Override
public void insertFill(MetaObject metaObject) {
System.out.println("MybastisColumnsHandler.insertFill() called"); // 调试日志
Date currentTime = new Date();
this.strictInsertFill(metaObject, "createTime", Date.class, currentTime);
this.strictInsertFill(metaObject, "create_time", Date.class, currentTime);
String username = getCurrentUsername();
System.out.println("Setting createBy to: " + username); // 调试日志
this.strictInsertFill(metaObject, "createBy", String.class, username);
this.strictInsertFill(metaObject, "create_by", String.class, username);
// ... 其他代码
}
```
通过以上步骤,应该能够诊断并解决自动填充不工作的问题。

View File

@@ -0,0 +1,145 @@
package com.core.framework.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.core.common.core.domain.model.LoginUser;
import com.core.common.utils.SecurityUtils;
import com.core.framework.config.TenantContext;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
* MyBatis-Plus 自动填充处理器
* 用于自动填充创建时间和更新时间,以及创建人和更新人
*/
@Component
public class MybastisColumnsHandler implements MetaObjectHandler {
// 设置数据新增时的字段自动赋值规则
@Override
public void insertFill(MetaObject metaObject) {
// 填充创建时间
Date currentTime = new Date();
this.strictInsertFill(metaObject, "createTime", Date.class, currentTime);
this.strictInsertFill(metaObject, "create_time", Date.class, currentTime);
// 获取当前登录用户名
String username = getCurrentUsername();
// 填充创建人
this.strictInsertFill(metaObject, "createBy", String.class, username);
this.strictInsertFill(metaObject, "create_by", String.class, username);
// 确保tenantId被设置
Integer tenantId = getCurrentTenantId();
if (tenantId == null) {
throw new RuntimeException("无法获取当前租户ID请确保用户已登录或正确设置租户上下文");
}
this.strictInsertFill(metaObject, "tenantId", Integer.class, tenantId);
this.strictInsertFill(metaObject, "tenant_id", Integer.class, tenantId);
}
// 设置数据修改时的字段自动赋值规则
@Override
public void updateFill(MetaObject metaObject) {
// 填充更新时间
Date currentTime = new Date();
this.strictUpdateFill(metaObject, "updateTime", Date.class, currentTime);
this.strictUpdateFill(metaObject, "update_time", Date.class, currentTime);
// 填充更新人
String username = getCurrentUsername();
this.strictUpdateFill(metaObject, "updateBy", String.class, username);
this.strictUpdateFill(metaObject, "update_by", String.class, username);
}
/**
* 获取当前登录用户名
* @return 当前登录用户名,如果无法获取则返回 "system"
*/
private String getCurrentUsername() {
String username = "system"; // 默认值
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
username = loginUser.getUsername();
} else {
// 尝试从请求中获取用户信息
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
// 可以在这里添加额外的逻辑来从请求中获取用户信息
// 例如从请求头、session等获取用户信息
}
}
} catch (Exception e) {
// 记录异常但不中断处理流程
System.err.println("获取当前登录用户时发生异常: " + e.getMessage());
// 可以考虑记录日志
}
return username;
}
/**
* 获取当前租户 ID
*/
private Integer getCurrentTenantId() {
Integer result = null;
// 首先尝试从线程局部变量中获取租户ID适用于定时任务等场景
Integer threadLocalTenantId = TenantContext.getCurrentTenant();
if (threadLocalTenantId != null) {
result = threadLocalTenantId;
} else {
// 获取当前登录用户的租户ID优先使用SecurityUtils中储存的LoginUser的租户ID
try {
if (SecurityUtils.getAuthentication() != null) {
LoginUser loginUser = SecurityUtils.getLoginUser();
if (loginUser != null) {
result = loginUser.getTenantId();
}
}
} catch (Exception e) {
// 记录异常但不中断处理
System.err.println("获取当前登录用户租户ID时发生异常: " + e.getMessage());
}
if (result == null) {
// 尝试从请求头中获取租户ID
ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
if (attributes != null) {
HttpServletRequest request = attributes.getRequest();
if (request != null) {
// 从请求头获取租户ID假设header名称为"X-Tenant-ID" ; 登录接口前端把租户id放到请求头里
String tenantIdHeader = request.getHeader("X-Tenant-ID");
String requestMethodName = request.getHeader("Request-Method-Name");
// 登录
if ("login".equals(requestMethodName)) {
if (tenantIdHeader != null && !tenantIdHeader.isEmpty()) {
try {
result = Integer.parseInt(tenantIdHeader);
} catch (NumberFormatException e) {
System.err.println("解析请求头中的租户ID时发生异常: " + e.getMessage());
}
}
}
}
}
}
}
// 如果仍然没有获取到租户ID返回默认值
if (result == null) {
System.out.println("警告: 未能获取当前租户ID将使用默认租户ID 1");
result = 1; // 默认租户ID
}
return result;
}
}

13
fragment.java Normal file
View File

@@ -0,0 +1,13 @@
package com.openhis;
/**
* 示例类 - 引用 OpenHisApplication
*/
public class Fragment {
public static void main(String[] args) {
// 引用 OpenHisApplication
Class<?> applicationClass = com.openhis.OpenHisApplication.class;
System.out.println("Application class: " + applicationClass.getName());
}
}

332
md/前端UI规范文档.md Normal file
View File

@@ -0,0 +1,332 @@
# OpenHIS UI 风格规范文档
## 1. 整体布局
### 1.1 容器结构
```
<div class="app-container [page-name]-container">
<div class="components-container">
<!-- 查询表单 -->
<el-form class="query-form">...</el-form>
<!-- 操作按钮 -->
<el-row class="button-group">...</el-row>
<!-- 数据表格 -->
<el-table border>...</el-table>
<!-- 分页 -->
<div class="pagination-container">...</div>
</div>
</div>
```
### 1.2 样式说明
- `app-container`: 最外层容器,全屏背景
- `components-container`: 白色卡片容器,带阴影
- `query-form`: 查询表单,底部无间距
- `button-group`: 按钮组,间距 8px
- `pagination-container`: 分页容器,顶部间距 16px
## 2. 统一样式规范
### 2.1 颜色规范
```scss
// 主色调
--color-primary: #409EFF;
--color-success: #67C23A;
--color-warning: #E6A23C;
--color-danger: #F56C6C;
--color-info: #909399;
// 文字颜色
--text-regular: #606266; // 常规文字
--text-secondary: #909399; // 次要文字
--text-placeholder: #A8ABB2; // 占位符
```
### 2.2 间距规范
```scss
// 容器内边距
$spacing-xs: 4px;
$spacing-sm: 8px;
$spacing-md: 16px;
$spacing-lg: 20px;
$spacing-xl: 24px;
// 表单项间距
$form-item-margin-bottom: 18px;
```
### 2.3 圆角规范
```scss
$border-radius-sm: 4px; // 小圆角 - 按钮、输入框
$border-radius-md: 8px; // 中圆角 - 卡片、对话框
$border-radius-lg: 12px; // 大圆角 - 特殊组件
```
### 2.4 阴影规范
```scss
// 卡片阴影
$box-shadow-card: 0 2px 8px rgba(0, 0, 0, 0.08);
// 表格阴影
$box-shadow-table: 0 1px 4px rgba(0, 0, 0, 0.05);
// 浮动元素阴影
$box-shadow-float: 0 2px 12px rgba(0, 0, 0, 0.1);
```
### 2.5 字体规范
```scss
$font-size-base: 14px; // 基础字号
$font-size-sm: 12px; // 小字号
$font-size-lg: 16px; // 大字号
$font-size-xl: 18px; // 特大字号
$font-weight-regular: 400; // 常规
$font-weight-medium: 500; // 中等
$font-weight-bold: 600; // 加粗
```
## 3. 组件规范
### 3.1 表单组件
#### 输入框
```vue
<el-input
v-model="value"
placeholder="请输入xxx"
clearable
style="width: 200px"
@keyup.enter="handleQuery"
/>
```
#### 下拉框
```vue
<el-select
v-model="value"
placeholder="请选择xxx"
clearable
style="width: 200px"
>
<el-option
v-for="dict in dictList"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
```
#### 按钮规范
```vue
<!-- 主按钮 -->
<el-button type="primary" icon="IconName">按钮文字</el-button>
<!-- 次要按钮 -->
<el-button type="success">按钮文字</el-button>
<el-button type="warning">按钮文字</el-button>
<el-button type="danger">按钮文字</el-button>
<!-- 次要按钮plain -->
<el-button type="primary" plain icon="IconName">按钮文字</el-button>
<!-- 链接按钮table内 -->
<el-button link type="primary" class="action-button">文字</el-button>
```
### 3.2 表格组件
```vue
<el-table
v-loading="loading"
:data="tableData"
@selection-change="handleSelectionChange"
border
>
<!-- 复选列 -->
<el-table-column type="selection" width="55" align="center" />
<!-- 序号列 -->
<el-table-column label="序号" align="center" prop="id" width="80" />
<!-- 普通列 -->
<el-table-column
label="列名"
align="center"
prop="fieldName"
min-width="200"
:show-overflow-tooltip="true"
/>
<!-- 带标签列 -->
<el-table-column label="状态" align="center" prop="status" width="90">
<template #default="scope">
<dict-tag :options="dictType" :value="scope.row.status" />
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column label="操作" align="center" min-width="280">
<template #default="scope">
<el-button link type="primary" @click="handleEdit(scope.row)" class="action-button">编辑</el-button>
<el-button link type="danger" @click="handleDelete(scope.row)" class="action-button">删除</el-button>
</template>
</el-table-column>
</el-table>
```
### 3.3 对话框组件
```vue
<el-dialog
:title="dialogTitle"
v-model="dialogVisible"
width="800px"
destroy-on-close
>
<el-form :model="form" :rules="rules" label-width="80px">
<!-- 表单内容 -->
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="handleSubmit"> </el-button>
<el-button @click="handleCancel"> </el-button>
</div>
</template>
</el-dialog>
```
## 4. 响应式设计
### 4.1 断点规范
```scss
$screen-xs: 480px;
$screen-sm: 768px;
$screen-md: 992px;
$screen-lg: 1200px;
```
### 4.2 响应式规范
```vue
<!-- 栅格系统 -->
<el-row :gutter="10">
<el-col :span="6" :xs="12" :sm="8">...</el-col>
<el-col :span="18" :xs="12" :sm="16">...</el-col>
</el-row>
<!-- 移动端表单 -->
<el-form :label-width="isMobile ? '80px' : '120px'">
```
## 5. 交互规范
### 5.1 加载状态
```vue
<!-- 表格加载 -->
<el-table v-loading="loading" :data="tableData">
<!-- 按钮加载 -->
<el-button :loading="saving">保存</el-button>
<!-- 全屏加载 -->
<el-button type="primary" :loading="true">提交</el-button>
```
### 5.2 空状态
```vue
<el-empty
description="暂无数据"
:image="emptyImage"
/>
```
### 5.3 确认对话框
```vue
<el-dialog title="确认提示" v-model="confirmVisible">
<p>{{ confirmMessage }}</p>
<template #footer>
<el-button @click="confirmVisible = false"> </el-button>
<el-button type="danger" @click="handleConfirm"> </el-button>
</template>
</el-dialog>
```
## 6. 命名规范
### 6.1 CSS 类名
- 使用 kebab-case短横线命名
- 遵循 BEM 命名规范
- 示例:`notice-container`, `button-group`, `action-button`
### 6.2 变量命名
- Vue使用 camelCase
- 事件处理:以 `handle` 开头
- 数据获取:以 `get`/`load` 开头
- 示例:`handleQuery`, `loadData`, `handleSubmit`
### 6.3 组件命名
- 使用 PascalCase
- 多个单词时使用驼峰命名
- 示例:`NoticePanel`, `TableHeader`, `SearchForm`
## 7. 国际化规范
```vue
<!-- 使用字典标签 -->
<dict-tag :options="dictType" :value="row.status" />
<!-- 使用占位符 -->
<el-input :placeholder="$t('common.placeholder')"/>
```
## 8. 性能优化
### 8.1 图片优化
- 使用 WebP 格式
- 图片懒加载
- 响应式图片
### 8.2 列表优化
- 虚拟滚动(大列表)
- 分页加载
- 骨架屏
### 8.3 缓存策略
- 使用 Vuex/Pinia 缓存用户数据
- 本地存储持久化配置
- 请求去重
## 9. 无障碍规范
### 9.1 语义化标签
```vue
<nav> <!-- 导航 -->
<main> <!-- 主内容 -->
<header> <!-- 头部 -->
<footer> <!-- 底部 -->
```
### 9.2 ARIA 属性
```vue
<el-button aria-label="提交按钮">提交</el-button>
<el-input aria-label="搜索框" />
```
### 9.3 键盘导航
- 支持键盘操作
- Tab 键焦点管理
- 快捷键支持
---
**注意事项:**
1. 所有新增页面必须遵循此规范
2. 修改现有页面时尽量统一样式
3. 保持与系统整体风格一致
4. 优先使用已有的组件和样式
5. 遵循响应式设计原则

View File

@@ -0,0 +1,273 @@
## 门诊手术中临时医嘱生成界面PRD文档
### 一、页面概述
**页面名称**:门诊手术中临时医嘱生成界面
**页面目标**:帮助麻醉医师在手术过程中快速生成临时医嘱,完成药品计费引用、医嘱预览和电子签名确认的全流程操作
**适用场景**:门诊手术过程中需要追加药品医嘱时使用
**页面类型**:表单页+数据展示页
**核心功能**
1. 患者手术信息展示
2. 已引用计费药品列表展示与汇总
3. 临时医嘱预览与编辑功能
4. 医师电子签名确认流程
5. 数据刷新与退出操作
**用户价值**:简化手术中医嘱生成流程,确保医嘱准确性,实现无纸化操作,提高手术室工作效率
原型图地址https://static.pm-ai.cn/prototype/20260122/e1d7f10b85e9efea543bf47bd6831600/index.html
**流程图:**
```mermaid
flowchart TD
Start(["Start"]) --> Enter["进入门诊手术中临时医嘱生成界面"]
Enter --> ShowBase["展示患者基本信息"]
ShowBase --> ShowQuoted["显示已引用计费药品列表"]
ShowQuoted --> ShowPreview["显示医嘱预览表格"]
ShowPreview --> UserOp{用户操作}
UserOp -- "引用计费" --> GetLatest{"获取最新计费药品数据\n获取成功?"}
GetLatest -- "否" --> ErrTip1["显示错误提示"]
GetLatest -- "是" --> UpdateTable["更新药品表格和汇总"]
UserOp -- "编辑" --> PopEdit["弹出医嘱编辑表单"]
PopEdit --> EditVal{"验证通过?"}
EditVal -- "否" --> ErrTip2["返回错误提示"]
EditVal -- "是" --> SaveClick{"点击保存?"}
SaveClick -- "是" --> GenTemp["生成临时药品医嘱"]
SaveClick -- "否" --> UserOp
GenTemp --> UpdatePreview["更新医嘱预览表格"]
UpdatePreview --> UpdateRecord["更新手术记录"]
UpdateRecord --> ShowResult["显示生成结果"]
UserOp -- "一键签名并生成医嘱" --> PopPwd["弹出账户密码输入框"]
PopPwd --> PopConfirm{"弹出确认对话框"}
PopConfirm -- "否" --> UserOp
PopConfirm -- "是" --> GenTemp
UserOp -- "刷新" --> Reload["重新加载界面数据"]
Reload --> ShowQuoted
UserOp -- "退出" --> ExitConfirm{"确认退出?"}
ExitConfirm -- "否" --> UserOp
ExitConfirm -- "是" --> ReturnUp["返回上级页面"]
ErrTip1 --> UserOp
ErrTip2 --> PopEdit
ShowResult --> UserOp
ReturnUp --> End([结束])
```
### 二、整体布局分析
**页面宽度**:自适应布局
**要区域划分**
1. 顶部信息区15%):患者基本信息+操作按钮区
2. 计费药品展示区35%):已引用计费药品表格+金额汇总
3. 医嘱预览区35%):待生成医嘱的预览表格
4. 签名确认区15%):医师签名信息+操作按钮
**布局特点**:上下分块布局,采用卡片式设计,主要区域间有明确分隔线
**响应式要求**768px以下时患者信息改为纵向排列操作按钮换行显示
### 三、页面区域详细描述
#### 1. 顶部信息区
**区域位置**:页面顶部
**区域尺寸**高度180px包含20px内边距
**区域功能**:展示患者基本信息+提供主要操作入口
**包含元素**
- **标题栏**
- 元素类型:标题文本
- 显示内容:“门诊术中临时医嘱”
- 样式特征白色文字1.5rem字号,居中显示,渐变蓝色背景
- **患者信息卡**
- 元素类型:信息展示区块
- 显示内容:患者姓名、就诊卡号、手术单号、科室、医师、角色
- 患者:样例值-张三
- 就诊卡号:样例值-202507010122
- 手术单号:样例值- S202507010135
- 科室: 样例值-手术室(OR101)-取值于手术安排的手术间号字段
- 医师:样例值-李麻(3015)
- 角色:样例值-麻醉医师
- 样式特征半透明白色背景圆角8px内部flex布局
- **操作按钮组**
- **[刷新按钮]**
- 元素类型:主要操作按钮
- 显示内容:↻ 刷新
- 交互行为:点击后重新加载当前界面的数据
- 样式特征:蓝色渐变背景,悬停有上浮效果
- **[引用计费按钮]**
- 元素类型:次要操作按钮
- 显示内容:引用计费
- 交互行为:点击后拉取当前患者最新计费药品的数据
#### 2. 计费药品展示区
**区域位置**:顶部信息区下方
**区域尺寸**高度约420px包含标题和表格
**区域功能**:展示待生成医嘱的计费药品清单
**包含元素**
- **表格标题**
- 显示内容:“一、已引用计费药品(待生成医嘱)”
- 样式特征1.2rem字号,底部边框线
- **药品数据表格**
**取值于门诊术中计费界面生成的药品计费数据adm_charge_item费用项管理、med_medication_request药品请求管理具体与系统实际业务数据为主。**
**(参考)关联字段adm_charge_item. encounter_id = med_medication_request. encounter_id and 就诊ID**
**adm_charge_item. service_table = 'med_medication_request' and --记录药品数据**
**adm_charge_item. bus_no = med_medication_request. bus_no -- adm_charge_item. bus_no的值之前多加了CI**
- 展示方式:斑马纹表格
- 数据字段:
- 序号:数字 - 自动生成
- 药品名称:文本 - 如"罗哌卡因注射液"
- 规格:文本 - 如"10ml"
- 数量:数字 - 可编辑
- 批号:文本 - 如"L240715"
- 单价:数字 - 如"38"
- 小计:数字 - 自动计算
- 医保:标签 - “甲/乙/自费”
- 样式特征:表头浅灰色背景,医保类型有颜色区分(蓝色=医保,绿色=自费)
- **金额汇总栏**
- 显示内容:
- 医保内金额(蓝色强调)
- 自费金额(绿色强调)
- 总计金额(红色强调)
- 位置:表格底部右对齐
#### 3. 医嘱预览区
**区域位置**:计费药品展示区下方
**区域尺寸**高度约420px包含标题和表格
**区域功能**:展示即将生成的药品医嘱
**包含元素**
\*生成门诊药品医嘱表相关的数据,满足**计费药品明细 ↔ 药品医嘱** 一一对应的要求。
可以对照参考:需结合门诊医生站开立药品医嘱时生成的药品医嘱表
- **表格标题**
- 显示内容:“二、临时医嘱预览(已生成)”
- **医嘱表格**
- 展示方式:斑马纹表格
- 数据字段:
- 序号:数字
- 医嘱名称:文本(取已引用计费药品的药品名称)
- 剂量:数字(自动计算=规格×数量)
- 单位:文本(根据药品类型自动判断)
- 用法:下拉选择(不可编辑)
- 频次:固定"临时"
- 执行时间:自动生成当前时间
- 操作:编辑/删除按钮
- 操作功能:
- 编辑:弹出表单修改剂量、用法等字段
- 删除:二次确认后移除该条医嘱
#### 4. 签名确认区
**区域位置**:页面底部
**区域尺寸**高度约180px
**区域功能**:完成医嘱确认和电子签名
**包含元素**
- **签名信息卡**
- 显示内容:医师姓名工号、签名状态、签名时间
- 样式特征:浅灰色背景,圆角边框
- **[一键签名按钮]**
- 元素类型:主要操作按钮
- 显示内容:“一键签名并生成医嘱”
- 交互行为:点击后弹出账户密码输入框
- 样式特征:绿色背景,悬停效果
- **[取消按钮]**
- 元素类型:次要操作按钮
- 显示内容:“取消”
- 交互行为:返回上级页面
### 四、交互功能详细说明
#### 1. 引用计费功能
**功能描述**:从术中计费药品获取患者当前最新的计费药品数据
**触发条件**:点击"引用计费"按钮
**操作流程**
1. 点击按钮获取患者当前最新的计费药品数据
2. 成功返回后更新药品表格数据
3. 自动计算并更新费用汇总
**反馈机制**:成功提示弹窗"已成功引用最新计费药品信息!"
**异常处理**:请求失败时显示错误提示“获取计费数据失败,请重试”,保留原数据
#### 2. 医嘱生成功能
**功能描述**:将计费药品转为正式医嘱
**触发条件**:点击"一键签名并生成医嘱"按钮
**操作流程**
1. 自动生成药品医嘱预览(带默认用法和剂量)
2. 弹出账户密码输入框
3. 验证通过后生成临时药品医嘱数据
4. 成功返回后显示生成结果
**数据转换规则**
- 剂量 = 规格数值 × 数量(如"10ml"×2 → 20ml
- 单位:根据药品名称自动判断(默认获取当前药品在《药品目录》维护剂量单位的值)
- 用法:根据药品名称自动判断(默认获取当前药品在《药品目录》维护用法的值,如果未维护默认空)
- 医嘱名称:取值药品名称
- 频次默认ST
- 执行时间:默认当前系统时间
#### 3. 医嘱编辑功能
**功能描述**:修改已生成的医嘱明细
**触发条件**:点击"编辑"按钮
**操作流程**
1. 弹出编辑表单(带当前值医嘱值)
2. 修改后点击保存更新表格
3. 自动重新计算相关字段得值
**字段限制**
- 剂量:必须为数字
- 用法:限定下拉选项,取值于字典管理:用药途径(用法)的值
- 频次:固定为"ST"不可编辑
### 五、数据结构说明
**关键数据字段**
| **字段名** | **说明** | **数据类型** | **示例值** | **是否必填** | **备注** |
|---------------|----------|--------------|--------------------|--------------|------------------|
| patientId | 患者ID | string | “202507010122” | 是 | 就诊卡号 |
| surgeryNo | 手术单号 | string | “S202507010135” | 是 | |
| medicineName | 药品名称 | string | “罗哌卡因注射液” | 是 | |
| spec | 规格 | string | “10ml” | 是 | 需包含数值和单位 |
| batchNo | 批号 | string | “L240715” | 是 | |
| insuranceType | 医保类型 | string | “乙” | 是 | 甲/乙/自费 |
| usage | 用法 | string | “静脉推注” | 是 | |
| execTime | 执行时间 | datetime | “2025-07-01 08:41” | 是 | 精确到分钟 |
### 六、开发实现要点
**样式规范**
- **主色调**\#4a90e2按钮/标题)
- **辅助色**\#5cb85c成功操作、\#e74c3c警告
- **字体规范**标题1.5rem/正文0.95rem行高1.6
- **间距系统**区块padding20px元素间距15px
- **表格样式**斑马纹行高56px单元格padding15px 20px
**技术要求**
- **浏览器兼容**Chrome/Firefox/Edge最新版
**注意事项**
1. 医嘱生成后需同步更新手术记录
2. 所有金额显示保留两位小数

View File

@@ -0,0 +1,505 @@
## 门诊医生站传染性报卡登记PRD文档
### 一、页面概述
**页面名称**:门诊医生站传染性报卡登记
**页面目标**:帮助医生完成法定传染病病例的电子报告卡填写与提交
**适用场景**:医生确诊或疑似发现法定传染病病例时,进行报卡登记
**页面类型**:表单页(复杂表单)
**核心功能**
1. 患者基本信息录入(含身份验证)
2. 传染病分类选择与疾病诊断信息登记
3. 病例分类与流行病学信息记录
4. 数据校验与表单提交
5. 地址四级联动选择(省-市-区县-街道)
**用户价值**
- 规范传染病报告流程,确保数据完整准确
- 减少手工填写错误,提高上报效率
- 自动关联患者基本信息,减少重复录入
- 内置校验规则防止漏报错报
**原型图地址**:https://static.pm-ai.cn/prototype/20260128/6041dcc237645108aa9e917e8d57705f/index.html
**流程图**:
```mermaid
flowchart TD
A(["开始报卡"]) --> B["填写患者基本信息"]
B --> C{"身份证格式错误"}
C -- 是 --> D["提示请输入有效身份证号码"]
C -- 否 --> E{"患者年龄≤14岁"}
E -- 是 --> F["显示家长姓名输入框"]
E -- 否 --> G["隐藏家长姓名输入框"]
F --> H["填写现住地址"]
G --> H
H --> I{"地址加载失败"}
I -- 是 --> J["显示手动输入选项"]
I -- 否 --> K["选择疾病分类"]
J --> K
K --> L{"选择特定疾病"}
L -- 是 --> M["显示疾病分型选择"]
L -- 否 --> N["跳过分型选择"]
M --> O["填写发病/诊断日期"]
N --> O
O --> P{"日期逻辑错误"}
P -- 是 --> Q["提示发病日期不能晚于诊断日期"]
P -- 否 --> R["填写报告信息"]
Q --> R
R --> S["表单校验"]
S --> T{"校验失败"}
T -- 是 --> U["显示错误提示"]
T -- 否 --> V["保存报卡"]
U --> S
V --> W{"点击重置按钮"}
W -- 是 --> X["保留关键信息重置其他字段"]
X --> S
V --> Y{"点击关闭按钮"}
Y -- 是 --> Z{"确认关闭"}
Z -- 是 --> AA(["结束流程"])
Z -- 否 --> V
```
### 二、整体布局分析
**页面宽度**:自适应布局
**主要区域划分**
1. **顶部标题区**5%):展示表单标题和卡片编号
2. **患者信息区**30%):患者基本信息、联系方式、现住地址等
3. **疾病信息区**50%):疾病分类选择、发病/诊断日期、疾病分型等
4. **报告信息区**10%):报告单位、医生、填卡日期等
**操作按钮区**5%):保存、重置、关闭按钮
**布局特点**:上下布局,采用响应式网格,表单分组清晰,必填项高亮标识
### 三、页面区域详细描述
#### 1. 标题区
**区域位置**:页面顶部
**区域尺寸**高度60px
**区域功能**:展示表单标题和唯一编号标识
**包含元素**
- 表单标题
- - 元素类型:标题文本
- 默认内容:“中华人民共和国传染病报告卡”
- 样式要求20px字号深蓝色(#2c3e50),居中加粗
- 卡片编号
- - 元素类型:输入框
- 默认值:空
- 提示文字:“单位自编,与网络直报一致”
- 交互行为支持手动输入12位编号
- 样式要求12px灰色文字带下划线分隔线
#### 2. 患者基本信息区
**区域位置**:标题区下方
**区域功能**:采集患者核心身份信息、联系方式、居住地等
**包含元素**
- 患者姓名输入框
- - 元素类型:文本输入框,自动引入当前就诊患者信息的姓名
- 校验规则必填项支持中文姓名2-10字
- 家长姓名输入框
- - 元素类型:文本输入框
- 条件显示当系统计算年龄≤14岁时自动显示必填标识
- 身份证号输入框
- - 元素类型:文本输入框,自动引入当前就诊患者信息的身份证号
- 校验规则必填项自动校验18位身份证格式
- 性别选择
- - 元素类型:单选按钮组
- 选项:男/女/未知,自动匹配当前就诊患者信息的性别
- 默认值:必填项
- 出生日期输入
- - 元素类型:复合输入区域
- 包含:年(4位)/月(2位)/日(2位)三个输入框,自动匹配当前就诊患者信息的出生年月
- 联动逻辑:自动计算实足年龄并填充到年龄输入框
- 工作单位输入框
- - 元素类型:文本输入框,自动引入当前就诊患者信息的工作单位
- 特殊场景:学生自动关联学校信息
- 联系电话
- - 元素类型:电话输入框,自动引入当前就诊患者信息的联系方式
- 校验规则必填11位手机号或带区号固话
- 紧急联系人电话
- - 元素类型:电话输入框
- 校验规则必填11位手机号或带区号固话
- 病人属于
- - 复选框类型:通过现地址自动判断
- 校验规则:必填
- 职业
- - 下拉选项类型:取值于字典管理的字典名称为“职业”维护的数据
- 校验规则:必填
#### 3. 现住地址选择区
**区域功能**:四级联动地址选择(省-市-区县-街道)
**交互逻辑**
1. 省份选择后动态加载对应城市
2. 城市选择后动态加载区县
3. 区县选择后动态加载街道
4. 村(居)和门牌号为手动输入
**数据要求**
- 初始默认值:省-市-区县-街道(自动引入当前就诊患者信息的现住址)
- 异常处理:当上级未选择时禁用下级选择
**字典取值跟新增患者的现住址保持一致(患者管理-)患者列表)**
![](media/clip_image001.png)
#### 4. 疾病信息区
**区域功能**:选择传染病类型及相关临床信息
**包含元素**
- **疾病分类选择**
- - 布局方式:网格布局(3列)
- 分类:甲类/乙类/丙类传染病
- 交互行为:多选但同类别互斥
- 特殊处理:选择炭疽/肺结核/病毒性肝炎/疟疾/梅毒/血吸虫病等疾病时激活分型选择
- **疾病复选框互斥逻辑:**
- - 选择炭疽病时显示分型选项(肺炭疽/皮肤炭疽/胃肠炭疽/未分型)
- 选择肺结核时显示分型选项(涂阳/仅培阳/菌阴/未痰检)
- 选择病毒性肝炎时显示分型选项(甲/乙/丙/戊型)
- 选择疟疾时显示分型选项(间日疟/恶性疟/三日疟/卵形疟/未分型)
- 选择梅毒时显示分型选项(Ⅰ期/Ⅱ期/Ⅲ期/胎传/隐性)
- 选择血吸虫病时显示分型选项(急性/慢性/晚期/未分型)
- **分型选择**
- - 元素类型:动态下拉框
- 数据源:根据疾病类型动态加载
- 示例:肺结核→涂阳/仅培阳/菌阴/未痰检
- **其他法定管理以及重点监测传染病输入框:**
- - 手动输入非列表疾病
- 自动关联传染病代码库
- **发病日期**
- - 元素类型:日期选择器
- 验证规则:不得晚于诊断日期
- **诊断日期**
- - 元素类型:日期选择器
- 取值:默认当前系统时间
- **死亡日期**
- - 元素类型:日期选择器
- 填写规则:根据实际情况填写
- **病例分类**
- - 复选框类型: 1疑似病例/2临床诊断病例/3确诊病例/4病原携带/5阳性检测结果
- 校验规则:必填
#### 5. 报告信息区
**区域功能**:记录报告单位和责任人信息等
**包含元素**
- **报告单位**
- - 元素类型:文本输入
- 默认值:当前登录医院
- 交互行为:只读
- **联系电话**
- - 元素类型:文本输入
- 默认值:当前登录医院的联系电话
- 交互行为:可编辑
- **报告医生**
- - 元素类型:文本输入
- 默认值:当前登录医生
- 验证规则:必填
- **填卡日期**
- - 默认当前系统日期,显示为"YYYY-MM-DD"格式
- **修订病名**
- - 元素类型:文本输入
- 默认值:空
- 填写:自定义编辑
- **退卡原因**
- - 元素类型:文本输入
- 默认值:空
- 填写:自定义编辑
- **备注**
- - 元素类型:文本输入
- 默认值:空
- 填写:自定义编辑
#### 6. 操作按钮区
**区域位置**:页面底部
**包含元素**
- **保存按钮**
- - 元素类型:主要操作按钮
- 交互行为:触发表单验证,通过后保存
- 样式特征:蓝色(#3498db)圆角8px
- **重置按钮**
- - 交互行为:清除非基础信息字段
- 特殊处理:保留患者姓名、身份证等关键信息
- **关闭按钮**
- - 交互行为:二次确认后关闭页面
- 样式特征:红色(#e74c3c)
### 四、交互功能详细说明
#### 1. 地址联动选择
**触发条件**:选择省级行政区
**操作流程**
1. 选择省份→加载该省下所有城市
2. 选择城市→加载该市所有区县
3. 选择区县→加载街道列表
**异常处理**:网络错误时显示"加载失败,请手动输入"
#### 2. 疾病分型联动
**触发条件**:选择特定疾病
**数据映射**
| **疾病类型** | **分型选项** |
| ------------ | ---------------------------------- |
| 肺结核 | 涂阳/仅培阳/菌阴/未痰检 |
| 梅毒 | I期/II期/III期/胎传/隐性 |
| 炭疽 | 肺炭疽/皮肤炭疽/胃肠炭疽/未分型 |
| 病毒性肝炎 | 甲/乙/丙/戊型 |
| 疟疾 | 间日疟/恶性疟/三日疟/卵形疟/未分型 |
| 血吸虫病 | 急性/慢性/晚期/未分型 |
#### 3. 表单验证
**全局验证**
1. 提交时检查必填字段
2. 验证身份证号格式
3. 确保至少选择一种疾病
**字段级验证**
- 电话号码11位数字错误提示“请输入有效的联系电话”
- 发病日期≤诊断日期≤填卡日期,错误提示“发病日期不能晚于诊断日期”
- 身份证号18位且符合校验算法错误提示“请输入有效的身份证号码”
### 五、数据结构说明
**传染病报卡表infectious_card**
| **字段** | **类型** | **国标含义** | **来源****/****说明** |
|---------------------| -------------- |-----------------|--------------------------------------|
| card_no | VARCHAR(20) PK | 卡片编号 | 机构代码+年月日+4位流水 |
| visit_id | BIGINT FK | 本次就诊ID | adm_encounter.id |
| diag_id | BIGINT FK | 诊断记录唯一ID | adm_encounter_diagnosis.condition_id |
| pat_id | BIGINT FK | 患者主索引 | adm_patient.id |
| id_type | TINYINT | 证件类型 | |
| id_no | VARCHAR(30) | 证件号码 | 18位校验 |
| pat_name | VARCHAR(50) | 患者姓名 | |
| parent_name | VARCHAR(50) | 家长姓名 | ≤14岁必填 |
| sex | CHAR(1) | 性别 | 1男/2女/0未知 |
| birthday | DATE | 出生日期 | |
| age | INT | 实足年龄 | 函数计算 |
| age_unit | CHAR(1) | 年龄单位 | 岁/月/天-》1岁/2月/3天 |
| workplace | VARCHAR(100) | 工作单位 | 学生填学校 |
| phone | VARCHAR(20) | 联系电话 | 患者本人电话 |
| contact_phone | VARCHAR(20) | 紧急联系人电话 | |
| address_prov | VARCHAR(6) | 现住址省 | GB2260 |
| address_city | VARCHAR(6) | 现住址市 | 同上 |
| address_county | VARCHAR(6) | 现住址县 | 同上 |
| address_town | VARCHAR(9) | 现住址街道 | 同上 |
| address_village | VARCHAR(80) | 现住址村/居委 | |
| address_house | VARCHAR(40) | 现住址门牌号 | |
| patient_belong | TINYINT | 病人属于 | 系统判定1本县区/2本市其他/3本省其他/4外省/5港澳台/6外籍 |
| occupation | VARCHAR(4) | 职业 | GB/T 6565取值于字典管理的字典名称为“职业”维护的数据 |
| disease_code | VARCHAR(8) | 疾病名称 | WS 218-2020,见下表 |
| disease_type | VARCHAR(8) | 分型 | 见下表6类必分型疾病必填 |
| other_disease | VARCHAR(50) | 其他法定管理以及重点监测传染病 | |
| case_class | TINYINT | 病例分类 | 1疑似病例/2临床诊断病例/3确诊病例/4病原携带/5阳性检测结果 |
| onset_date | DATE | 发病日期 | 默认诊断时间,病原携带者填初检日期 |
| diag_date | DATETIME | 诊断日期 | 精确到小时 |
| death_date | DATE | 死亡日期 | 死亡病例必填 |
| correct_name | VARCHAR(50) | 订正病名 | 订正报告必填 |
| withdraw_reason | VARCHAR(100) | 退卡原因 | 退卡时必填 |
| report_org | VARCHAR(18) | 报告单位 | 统一信用代码(医院名称) |
| report_org_phone | VARCHAR(20) | 联系电话 | 报告单位电话:医院总值班/防保科座机 |
| report_doc | VARCHAR(20) | 报告医生 | 医生姓名 |
| report_date | DATE | 填卡日期 | 当天日期 |
| status | TINYINT | 状态 | 0暂存1已提交2已审核3已上报4失败5作废 |
| fail_msg | VARCHAR(500) | 失败原因 | 国家平台返回 |
| xml_content | TEXT | 上报XML | 日志 |
| create_time | DATETIME | 创建时间 | |
| update_time | DATETIME | 更新时间 | |
| card_name_code | TINYINT | 报卡名称代码 | 数值对照(取值于字典管理-》报卡名称代码1-中华人民共和国传染病报告卡 |
| registration source | TINYINT | 登记来源 | 1门诊/2住院 |
| dept_id | TINYINT | 科室ID | 患者当前就诊科室 |
| doctor_id | TINYINT | 医生ID | 患者当前开单医生 |
**甲类传染病2 种)―― 01xxxx**
| **disease_code** | **疾病名称** | **国家平台码** |
| ---------------- | ------------ | -------------- |
| 0101 | 鼠疫 | 甲类 |
| 0102 | 霍乱 | 甲类 |
存值示例:`0101`(鼠疫)、`0102`(霍乱)
**乙类传染病27 种)―― 02xxxx**
| **disease_code** | **疾病名称** | **国家平台码** |
| ---------------- | -------------------- | ------------------ |
| 0201 | 传染性非典型肺炎 | 乙类(按甲类管理) |
| 0202 | 艾滋病 | 乙类 |
| 0203 | 病毒性肝炎 | 乙类 |
| 0204 | 脊髓灰质炎 | 乙类(按甲类管理) |
| 0205 | 人感染高致病性禽流感 | 乙类(按甲类管理) |
| 0206 | 麻疹 | 乙类 |
| 0207 | 流行性出血热 | 乙类 |
| 0208 | 狂犬病 | 乙类 |
| 0209 | 流行性乙型脑炎 | 乙类 |
| 0210 | 登革热 | 乙类 |
| 0211 | 炭疽 | 乙类(按甲类管理) |
| 0212 | 细菌性和阿米巴性痢疾 | 乙类 |
| 0213 | 肺结核 | 乙类 |
| 0214 | 伤寒和副伤寒 | 乙类 |
| 0215 | 流行性脑脊髓膜炎 | 乙类 |
| 0216 | 百日咳 | 乙类 |
| 0217 | 白喉 | 乙类 |
| 0218 | 新生儿破伤风 | 乙类 |
| 0219 | 猩红热 | 乙类 |
| 0220 | 布鲁氏菌病 | 乙类 |
| 0221 | 淋病 | 乙类 |
| 0222 | 梅毒 | 乙类 |
| 0223 | 钩端螺旋体病 | 乙类 |
| 0224 | 血吸虫病 | 乙类 |
| 0225 | 疟疾 | 乙类 |
存值示例:乙肝→`0203`;肺结核→`0213`;梅毒→`0222`
**丙类传染病11 种)―― 03xxxx**
| **disease_code** | **疾病名称** | **国家平台码** |
| ---------------- | ---------------------- | -------------- |
| 0301 | 流行性感冒 | 丙类 |
| 0302 | 流行性腮腺炎 | 丙类 |
| 0303 | 风疹 | 丙类 |
| 0304 | 急性出血性结膜炎 | 丙类 |
| 0305 | 麻风病 | 丙类 |
| 0306 | 流行性和地方性斑疹伤寒 | 丙类 |
| 0307 | 黑热病 | 丙类 |
| 0308 | 包虫病 | 丙类 |
| 0309 | 丝虫病 | 丙类 |
| 0310 | 其它感染性腹泻病 | 丙类 |
| 0311 | 手足口病 | 丙类 |
存值示例:手足口病→`0311`;流感→`0301`
**分型码与名称对照(系统存值用)**
| **大类疾病** | **disease_code** | **分型中文** | **disease_type** **存值** |
| -------------- | ---------------- | ------------ | ------------------------- |
| **病毒性肝炎** | 0203 | 甲型 | 020301 |
| | | 乙型 | 020302 |
| | | 丙型 | 020303 |
| | | 戊型 | 020304 |
| | | 未分型 | 020305 |
| **炭疽** | 0211 | 肺炭疽 | 021101 |
| | | 皮肤炭疽 | 021102 |
| | | 胃肠炭疽 | 021103 |
| | | 未分型 | 021104 |
| **肺结核** | 0213 | 涂阳 | 021301 |
| | | 仅培阳 | 021302 |
| | | 菌阴 | 021303 |
| | | 未痰检 | 021304 |
| **梅毒** | 0222 | Ⅰ期 | 022201 |
| | | Ⅱ期 | 022202 |
| | | Ⅲ期 | 022203 |
| | | 胎传 | 022204 |
| | | 隐性 | 022205 |
| **疟疾** | 0225 | 间日疟 | 022501 |
| | | 恶性疟 | 022502 |
| | | 三日疟 | 022503 |
| | | 卵形疟 | 022504 |
| | | 未分型 | 022505 |
| **血吸虫病** | 0224 | 急性 | 022401 |
| | | 慢性 | 022402 |
| | | 晚期 | 022403 |
| | | 未分型 | 022404 |
### 六、开发实现要点
**样式规范**
- 主色调:#3498db(按钮/重要标签)
- 错误状态:#e74c3c(边框+文字)
- 表单间距8px垂直间距16px水平间距
**技术要求**
- 支持Chrome/Firefox/Edge最新版
**注意事项**
1. 身份证号不需脱敏显示

View File

@@ -0,0 +1,287 @@
## 手术室维护界面PRD文档
### 一、页面概述
**页面名称**:手术室维护界面
**页面目标**:提供手术室基础数据的维护功能,包括新增、编辑、启用/停用手术室信息,为手术安排提供基础数据支持
**适用场景**:医院管理员需要新增、修改、启用/停用手术室信息时使用
**页面类型**:列表页+表单页(含模态框)
**原型图地址:**https://static.pm-ai.cn/prototype/20260104/ee5d222231effefcb39624d1646a2e20/index.html
**核心功能**
1. 手术室列表展示与查询
2. 新增手术室信息
3. 编辑现有手术室信息
4. 启用/停用手术室状态
5. 数据有效性校验
**用户价值**
- 管理员可集中管理所有手术室基础信息
- 确保手术安排时能获取准确的手术室数据
- 通过状态管理控制手术室可用性
**流程图:**
![](media/6a369a41c55f8727aa574bf43fa7500b.png)
```mermaid
flowchart TD
A[手术室维护界面] --> B[手术室列表展示]
B --> C[新增手术室]
B --> D[编辑手术室]
B --> E[启用/停用手术室]
B --> F[查询手术室]
C --> G[点击新增按钮]
G --> H[打开新增模态框]
H --> I[填写表单字段]
I --> J{必填字段校验}
J -->|通过| K[提交数据]
J -->|不通过| L[提示请填写所有必填项]
K --> M[表格新增数据行]
D --> N[点击修改按钮]
N --> O[打开编辑模态框]
O --> P[修改表单字段]
P --> Q{必填字段校验}
Q -->|通过| R[保存数据]
Q -->|不通过| S[提示请填写所有必填项]
R --> T[更新表格对应行]
E --> U[点击启用/停用按钮]
U --> V{二次确认}
V -->|确认| W[切换状态标签]
V -->|取消| X[取消操作]
W --> Y[更新按钮状态]
F --> Z[输入查询条件]
Z --> AA[筛选表格数据]
K --> AB{房间号重复校验}
AB -->|不重复| AC[提示房间号已存在]
AB -->|重复| AD[更新按钮状态]
```
### 二、整体布局分析
**页面宽度**:自适应布局
**主要区域划分**
1. 页头区域15%高度)
2. 表格展示区85%高度)
**布局特点**:上下布局,表格采用固定表头+滚动内容区设计
**响应式要求**:移动端适配时改为纵向堆叠布局,操作按钮组变为纵向排列
### 三、页面区域详细描述
#### 1. 页头区域
**区域位置**:页面顶部
**区域尺寸**高度60px宽度100%
**区域功能**:展示标题和主要操作入口
**包含元素**
- **标题文本**
- 元素类型H1标题
- 显示内容:"手术室列表"
- 样式特征1.75rem/600字重深灰色(#333)
- **新增按钮**
- 元素类型:主要操作按钮
- 显示内容:"新增"(带+图标)
- 交互行为:点击触发新增模态框
- 样式特征:蓝色背景(#5a7cff)白色文字8px圆角悬停上浮1px
#### 2. 表格展示区(手术室列表表格)
**区域位置**:页头下方
**区域尺寸**高度自适应宽度100%
**区域功能**:展示手术室数据并支持行级操作
**包含元素**
- **数据表格**
- 展示方式:固定表头表格
- 数据字段:
- 房间号:文本 - OR01 - 不可操作
- 手术室名称:文本 - 第一手术室 - 不可操作
- 类型:文本 - 普通/日间/复合 - 不可操作
- 所属科室:文本 - 外科 - 不可操作
- 状态:标签 - 有效/无效 - 通过操作按钮切换
- 操作功能:每行包含"修改"和"状态切换(停用-黄色/启用-绿色)"按钮
- **表格样式**
- 表头:浅灰色背景(#f8f9fa)大写字母14px字号
- 行悬停:浅灰色背景(#f8f9fa)
- 状态标签:
- 有效:绿色背景+文字(#28a745)
- 无效:灰色背景+文字(#6c757d)
#### 3. 新增手术室弹窗
**区域位置**:页面居中模态弹窗
**区域功能**:收集新增手术室所需信息
**包含元素**
- 表单字段:
1. 房间号输入框
2. 类型:文本输入
3. 必填:是
4. 示例值OR04
5. 校验规则:非空校验
6. 手术室名称输入框
- 类型:文本输入
- 必填:是
- 示例值:第四手术室
1. 手术室类型下拉框
- 类型:单选下拉
- 选项:普通/日间/复合/特殊
- 默认值:普通
1. 所属科室下拉框
- 类型:单选下拉
- 必填:是
- 选项:外科/妇产科等8个科室
- 默认提示:"请选择科室"
- 操作按钮:
- 取消按钮(灰色边框)
- 确认按钮(蓝色填充)
- 校验逻辑:必填字段非空校验
- 成功反馈:提示"手术室添加成功"
- 失败反馈:提示"请填写所有必填项"
#### 4. 编辑手术室弹窗
**区域位置**:页面居中模态弹窗
**区域功能**:修改现有手术室信息
**包含元素**
- 表单字段(同新增弹窗,带初始值)
- 操作按钮:
- 取消按钮
- 保存按钮
- 校验逻辑:同新增弹窗
- 成功反馈:提示"手术室信息已更新"
### 四、交互功能详细说明
#### 1. 新增手术室
**功能描述**:添加新的手术室记录
**触发条件**:点击页头"新增"按钮
**操作流程**
1. 打开新增模态框
2. 填写必填字段(房间号、名称、科室)
3. 点击确认提交插入his_or_room表
4. 表格末尾新增数据行
**异常处理**
- 必填项为空时弹出"请填写所有必填项"提示
- 房间号重复需在后端校验并提示
#### 2. 编辑手术室
**功能描述**:修改现有手术室信息
**触发条件**:点击行内"修改"按钮
**操作流程**
1. 打开编辑模态框(自动填充当前行数据)
2. 用户修改数据
3. 点击"保存"时校验并更新对应行数据
**状态保持**:记录当前编辑行索引确保数据更新准确
#### 3. 状态切换
**功能描述**:启用/停用手术室
**触发条件**:点击"停用"或"启用"按钮
**操作流程**
1. 弹出二次确认对话框
2. 用户确认后切换状态标签
3. 按钮变为相反操作(停用↔启用)
4. 、停用手术室
- **步骤**
1. 查询需要停用的手术室记录。
2. 将 valid_flag 设置为 0无效
- **示例**
UPDATE his_or_room
SET valid_flag = '0'
WHERE room_code = 'OR06';
5\. 启用手术室
**步骤**
1. 查询需要启用的手术室记录。
1. 将 valid_flag 设置为 1有效
- **示例**
UPDATE his_or_room
SET valid_flag = '1'
WHERE room_code = 'OR06';
**防误操作**:所有状态变更需二次确认
### 五、数据结构说明HIS_OR_ROOM手术室字典表
| **字段名称** | **数据类型** | **是否为空** | **说明/典型值** | **外键/来源** |
|--------------|--------------|--------------|-----------------|-------------------------------|
| room_id | VARCHAR(10) | N | 主键 | 自增主键 |
| room_code | VARCHAR(10) | N | 手术室房间号 | 自定义编码,如 OR01、OR02 |
| room_name | VARCHAR(100) | N | 手术室名称 | 如 "第一手术室"、"第二手术室" |
| room_type | VARCHAR(10) | N | 手术室类型 | 普通、日间、复合 |
| dept_code | VARCHAR(10) | N | 所属科室 | FK → 科室管理的科室代码 |
| valid_flag | CHAR(1) | N | 是否有效 | 1有效0无效 |
| created_time | DATETIME | N | 创建时间 | 默认当前时间 |
| updated_time | DATETIME | N | 更新时间 | 默认当前时间,自动更新 |
### 六、开发实现要点
**样式规范**
- 主色调:#5a7cff(按钮/交互元素)
- 辅助色:#7b8a8b(次要文本)
- 字体:
- 标题1.75rem/600字重
- 正文0.875rem/400字重
- 间距系统:
- 卡片内边距24px
- 表单字段间距16px
**技术要求**
**注意事项**
1. 数据安全:
- 所有变更操作需记录操作日志
- 停用状态的手术室需在前端标记不可预约
2. 性能优化:
- 表格数据分页加载
- 模态框使用懒加载

View File

@@ -0,0 +1,387 @@
## 门诊医生站开立会诊申请单界面PRD文档
### 一、页面概述
**页面名称**:门诊医生站开立会诊申请单界面**页面目标**:帮助门诊医生完成会诊申请单的创建、编辑、提交和作废操作,实现多科室会诊流程的电子化管理**适用场景**
1. 门诊医生需要邀请其他科室专家进行会诊时
2. 会诊申请单需要修改或补充信息时
3. 会诊流程需要跟踪管理时
**页面类型**:表单页+列表页复合型界面
**核心功能**
1. 会诊申请单的新增、保存、提交、作废功能
2. 会诊科室/专家可视化选择
3. 申请单数据表格展示与交互
4. 表单数据自动填充与校验
5. 申请单打印输出
**用户价值**
- 规范会诊申请流程,减少纸质单据使用
- 通过智能填充减少医生重复录入
- 实时查看会诊申请状态(新开/已提交/已确认/已签名/已完成/已取消)
原型图地址https://static.pm-ai.cn/prototype/20260115/4eb1bd5367f9d5610b32c0ecc6c793f5/index.html
流程图:
```mermaid
flowchart TD
%% ---------- 开始 ----------
START(["开始"]) --> A["医生进入会诊申请单界面"]
%% ---------- 操作选择 ----------
A --> B{"操作选择"}
B -->|"打印"| C["选择已有申请单"]
B -->|"提交/取消提交"| D{"校验状态为“已提交”?"}
B -->|"删除"| E["弹出确认对话框"]
B -->|"结束"| F{"校验状态为“已提交”?"}
B -->|"编辑"| G["修改表单内容"]
B -->|"新增"| H["清空表单(保留患者信息)"]
%% ---------- 打印分支 ----------
C --> I["高亮选中行"]
I --> J["生成打印视图"]
J --> K["输出打印样式"]
K --> L(["取消"])
%% ---------- 提交/取消提交分支 ----------
D -->|"不通过"| M["提示“请完善必填信息”"]
D -->|"通过"| N["更新状态为“已提交/新开”"]
%% ---------- 删除分支 ----------
E --> O{"确认?"}
O -->|"是"| P["标记状态为“已取消”"]
O -->|"否"| L
%% ---------- 结束分支 ----------
F -->|"不通过"| Q["提示“请先提交申请”"]
F -->|"通过"| R["标记状态为“已完成”"]
%% ---------- 编辑分支 ----------
G --> S{"校验必填字段"}
S -->|"不通过"| M
S -->|"通过"| T["保存到表格"]
%% ---------- 新增/保存通用路径 ----------
H --> U["填写表单"]
U --> V["选择会诊科室/专家"]
V --> W["自动填充邀请对象"]
W --> X["填写病史及目的"]
X --> Y["点击保存"]
Y --> Z{"校验必填字段"}
Z -->|"不通过"| M
Z -->|"通过"| AA["生成会诊申请记录"]
AA --> AB["保存到表格"]
AB --> AC["新增/更新记录"]
%% ---------- 循环 ----------
AC --> A
N --> A
P --> A
R --> A
T --> A
M --> A
Q --> A
L --> A
```
### 二、整体布局分析
**页面宽度**自适应宽度主内容区采用7:3比例分割
**主要区域划分**
1. 顶部操作栏48px固定高度
2. 会诊申请单列表区(高度自适应)
3. 主内容区分左右结构7:3比例
- 左侧:会诊申请单表单区
- 右侧:会诊科室/专家选择区
**布局特点**:响应式上下+左右混合布局,主要对齐方式为左对齐
### 三、页面区域详细描述
#### 1. 顶部操作栏区域
**区域位置**:页面顶部固定位置**区域尺寸**高度48px宽度100%**区域功能**:提供全局操作功能入口**包含元素**
- **打印按钮**
- 元素类型:操作按钮
- 显示内容:“打印”
- 交互行为点击后生成A4打印视图自动适配医院抬头格式
- 样式特征:绿色背景(\#13C2C2)圆角4px32px高度
- **新增按钮**
- 元素类型:操作按钮
- 显示内容:“新增”
- 交互行为:点击清空表单(保留当前患者基本信息)
- 样式特征:蓝色背景(\#1890FF)
- **结束按钮**
- 元素类型:危险操作按钮
- 显示内容:“结束”
- 交互行为:点击结束已提交的会诊流程,标记申请单状态为"已结束",禁用后续操作
- 样式特征:红色背景(\#FF4D4F)
- 限制条件:需先选中已提交的会诊单
- **保存按钮**
- 元素类型:主要操作按钮
- 显示内容:“保存”
- 交互行为:点击保存当前表单数据,校验必填字段后保存至表格,自动生成时间戳
- 样式特征:绿色背景(\#52C41A)
#### 2. 会诊申请单列表区
**区域位置**:顶部操作栏下方**区域尺寸**高度自适应宽度100%**区域功能**:展示当前医生的会诊申请记录**包含元素**
- **申请单表格**
- 展示方式:带边框表格
- 数据字段:
- 序号:文本 - 自增序号 - 不可操作
- 急:布尔 - ✓表示紧急 - 不可操作
- 申请单号:文本 - CS20260105001 - 不可操作
- 会诊时间:日期 - 2026-01-05 15:08 - 不可操作
- 邀请对象:文本 - 吴院长 - 不可操作
- 申请科室:文本 - 内科 - 不可操作
- 申请医师:文本 - 张医生 - 不可操作
- 申请时间:日期 - 2026-01-05 15:08 - 不可操作
- 提交状态:布尔 - 复选框 - 仅查看
- 结束状态:布尔 - 复选框 - 仅查看
- 操作功能:
- - o 提交/取消提交按钮
```
样式要求:蓝色小按钮,禁用状态显示灰色
```
```
交互行为:切换提交状态,需二次确认
```
```
o 删除图标
```
```
样式要求红色垃圾桶图标hover时放大10%
```
```
交互行为:弹出确认对话框后作废该记录
```
[删除]**将状态改为“已取消”****
UPDATE ConsultationRequest
SET ConsultationStatus = 50,cancelnatureDate = <作废会诊时间>
WHERE ConsultationID = <会诊申请单ID> and ConsultationStatus <> 40 ;
- 交互特性:
- 行点击选中效果(蓝色高亮+左侧边框)
- 行hover浅灰色背景
- 提交按钮状态联动(切换提交状态,需二次确认)
#### 3. 会诊申请单表单区
**区域位置**:主内容区左侧**区域尺寸**占主内容区70%宽度**区域功能**:会诊申请单的详细表单填写**包含元素**
- **基础信息区**
- 申请单号只读文本【保存】时自动生成规则CS+年月日时分秒+4位随机数
- 申请时间:只读文本,自动获取系统当前时间
- 病人信息:病人姓名/性别/年龄/就诊卡号/申请医师/申请科室(不可编辑),自动获取当前患者档案信息。
- **会诊信息区**
- 会诊时间:时间控件可编辑
- 紧急标识:复选框控件
- 申请医师:默认当前登录医生
- 申请科室:默认当前医生登录的开单科室
- 门诊诊断:自动获取医生开立的门诊诊断(主诊断)
- **病史及目的**
- 多行文本域最小高度100px
- **会诊邀请**
- 会诊邀请对象:支持多选(逗号分隔)-》(可从右侧会诊邀请对象选择)
- **会诊记录区**
- 会诊意见:只读文本域
- 会诊确认参加医师:只读字段
- 所属医生、代表科室、签名医生、签名时间:只读字段
#### 4. 会诊邀请对象选择区(侧边栏)
**区域位置**:主内容区右侧**区域尺寸**占主内容区30%宽度**区域功能**:快速选择会诊科室和专家**包含元素**
- **会诊科室列表**
- 展示方式:带边框可滚动列表
- 交互行为:选择科室后动态加载对应专家
- **会诊专家列表**
- 展示方式:带边框可滚动列表
- 交互行为:点击专家自动填入会诊邀请对象字段(防重复:已选专家提示"请勿重复选择"
- 特殊逻辑:支持多选(自动用逗号分隔)
### 四、交互功能详细说明
#### 1. 会诊申请单提交流程
**功能描述**:完成会诊申请单的提交操作**触发条件**:点击表格行的"提交"按钮**操作流程**
1. 医生点击行内"提交"按钮
2. 系统校验必填字段(会诊时间、邀请对象)
3. 提交状态复选框变为已勾选
4. 按钮文字变为"取消提交"
5. 禁用该行编辑功能
【提交】**将状态从“新开”改为“已提交”**
UPDATE ConsultationRequest
SET ConsultationStatus = 10,ConfirmingPhysician = <提交会诊医生姓名> ,ConfirmingPhysicianID = <提交会诊医生ID> ,ConfirmingDate = <提交会诊时间>
WHERE ConsultationID = <会诊申请单ID> and ConsultationStatus = 0 ;
【取消提交】**将状态从“已提交”改为“新开”**
UPDATE ConsultationRequest
SET ConsultationStatus = 0,ConfirmingPhysician = '',ConfirmingPhysicianID = '',ConfirmingDate = ''
WHERE ConsultationID = <会诊申请单ID> and ConsultationStatus = 10 ;
**异常处理**
- 必填字段缺失:弹出"请完善会诊时间和邀请对象信息"
- 重复提交:提示"该申请已提交,请勿重复操作"
#### 2. 会诊流程结束功能
**功能描述**:标记会诊流程已结束**触发条件**:选中已提交的申请单后点击顶部"结束"按钮**操作流程**
1. 医生选中已提交的申请单(行高亮)
2. 点击顶部"结束"按钮
3. 系统校验提交状态为已提交
4. 结束状态复选框变为已勾选
5. 禁用该行的取消提交功能
【结束】**将状态从“已签名”改为“已完成”**
UPDATE ConsultationRequest
SET ConsultationStatus = 40,Signature = <结束会诊医生姓名> ,SignatureDate=<结束会诊时间>
WHERE ConsultationID = <会诊申请单ID> and ConsultationStatus = 30 ;
**异常处理**
- 未选中记录:提示"请先选择要结束的会诊申请"
- 未提交记录:提示"请先提交该会诊申请"
#### 3. 申请单保存功能
**功能描述**:保存会诊申请单数据**触发条件**:点击顶部"保存"按钮**操作流程**
1. 系统自动生成申请单号(如为空)
2. 保存当前表单所有字段值
3. 新增记录插入表格末尾
4. 已有记录更新对应行数据
【保存】
①、写入门诊医嘱表(医嘱状态为新开,医嘱名称为"门诊会诊"
②、写入门诊会诊申请单表ConsultationRequest
**数据校验**
- 必填字段:病人姓名、会诊时间、申请科室、会诊时间、会诊邀请对象、简要病史及会诊目的
- 未选会诊对象:提示"请至少选择1位会诊专家"
- 过期时间:提示"会诊时间不能早于当前时间"
#### 4. 会诊邀请对象选择联动
**触发方式**:点击科室列表项
**数据联动**
1. 根据选中会诊科室过滤会诊专家列表
2. 记忆已选专家(跨科室切换时不丢失)
**技术要点**
- 使用对象存储会诊科室-会诊专家映射关系
- 采用事件委托处理动态生成的列表项
### 五、数据结构说明
门诊会诊申请单表ConsultationRequest
| **字段名称** | **数据类型** | **长度** | **描述** | **取值范围** |
|-----------------------------| ------------ | -------- |----------------| --------------------------------------------------------- |
| **PatientID** | Text | 20 | 患者唯一标识 | 患者就诊卡号 (取值患者档案) |
| **ConsultationID** | Text | 20 | 会诊申请单唯一标识 | 系统自动生成的唯一编号生成规则CS+年月日时分秒+4位随机数 |
| **VisitID** | BIGINT | 20 | 门诊就诊流水号(逻辑外键) | 取值于本次门诊就诊记录表的主键 |
| **OrderID** | BIGINT | 20 | 门诊医嘱表主键(一对一外键) | 门诊医嘱表 |
| **PatientName** | Text | 50 | 患者姓名 | 患者的姓名 (取值患者档案) |
| **Gender** | Text | 10 | 患者性别 | 男/女/其他 (取值患者档案) |
| **Age** | Integer | - | 患者年龄 | 取值患者档案 |
| **Department** | Text | 50 | 申请会诊的科室 | 当前科室名称 |
| **RequestingPhysician** | Text | 50 | 申请会诊的医生 | 当前医生姓名 |
| **ConsultationrequestDate** | DateTime | - | 会诊申请时间 | YYYY-MM-DD HH:MM:SS
| **ConsultationPurpose** | Text | 255 | 简要病史及会诊目的 | 文本描述,自定义编辑 |
| **ProvisionalDiagnosis** | Text | 255 | 门诊诊断 | 文本描述,自动获取医生开立的门诊诊断(主诊断) |
| **ConsultationDate** | DateTime | - | 会诊时间 | YYYY-MM-DD HH:MM:SS |
| **ConsultationStatus** | Text | 20 | 会诊状态 | 新开/已提交/已确认/已签名/已完成/已取消 |
| **ConsultationUrgency** | Text | 20 | 是否紧急 | 勾选框:一般/紧急 |
| **ConsultationOpinion** | Text | 255 | 会诊意见 | 文本描述 |
| **ConfirmingPhysician** | Text | 50 | 提交会诊的医生 | 医生姓名 |
| **ConfirmingPhysicianID** | Text | 20 | 提交会诊的医生ID | 医生唯一标识 |
| **ConfirmingDate** | DateTime | - | 提交会诊日期 | YYYY-MM-DD HH:MM:SS |
| **Signature** | Text | 50 | 结束会诊医生 | 医生姓名 |
| **SignatureDate** | DateTime | - | 结束会诊日期 | YYYY-MM-DD HH:MM:SS |
| **cancelnatureDate** | DateTime | - | 作废会诊日期 | YYYY-MM-DD HH:MM:SS |
| InvitedObject | Text | 50 | 会诊邀请对象 | |
**诊状态用于记录会诊申请在不同阶段的状态,以下是常见的会诊状态及其说明:**
| **状态名称** | **状态值** | **描述** |
| ------------ | ---------- | ---------------------------------------------------------------------- |
| **新开** | 0 | 会诊申请单已保存 |
| **已提交** | 10 | 会诊申请已提交,但尚未被会诊医生确认。 |
| **已确认** | 20 | 会诊医生已确认会诊申请,并准备进行会诊。 |
| **已签名** | 30 | 会诊完成后进行签名 |
| **已完成** | 40 | 会诊已经完成,会诊意见已记录。 |
| **已取消** | 50 | 会诊申请被取消,可能由于患者情况变化或其他原因,申请医生进行作废操作。 |
**门诊医嘱表在相关会诊操作步骤的相关事务**
把“门诊会诊申请”当成**一种特殊医嘱**OrderType = 'Consult')由系统**在同一事务内**自动插入 门诊医嘱表,再挂到 `ConsultationRequest` **注意:按照现有系统的门诊医嘱表进行设置相关字段的值**
| **节点** | **是否自动** | **说明** |
| --------------------- | ------------ | --------------------------------------------------------------------------------------------------- |
| 医生点击【保存】 | ✅ | 后台事务:先插门诊医嘱表(医嘱状态为“新开”),再插`ConsultationRequest`.Status=0 |
| 医生点击【提交】 | ✅ | 仅更新两表状态 → 门诊医嘱表的医嘱状态和`ConsultationRequest.Status=10` (已提交),不重复生成医嘱 |
| 医生点击【作废/删除】 | ✅ | 自动将门诊医嘱表的医嘱状态字段置为“作废”,级联`ConsultationRequest.Status=50` |
| 医生点击【结束】 | ✅ | 将 门诊医嘱表的医嘱状态字段置为“已完成”,同时写`ConsultationRequest.Status=40` |
### 六、开发实现要点
**样式规范**
- **主色调**\#1890FF操作按钮
- **辅助色**\#13C2C2打印、\#52C41A保存、\#FF4D4F结束
- **字体规范**14px/1.5,中文字体优先使用"PingFang SC"
- **间距系统**16px基准表单行间距12px
- **组件样式**
- 按钮4px圆角32px高度
- 输入框4px圆角1px \#D9D9D9边框
- 表格行:选中状态\#E6F7FF背景+左侧3px蓝色边框
**技术要求**
- **浏览器兼容**支持Chrome/Firefox/Edge最新版
- **性能要求**:表单提交响应时间\<1秒
**注意事项**
1. 时间字段需统一处理为YYYY-MM-DD HH:mm:ss格式
2. 申请单号生成需加锁防止重复
3. 移动端需优化表格横向滚动体验
4. 打印功能需特殊样式处理(隐藏操作按钮)

View File

@@ -0,0 +1,310 @@
## 门诊医生站会诊申请确认界面PRD文档
### 一、页面概述
**页面名称**:门诊医生站会诊申请确认界面
**页面目标**:帮助医生完成会诊申请的确认、签名和打印操作,展示会诊申请详细信息
**适用场景**:医生在收到会诊申请后,查看申请信息并给出会诊意见
**页面类型**:表单页+列表页复合型页面
**核心功能**
1. 会诊申请单列表展示与选择
2. 会诊确认与取消确认功能
3. 签名功能
4. 会诊记录单打印
5. 会诊意见编辑与保存
**用户价值**
- 规范会诊申请流程
- 电子化确认和签名提高效率
- 完整记录会诊意见便于后续诊疗
- 打印功能满足纸质存档需求
**原型图地址:**https://static.pm-ai.cn/prototype/20260115/7c45e175239257e0f04c9081bf2ca204/index.html
**流程图:**
```mermaid
flowchart TD
Start(["医生进入会诊申请确认界面"]) --> LoadList["加载会诊申请列表"]
LoadList --> HasUntreated{"是否有未处理申请?"}
HasUntreated -- "否" --> ShowNoTip["显示无申请提示"]
HasUntreated -- "是" --> SelectApp["医生选择会诊申请"]
SelectApp --> ShowDetail["显示会诊申请详情"]
ShowDetail --> EditOpinion["医生编辑会诊意见"]
EditOpinion --> ConfirmClick{"点击确认按钮?"}
ConfirmClick -- "否" --> SignClick{"点击签名按钮?"}
ConfirmClick -- "是" --> ValidateConfirm{"校验必填字段"}
ValidateConfirm -- "不通过" --> TipFill["提示\n请先填写会诊意见"]
ValidateConfirm -- "通过" --> CheckConfirmed{"是否已确认?"}
CheckConfirmed -- "是" --> UpdateConfirmed["更新状态为\n已确认"]
UpdateConfirmed --> AutoFill["自动填充医生科室信息"]
AutoFill --> DisableCancel["禁用取消确认功能"]
CheckConfirmed -- "否" --> KeepState["保持当前状态"]
SignClick -- "否" --> PrintClick{"点击打印按钮?"}
SignClick -- "是" --> ValidateSign{"校验通过?"}
ValidateSign -- "不通过" --> TipConfirmFirst["提示\n请先确认会诊申请"]
ValidateSign -- "通过" --> UpdateSigned["更新状态为\n已签名"]
UpdateSigned --> RecordSign["记录签名医生和时间"]
PrintClick -- "否" --> RefreshClick{"点击刷新按钮?"}
PrintClick -- "是" --> GenPrintView["生成打印优化视图"]
GenPrintView --> BrowserPrint["调用浏览器打印功能"]
RefreshClick -- "是" --> LoadList
RefreshClick -- "否" --> KeepState
TipFill --> EditOpinion
TipConfirmFirst --> EditOpinion
KeepState --> End(["结束"])
BrowserPrint --> End
DisableCancel --> End
```
### 二、整体布局分析
**页面宽度**:自适应布局
**主要区域划分**
1. 顶部标签导航高度48px
2. 操作按钮区高度36px+间距)
3. 会诊申请列表区(高度自适应)
4. 会诊记录单表单区(高度自适应)
**布局特点**:上下布局,采用网格系统对齐,左侧对齐为主
### 三、页面区域详细描述
#### 1. 顶部标签导航区域
**区域位置**:页面顶部
**区域尺寸**高度48px宽度100%
**区域功能**:页面导航标识
**包含元素**
- **会诊确认标签**
- 元素类型:文本标签
- 显示内容:“会诊确认”
- 交互行为:无点击交互(当前页面)
- 样式特征蓝色下划线16px字体700字重
#### 2. 操作按钮区域
**区域位置**:标签导航下方
**区域尺寸**高度36px宽度100%
**区域功能**:提供页面主要操作入口
**包含元素**
- **打印按钮**
- 元素类型:操作按钮
- 显示内容:“打印”
- 交互行为:点击触发打印会诊记录单
- 样式特征绿色背景白色文字圆角6px
- **刷新按钮**
- 元素类型:操作按钮
- 显示内容:“刷新”
- 交互行为:点击重新加载页面数据
- 样式特征:白色背景,灰色边框,黑色文字
- **确认按钮**
- 元素类型:状态切换按钮
- 显示内容:“确认”/“取消确认”
- 交互行为:
- 点击后变为"取消确认"状态(红色样式)
- 已签名时禁用取消操作
- 样式特征:蓝色背景,白色文字
- 限制条件:需选中表格行才可操作
- **签名按钮**
- 元素类型:操作按钮
- 显示内容:“签名”
- 交互行为:
- 需先确认才能签名
- 签名后自动记录签名时间和签名医生
- 样式特征:蓝色背景,白色文字
- 限制条件:需先完成确认操作
#### 3. 会诊申请列表区域
**区域位置**:按钮区域下方
**区域尺寸**高度自适应宽度100%
**区域功能**:展示待处理的会诊申请列表
**包含元素**
- **申请列表表格** 取值于门诊会诊申请单表ConsultationRequest
- 检索要求:医生登录门诊医生站打开会诊申请确认界面时只能检索出当前登录医生姓名包含在会诊邀请对象内(只能查看自己受会诊邀请对象)
- 展示方式:带斑马纹表格
- 表头字段:
- 序号 \| 紧急 \| 申请单号 \| 病人姓名 \| 会诊时间 \| 邀请对象 \| 申请科室 \| 申请医师 \| 申请时间 \| 确认 \| 签名
- 数据字段:
- 序号:文本 - 自动编号 - “1” - 不可操作
- 紧急:复选框 - 布尔值 - 未勾选 - 可操作
- 申请单号:文本 - 字符串 - “CS20250812001” - 不可操作
- 病人姓名:文本 - 字符串 - “陈明” - 不可操作
- 会诊时间:日期 - 日期时间 - “2025-08-12 17:48” - 不可操作
- 邀请对象:文本 - 字符串 - “演示测试” - 不可操作
- 申请科室:文本 - 字符串 - “内科” - 不可操作
- 申请医师:文本 - 字符串 - “徐斌” - 不可操作
- 申请时间:日期 - 日期时间 - “2025-08-12 17:48” - 不可操作
- 确认:复选框 - 布尔值 - 勾选框 不可操作
- 签名:复选框 - 布尔值 - 勾选框 不可操作
- 操作功能:点击行选中查看会诊申请详情
- 样式特征:斑马纹交替背景,悬停高亮
#### 4. 会诊记录单表单区域
**区域位置**:列表区域下方
**区域尺寸**高度自适应宽度100%
**区域功能**:展示和编辑会诊详细信息
**包含元素**
- **基础信息区**
- 布局方式8列网格
- 包含字段:
- 病人姓名/性别/年龄/就诊卡号
- 申请单号/申请科室
- 会诊时间/紧急标志
- 会诊邀请对象
- 提交医生/提交时间
- **病史及目的区**
- 元素类型:文本区域
- 显示内容:患者主诉和会诊目的
- 交互行为:只读展示
- **会诊确认参加医师**
- **会诊意见区**
- 元素类型:可编辑文本域
- 显示内容:会诊意见文本
- 交互行为:支持多行编辑
- 样式特征浅灰色背景120px最小高度
- **确认/签名信息区**
- 包含字段:
- 所属医生/代表科室(确认后自动填充当前医生和科室)
- 签名医生/签名时间(自动填充签名医生和签名时间(系统当前时间))
### 四、交互功能详细说明
#### 1. 会诊申请选择功能
**触发方式**:点击表格行
**执行流程**
1. 高亮选中行(浅蓝色背景)
2. 同步该行数据到下方表单
3. 根据确认状态更新按钮文字
4. 加载存储的会诊意见到文本域
**异常处理**
- 无选中行时禁用确认/签名按钮
- 已签名行禁止取消确认
#### 2. 会诊确认功能
**触发方式**:点击确认按钮
**执行流程**
1. 校验必填字段(会诊意见、会诊确认参加医师)
2. 保存会诊意见等相关内容到行数据写入门诊会诊申请确认表ConsultationConfirmation
3. 勾选确认复选框
4. 更新按钮为"取消确认"状态
5. 所属医生和代表科室(自动填充当前医生和科室)
**异常处理**
- 未填写会诊意见时提示"请先填写会诊意见"
- 保存失败时保持原状态并提示错误
#### 2. 电子签名功能
**功能描述**:医生对确认的会诊进行电子签名
**触发条件**:已确认的会诊申请点击"签名"按钮
**操作流程**
1. 医生确认会诊申请
2. 点击"签名"按钮
3. 校验确认状态
4. 表格中"签名"列复选框被勾选
5. 自动记录签名医生(当前用户)
6. 自动填充签名时间为系统时间
7. 禁用取消确认功能
**成功反馈**:表单区显示签名信息
**失败处理**:提示"请先确认会诊申请"
#### 3. 打印会诊记录单
**功能描述**:打印格式化的会诊记录
**触发条件**:点击"打印"按钮
**操作流程**
1. 点击"打印"按钮
2. 系统生成打印优化视图
3. 调用浏览器打印功能
**特殊处理**:隐藏交互元素,优化打印布局
### 五、数据结构说明
**门诊会诊申请确认表(**ConsultationConfirmation****
| **字段名称** | **数据类型** | **长度** | **描述** | **约束/说明** |
|-----------------------------|--------------|----------|--------------------|------------------------------------------------------------------------------------|
| **ConsultationID** | INTEGER | 20 | 会诊申请单唯一标识 | FOREIGN KEY REFERENCES ConsultationRequest(ConsultationID) |
| **ConfirmingPhysicianID** | TEXT | -20 | 确认会诊的医生ID | 操作【确认】按钮的当前医生ID |
| **ConfirmingPhysicianName** | TEXT | -20 | 确认会诊的医生姓名 | 操作【确认】按钮的当前医生姓名 |
| **ConfirmingDeptName** | TEXT | 20 | 代表科室 | 操作【确认】按钮的当前开单科室 |
| **ConfirmingDate** | DateTime | - | 确认会诊的日期 | 操作【确认】按钮当前系统时间 |
| **ConsultationStatus** | TEXT | 20 | 会诊状态 | CHECK (ConsultationStatus IN ('已确认', '取消确认', '已签名', '已完成')), NOT NULL |
| **ConsultationOpinion** | TEXT | 500 | 会诊意见 | |
| **ConfirmingPhysician** | TEXT | 100 | 会诊确认参加医师 | |
| **Signature** | TEXT | 20 | 签名医生 | |
| **SignatureDate** | DateTime | - | 签名时间 | - |
ConsultationConfirmation.ConsultationStatu会诊状态
| **状态值** | **状态名** | **描述** |
|------------|------------|-----------------------------------|
| **0** | 取消确认 | 作废 |
| **20** | 已确认 | 会诊医生已查看/同意,可写初步意见 |
| **30** | 已签名 | 已电子签名,意见最终生效 |
| **40** | 已完成 | 会诊报告已回写,流程关闭 |
**按钮涉及的事务**
| **按钮** | **涉及表** | **执行事务** | **锁/并发** | **成功状态** | **失败处理** |
|--------------|----------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------|------------------|--------------------------|
| **确认** | 1、ConsultationRequest<br>2、门诊医嘱<br>3、ConsultationConfirmation | 1、ConsultationRequest.ConsultationStatus =20<br>2、医嘱 状态='已执行'<br>3、写入ConsultationConfirmation表相关的数据 | SELECT ... FOR UPDATE | 已提交 → 已确认 | 任何异常 → 整体 ROLLBACK |
| **取消确认** | 1、ConsultationRequest<br>2、门诊医嘱<br>3、ConsultationConfirmation | 1、ConsultationRequest.ConsultationStatus =10<br>2、医嘱 状态='已提交'<br>3、ConsultationConfirmation. ConsultationStatus = 0 | 同上 | 已确认→ 取消确认 | 同上回滚 |
| **签名** | 1、ConsultationRequest<br>2、门诊医嘱<br>3、ConsultationConfirmation | 1、ConsultationRequest.ConsultationStatus =30<br>2、医嘱 Status='已完成'<br>3、写入ConsultationConfirmation. Signature, SignatureDate,ConsultationStatus =30 | 同上 | 已确认 → 已签名 | 同上回滚 |
### 六、开发实现要点
**样式规范**
- **主色调**\#4A89DC按钮蓝色
- **辅助色**\#4CAF50成功绿色
- **字体规范**14px/1.5 常规16px 标题
- **间距系统**8px基础间距24px区块间距
- **组件样式**
- 按钮6px圆角1px边框
- 输入框4px圆角1px \#E0E0E0边框
**技术要求**
- **浏览器兼容**Chrome/Firefox/Edge最新版
- **性能要求**:列表加载时间\<1s
**注意事项**
1. 确认和签名状态需要联动控制
2. 打印功能需要特殊样式处理
3. 时间字段需统一使用YYYY-MM-DD HH:mm:ss格式
4. 移动端需优化表单布局

View File

@@ -0,0 +1,267 @@
## 门诊会诊申请管理界面PRD文档
### 一、页面概述
**页面名称**:门诊会诊申请管理界面
**页面目标**:提供会诊申请的全流程管理功能,包括申请记录查询、编辑申请、查看详情、状态变更等核心操作
**适用场景**:门诊医生需要查看会诊申请或管理已有申请记录时使用
**页面类型**:列表页+表单弹窗复合型页面
**核心功能**
1. 多条件组合筛选会诊申请记录
2. 会诊申请表格展示与操作(编辑/查看/删除)
3. 会诊申请单的填写与提交
4. 会诊状态标记(提交/结束)
**用户价值**:规范会诊申请流程,减少纸质单据流转,提高多科室协作效率
原型图地址https://static.pm-ai.cn/prototype/20260116/aed1f102d614677f100c0d1fe3104999/index.html
**流程图:**
```mermaid
flowchart TD
Start([Start]) --> A[进入门诊会诊申请管理界面]
A --> B{用户操作类型}
B -->|筛选查询| C[设置筛选条件]
B -->|编辑申请| D[点击编辑按钮]
B -->|查看详情| E[点击查看按钮]
B -->|删除申请| G[点击删除按钮]
C --> H{验证筛选条件}
H -->|有效| I[展示筛选结果]
H -->|无效| J[显示错误提示]
J --> C
I --> K[用户浏览列表]
D --> L{检查会诊状态}
L -->|未结束| M[打开编辑弹窗]
L -->|已结束| N[提示不可编辑]
N --> O[关闭弹窗]
M --> P[修改表单内容]
P --> Q{表单验证}
Q -->|通过| R[保存修改]
Q -->|不通过| S[标红错误字段]
S --> P
E --> T{检查会诊状态}
T -->|未结束| U[打开只读弹窗]
T -->|已结束| U
G --> Z{删除验证}
Z -->|可删除| AA[确认删除]
Z -->|不可删除| AB[提示删除失败]
AB --> K
AA --> AC[更新状态为已取消]
AC --> AD[更新列表显示]
R --> AD
AD --> K
K --> AE([End])
```
### 二、整体布局分析
**页面宽度**:自适应布局
**主要区域划分**
1. 顶部筛选区高度自适应约80px
2. 表格展示区(高度自适应,占主要空间)
3. 底部页码区固定高度56px
**布局特点**:上下布局+弹性布局,采用左右对齐方式
### 三、页面区域详细描述
#### 1. 顶部筛选区
**区域位置**:页面顶部
**区域尺寸**100%宽度,高度自适应
**区域功能**:提供多维度筛选和快速搜索功能
**包含元素**
- **时间类型选择器**
- 元素类型:下拉选择框
- 显示内容:默认"会诊时间",可选"申请时间"
- 交互行为:点击展开下拉选项
- 样式特征宽度120px高度32px圆角4px
- **时间范围选择器**(开始/结束时间)
- 元素类型:日期时间输入框
- 显示内容placeholder提示"开始时间"/“结束时间”
- 交互行为:点击弹出日期选择面板
- 样式特征宽度180px高度32px
- **申请科室/申请医生选择器**
- 元素类型带datalist的输入框
- 显示内容placeholder提示"选择或输入科室/医生"
- 交互行为:输入时显示匹配选项
- 数据来源:动态生成申请科室/医生候选列表取值于门诊会诊申请单表ConsultationRequest.Department/ RequestingPhysician
- **会诊状态筛选器**
- 元素类型:下拉选择框
- 可选值:全部/未提交/提交/结束
- 默认值:全部
- **病人姓名搜索框**
- 元素类型:文本输入框
- 显示内容placeholder提示"病人姓名"
- 交互行为:支持模糊搜索
- **操作按钮组**
- 查询按钮
- 样式:蓝色背景,带搜索图标
- 交互:触发筛选条件应用
- 重置按钮
- 样式:灰色背景,带刷新图标
- 交互:清空所有筛选条件
- 打印按钮
- 样式:深灰色背景,带打印图标
- 交互:调起浏览器打印功能
#### 2. 表格展示区
**区域位置**:页面中部
**区域尺寸**100%宽度,高度自适应
**区域功能**:展示会诊申请列表数据,支持行内操作
**包含元素**
取值于门诊会诊申请单表ConsultationRequest和门诊会诊申请单表ConsultationRequest)
- **数据表格**
- 展示方式11列固定表头表格
- 数据字段:
- ID文本 - 15 -申请单号
- 急:复选框 - 布尔值 - 示例false 不可编辑
- 病人姓名:文本 - 朱某某 - 红色高亮
- 会诊时间:日期 - 2026-01-05 15:08
- 申请科室:文本 - 内科
- 邀请对象:文本 - 吴院长
- 申请时间:日期 - 2026-01-05 15:08
- 申请医师:文本 - 演示测试
- 提交:复选框 - 布尔值 - 示例false
- 结束:复选框 - 布尔值 - 示例false
- 操作功能:
- 编辑按钮(✏️):点击打开编辑弹窗
- 查看按钮(👁️):点击打开只读弹窗
- 删除按钮(🗑️):点击确认删除
- 【删除】将状态改为“已取消”
- UPDATE ConsultationRequest
- SET ConsultationStatus = 50,cancelnatureDate = \<作废会诊时间\>
- WHERE ConsultationID = \<会诊申请单ID\> and ConsultationStatus \<\> 40 ;
- 交互行为:
- 行悬停效果:浅蓝色背景
- 复选框点击:即时更新状态(需防抖处理)
#### 3. 底部页码区
**区域位置**:页面底部
**区域尺寸**100%宽度固定高度56px
**区域功能**:分页控制和数据统计
**包含元素**
- **总数统计**总数统计文本“总数15”
- **分页控制器**
- 上一页按钮(\<
- 当前页按钮1active状态
- 下一页按钮(\>
- 交互反馈hover时边框变蓝
#### 4. 会诊申请弹窗(模态框)
**触发方式**:点击表格行操作列的编辑/查看按钮
**区域功能**:展示/编辑会诊申请详细信息
**包含元素**
- 头部区域
- 标题:“会诊申请单”
- 关闭按钮(×图标)
- 表单区域(分两栏布局)
- 基础信息区:
- 申请单号(只读)
- 申请时间(不可编辑)
- 病人姓名(不可编辑)
- 性别/年龄(不可编辑)
- 就诊卡号(不可编辑)
- 会诊信息区:
- 会诊时间(日期时间选择器)
- 申请医师(不可编辑)
- 紧急程度(复选框)
- 申请科室(不可编辑)
- 门诊诊断(不可编辑)
- 会诊邀请对象
- 会诊确认参加医师
- 所属医生
- 代表科室
- 签名医生
- 签名时间
- 文本域:
- 病史及会诊目的(多行文本)
- 会诊意见(多行文本)
- 底部按钮区:
- 取消按钮(左对齐)
- 保存按钮(右对齐,蓝色)
### 四、交互功能详细说明
#### 1. 会诊申请编辑功能
**功能描述**:修改已有会诊申请信息
**触发条件**:点击表格行中的"✏️"按钮
**操作流程**
1. 检查会诊状态是否为"结束",若已结束则提示不可编辑
2. 弹出会诊申请编辑弹窗,填充当前行数据的会诊申请和确认相关的数据
3. 用户修改表单内容(必填字段校验)
4. 点击"保存"按钮提交修改
**异常处理**
- 必填字段为空时,标红提示
- 保存失败时显示toast提示"保存失败,请重试"
#### 2. 会诊申请查看功能
**功能描述**:查看会诊申请详细信息
**触发条件**:点击表格行中的"👁️"按钮
**操作流程**
1. 弹出只读弹窗,显示完整申请信息
2. 所有字段禁用编辑
3. 仅显示"取消"按钮用于关闭弹窗
#### 3. 数据筛选功能
**功能描述**:多条件组合查询会诊记录
**触发条件**:点击"查询"按钮
**数据过滤逻辑**
- 时间范围:根据选择的时间类型(会诊/申请)进行筛选
- 申请科室/申请医生:支持模糊匹配
- 会诊状态筛选:支持多选逻辑(未提交/提交/结束)
1. 收集所有筛选条件值
2. 发起异步请求(示例中为前端过滤)
3. 更新表格数据展示
**异常处理**
- 时间范围不合法:提示"结束时间不能早于开始时间"
- 无查询结果:显示空白表格+提示文字
**性能优化**:前端本地缓存数据,减少服务器请求
### 五、数据结构说明
门诊会诊申请单表ConsultationRequest和门诊会诊申请单表ConsultationRequest)
### 六、开发实现要点
**样式规范**
- **主色调**\#5D9CEC按钮/交互元素)
- **辅助色**\#8E8E8E次要按钮
- **字体规范**14px/1.5主要内容16px/1.5(标题)
- **间距系统**16px元素间距24px区块间距
- **组件样式**
- 按钮圆角6px内边距0 16px
- 输入框1px实线边框\#D9D9D9圆角4px
**技术要求**
- **浏览器兼容**支持Chrome/Firefox/Edge最新版
- **性能要求**:列表数据筛选响应时间\<200ms
**注意事项**
1. 状态变更逻辑:已结束的记录不可编辑
2. 时间字段需要做时区转换处理
3. 申请科室/申请医生选择器需要支持拼音首字母检索

View File

@@ -0,0 +1,62 @@
**门诊手术中计费PRD文档**
**目标:**
支持手术中追加计费(耗材、药品等)、退费等场景使用
术后一站式结算(发票、清单、医保等)
**流程图:**
```mermaid
flowchart TD
A["医生开立手术申请单"] --> B{"系统生成计费包"}
B --> C["患者缴费"]
C --> D["手术室确认"]
D --> E{"术中追加/退费?"}
E -- "是" --> F{"术中计费"}
F -- "耗材" --> F2["护士扫码追加耗材\n实时计价 更新库存"]
F -- "药品" --> F3["麻醉师追加药品\n实时计价 更新库存"]
F -- "诊疗项目" --> F4["追加麻醉时长/项目\n实时计价"]
F2 --> F6["生成术中追加计费单"]
F3 --> F6
F4 --> F6
F6 --> G{"患者支付?"}
G -- "是" --> P["提示支付成功"]--> J
G -- "否" --> H["提示支付失败\n保持待支付"]
H --> D
E -- "否" --> I["手术完成"]
I --> J["术后统一结算"]
J --> K["发票/清单/分割单"]
K --> L["财务对账"]
```
**注意:**待门诊手术安排界面禅道需求编号93完成后再执行
![](media/4fa3fca6b8362de7b938ded77d6e4982.png)
图1门诊手术安排界面禅道需求编号93
![](media/2756f39fb624c7f686d56b675b4d4d10.png)
图2门诊管理-》门诊划价:手术计费界面复制《门诊划价》界面红色框内容
1、如上图1、2所示在门诊手术安排界面增加【计费】按钮实现对门诊手术中追加的费用进行记账手术计费界面如图2所示复制《门诊划价》界面红色框内容进行个性化改造患者信息取值于手术安排界面选中行的患者信息计费账号为当前系统登录的账号。
\*比如在手术计费界面给患者1计费成功后重新从手术按钮界面选中患者1点击【计费】打开界面时显示当前患者已计费成功的手术费用。
写入事务注意:
adm_charge_item费用项管理表
①、术中费用仍走“门诊就诊管理”的就诊IDadm_encounter.id = adm_charge_item.encounter_id
2\. 为了事后能追溯“这些费用是术中发生的”,在费用项管理表明细上加一个 “来源业务单据SourceBillNo” 字段adm_charge_item.generate_source_enum = 2帐单生成来源为手术计费SourceBillNo = 手术申请单号)。
3\. 其他内容按照《门诊划价》的业务数据流程走。

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB

View File

@@ -1,2 +0,0 @@
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">OpenHis v0.0.1</h1>

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.openhis</groupId>
<artifactId>openhis-server</artifactId>
@@ -25,6 +25,11 @@
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- swagger3-->
<dependency>
@@ -38,9 +43,10 @@
<artifactId>swagger-models</artifactId>
</dependency>
<!-- Mysql驱动包 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- 核心模块-->
@@ -66,45 +72,12 @@
<groupId>com.core</groupId>
<artifactId>core-flowable</artifactId>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.core</groupId>
<artifactId>core-common</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
<!-- <build>-->
<!-- <plugins>-->
<!-- <plugin>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-maven-plugin</artifactId>-->
<!-- <version>2.5.15</version>-->
<!-- <configuration>-->
<!-- <fork>true</fork> &lt;!&ndash; 如果没有该配置devtools不会生效 &ndash;&gt;-->
<!-- </configuration>-->
<!-- <executions>-->
<!-- <execution>-->
<!-- <goals>-->
<!-- <goal>repackage</goal>-->
<!-- </goals>-->
<!-- </execution>-->
<!-- </executions>-->
<!-- </plugin>-->
<!-- <plugin>-->
<!-- <groupId>org.apache.maven.plugins</groupId>-->
<!-- <artifactId>maven-war-plugin</artifactId>-->
<!-- <version>3.1.0</version>-->
<!-- <configuration>-->
<!-- <failOnMissingWebXml>false</failOnMissingWebXml>-->
<!-- <warName>${project.artifactId}</warName>-->
<!-- </configuration>-->
<!-- </plugin>-->
<!-- <plugin>-->
<!-- <groupId>org.apache.maven.plugins</groupId>-->
<!-- <artifactId>maven-compiler-plugin</artifactId>-->
<!-- <configuration>-->
<!-- <source>8</source>-->
<!-- <target>8</target>-->
<!-- </configuration>-->
<!-- </plugin>-->
<!-- </plugins>-->
<!-- <finalName>${project.artifactId}</finalName>-->
<!-- </build>-->
</project>

View File

@@ -1,18 +1,5 @@
package com.core.web.controller.common;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.core.common.config.CoreConfig;
import com.core.common.constant.CacheConstants;
import com.core.common.constant.Constants;
@@ -22,6 +9,17 @@ import com.core.common.utils.sign.Base64;
import com.core.common.utils.uuid.IdUtils;
import com.core.system.service.ISysConfigService;
import com.google.code.kaptcha.Producer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
/**
* 验证码操作处理

View File

@@ -1,11 +1,12 @@
package com.core.web.controller.common;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.core.common.config.CoreConfig;
import com.core.common.constant.Constants;
import com.core.common.core.domain.AjaxResult;
import com.core.common.utils.StringUtils;
import com.core.common.utils.file.FileUploadUtils;
import com.core.common.utils.file.FileUtils;
import com.core.framework.config.ServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -16,13 +17,10 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.core.common.config.CoreConfig;
import com.core.common.constant.Constants;
import com.core.common.core.domain.AjaxResult;
import com.core.common.utils.StringUtils;
import com.core.common.utils.file.FileUploadUtils;
import com.core.common.utils.file.FileUtils;
import com.core.framework.config.ServerConfig;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
* 通用请求处理

View File

@@ -1,13 +1,5 @@
package com.core.web.controller.common;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.core.common.annotation.Anonymous;
import com.core.common.config.CoreConfig;
import com.core.common.core.domain.AjaxResult;
@@ -16,6 +8,13 @@ import com.core.common.utils.StringUtils;
import com.core.common.utils.file.FileUploadUtils;
import com.core.common.utils.file.FileUtils;
import com.core.framework.config.ServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/file")

View File

@@ -1,17 +1,16 @@
package com.core.web.controller.monitor;
import java.util.*;
import com.core.common.constant.CacheConstants;
import com.core.common.core.domain.AjaxResult;
import com.core.common.utils.StringUtils;
import com.core.system.domain.SysCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.core.common.constant.CacheConstants;
import com.core.common.core.domain.AjaxResult;
import com.core.common.utils.StringUtils;
import com.core.system.domain.SysCache;
import java.util.*;
/**
* 缓存监控

View File

@@ -1,13 +1,12 @@
package com.core.web.controller.monitor;
import com.core.common.core.domain.AjaxResult;
import com.core.framework.web.domain.Server;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.core.common.core.domain.AjaxResult;
import com.core.framework.web.domain.Server;
/**
* 服务器监控
*

View File

@@ -1,13 +1,5 @@
package com.core.web.controller.monitor;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
@@ -17,15 +9,23 @@ import com.core.common.utils.poi.ExcelUtil;
import com.core.framework.web.service.SysPasswordService;
import com.core.system.domain.SysLogininfor;
import com.core.system.service.ISysLogininforService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 系统访问记录
*
*
*
* @author system
*/
@RestController
@RequestMapping("/monitor/logininfor")
public class SysLogininforController extends BaseController {
@Autowired
private ISysLogininforService logininforService;

View File

@@ -1,13 +1,5 @@
package com.core.web.controller.monitor;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
@@ -16,6 +8,12 @@ import com.core.common.enums.BusinessType;
import com.core.common.utils.poi.ExcelUtil;
import com.core.system.domain.SysOperLog;
import com.core.system.service.ISysOperLogService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 操作日志记录

View File

@@ -1,14 +1,5 @@
package com.core.web.controller.monitor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.constant.CacheConstants;
import com.core.common.core.controller.BaseController;
@@ -20,6 +11,14 @@ import com.core.common.enums.BusinessType;
import com.core.common.utils.StringUtils;
import com.core.system.domain.SysUserOnline;
import com.core.system.service.ISysUserOnlineService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* 在线用户监控

View File

@@ -1,14 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
@@ -17,6 +8,13 @@ import com.core.common.enums.BusinessType;
import com.core.common.utils.poi.ExcelUtil;
import com.core.system.domain.SysConfig;
import com.core.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 参数配置 信息操作处理
@@ -63,7 +61,25 @@ public class SysConfigController extends BaseController {
*/
@GetMapping(value = "/configKey/{configKey}")
public AjaxResult getConfigKey(@PathVariable String configKey) {
return success(configService.selectConfigByKey(configKey));
String configValue = configService.selectConfigByKey(configKey);
// 确保即使返回 null 或空字符串,也明确设置 data 字段
// 如果 configValue 是 null转换为空字符串
if (configValue == null) {
configValue = "";
}
// 直接创建 AjaxResult 并明确设置 data 字段,确保 data 字段始终存在
AjaxResult result = new AjaxResult();
result.put("code", 200);
result.put("msg", "操作成功");
result.put("data", configValue); // 明确设置 data 字段,即使值为空字符串
System.out.println("=== getConfigKey 调试信息 ===");
System.out.println("configKey: " + configKey);
System.out.println("configValue: [" + configValue + "]");
System.out.println("result.data: " + result.get("data"));
System.out.println("result.msg: " + result.get("msg"));
System.out.println("result.code: " + result.get("code"));
System.out.println("============================");
return result;
}
/**

View File

@@ -1,13 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.constant.UserConstants;
import com.core.common.core.controller.BaseController;
@@ -16,6 +8,13 @@ import com.core.common.core.domain.entity.SysDept;
import com.core.common.enums.BusinessType;
import com.core.common.utils.StringUtils;
import com.core.system.service.ISysDeptService;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 部门信息

View File

@@ -1,15 +1,5 @@
package com.core.web.controller.system;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
@@ -20,6 +10,14 @@ import com.core.common.utils.StringUtils;
import com.core.common.utils.poi.ExcelUtil;
import com.core.system.service.ISysDictDataService;
import com.core.system.service.ISysDictTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
/**
* 数据字典信息
@@ -62,11 +60,12 @@ public class SysDictDataController extends BaseController {
}
/**
* 根据字典类型查询字典数据信息
* 根据字典类型查询字典数据信息(支持拼音搜索)
*/
@GetMapping(value = "/type/{dictType}")
public AjaxResult dictType(@PathVariable String dictType) {
List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
public AjaxResult dictType(@PathVariable String dictType,
@RequestParam(value = "searchKey", required = false) String searchKey) {
List<SysDictData> data = dictTypeService.selectDictDataByType(dictType, searchKey);
if (StringUtils.isNull(data)) {
data = new ArrayList<SysDictData>();
}

View File

@@ -1,14 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
@@ -17,6 +8,13 @@ import com.core.common.core.page.TableDataInfo;
import com.core.common.enums.BusinessType;
import com.core.common.utils.poi.ExcelUtil;
import com.core.system.service.ISysDictTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 数据字典信息

View File

@@ -1,11 +1,10 @@
package com.core.web.controller.system;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.core.common.config.CoreConfig;
import com.core.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 首页

View File

@@ -1,14 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.core.common.constant.Constants;
import com.core.common.core.domain.AjaxResult;
import com.core.common.core.domain.entity.SysMenu;
@@ -20,6 +11,15 @@ import com.core.framework.web.service.SysLoginService;
import com.core.framework.web.service.SysPermissionService;
import com.core.framework.web.service.TokenService;
import com.core.system.service.ISysMenuService;
import com.core.system.service.ISysTenantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Set;
/**已评审
* 登录验证
@@ -40,6 +40,9 @@ public class SysLoginController {
@Autowired
private TokenService tokenService;
@Autowired
private ISysTenantService tenantService;
/**已评审
* 登录方法
*
@@ -73,12 +76,22 @@ public class SysLoginController {
loginUser.setPermissions(permissions);
tokenService.refreshToken(loginUser);
}
// 获取租户名称
String tenantName = null;
if (loginUser.getTenantId() != null) {
com.core.system.domain.SysTenant tenant = tenantService.getById(loginUser.getTenantId());
if (tenant != null) {
tenantName = tenant.getTenantName();
}
}
AjaxResult ajax = AjaxResult.success();
ajax.put("optionJson", loginUser.getOptionJson());
ajax.put("optionMap", loginUser.getOptionMap());
ajax.put("practitionerId", String.valueOf(loginUser.getPractitionerId()));
ajax.put("user", user);
ajax.put("roles", roles);
ajax.put("permissions", permissions);
ajax.put("tenantName", tenantName);
return ajax;
}

View File

@@ -1,12 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.constant.UserConstants;
import com.core.common.core.controller.BaseController;
@@ -15,6 +8,12 @@ import com.core.common.core.domain.entity.SysMenu;
import com.core.common.enums.BusinessType;
import com.core.common.utils.StringUtils;
import com.core.system.service.ISysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 菜单信息
@@ -34,7 +33,9 @@ public class SysMenuController extends BaseController {
@GetMapping("/list")
public AjaxResult list(SysMenu menu) {
List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
return success(menus);
// 构建带完整路径的菜单树
List<SysMenu> menuTreeWithFullPath = menuService.buildMenuTreeWithFullPath(menus);
return success(menuTreeWithFullPath);
}
/**
@@ -116,4 +117,25 @@ public class SysMenuController extends BaseController {
}
return toAjax(menuService.deleteMenuById(menuId));
}
/**
* 获取菜单完整路径
*/
@PreAuthorize("@ss.hasPermi('system:menu:query')")
@GetMapping("/fullPath/{menuId}")
public AjaxResult getFullPath(@PathVariable("menuId") Long menuId) {
String fullPath = menuService.getMenuFullPath(menuId);
return success(fullPath);
}
/**
* 生成完整路径
*/
@PreAuthorize("@ss.hasPermi('system:menu:query')")
@PostMapping("/generateFullPath")
public AjaxResult generateFullPath(@RequestParam(required = false) Long parentId,
@RequestParam String currentPath) {
String fullPath = menuService.generateFullPath(parentId, currentPath);
return success(fullPath);
}
}

View File

@@ -1,19 +1,21 @@
package com.core.web.controller.system;
import java.util.List;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
import com.core.common.core.domain.entity.SysUser;
import com.core.common.core.domain.model.LoginUser;
import com.core.common.core.page.TableDataInfo;
import com.core.common.enums.BusinessType;
import com.core.system.domain.SysNotice;
import com.core.system.service.ISysNoticeReadService;
import com.core.system.service.ISysNoticeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
import com.core.common.core.page.TableDataInfo;
import com.core.common.enums.BusinessType;
import com.core.system.domain.SysNotice;
import com.core.system.service.ISysNoticeService;
import java.util.List;
/**
* 公告 信息操作处理
@@ -26,6 +28,9 @@ public class SysNoticeController extends BaseController {
@Autowired
private ISysNoticeService noticeService;
@Autowired
private ISysNoticeReadService noticeReadService;
/**
* 获取通知公告列表
*/
@@ -37,6 +42,108 @@ public class SysNoticeController extends BaseController {
return getDataTable(list);
}
/**
* 获取当前用户的公告列表(公开接口)
* 公告类型:通常 noticeType = '1' 代表通知noticeType = '2' 代表公告
*/
@GetMapping("/public/list")
public TableDataInfo getPublicList(SysNotice notice) {
// 只查询状态为正常0且已发布1的公告
notice.setStatus("0");
notice.setPublishStatus("1");
// 公告类型设置为 '2'(公告)
notice.setNoticeType("2");
// 设置分页参数
startPage();
List<SysNotice> list = noticeService.selectNoticeList(notice);
return getDataTable(list);
}
/**
* 获取当前用户的通知列表(公开接口)
* 通知类型:通常 noticeType = '1' 代表通知noticeType = '2' 代表公告
* 返回已发布且状态正常的所有公告和通知,并标注已读状态
* 按优先级排序,高优先级在前
*/
@GetMapping("/public/notice")
public AjaxResult getUserNotices() {
// 获取当前用户信息
LoginUser loginUser = getLoginUser();
SysUser currentUser = loginUser.getUser();
// 查询已发布且状态正常的所有公告和通知
SysNotice notice = new SysNotice();
notice.setStatus("0");
notice.setPublishStatus("1");
List<SysNotice> list = noticeService.selectNoticeList(notice);
// 按优先级排序1高 2中 3低相同优先级按创建时间降序
list.sort((a, b) -> {
String priorityA = a.getPriority() != null ? a.getPriority() : "3";
String priorityB = b.getPriority() != null ? b.getPriority() : "3";
int priorityCompare = priorityA.compareTo(priorityB);
if (priorityCompare != 0) {
return priorityCompare;
}
// 相同优先级,按创建时间降序
return b.getCreateTime().compareTo(a.getCreateTime());
});
// 获取用户已读的公告/通知ID列表
List<Long> readIds = noticeReadService.selectReadNoticeIdsByUserId(currentUser.getUserId());
// 为每个公告/通知添加已读状态
for (SysNotice item : list) {
boolean isRead = readIds.contains(item.getNoticeId());
item.setIsRead(isRead);
}
return success(list);
}
/**
* 获取用户未读公告/通知数量(公开接口)
*/
@GetMapping("/public/unread/count")
public AjaxResult getUnreadCount() {
LoginUser loginUser = getLoginUser();
SysUser currentUser = loginUser.getUser();
int count = noticeReadService.getUnreadCount(currentUser.getUserId());
return success(count);
}
/**
* 标记公告/通知为已读(公开接口)
*/
@PostMapping("/public/read/{noticeId}")
public AjaxResult markAsRead(@PathVariable Long noticeId) {
LoginUser loginUser = getLoginUser();
SysUser currentUser = loginUser.getUser();
return noticeReadService.markAsRead(noticeId, currentUser.getUserId());
}
/**
* 批量标记公告/通知为已读(公开接口)
*/
@PostMapping("/public/read/all")
public AjaxResult markAllAsRead(@RequestBody Long[] noticeIds) {
LoginUser loginUser = getLoginUser();
SysUser currentUser = loginUser.getUser();
return noticeReadService.markAllAsRead(noticeIds, currentUser.getUserId());
}
/**
* 获取用户已读公告/通知ID列表公开接口
*/
@GetMapping("/public/read/ids")
public AjaxResult getReadNoticeIds() {
LoginUser loginUser = getLoginUser();
SysUser currentUser = loginUser.getUser();
List<Long> readIds = noticeReadService.selectReadNoticeIdsByUserId(currentUser.getUserId());
return success(readIds);
}
/**
* 根据通知公告编号获取详细信息
*/
@@ -54,6 +161,14 @@ public class SysNoticeController extends BaseController {
@PostMapping
public AjaxResult add(@Validated @RequestBody SysNotice notice) {
notice.setCreateBy(getUsername());
// 新建的公告默认为未发布状态
if (notice.getPublishStatus() == null || notice.getPublishStatus().isEmpty()) {
notice.setPublishStatus("0");
}
// 设置默认优先级为中2
if (notice.getPriority() == null || notice.getPriority().isEmpty()) {
notice.setPriority("2");
}
return toAjax(noticeService.insertNotice(notice));
}
@@ -77,4 +192,42 @@ public class SysNoticeController extends BaseController {
public AjaxResult remove(@PathVariable Long[] noticeIds) {
return toAjax(noticeService.deleteNoticeByIds(noticeIds));
}
/**
* 发布公告/通知
*/
@PreAuthorize("@ss.hasPermi('system:notice:edit')")
@Log(title = "发布公告", businessType = BusinessType.UPDATE)
@PutMapping("/publish/{noticeId}")
public AjaxResult publish(@PathVariable Long noticeId) {
SysNotice notice = noticeService.selectNoticeById(noticeId);
if (notice == null) {
return error("公告不存在");
}
if ("1".equals(notice.getPublishStatus())) {
return error("该公告已发布");
}
notice.setPublishStatus("1");
notice.setUpdateBy(getUsername());
return toAjax(noticeService.updateNotice(notice));
}
/**
* 取消发布公告/通知
*/
@PreAuthorize("@ss.hasPermi('system:notice:edit')")
@Log(title = "取消发布", businessType = BusinessType.UPDATE)
@PutMapping("/unpublish/{noticeId}")
public AjaxResult unpublish(@PathVariable Long noticeId) {
SysNotice notice = noticeService.selectNoticeById(noticeId);
if (notice == null) {
return error("公告不存在");
}
if ("0".equals(notice.getPublishStatus())) {
return error("该公告未发布");
}
notice.setPublishStatus("0");
notice.setUpdateBy(getUsername());
return toAjax(noticeService.updateNotice(notice));
}
}

View File

@@ -1,14 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
@@ -17,6 +8,13 @@ import com.core.common.enums.BusinessType;
import com.core.common.utils.poi.ExcelUtil;
import com.core.system.domain.SysPost;
import com.core.system.service.ISysPostService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 岗位信息操作处理

View File

@@ -1,9 +1,5 @@
package com.core.web.controller.system;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.core.common.annotation.Log;
import com.core.common.config.CoreConfig;
import com.core.common.core.controller.BaseController;
@@ -17,6 +13,9 @@ import com.core.common.utils.file.FileUploadUtils;
import com.core.common.utils.file.MimeTypeUtils;
import com.core.framework.web.service.TokenService;
import com.core.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
/**
* 个人信息 业务处理

View File

@@ -1,16 +1,15 @@
package com.core.web.controller.system;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
import com.core.common.core.domain.model.RegisterBody;
import com.core.common.utils.StringUtils;
import com.core.framework.web.service.SysRegisterService;
import com.core.system.service.ISysConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* 注册验证

View File

@@ -1,14 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
@@ -26,6 +17,13 @@ import com.core.system.domain.SysUserRole;
import com.core.system.service.ISysDeptService;
import com.core.system.service.ISysRoleService;
import com.core.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 角色信息

View File

@@ -1,11 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.core.common.annotation.Anonymous;
import com.core.common.core.controller.BaseController;
@@ -13,6 +7,11 @@ import com.core.common.core.domain.R;
import com.core.common.core.domain.entity.SysUser;
import com.core.system.domain.SysTenant;
import com.core.system.service.ISysTenantService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 租户信息controller

View File

@@ -1,16 +1,15 @@
package com.core.web.controller.system;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.R;
import com.core.system.domain.dto.SaveTenantOptionDetailDto;
import com.core.system.domain.dto.TenantOptionDto;
import com.core.system.service.ISysTenantOptionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 租户配置项信息controller

View File

@@ -1,17 +1,5 @@
package com.core.web.controller.system;
import java.util.List;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import com.core.common.annotation.Log;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.AjaxResult;
@@ -27,6 +15,16 @@ import com.core.system.service.ISysDeptService;
import com.core.system.service.ISysPostService;
import com.core.system.service.ISysRoleService;
import com.core.system.service.ISysUserService;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.stream.Collectors;
/**
* 用户信息

View File

@@ -1,18 +1,16 @@
package com.core.web.controller.tool;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.R;
import com.core.common.utils.StringUtils;
import io.swagger.annotations.*;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.springframework.web.bind.annotation.*;
import com.core.common.core.controller.BaseController;
import com.core.common.core.domain.R;
import com.core.common.utils.StringUtils;
import io.swagger.annotations.*;
/**
* swagger 用户测试方法
*

View File

@@ -1,17 +1,12 @@
package com.core.web.core.config;
import java.util.ArrayList;
import java.util.List;
import com.core.common.config.CoreConfig;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.core.common.config.CoreConfig;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
@@ -20,6 +15,9 @@ import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.List;
/**
* Swagger2的接口配置
*

View File

@@ -16,6 +16,33 @@
common通用工具
</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-parameters</arg>
<arg>--add-modules</arg>
<arg>java.base</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- mybatis-plus 增强CRUD -->
@@ -54,6 +81,12 @@
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!-- jsr250 annotations -->
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
</dependency>
<!-- 自定义验证注解 -->
<dependency>
<groupId>org.springframework.boot</groupId>
@@ -77,10 +110,6 @@
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!-- io常用工具类 -->
<dependency>
@@ -140,6 +169,7 @@
<dependency>
<groupId>com.belerweb</groupId>
<artifactId>pinyin4j</artifactId>
<version>2.5.1</version>
</dependency>
<dependency>

View File

@@ -1,9 +1,9 @@
package com.core.common.annotation;
import java.lang.annotation.*;
import com.core.common.enums.DataSourceType;
import java.lang.annotation.*;
/**
* 自定义多数据源切换注解
*

View File

@@ -1,16 +1,15 @@
package com.core.common.annotation;
import com.core.common.utils.poi.ExcelHandlerAdapter;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.math.BigDecimal;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.core.common.utils.poi.ExcelHandlerAdapter;
/**
* 自定义导出Excel数据注解
*

View File

@@ -0,0 +1,38 @@
package com.core.common.annotation;
import java.lang.annotation.*;
/**
* Excel额外表头信息注解
*
* @author swb
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelExtra {
/**
* 表头名称
*/
String name();
/**
* 日期格式yyyy-MM-dd HH:mm:ss
*/
String dateFormat() default "";
/**
* 排序(越小越靠前)
*/
int sort() default 0;
/**
* 默认值
*/
String defaultValue() default "";
/**
* 是否导出
*/
boolean isExport() default true;
}

View File

@@ -1,10 +1,10 @@
package com.core.common.annotation;
import java.lang.annotation.*;
import com.core.common.enums.BusinessType;
import com.core.common.enums.OperatorType;
import java.lang.annotation.*;
/**
* 自定义操作日志记录注解
*

View File

@@ -1,10 +1,10 @@
package com.core.common.annotation;
import java.lang.annotation.*;
import com.core.common.constant.CacheConstants;
import com.core.common.enums.LimitType;
import java.lang.annotation.*;
/**
* 限流注解
*

View File

@@ -1,15 +1,15 @@
package com.core.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.core.common.config.serializer.SensitiveJsonSerializer;
import com.core.common.enums.DesensitizedType;
import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 数据脱敏注解
*

View File

@@ -1,8 +1,5 @@
package com.core.common.config.serializer;
import java.io.IOException;
import java.util.Objects;
import com.core.common.annotation.Sensitive;
import com.core.common.core.domain.model.LoginUser;
import com.core.common.enums.DesensitizedType;
@@ -14,6 +11,9 @@ import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import java.io.IOException;
import java.util.Objects;
/**
* 数据脱敏序列化过滤
*

View File

@@ -1,9 +1,9 @@
package com.core.common.constant;
import java.util.Locale;
import io.jsonwebtoken.Claims;
import java.util.Locale;
/**
* 通用常量信息
*

View File

@@ -1,14 +1,5 @@
package com.core.common.core.controller;
import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import com.core.common.constant.HttpStatus;
import com.core.common.core.domain.AjaxResult;
import com.core.common.core.domain.model.LoginUser;
@@ -22,6 +13,14 @@ import com.core.common.utils.StringUtils;
import com.core.common.utils.sql.SqlUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import java.beans.PropertyEditorSupport;
import java.util.Date;
import java.util.List;
/**
* web层通用数据处理

View File

@@ -1,11 +1,11 @@
package com.core.common.core.domain;
import java.util.HashMap;
import java.util.Objects;
import com.core.common.constant.HttpStatus;
import com.core.common.utils.StringUtils;
import java.util.HashMap;
import java.util.Objects;
/**
* 操作消息提醒
*

View File

@@ -1,15 +1,15 @@
package com.core.common.core.domain;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Entity基类
*

View File

@@ -1,19 +1,19 @@
package com.core.common.core.domain;
import java.io.Serializable;
import java.util.Date;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* Entity基类
*
*
* @author system
*/
@Data
@@ -28,6 +28,7 @@ public class HisBaseEntity implements Serializable {
/** 创建时间 */
@TableField(fill = FieldFill.INSERT)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/** 更新者 */
@@ -36,6 +37,7 @@ public class HisBaseEntity implements Serializable {
/** 更新时间 */
@TableField(fill = FieldFill.UPDATE)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** 租户ID */

View File

@@ -1,9 +1,9 @@
package com.core.common.core.domain;
import java.io.Serializable;
import com.core.common.constant.HttpStatus;
import java.io.Serializable;
/**
* 响应信息主体
*

View File

@@ -1,13 +1,13 @@
package com.core.common.core.domain;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
import com.core.common.core.domain.entity.SysDept;
import com.core.common.core.domain.entity.SysMenu;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;
/**
* Treeselect树结构实体类
*

View File

@@ -1,17 +1,15 @@
package com.core.common.core.domain.entity;
import java.util.ArrayList;
import java.util.List;
import com.core.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.core.common.core.domain.BaseEntity;
import java.util.ArrayList;
import java.util.List;
/**
* 部门表 sys_dept

View File

@@ -1,15 +1,14 @@
package com.core.common.core.domain.entity;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.core.common.annotation.Excel;
import com.core.common.annotation.Excel.ColumnType;
import com.core.common.constant.UserConstants;
import com.core.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* 字典数据表 sys_dict_data
@@ -53,6 +52,9 @@ public class SysDictData extends BaseEntity {
@Excel(name = "状态", readConverterExp = "0=正常,1=停用")
private String status;
/** 拼音首字母 */
private String pyStr;
public Long getDictCode() {
return dictCode;
}
@@ -136,13 +138,21 @@ public class SysDictData extends BaseEntity {
this.status = status;
}
public String getPyStr() {
return pyStr;
}
public void setPyStr(String pyStr) {
this.pyStr = pyStr;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("dictCode", getDictCode())
.append("dictSort", getDictSort()).append("dictLabel", getDictLabel()).append("dictValue", getDictValue())
.append("dictType", getDictType()).append("cssClass", getCssClass()).append("listClass", getListClass())
.append("isDefault", getIsDefault()).append("status", getStatus()).append("createBy", getCreateBy())
.append("createTime", getCreateTime()).append("updateBy", getUpdateBy())
.append("isDefault", getIsDefault()).append("status", getStatus()).append("pyStr", getPyStr())
.append("createBy", getCreateBy()).append("createTime", getCreateTime()).append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime()).append("remark", getRemark()).toString();
}
}

View File

@@ -1,15 +1,14 @@
package com.core.common.core.domain.entity;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.core.common.annotation.Excel;
import com.core.common.annotation.Excel.ColumnType;
import com.core.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
/**
* 字典类型表 sys_dict_type

View File

@@ -1,16 +1,14 @@
package com.core.common.core.domain.entity;
import java.util.ArrayList;
import java.util.List;
import com.core.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.core.common.core.domain.BaseEntity;
import java.util.ArrayList;
import java.util.List;
/**
* 菜单权限表 sys_menu
@@ -71,6 +69,9 @@ public class SysMenu extends BaseEntity {
/** 子菜单 */
private List<SysMenu> children = new ArrayList<SysMenu>();
/** 完整路径 */
private String fullPath;
public Long getMenuId() {
return menuId;
}
@@ -214,6 +215,14 @@ public class SysMenu extends BaseEntity {
this.children = children;
}
public String getFullPath() {
return fullPath;
}
public void setFullPath(String fullPath) {
this.fullPath = fullPath;
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE).append("menuId", getMenuId())
@@ -221,8 +230,8 @@ public class SysMenu extends BaseEntity {
.append("path", getPath()).append("component", getComponent()).append("query", getQuery())
.append("routeName", getRouteName()).append("isFrame", getIsFrame()).append("IsCache", getIsCache())
.append("menuType", getMenuType()).append("visible", getVisible()).append("status ", getStatus())
.append("perms", getPerms()).append("icon", getIcon()).append("createBy", getCreateBy())
.append("createTime", getCreateTime()).append("updateBy", getUpdateBy())
.append("perms", getPerms()).append("icon", getIcon()).append("fullPath", getFullPath())
.append("createBy", getCreateBy()).append("createTime", getCreateTime()).append("updateBy", getUpdateBy())
.append("updateTime", getUpdateTime()).append("remark", getRemark()).toString();
}
}

View File

@@ -1,17 +1,15 @@
package com.core.common.core.domain.entity;
import java.util.Set;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.core.common.annotation.Excel;
import com.core.common.annotation.Excel.ColumnType;
import com.core.common.core.domain.BaseEntity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.Set;
/**
* 角色表 sys_role

View File

@@ -1,16 +1,8 @@
package com.core.common.core.domain.entity;
import java.util.Date;
import java.util.List;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.core.common.annotation.Excel;
import com.core.common.annotation.Excel.ColumnType;
import com.core.common.annotation.Excel.Type;
@@ -19,8 +11,15 @@ import com.core.common.core.domain.BaseEntity;
import com.core.common.xss.Xss;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
/**
* 用户对象 sys_user
@@ -32,6 +31,7 @@ public class SysUser extends BaseEntity {
private static final long serialVersionUID = 1L;
/** 用户ID */
@TableId(type = IdType.ASSIGN_ID)
@Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
private Long userId;

View File

@@ -1,20 +1,18 @@
package com.core.common.core.domain.model;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.annotation.JSONField;
import com.core.common.core.domain.entity.SysRole;
import com.core.common.core.domain.entity.SysUser;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.core.common.core.domain.entity.SysRole;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.annotation.JSONField;
import com.core.common.core.domain.entity.SysUser;
import lombok.Data;
/**
* 登录用户身份权限
*

View File

@@ -1,13 +1,16 @@
package com.core.common.core.redis;
import java.util.*;
import java.util.concurrent.TimeUnit;
import com.core.common.exception.UtilException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* spring redis 工具类
*

View File

@@ -1,10 +1,10 @@
package com.core.common.core.text;
import com.core.common.utils.StringUtils;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import com.core.common.utils.StringUtils;
/**
* 字符集工具类
*

View File

@@ -1,5 +1,8 @@
package com.core.common.core.text;
import com.core.common.utils.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
@@ -8,10 +11,6 @@ import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.Set;
import org.apache.commons.lang3.ArrayUtils;
import com.core.common.utils.StringUtils;
/**
* 类型转换器
*

View File

@@ -1,10 +1,13 @@
package com.openhis.common.enums;
package com.core.common.enums;
import lombok.Getter;
/**
* 删除标识
*
* @author system
*/
@Getter
public enum DelFlag {
/**
* 未删除
@@ -25,6 +28,23 @@ public enum DelFlag {
this.info = info;
}
public static DelFlag getByValue(Integer value) {
if (value == null) {
return null;
}
for (DelFlag val : values()) {
if (val.value.equals(value)) {
return val;
}
}
return null;
}
// 手动添加 getter 方法以解决 Lombok 兼容性问题
public Integer getValue() {
return value;
}
public String getCode() {
return code;
}
@@ -32,20 +52,4 @@ public enum DelFlag {
public String getInfo() {
return info;
}
public Integer getValue() {
return value;
}
public static DelFlag getByValue(Integer value) {
if (value == null) {
return null;
}
for (DelFlag val : values()) {
if (val.getValue().equals(value)) {
return val;
}
}
return null;
}
}

View File

@@ -1,26 +0,0 @@
package com.core.common.enums;
/**
* 删除标志
*
* @author system
*/
public enum DeleteFlag {
NOT_DELETED("0", "未删除"), DELETED("1", "已删除");
private final String code;
private final String info;
DeleteFlag(String code, String info) {
this.code = code;
this.info = info;
}
public String getCode() {
return code;
}
public String getInfo() {
return info;
}
}

View File

@@ -1,9 +1,9 @@
package com.core.common.enums;
import java.util.function.Function;
import com.core.common.utils.DesensitizedUtil;
import java.util.function.Function;
/**
* 脱敏类型
*

View File

@@ -1,10 +1,10 @@
package com.core.common.enums;
import org.springframework.lang.Nullable;
import java.util.HashMap;
import java.util.Map;
import org.springframework.lang.Nullable;
/**
* 请求方式
*

View File

@@ -11,7 +11,6 @@ public enum TenantOptionDict {
* 医院名称
*/
YB_HOSPITAL_NAME("hospitalName", "医保-医院名称", 0),
/**
* 医保-医疗机构等级(3101接口)
*/
@@ -24,37 +23,30 @@ public enum TenantOptionDict {
* 电子发票appid
*/
EINVOICE_APP_ID("app_id", "电子发票-appid", 3),
/**
* 电子发票key
*/
EINVOICE_KEY("key", "电子发票-key", 4),
/**
* 电子发票url
*/
EINVOICE_URL("url", "电子发票-url", 5),
/**
* 医保开关
*/
YB_SWITCH("yb_switch", "医保开关", 6),
/**
* 电子地址
*/
ELE_ADDRESS("eleAddress", "电子处方-请求地址", 22),
/**
* 服务地址
*/
ADDRESS("address", "服务地址", 23),
/**
* 超时时间
*/
TIME("time", "超时时间", 24),
/**
* 是否加密
*/
@@ -63,32 +55,26 @@ public enum TenantOptionDict {
* 医保区划
*/
YB_INSUPLC_ADMDVS("insuplc_admdvs", "医保-区划", 26),
/**
* 电子处方appId
*/
ELE_PRE_APP_ID("pre_app_id", "电子处方-appId", 27),
/**
* 电子处方appSecret
*/
ELE_PRE_APP_SECRET("pre_app_secret", "电子处方-appSecret", 28),
/**
* 电子处方私钥
*/
ELE_APP_PRVKEY("APP_PRVKEY", "电子处方-私钥", 29),
/**
* 电子处方公钥
*/
ELE_PLAF_PUBKEY("PLAF_PUBKEY", "电子处方-公钥", 30),
/**
* 医院等级
*/
EINVOICE_HOSPITAL_LV("hospital_lv", "电子发票-医院等级", 39),
/**
* 无视LIS&PACS报错
*/
@@ -118,11 +104,11 @@ public enum TenantOptionDict {
*/
PACS_APP_SECRET("pacsAppSecret", "PACSAppSecret", 45),
/**
* PACSAppSecret
* 电子发票-中转服务的路径
*/
INVOICE_FORWARD_URL("invoiceUrl", "电子发票-中转服务的路径", 46),
/**
* PACSAppSecret
* 电子发票-中转服务开关
*/
FORWARD_SWITCH("forwardSwitch", "电子发票-中转服务开关", 47),
/**
@@ -160,51 +146,160 @@ public enum TenantOptionDict {
/**
* 电子发票开关
*/
INVOICE_SWITCH("invoiceSwitch", "电子发票开关 (0:关闭 1:开启)", 56),
INVOICE_SWITCH("invoiceSwitch", "电子发票开关", 56),
/**
* 医嘱定价来源
*/
ORDER_PRICING_SOURCE("orderPricingSource", "定价来源 batchSellingPrice/retailPrice", 57),
/**
* 三方支付(签到)
*/
THREE_PART_SIGN_URL("threePartSignUrl", "三方支付GET请求", 58),
THREE_PART_SIGN_URL("threePartSignUrl", "三方支付【签到】请求路径", 58),
/**
* 三方支付(签到)
*/
THREE_PART_SIGN_STATIC_PARAM("threePartSignStaticParam", "三方支付【签到】固定参数", 59),
/**
* 三方支付(签到)
*/
THREE_PART_SIGN_ACTIVE_PARAM("threePartSignActiveParam", "三方支付【签到】可变参数", 60),
/**
* 三方支付(签到)
*/
THREE_PART_SIGN_MAPPING_METHOD("threePartSignMappingMethod", "三方支付【签到】请求方式", 61),
/**
* 三方支付(消费)
*/
THREE_PART_PAY_URL("threePartPayUrl", "三方支付GET请求", 59),
THREE_PART_PAY_URL("threePartPayUrl", "三方支付【消费】请求路径", 62),
/**
* 三方支付(消费)
*/
THREE_PART_PAY_STATIC_PARAM("threePartPayStaticParam", "三方支付【消费】固定参数", 63),
/**
* 三方支付(消费)
*/
THREE_PART_PAY_ACTIVE_PARAM("threePartPayActiveParam", "三方支付【消费】可变参数", 64),
/**
* 三方支付(消费)
*/
THREE_PART_PAY_MAPPING_METHOD("threePartPayMappingMethod", "三方支付【消费】请求方式", 65),
/**
* 三方支付(退费)
*/
THREE_PART_RETURN_URL("threePartReturnUrl", "三方支付GET请求", 60),
THREE_PART_RETURN_URL("threePartReturnUrl", "三方支付【退费】请求路径", 66),
/**
* 三方支付(退费)
*/
THREE_PART_RETURN_STATIC_PARAM("threePartReturnStaticParam", "三方支付【退费】固定参数", 67),
/**
* 三方支付(退费)
*/
THREE_PART_RETURN_ACTIVE_PARAM("threePartReturnActiveParam", "三方支付【退费】可变参数", 68),
/**
* 三方支付(退费)
*/
THREE_PART_RETURN_MAPPING_METHOD("threePartReturnMappingMethod", "三方支付【退费】请求方式", 69),
/**
* 三方支付(隔天退费)
*/
THREE_PART_NEXT_DAY_RETURN_URL("threePartNextDayReturnUrl", "三方支付GET请求", 61),
THREE_PART_NEXT_DAY_RETURN_URL("threePartNextDayReturnUrl", "三方支付【隔天退费】请求路径", 70),
/**
* 三方支付(隔天退费)
*/
THREE_PART_NEXT_DAY_RETURN_STATIC_PARAM("threePartNextDayReturnStaticParam", "三方支付【隔天退费】固定参数", 71),
/**
* 三方支付(隔天退费)
*/
THREE_PART_NEXT_DAY_RETURN_ACTIVE_PARAM("threePartNextDayReturnActiveParam", "三方支付【隔天退费】可变参数", 72),
/**
* 三方支付(隔天退费)
*/
THREE_PART_NEXT_DAY_RETURN_MAPPING_METHOD("threePartNextDayReturnMappingMethod", "三方支付【隔天退费】请求方式", 73),
/**
* 三方支付路径(支付结果查询)
*/
THREE_PART_PAY_QUERY_URL("threePartPayQueryUrl", "三方支付GET请求", 62),
THREE_PART_PAY_QUERY_URL("threePartPayQueryUrl", "三方支付【支付结果查询】请求路径", 74),
/**
* 三方支付(支付结果查询)
*/
THREE_PART_PAY_QUERY_STATIC_PARAM("threePartPayQueryStaticParam", "三方支付【支付结果查询】固定参数", 75),
/**
* 三方支付(支付结果查询)
*/
THREE_PART_PAY_QUERY_ACTIVE_PARAM("threePartPayQueryActiveParam", "三方支付【支付结果查询】可变参数", 76),
/**
* 三方支付(支付结果查询)
*/
THREE_PART_PAY_QUERY_MAPPING_METHOD("threePartPayQueryMappingMethod", "三方支付【支付结果查询】请求方式", 77),
/**
* 三方支付路径(退费结果查询)
*/
THREE_PART_RETURN_QUERY_URL("threePartReturnQueryUrl", "三方支付GET请求", 63),
THREE_PART_RETURN_QUERY_URL("threePartReturnQueryUrl", "三方支付【退费结果查询】请求路径", 78),
/**
* 三方支付(退费结果查询)
*/
THREE_PART_RETURN_QUERY_STATIC_PARAM("threePartReturnQueryStaticParam", "三方支付【退费结果查询】固定参数", 79),
/**
* 三方支付(退费结果查询)
*/
THREE_PART_RETURN_QUERY_ACTIVE_PARAM("threePartReturnQueryActiveParam", "三方支付【退费结果查询】可变参数", 80),
/**
* 三方支付(退费结果查询)
*/
THREE_PART_RETURN_QUERY_MAPPING_METHOD("threePartReturnQueryMappingMethod", "三方支付【退费结果查询】请求方式", 81),
/**
* 三方支付路径(隔天退费结果查询)
*/
THREE_PART_NEXT_DAY_RETURN_QUERY_URL("threePartNextDayReturnQueryUrl", "三方支付GET请求", 64),
THREE_PART_NEXT_DAY_RETURN_QUERY_URL("threePartNextDayReturnQueryUrl", "三方支付【隔天退费结果查询】请求路径", 82),
/**
* 三方支付参数
* 三方支付(隔天退费结果查询)
*/
THREE_PART_PARAM("threePartParam", "三方支付GET请求", 65);
THREE_PART_NEXT_DAY_RETURN_QUERY_STATIC_PARAM("threePartNextDayReturnQueryStaticParam", "三方支付【隔天退费结果查询】固定参数", 83),
/**
* 三方支付(隔天退费结果查询)
*/
THREE_PART_NEXT_DAY_RETURN_QUERY_ACTIVE_PARAM("threePartNextDayReturnQueryActiveParam", "三方支付【隔天退费结果查询】可变参数", 84),
/**
* 三方支付(隔天退费结果查询)
*/
THREE_PART_NEXT_DAY_RETURN_QUERY_MAPPING_METHOD("threePartNextDayReturnQueryMappingMethod", "三方支付【隔天退费结果查询】请求方式",
85),
/**
* 三方支付(签出)
*/
THREE_PART_SIGN_OUT_URL("threePartSignOutUrl", "三方支付【签出】请求路径", 86),
/**
* 三方支付(签出)
*/
THREE_PART_SIGN_OUT_STATIC_PARAM("threePartSignOutStaticParam", "三方支付【签出】固定参数", 87),
/**
* 三方支付(签出)
*/
THREE_PART_SIGN_OUT_ACTIVE_PARAM("threePartSignOutActiveParam", "三方支付【签出】可变参数", 88),
/**
* 三方支付(签出)
*/
THREE_PART_SIGN_OUT_MAPPING_METHOD("threePartSignOutMappingMethod", "三方支付【签出】请求方式", 89),
/**
* 三方支付(签出)
*/
YB_INPATIENT_SETTLEMENT_UP_URL("ybInpatientSetlUp", "选填4101或4101A", 90),
/**
* PACS查看报告地址
*/
PACS_REPORT_URL("pacsReportUrl", "PACS查看报告地址", 91),
/**
* LIS查看报告地址
*/
LIS_REPORT_URL("lisReportUrl", "LIS查看报告地址", 92),
/**
* 开药时药房允许多选开关
*/
PHARMACY_MULTIPLE_CHOICE_SWITCH("pharmacyMultipleChoiceSwitch", "开药时药房允许多选开关", 93),
/**
* PEIS服务地址
*/
PEIS_SERVER_URL("peisServerUrl", "PEIS服务地址", 94);
private final String code;
private final String name;

View File

@@ -21,7 +21,7 @@ public final class ServiceException extends RuntimeException {
/**
* 错误明细,内部调试错误
*
* 和 {@link CommonResult#getDetailMessage()} 一致的设计
* 和
*/
private String detailMessage;

View File

@@ -1,13 +1,11 @@
package com.core.common.filter;
import java.io.IOException;
import com.core.common.utils.StringUtils;
import org.springframework.http.MediaType;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.MediaType;
import com.core.common.utils.StringUtils;
import java.io.IOException;
/**
* Repeatable 过滤器

View File

@@ -1,18 +1,17 @@
package com.core.common.filter;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import com.core.common.constant.Constants;
import com.core.common.utils.http.HttpHelper;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import com.core.common.constant.Constants;
import com.core.common.utils.http.HttpHelper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 构建可重复读取inputStream的request

View File

@@ -1,15 +1,14 @@
package com.core.common.filter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import com.core.common.enums.HttpMethod;
import com.core.common.utils.StringUtils;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.core.common.enums.HttpMethod;
import com.core.common.utils.StringUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 防止XSS攻击的过滤器

View File

@@ -1,19 +1,17 @@
package com.core.common.filter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import com.core.common.utils.StringUtils;
import com.core.common.utils.html.EscapeUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.commons.io.IOUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import com.core.common.utils.StringUtils;
import com.core.common.utils.html.EscapeUtil;
import java.io.ByteArrayInputStream;
import java.io.IOException;
/**
* XSS过滤处理

View File

@@ -0,0 +1,50 @@
package com.core.common.service;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.core.common.utils.AuditFieldUtil;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
/**
* 包含审计字段自动设置功能的基础服务类
*
* @param <M> Mapper 类型,必须继承 BaseMapper<T>
* @param <T> 实体类型
*/
public abstract class BaseService<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> {
/**
* 重写保存方法,自动设置创建审计字段
*/
@Override
@Transactional
public boolean save(T entity) {
// 在保存前设置创建审计字段
AuditFieldUtil.setCreateInfo(entity);
return super.save(entity);
}
/**
* 重写批量保存方法,自动设置创建审计字段
*/
@Override
@Transactional
public boolean saveBatch(Collection<T> entityList) {
// 为每个实体设置创建审计字段
entityList.forEach(AuditFieldUtil::setCreateInfo);
return super.saveBatch(entityList);
}
/**
* 重写更新方法,自动设置更新审计字段
*/
@Override
@Transactional
public boolean updateById(T entity) {
// 在更新前设置更新审计字段
AuditFieldUtil.setUpdateInfo(entity);
return super.updateById(entity);
}
}

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