后端最新版本同步

This commit is contained in:
Zhang.WH
2025-09-25 10:43:25 +08:00
parent 1276dc4adb
commit c8014404f1
355 changed files with 10070 additions and 5578 deletions

View File

@@ -26,6 +26,8 @@ public interface IDocDefinitionAppService {
*/
R<?> updateDefinition(DocDefinitionDto definitionDto);
R<?> deleteDefinition(Long id);
/**
* 获取文书定义列表 树形结构
*

View File

@@ -28,7 +28,7 @@ public interface IDocRecordAppService {
/**
* 根据患者ID或就诊ID获取文书记录列表,只针对不需返回患者具体信息的列表,体温单除外,单独处理
*/
R<?> getRecordByEncounterIdList(DocRecordQueryParam docRecordQueryParam, Integer IsPage, Integer pageNo, Integer pageSize, String searchKey, HttpServletRequest request);
R<?> getRecordByEncounterIdList(DocRecordQueryParam docRecordQueryParam, Integer isPage, Integer pageNo, Integer pageSize, String searchKey, HttpServletRequest request);
R<?> getRecordPageList(DocRecordPatientQueryParam docRecordPatientQueryParam, List<Integer> primaryMenuEnumList, Integer pageNo, Integer pageSize, String searchKey, HttpServletRequest request);

View File

@@ -2,8 +2,11 @@ package com.openhis.web.document.appservice;
import com.core.common.core.domain.R;
import com.openhis.document.domain.DocStatistics;
import com.openhis.web.document.dto.DocRecordQueryParam;
import com.openhis.web.document.dto.DocStatisticsDto;
import com.openhis.web.document.dto.DocStatisticsQueryParam;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
@@ -20,4 +23,6 @@ public interface IDocStatisticsAppService {
public R<?> queryByEncounterId(Long encounterId);
R<?> getStatisticsList(DocStatisticsQueryParam queryParam, Integer isPage, Integer pageNo, Integer pageSize, String searchKey, HttpServletRequest request);
}

View File

@@ -58,6 +58,9 @@ public class DocDefinitionAppServiceImpl implements IDocDefinitionAppService {
if (definitionDto.getVueRouter() == null || definitionDto.getVueRouter().trim().isEmpty()) {
return R.fail("新增文书定义失败:文书路由不能为空(或不能为空白字符)");
}
if (definitionDto.getUseRangeEnum() != null && DocUseRangeEnum.DEPT_USE.getValue().equals(definitionDto.getUseRangeEnum()) && definitionDto.getOrganizationIds() == null) {
return R.fail("新增文书定义失败:科室分配时,科室不能为空");
}
// 2. 校验"名称+版本号"唯一性(避免重复创建)
long duplicateCount = docDefinitionService.lambdaQuery()
@@ -146,7 +149,9 @@ public class DocDefinitionAppServiceImpl implements IDocDefinitionAppService {
if (definitionDto.getBusNo() == null || definitionDto.getBusNo().trim().isEmpty()) {
return R.fail("修改文书定义失败:文书业务编号不能为空(或不能为空白字符)");
}
if (definitionDto.getUseRangeEnum() != null && DocUseRangeEnum.DEPT_USE.getValue().equals(definitionDto.getUseRangeEnum()) && definitionDto.getOrganizationIds() == null) {
return R.fail("修改文书定义失败:科室分配时,科室不能为空");
}
// 2. 校验文书是否存在
DocDefinition existingDoc = docDefinitionService.getById(definitionDto.getId());
if (existingDoc == null) {
@@ -193,15 +198,31 @@ public class DocDefinitionAppServiceImpl implements IDocDefinitionAppService {
log.error("修改文书定义失败数据库更新异常ID={}, 业务编号={}",
definitionDto.getId(), definitionDto.getBusNo());
return R.fail("修改文书定义失败:数据库更新操作异常");
} else {
// 7. 更新科室分配(仅当使用范围为"科室级"时执行)
DocDefinitionOrganizationDto orgDto = new DocDefinitionOrganizationDto();
orgDto.setBusNo(existingDoc.getBusNo());
orgDto.setDefinitionId(existingDoc.getId());
orgDto.setOrganizationIds(definitionDto.getOrganizationIds());
// 复用科室分配服务的更新逻辑(先删后加,全量覆盖)
return docDefinitionOrganizationAppService.updateOrganization(orgDto);
}
}
// 7. 更新科室分配(仅当使用范围为"科室级"时执行)
DocDefinitionOrganizationDto orgDto = new DocDefinitionOrganizationDto();
orgDto.setBusNo(existingDoc.getBusNo());
orgDto.setDefinitionId(existingDoc.getId());
orgDto.setOrganizationIds(definitionDto.getOrganizationIds());
// 复用科室分配服务的更新逻辑(先删后加,全量覆盖)
return docDefinitionOrganizationAppService.updateOrganization(orgDto);
@Override
public R<?> deleteDefinition(Long id) {
// 1. 参数校验
if (id == null) {
return R.fail("删除文书定义失败文书ID不能为空");
}
boolean result = docDefinitionService.removeById(id);
if (result) {
log.info("删除文书定义成功ID={}", id);
return R.ok("删除文书定义成功");
} else {
log.error("删除文书定义失败数据库删除异常ID={})", id);
return R.fail("删除文书定义失败:数据库删除操作异常");
}
}
/**

View File

@@ -129,9 +129,6 @@ public class DocDefinitionOrganizationAppServiceImpl implements IDocDefinitionOr
if (definitionOrganizationDto == null) {
return R.fail("文书科室分配更新失败:请求参数不能为空");
}
if (definitionOrganizationDto.getOrganizationIds() == null || definitionOrganizationDto.getOrganizationIds().isEmpty()) {
return R.fail("文书科室分配更新失败科室ID列表不能为空");
}
if (definitionOrganizationDto.getDefinitionId() == null || definitionOrganizationDto.getDefinitionId() == 0) {
return R.fail("文书科室分配更新失败文书定义ID不能为空或不能为0");
}
@@ -140,34 +137,38 @@ public class DocDefinitionOrganizationAppServiceImpl implements IDocDefinitionOr
}
// 2. 先删除原有分配关系
LambdaQueryWrapper<DocDefinitionOrganization> deleteWrapper = new LambdaQueryWrapper<>();
deleteWrapper.eq(DocDefinitionOrganization::getDefinitionId, definitionOrganizationDto.getDefinitionId())
LambdaQueryWrapper<DocDefinitionOrganization> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DocDefinitionOrganization::getDefinitionId, definitionOrganizationDto.getDefinitionId())
.eq(DocDefinitionOrganization::getBusNo, definitionOrganizationDto.getBusNo().trim());
boolean deleteSuccess = docDefinitionOrganizationService.remove(deleteWrapper);
if (!deleteSuccess) {
log.error("文书科室分配更新失败删除原有分配记录异常文书定义ID={}, 业务编号={}",
definitionOrganizationDto.getDefinitionId(), definitionOrganizationDto.getBusNo());
return R.fail("文书科室分配更新失败:删除原有分配记录异常");
Long count = docDefinitionOrganizationService.count(wrapper);
if (count > 0) {
boolean deleteSuccess = docDefinitionOrganizationService.remove(wrapper);
if (!deleteSuccess) {
log.error("文书科室分配更新失败删除原有分配记录异常文书定义ID={}, 业务编号={}",
definitionOrganizationDto.getDefinitionId(), definitionOrganizationDto.getBusNo());
return R.fail("文书科室分配更新失败:删除原有分配记录异常");
}
}
// 3. 再新增新的分配关系
List<DocDefinitionOrganization> newOrgList = new ArrayList<>();
for (Long orgId : definitionOrganizationDto.getOrganizationIds()) {
DocDefinitionOrganization docOrg = new DocDefinitionOrganization();
docOrg.setDefinitionId(definitionOrganizationDto.getDefinitionId());
docOrg.setBusNo(definitionOrganizationDto.getBusNo().trim());
docOrg.setOrganizationId(orgId);
newOrgList.add(docOrg);
}
boolean saveSuccess = docDefinitionOrganizationService.saveBatch(newOrgList);
if (saveSuccess) {
if (definitionOrganizationDto.getOrganizationIds() == null || definitionOrganizationDto.getOrganizationIds().isEmpty()) {
return R.ok("文书科室分配更新成功");
} else {
log.error("文书科室分配更新失败:新增新分配记录异常文书定义ID={}, 业务编号={}",
definitionOrganizationDto.getDefinitionId(), definitionOrganizationDto.getBusNo());
return R.fail("文书科室分配更新失败:新增新分配记录异常");
// 3. 再新增新分配关系
List<DocDefinitionOrganization> newOrgList = new ArrayList<>();
for (Long orgId : definitionOrganizationDto.getOrganizationIds()) {
DocDefinitionOrganization docOrg = new DocDefinitionOrganization();
docOrg.setDefinitionId(definitionOrganizationDto.getDefinitionId());
docOrg.setBusNo(definitionOrganizationDto.getBusNo().trim());
docOrg.setOrganizationId(orgId);
newOrgList.add(docOrg);
}
boolean saveSuccess = docDefinitionOrganizationService.saveBatch(newOrgList);
if (saveSuccess) {
return R.ok("文书科室分配更新成功");
} else {
log.error("文书科室分配更新失败新增新分配记录异常文书定义ID={}, 业务编号={}",
definitionOrganizationDto.getDefinitionId(), definitionOrganizationDto.getBusNo());
return R.fail("文书科室分配更新失败:新增新分配记录异常");
}
}
}
}

View File

@@ -1,5 +1,8 @@
package com.openhis.web.document.appservice.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -19,15 +22,15 @@ import com.openhis.document.mapper.DocRecordMapper;
import com.openhis.document.service.IDocRecordService;
import com.openhis.web.document.appservice.IDocDefinitionAppService;
import com.openhis.web.document.appservice.IDocRecordAppService;
import com.openhis.web.document.dto.DocDefinitionDto;
import com.openhis.web.document.dto.DocRecordDto;
import com.openhis.web.document.dto.DocRecordPatientDto;
import com.openhis.web.document.dto.DocRecordPatientQueryParam;
import com.openhis.web.document.dto.DocRecordQueryParam;
import com.openhis.web.document.appservice.IDocStatisticsAppService;
import com.openhis.web.document.appservice.IDocStatisticsDefinitionAppService;
import com.openhis.web.document.dto.*;
import com.openhis.web.document.mapper.DocRecordAppMapper;
import com.openhis.web.document.util.ConvertToDocStatistics;
import com.openhis.web.document.util.PermissionProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;
@@ -37,6 +40,9 @@ import javax.servlet.http.HttpServletRequest;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@Slf4j
@@ -51,6 +57,12 @@ public class DocRecordAppServiceImpl implements IDocRecordAppService {
private IDocDefinitionAppService docDefinitionAppService;
@Resource
private DocRecordAppMapper docRecordAppMapper;
@Resource
private IDocStatisticsDefinitionAppService docStatisticsDefinitionAppService;
@Resource
private IDocStatisticsAppService docStatisticsAppService;
@Resource
ConvertToDocStatistics convertToDocStatistics;
@Autowired
private JdbcTemplate jdbcTemplate; // 使用 JdbcTemplate 执行 SQL
@@ -198,6 +210,27 @@ public class DocRecordAppServiceImpl implements IDocRecordAppService {
return "";
}
/**
* 文书统计 - 新增、编辑记录
*
* @param docRecordDto
* @return
*/
private R<?> createOrUpdateStatistics(DocRecordDto docRecordDto) {
if (docRecordDto == null) {
return R.fail("插入文书统计数据失败:原始文书记录不能为空");
}
if (docRecordDto.getContentJson() == null) {
return R.fail("插入文书统计数据失败:原始文书记录内容不能为空");
}
List<DocStatisticsDto> list = convertToDocStatistics.convertToStatisticsDtoList(docRecordDto);
if (list == null || list.isEmpty()) {
return R.fail("插入文书统计数据失败:统计数据为空");
}
return docStatisticsAppService.createOrUpdte(list);
}
/**
* 新增记录
*
@@ -213,7 +246,6 @@ public class DocRecordAppServiceImpl implements IDocRecordAppService {
docRecord.setDefinitionId(docRecordDto.getDefinitionId());
docRecord.setDefinitionBusNo(docRecordDto.getDefinitionBusNo());
docRecord.setContentJson(docRecordDto.getContentJson());
// 状态默认设为草稿(修复原逻辑:原代码先判断再覆盖,导致默认值无效)
docRecord.setStatusEnum(docRecordDto.getStatusEnum() == null ? DocStatusEnum.DRAFT.getValue() : docRecordDto.getStatusEnum());
docRecord.setOrganizationId(SecurityUtils.getLoginUser().getOrgId());
docRecord.setEncounterId(docRecordDto.getEncounterId());
@@ -222,6 +254,8 @@ public class DocRecordAppServiceImpl implements IDocRecordAppService {
docRecord.setIsEdit(0);
boolean saveSuccess = docRecordService.save(docRecord);
if (saveSuccess) {
docRecordDto.setId(docRecord.getId());
createOrUpdateStatistics(docRecordDto);
return R.ok("新增患者文书记录成功");
} else {
return R.fail("新增患者文书记录失败");
@@ -259,7 +293,6 @@ public class DocRecordAppServiceImpl implements IDocRecordAppService {
docRecord.setPatientId(docRecordDto.getPatientId());
docRecord.setRecordTime(docRecordDto.getRecordTime());
docRecord.setIsEdit(0);
// 执行修改
boolean updateSuccess = docRecordService.updateById(docRecord);
if (updateSuccess) {
@@ -268,6 +301,7 @@ public class DocRecordAppServiceImpl implements IDocRecordAppService {
if (!logSuccess) {
return R.fail("修改患者文书记录成功,但插入文档操作日志失败");
}
createOrUpdateStatistics(docRecordDto);
return R.ok("修改患者文书记录成功");
} else {
return R.fail("修改患者文书记录失败");
@@ -287,19 +321,16 @@ public class DocRecordAppServiceImpl implements IDocRecordAppService {
return R.fail("患者文书记录患者ID和就诊ID不能同时为空");
}
if (docRecordQueryParam.getDefinitionId() == null) {
return R.fail("患者文书记录文书类型ID不能为空");
return R.fail("患者文书记录:文书类型(定义)ID不能为空");
}
// 2. 分页查询逻辑
if (isPage != null && isPage == 1) {
QueryWrapper<DocRecord> queryWrapper = HisQueryUtils.buildQueryWrapper(
QueryWrapper<DocRecordDto> queryWrapper = HisQueryUtils.buildQueryWrapper(
docRecordQueryParam, null, null, request);
// 按记录时间倒序(最新记录在前)
queryWrapper.lambda().orderByDesc(DocRecord::getRecordTime);
Page<DocRecordDto> recordPage = HisPageUtils.selectPage(
docRecordMapper, queryWrapper, pageNo, pageSize, DocRecordDto.class);
return R.ok(recordPage, "获取患者文书记录列表成功");
IPage<DocRecordDto> pageResult = docRecordAppMapper.getRecordPageListByEncounterId(
new Page<>(pageNo, pageSize), queryWrapper);
return R.ok(pageResult, "获取患者文书记录列表成功");
}
// 3. 不分页查询逻辑
else {
@@ -319,12 +350,15 @@ public class DocRecordAppServiceImpl implements IDocRecordAppService {
queryWrapper.eq(DocRecord::getOrganizationId, docRecordQueryParam.getOrganizationId());
}
DocDefinitionDto docDefinitionDto = docDefinitionAppService.getDefinitionById(docRecordQueryParam.getDefinitionId());
// 实体转DTO
List<DocRecordDto> dtoList = new ArrayList<>();
List<DocRecord> recordList = docRecordService.list(queryWrapper);
for (DocRecord record : recordList) {
DocRecordDto dto = new DocRecordDto();
BeanUtils.copyProperties(record, dto);
dto.setName(docDefinitionDto!=null?docDefinitionDto.getName():"");
dto.setVersion(docDefinitionDto!=null?docDefinitionDto.getVersion():"");
dtoList.add(dto);
}
return R.ok(dtoList, "获取患者文书记录列表成功");

View File

@@ -1,16 +1,25 @@
package com.openhis.web.document.appservice.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.core.common.utils.SecurityUtils;
import com.core.common.utils.bean.BeanUtils;
import com.openhis.common.utils.HisPageUtils;
import com.openhis.common.utils.HisQueryUtils;
import com.openhis.document.domain.DocStatistics;
import com.openhis.document.mapper.DocStatisticsMapper;
import com.openhis.document.service.IDocStatisticsService;
import com.openhis.web.document.appservice.IDocStatisticsAppService;
import com.openhis.web.document.appservice.IDocTemplateAppService;
import com.openhis.web.document.dto.DocStatisticsDto;
import com.openhis.web.document.dto.DocStatisticsQueryParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
/**
@@ -22,6 +31,9 @@ public class DocStatisticsAppServiceImpl implements IDocStatisticsAppService {
@Resource
private IDocStatisticsService docStatisticsService;
@Resource
private DocStatisticsMapper docStatisticsMapper;
@Override
public R<?> createOrUpdte(List<DocStatisticsDto> docStatisticsList) {
@@ -31,12 +43,13 @@ public class DocStatisticsAppServiceImpl implements IDocStatisticsAppService {
//根据recordId和statisticDefinitionId判断是否存在存在则更新不存在则新增
LambdaQueryWrapper<DocStatistics> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(DocStatistics::getRecordId, docStatisticsList.get(0).getRecordId());
queryWrapper.eq(DocStatistics::getStatisticDefinitionId, docStatisticsList.get(0).getStatisticDefinitionId());
// queryWrapper.eq(DocStatistics::getStatisticDefinitionId, docStatisticsList.get(0).getStatisticDefinitionId());
List<DocStatistics> docStatisticsOldList = docStatisticsService.list(queryWrapper);
if (docStatisticsOldList.size() > 0) {
//批量删除
docStatisticsService.removeByIds(docStatisticsOldList.stream().map(DocStatistics::getId).toList());
}
List<DocStatistics> docStatisticsInsertList = new ArrayList<>();
//批量新增
for (DocStatisticsDto docStatisticsDto : docStatisticsList) {
DocStatistics docStatistics = new DocStatistics();
@@ -45,13 +58,18 @@ public class DocStatisticsAppServiceImpl implements IDocStatisticsAppService {
docStatistics.setEncounterId(docStatisticsDto.getEncounterId());
docStatistics.setPatientId(docStatisticsDto.getPatientId());
docStatistics.setStatisticDefinitionCode(docStatisticsDto.getStatisticDefinitionCode());
docStatistics.setOrgnizationId(docStatisticsDto.getOrgnizationId()); //TODO: 待确定
docStatistics.setOrganizationId(SecurityUtils.getLoginUser().getOrgId());
docStatistics.setValue(docStatisticsDto.getValue());
docStatistics.setRecordingDate(docStatisticsDto.getRecordingDate());
docStatistics.setRecordingTime(docStatisticsDto.getRecordingTime());
docStatistics.setRecordTime(docStatisticsDto.getRecordTime());
docStatistics.setSource(docStatisticsDto.getSource());
docStatisticsInsertList.add(docStatistics);
}
boolean result = docStatisticsService.saveBatch(docStatisticsInsertList);
if (result) {
return R.ok();
} else {
return R.fail("新增或更新文档统计数据失败");
}
return null;
}
@Override
@@ -66,6 +84,68 @@ public class DocStatisticsAppServiceImpl implements IDocStatisticsAppService {
@Override
public R<?> queryByEncounterId(Long encounterId) {
return null;
LambdaQueryWrapper<DocStatistics> queryWrapper = new LambdaQueryWrapper();
queryWrapper.eq(DocStatistics::getEncounterId, encounterId);
List<DocStatistics> docStatisticsList = docStatisticsService.list(queryWrapper);
List<DocStatisticsDto> docStatisticsDtoList = new ArrayList<>();
for (DocStatistics docStatistics : docStatisticsList) {
DocStatisticsDto docStatisticsDto = new DocStatisticsDto();
docStatisticsDto.setId(docStatistics.getId());
docStatisticsDto.setRecordId(docStatistics.getRecordId());
docStatisticsDto.setStatisticDefinitionId(docStatistics.getStatisticDefinitionId());
docStatisticsDto.setEncounterId(docStatistics.getEncounterId());
docStatisticsDto.setPatientId(docStatistics.getPatientId());
docStatisticsDto.setStatisticDefinitionCode(docStatistics.getStatisticDefinitionCode());
docStatisticsDto.setOrganizationId(docStatistics.getOrganizationId());
docStatisticsDto.setValue(docStatistics.getValue());
docStatisticsDto.setRecordTime(docStatistics.getRecordTime());
docStatisticsDto.setSource(docStatistics.getSource());
docStatisticsDtoList.add(docStatisticsDto);
}
return R.ok(docStatisticsDtoList);
}
@Override
public R<?> getStatisticsList(DocStatisticsQueryParam queryParam, Integer isPage, Integer pageNo, Integer pageSize, String searchKey, HttpServletRequest request) {
// 1. 分页查询逻辑
if (isPage != null && isPage == 1) {
QueryWrapper<DocStatistics> queryWrapper = HisQueryUtils.buildQueryWrapper(
queryParam, null, null, request);
// 按记录时间倒序(最新记录在前)
queryWrapper.lambda().orderByDesc(DocStatistics::getRecordTime);
Page<DocStatisticsDto> recordPage = HisPageUtils.selectPage(
docStatisticsMapper, queryWrapper, pageNo, pageSize, DocStatisticsDto.class);
return R.ok(recordPage, "获取患者文书统计数据成功");
}
//2. 不分页查询逻辑
else {
LambdaQueryWrapper<DocStatistics> queryWrapper = new LambdaQueryWrapper<>();
// 患者ID查询条件
if (queryParam.getPatientId() != null) {
queryWrapper.eq(DocStatistics::getPatientId, queryParam.getPatientId());
}
// 就诊ID查询条件修复原逻辑原代码字段匹配错误用EncounterId匹配DefinitionBusNo
if (queryParam.getEncounterId() != null) {
queryWrapper.eq(DocStatistics::getEncounterId, queryParam.getEncounterId());
}
// 科室ID查询条件修复原逻辑原代码字段匹配错误用OrganizationId匹配EncounterId
if (queryParam.getOrganizationId() != null) {
queryWrapper.eq(DocStatistics::getOrganizationId, queryParam.getOrganizationId());
}
if (queryParam.getStatisticsDefinitionCode() != null) {
queryWrapper.eq(DocStatistics::getStatisticDefinitionCode, queryParam.getStatisticsDefinitionCode());
}
// 实体转DTO
List<DocStatisticsDto> dtoList = new ArrayList<>();
List<DocStatistics> statisticsList = docStatisticsService.list(queryWrapper);
for (DocStatistics statistics : statisticsList) {
DocStatisticsDto dto = new DocStatisticsDto();
BeanUtils.copyProperties(statistics, dto);
dtoList.add(dto);
}
return R.ok(dtoList, "获取患者文书统计数据成功");
}
}
}

View File

@@ -84,6 +84,19 @@ public class DocDefinitionController {
return iDocDefinitionAppService.getDefinitionDetailById(id);
}
/**
* 获取文书定义详情
*
* @param id 文书定义ID
* @return 文书定义详情
*/
@DeleteMapping("/delete/{id}")
public R<?> deleteDefinition(@PathVariable("id") Long id) {
log.info("删除文书定义ID={}", id);
// 调用删除服务注意方法名应改为删除相关如removeById
return iDocDefinitionAppService.deleteDefinition(id);
}
/**
* 查询获取文书定义列表 树形结构
*

View File

@@ -90,11 +90,11 @@ public class DocRecordController {
*/
@GetMapping("/getRecordByEncounterIdList")
R<?> getRecordByEncounterIdList(DocRecordQueryParam docRecordQueryParam,
@RequestParam(value = "IsPage", defaultValue = "1") Integer IsPage,
@RequestParam(value = "isPage", defaultValue = "1") Integer isPage,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) {
return docRecordAppService.getRecordByEncounterIdList(docRecordQueryParam, IsPage, pageNo, pageSize, searchKey, request);
return docRecordAppService.getRecordByEncounterIdList(docRecordQueryParam, isPage, pageNo, pageSize, searchKey, request);
}
/**

View File

@@ -1,24 +1,59 @@
package com.openhis.web.document.controller;
import com.core.common.core.domain.R;
import com.openhis.web.document.appservice.IDocRecordAppService;
import com.openhis.web.document.appservice.IDocStatisticsAppService;
import com.openhis.web.document.dto.DocStatisticsDto;
import com.openhis.web.document.dto.DocStatisticsQueryParam;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* 文档模板-病历另存为模板使用 controller
* DocStatistics文书统计 controller
*
* @author wanghaiming
* @date 2025-08-12
*/
@RestController
@RequestMapping("/document/template")
@RequestMapping("/document/statistics")
@Slf4j
@AllArgsConstructor
public class DocStatisticsController {
private final IDocRecordAppService docRecordAppService;
private final IDocStatisticsAppService docStatisticsAppService;
@PostMapping("/createOrUpdte")
public R<?> createOrUpdte(List<DocStatisticsDto> docStatisticsList) {
return docStatisticsAppService.createOrUpdte(docStatisticsList);
}
@DeleteMapping("/delete")
public R<?> delete(List<Long> ids) {
return docStatisticsAppService.delete(ids);
}
@GetMapping("/queryByRecordId")
public R<?> queryByRecordId(Long recordId) {
return docStatisticsAppService.queryByRecordId(recordId);
}
@GetMapping("/queryByEncounterId")
public R<?> queryByEncounterId(Long encounterId) {
return docStatisticsAppService.queryByEncounterId(encounterId);
}
@GetMapping("/getStatisticsList")
R<?> getStatisticsList(DocStatisticsQueryParam queryParam,
@RequestParam(value = "isPage", defaultValue = "1") Integer isPage,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(name = "searchKey", required = false) String searchKey, HttpServletRequest request) {
return docStatisticsAppService.getStatisticsList(queryParam, isPage, pageNo, pageSize, searchKey, request);
}
}

View File

@@ -18,7 +18,7 @@ import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletRequest;
/**
* DOC模板 controller
* 文书模板 controller
*
* @author wanghaiming
* @date 2025-08-12

View File

@@ -1,5 +1,7 @@
package com.openhis.web.document.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.experimental.Accessors;
@@ -12,6 +14,8 @@ public class DirectoryNode {
private String name;
private int level;
private DocDefinitionDto document;
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
private List<DirectoryNode> children = new ArrayList<>();
}

View File

@@ -81,5 +81,7 @@ public class DocDefinitionDto {
* 文书权限 0-不限制 1-查看 2- 编辑
*/
private Integer pharmacistPermissionEnum;
// 关键通过contentUsing指定集合中元素的序列化器
@JsonSerialize(contentUsing = ToStringSerializer.class)
private List<Long> organizationIds;
}

View File

@@ -19,6 +19,6 @@ public class DocDefinitionOrganizationDto {
@JsonSerialize(using = ToStringSerializer.class)
private Long definitionId;
private String busNo;
@JsonSerialize(using = ToStringSerializer.class)
@JsonSerialize(contentUsing = ToStringSerializer.class)
private List<Long> organizationIds;
}

View File

@@ -17,8 +17,5 @@ public class DocDefinitonParam {
@JsonSerialize(using = ToStringSerializer.class)
private Long organizationId;
private String name;
@JsonSerialize(using = ToStringSerializer.class)
private List<Integer> useRanges;
}

View File

@@ -53,4 +53,10 @@ public class DocRecordDto {
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date recordTime;
private String createBy;
private String source;
/**
* 记录名称
*/
private String name;
private String version;
}

View File

@@ -60,7 +60,7 @@ public class DocRecordPatientDto extends DocRecordDto {
/**
* 病历名称
*/
private String docName;
private String name;
/**
* 主菜单枚举值/病历类型

View File

@@ -1,9 +1,11 @@
package com.openhis.web.document.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.experimental.Accessors;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
@@ -15,6 +17,7 @@ public class DocStatisticsDto {
/**
* 记录ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long recordId;
/**
* 统计项定义ID
@@ -33,19 +36,18 @@ public class DocStatisticsDto {
* 记录科室ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long orgnizationId;
private Long organizationId;
/**
* 统计值
*/
private String value;
/**
* 记录日期 yyyy-MM-dd
* 记录时间
*/
private Date recordingDate;
/**
* 记录时间 yyyy-MM-dd HH:mm:ss
*/
private Date recordingTime;
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date recordTime;
/**
* 记录来源
*/

View File

@@ -0,0 +1,30 @@
package com.openhis.web.document.dto;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* 查询单个患者的文档记录参数
*/
@Data
@Accessors(chain = true)
public class DocStatisticsQueryParam {
@JsonSerialize(using = ToStringSerializer.class)
private Long definitionId;
@JsonSerialize(using = ToStringSerializer.class)
private Long patientId;
@JsonSerialize(using = ToStringSerializer.class)
private Long encounterId;
@JsonSerialize(using = ToStringSerializer.class)
private Long organizationId;
private String statisticsDefinitionCode;
/**
* 记录时间 yyyy-MM-dd HH:mm:ss
*/
private Date recordTime;
}

View File

@@ -28,6 +28,7 @@ public class DocTemplateDto {
/**
* 文书定义ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long definitionId;
/**
@@ -37,10 +38,12 @@ public class DocTemplateDto {
/**
* 当useRange=1时指定机构ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long organizationId;
/**
* 当useRange=2时指定用户ID
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long userId;
/**
* 备注

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.openhis.web.document.dto.DocRecordDto;
import com.openhis.web.document.dto.DocRecordPatientDto;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
@@ -23,4 +24,7 @@ public interface DocRecordAppMapper {
IPage<DocRecordPatientDto> getRecordPageList(@Param("page") Page<DocRecordPatientDto> page,
@Param("primaryMenuEnumList") List<Integer> primaryMenuEnumList,
@Param(Constants.WRAPPER) QueryWrapper<DocRecordPatientDto> queryWrapper);
IPage<DocRecordDto> getRecordPageListByEncounterId(@Param("page") Page<DocRecordPatientDto> page,
@Param(Constants.WRAPPER) QueryWrapper<DocRecordDto> queryWrapper);
}

View File

@@ -0,0 +1,171 @@
package com.openhis.web.document.util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.openhis.web.document.appservice.IDocStatisticsDefinitionAppService;
import com.openhis.web.document.dto.DocRecordDto;
import com.openhis.web.document.dto.DocStatisticsDefinitionDto;
import com.openhis.web.document.dto.DocStatisticsDto;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import static com.core.framework.datasource.DynamicDataSourceContextHolder.log;
@Component
public class ConvertToDocStatistics {
@Resource
IDocStatisticsDefinitionAppService docStatisticsDefinitionAppService;
/**
* 将文档记录转换为统计DTO列表的工具方法
* 支持两种JSON结构
* 1. 简单键值对:{"目标code": 值, "recordTime": "yyyy-MM-dd HH:mm:ss"}
* 2. 嵌套Item列表{"目标code+Item": [{"目标code": 值1}, {"目标code": 值2}],"recordTime": "yyyy-MM-dd HH:mm:ss"}
* 3. 记录 Time 字段:{"目标code+Item": [{"目标code": 值1, "recordTime": "yyyy-MM-dd HH:mm:ss"}, {"目标code": 值2, "recordTime": "yyyy-MM-dd HH:mm:ss"}]}
* 4. 记录 Time 字段:{"目标code": 值, "recordTime": "yyyy-MM-dd HH:mm:ss", "目标code+Item": [{"目标code": 值1, "recordTime": "yyyy-MM-dd HH:mm:ss"}, {"目标code": 值2, "recordTime": "yyyy-MM-dd HH:mm:ss"}]}
* 日期类型使用java.util.Date
*/
public List<DocStatisticsDto> convertToStatisticsDtoList(DocRecordDto docRecordDto) {
// 初始化返回的统计DTO列表
List<DocStatisticsDto> statisticsDtoList = new ArrayList<>();
// 防御性判断:如果文档记录为空,直接返回空列表
if (docRecordDto == null) {
return statisticsDtoList;
}
// 获取JSON格式的内容字符串待解析的原始数据
String contentJson = docRecordDto.getContentJson();
// 获取系统中定义的统计项列表需要解析的目标code集合
List<DocStatisticsDefinitionDto> definitionList = docStatisticsDefinitionAppService.getList(1);
// 防御性判断:如果统计项定义为空,直接返回空列表
if (definitionList == null || definitionList.isEmpty()) {
return statisticsDtoList;
}
// 解析JSON字符串为JSONObject方便操作嵌套结构
JSONObject contentJsonObj = parseJson(contentJson);
// 如果JSON解析失败返回null直接返回空列表
if (contentJsonObj == null) {
return statisticsDtoList;
}
// 遍历每个统计项定义,解析对应的值
for (DocStatisticsDefinitionDto definition : definitionList) {
// 当前需要解析的目标字段code如"BQ"、"DrugCode"
String targetCode = definition.getCode();
// 场景1先尝试解析顶级键值对结构如{"BQ": 123}
if (contentJsonObj.containsKey(targetCode)) {
// 提取值并转换为字符串
String value = String.valueOf(contentJsonObj.get(targetCode));
Date recordTime = docRecordDto.getRecordTime();
// 创建DTO并添加到结果列表
addSingleDto(statisticsDtoList, definition, docRecordDto, value,
recordTime);
// 处理完当前统计项,继续下一个
continue;
}
// 场景2如果顶级键不存在尝试解析嵌套的Item列表
// 列表字段名规则目标code + "Item"如code=BQ → 列表字段名=BQItem
String itemListKey = targetCode + "Item";
// 从JSON中获取对应的列表
JSONArray itemArray = contentJsonObj.getJSONArray(itemListKey);
// 判断列表是否存在且不为空
if (itemArray != null && !itemArray.isEmpty()) {
// 遍历列表中的每个元素每个元素是一个JSONObject
for (int i = 0; i < itemArray.size(); i++) {
JSONObject itemObj = itemArray.getJSONObject(i);
// 检查元素是否包含目标code
if (itemObj != null && itemObj.containsKey(targetCode)) {
// 提取当前元素的目标值
String value = String.valueOf(itemObj.get(targetCode));
Date recordTime = new Date();
if (itemObj.containsKey("recordTime")) {
recordTime = itemObj.getDate("recordTime");
} else if (contentJsonObj.containsKey("recordTime")) {
recordTime = contentJsonObj.getDate("recordTime");
} else {
recordTime = docRecordDto.getRecordTime();
}
// 创建DTO并添加到结果列表
addSingleDto(statisticsDtoList, definition, docRecordDto, value,
recordTime);
}
}
// 日志提示如果列表存在但未找到匹配的code
if (statisticsDtoList.isEmpty()) {
log.warn("列表{}中未找到包含{}的元素,可能数据格式不匹配", itemListKey, targetCode);
}
} else {
// 日志提示未找到对应的Item列表或列表为空
log.error("未找到列表{}或列表为空,无法解析统计项: {}", itemListKey, targetCode);
}
}
return statisticsDtoList;
}
/**
* 工具方法解析JSON字符串为JSONObject
*
* @param jsonStr 原始JSON字符串
* @return 解析后的JSONObject失败则返回null
*/
private JSONObject parseJson(String jsonStr) {
// 如果JSON字符串为空直接返回null
if (jsonStr == null) {
return null;
}
try {
// 解析JSON字符串
return JSON.parseObject(jsonStr);
} catch (Exception e) {
// 记录解析异常日志
log.error("JSON解析失败原始字符串: {}", jsonStr, e);
return null;
}
}
/**
* 工具方法创建单个统计DTO并添加到列表
*
* @param dtoList 目标DTO列表
* @param definition 统计项定义
* @param docRecordDto 文档记录DTO
* @param value 解析出的统计值
* @param recordTime 记录时间
*/
private void addSingleDto(List<DocStatisticsDto> dtoList,
DocStatisticsDefinitionDto definition,
DocRecordDto docRecordDto,
String value,
Date recordTime) {
// 创建统计DTO对象
DocStatisticsDto dto = new DocStatisticsDto();
// 设置统计值和关联的统计项定义信息
dto.setValue(value);
dto.setStatisticDefinitionCode(definition.getCode());
dto.setStatisticDefinitionId(definition.getId());
// 设置关联的文档记录信息
dto.setRecordId(docRecordDto.getId());
dto.setEncounterId(docRecordDto.getEncounterId());
dto.setPatientId(docRecordDto.getPatientId());
dto.setOrganizationId(docRecordDto.getOrganizationId());
dto.setRecordTime(recordTime);
dto.setSource(docRecordDto.getSource());
// 将创建好的DTO添加到结果列表
dtoList.add(dto);
}
}

View File

@@ -8,6 +8,8 @@ import java.util.*;
public class DocumentDirectoryProcessor {
private static Long id;
/**
* 构建文档目录树
*
@@ -16,6 +18,7 @@ public class DocumentDirectoryProcessor {
*/
public static List<DirectoryNode> buildDocumentDirectory(List<DocDefinitionDto> documents) {
// 第一步按一级菜单分组使用LinkedHashMap保持插入顺序
id = 1L;
Map<Object, List<DocDefinitionDto>> level1Groups = new LinkedHashMap<>();
for (DocDefinitionDto doc : documents) {
Object key = doc.getPrimaryMenuEnum() != null ? doc.getPrimaryMenuEnum() : doc.getName();
@@ -58,6 +61,7 @@ public class DocumentDirectoryProcessor {
} else {
level1Node.setName(level1Key.toString());
}
level1Node.setId(id++);
level1Node.setLevel(1);
buildSubNodes(level1Node, level1Docs);
@@ -99,6 +103,7 @@ public class DocumentDirectoryProcessor {
DirectoryNode childNode = new DirectoryNode();
childNode.setName(groupKey);
childNode.setLevel(parentNode.getLevel() + 1);
childNode.setId(id++);
// 递归构建子节点
buildSubNodes(childNode, groupDocs);
@@ -127,6 +132,7 @@ public class DocumentDirectoryProcessor {
DirectoryNode node = new DirectoryNode();
node.setName(doc.getName() + " (" + doc.getVersion() + ")");
node.setLevel(3);
node.setId(id++);
node.setDocument(doc);
return node;
}