Przeglądaj źródła

新增
1、员工导入增加分配角色
2、增加导入长者入住办理接口
3、增加导入长者押金接口
4、增加获取机构看板统计(院内动态、护理情况)
BUGFIX
1、解决长护险面对多账单时新增报错问题

liangwenxuan 2 miesięcy temu
rodzic
commit
a262857a8e
18 zmienionych plików z 596 dodań i 9 usunięć
  1. 7 0
      yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/business/BpmElderlApplyServiceApi.java
  2. 20 0
      yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/business/BpmElderlApplyServiceApiImpl.java
  3. 2 2
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/kingdee/KingdeeApiImpl.java
  4. 21 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/ElderlyInfoController.java
  5. 29 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/InstitutionDashboardRespVO.java
  6. 59 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/excel/ElderlyCheckInImportVO.java
  7. 24 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/excel/ElderlyDepositImportVO.java
  8. 5 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/pay/WeChatPayController.java
  9. 3 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserImportExcelVO.java
  10. 6 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/biz/BuildBedMapper.java
  11. 1 1
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyConsumerVouchersServiceImpl.java
  12. 6 4
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyInfoService.java
  13. 371 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyInfoServiceImpl.java
  14. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseSubsidyServiceImpl.java
  15. 2 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/nursing/NurseLevelServiceImpl.java
  16. 25 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
  17. 14 1
      yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/BuildBedMapper.xml
  18. BIN
      yudao-server/src/main/resources/files/员工导入模板.xls

+ 7 - 0
yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/business/BpmElderlApplyServiceApi.java

@@ -0,0 +1,7 @@
+package cn.iocoder.yudao.module.bpm.api.business;
+
+import com.alibaba.fastjson.JSONObject;
+
+public interface BpmElderlApplyServiceApi {
+    Long checkInCreate(Long loginUserId, JSONObject data);
+}

+ 20 - 0
yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/business/BpmElderlApplyServiceApiImpl.java

@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.bpm.api.business;
+
+import cn.iocoder.yudao.module.bpm.service.business.BpmElderlApplyService;
+import cn.iocoder.yudao.module.system.api.bpm.vo.CheckInCreateReqVO;
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class BpmElderlApplyServiceApiImpl implements BpmElderlApplyServiceApi{
+
+
+    @Autowired
+    private BpmElderlApplyService bpmElderlApplyService;
+
+    @Override
+    public Long checkInCreate(Long loginUserId, JSONObject data){
+        return bpmElderlApplyService.checkInCreate(loginUserId,data.toJavaObject(CheckInCreateReqVO.class));
+    }
+}

+ 2 - 2
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/kingdee/KingdeeApiImpl.java

@@ -30,6 +30,7 @@ import com.kingdee.bos.webapi.entity.IdentifyInfo;
 import com.kingdee.bos.webapi.entity.RepoRet;
 import com.kingdee.bos.webapi.sdk.K3CloudApi;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
@@ -133,9 +134,8 @@ public class KingdeeApiImpl implements KingdeeApi {
             List<ReceivableFEntityDetail> FEntityDetailList = new ArrayList<>();
             List<ExpenseOrderItemDO> expenseOrderItemDOS = orderItemMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderItemDO>()
                     .eq(ExpenseOrderItemDO::getExpenseOrderId, expenseOrderDO.getId())
-                    .eq(ExpenseOrderItemDO::getPayStatus, expenseOrderDO.getPayStatus())
                     .eq(ExpenseOrderItemDO::getTenantId, tenantId));
-            if (null == expenseOrderItemDOS) {
+            if (CollectionUtils.isEmpty(expenseOrderItemDOS)) {
                 return;
             }
             expenseOrderItemDOS.forEach(expenseOrderItemDO -> {

+ 21 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/ElderlyInfoController.java

@@ -308,6 +308,13 @@ public class ElderlyInfoController {
         return success(elderlyInfoService.getWeeklyOperationSummary(tenantId));
     }
 
+    @GetMapping("/getInstitutionDashboard")
+    @Operation(summary = "获取机构看板统计(院内动态、护理情况)")
+    @TenantIgnore
+    public CommonResult<InstitutionDashboardRespVO> getInstitutionDashboard() {
+        return success(elderlyInfoService.getInstitutionDashboard());
+    }
+
     @PostMapping("/getHomeDataElderlyPortrait")
     @Operation(summary = "获取大屏长者画像")
     public CommonResult<ElderlyHomeRespVO> getHomeDataElderlyPortrait(@Valid ElderlyInfoHomeDataReqVO reqVO) {
@@ -402,4 +409,18 @@ public class ElderlyInfoController {
         List<KingdeeElderlyExcelVO> list = ExcelUtils.read(file, KingdeeElderlyExcelVO.class);
         return success( elderlyInfoService.importKingdeeElderlyExcel(list));
     }
+
+    @PostMapping("/importCheckIn")
+    @Operation(summary = "入住办理导入")
+    public CommonResult<String> importCheckIn(@RequestParam("file") MultipartFile file) throws IOException {
+        List<ElderlyCheckInImportVO> list = ExcelUtils.read(file, ElderlyCheckInImportVO.class);
+        return success(elderlyInfoService.importCheckIn(list));
+    }
+
+    @PostMapping("/importDeposit")
+    @Operation(summary = "押金导入")
+    public CommonResult<String> importDeposit(@RequestParam("file") MultipartFile file) throws IOException {
+        List<ElderlyDepositImportVO> list = ExcelUtils.read(file, ElderlyDepositImportVO.class);
+        return success(elderlyInfoService.importDeposit(list));
+    }
 }

+ 29 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/InstitutionDashboardRespVO.java

@@ -0,0 +1,29 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+@Schema(description = "管理后台 - 机构看板(院内动态、护理情况) Response VO")
+public class InstitutionDashboardRespVO {
+
+    @Schema(description = "院内动态")
+    private List<StatisticItemVO> hospitalDynamics;
+
+    @Schema(description = "护理情况")
+    private List<StatisticItemVO> nursingSituation;
+
+    @Data
+    @Schema(description = "统计项")
+    public static class StatisticItemVO {
+
+        @Schema(description = "名称", example = "总床位数")
+        private String name;
+
+        @Schema(description = "数量", example = "400")
+        private Long count;
+    }
+}
+

+ 59 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/excel/ElderlyCheckInImportVO.java

@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.format.DateTimeFormat;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
+public class ElderlyCheckInImportVO {
+    @ExcelProperty("长者名称")
+    private String elderName;
+    @ExcelProperty("长者身份证号码")
+    private String idCard;
+    @ExcelProperty("合同开始日期")
+    @DateTimeFormat("yyyy-MM-dd")
+    private Date contractBeginDate;
+    @ExcelProperty("合同年限")
+    private String contractYear;
+    @ExcelProperty("合同编号")
+    private String contractNumber;
+    @ExcelProperty("护理等级")
+    private String nurseLevel;
+    @ExcelProperty("床位号")
+    private String bedName;
+    @ExcelProperty("是否包房")
+    private String isPrivate;
+    @ExcelProperty("床位类型")
+    private String bedType;
+    @ExcelProperty("床位费")
+    private BigDecimal bedFee;
+    @ExcelProperty("护理标准")
+    private String nurseType;
+    @ExcelProperty("护理费")
+    private BigDecimal nurseFee;
+    @ExcelProperty("餐饮标准")
+    private String cateringType;
+    @ExcelProperty("餐饮费")
+    private BigDecimal cateringFee;
+    @ExcelProperty("服务标准")
+    private String serviceType;
+    @ExcelProperty("服务费")
+    private BigDecimal serviceFee;
+    @ExcelProperty("押金")
+    private BigDecimal deposit;
+    @ExcelProperty("备注")
+    private String remark;
+    @ExcelProperty("诊查费")
+    private BigDecimal examinationFee;
+}

+ 24 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/biz/vo/excel/ElderlyDepositImportVO.java

@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@Accessors(chain = false) // 设置 chain = false,避免用户导入有问题
+public class ElderlyDepositImportVO {
+    @ExcelProperty("长者名称")
+    private String elderName;
+    @ExcelProperty("长者身份证号码")
+    private String idCard;
+    @ExcelProperty("押金")
+    private BigDecimal deposit;
+}

+ 5 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/pay/WeChatPayController.java

@@ -78,6 +78,7 @@ public class WeChatPayController {
     @PermitAll
     @TenantIgnore
     public CommonResult<JSONObject> unifiedOrder(@RequestBody WechatMiniOrderDO req) throws Exception {
+        log.info("req:{}",req.toString());
         String openId = miniAppUserService.getByPhone(req.getPhone()).getOpenId();
         String outTradeNo = generateOrderNo();
         req.setOutTradeNo(outTradeNo);
@@ -113,7 +114,9 @@ public class WeChatPayController {
         request.setDescription(description);
         request.setNotifyUrl(wechatMiniPayRequestInfoDO.getNotifyUrl());
         request.setOutTradeNo(outTradeNo);
-        request.setAttach("{}");
+        JSONObject attach = new JSONObject();
+        attach.put("outTradeNo",outTradeNo);
+        request.setAttach(attach.toJSONString());
 
         Payer payer = new Payer();
         payer.setSpOpenid(openId); // 必须传入用户的openid
@@ -136,6 +139,7 @@ public class WeChatPayController {
     @PermitAll
     @TenantIgnore
     public String weChatPayCallBack(HttpServletRequest request){
+        log.info("微信支付回调");
         try {
             // 1. 读取请求体
             String requestBody = getRequestBody(request);

+ 3 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/vo/user/UserImportExcelVO.java

@@ -48,6 +48,9 @@ public class UserImportExcelVO {
     @ExcelProperty("部门")
     private String deptName;
 
+    @ExcelProperty("角色")
+    private String roleName;
+
     @ExcelProperty("用户邮箱")
     private String email;
 

+ 6 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/biz/BuildBedMapper.java

@@ -17,4 +17,10 @@ public interface BuildBedMapper extends BaseMapperX<BuildBedDO> {
 
 
     Integer selectCurrentPresetCount(@Param("reqVO") ElderlyInfoHomeDataReqVO reqVO);
+
+    Long selectBedIdByFullName(@Param("tenantId") Long tenantId,
+                               @Param("buildName") String buildName,
+                               @Param("floorName") String floorName,
+                               @Param("roomName") String roomName,
+                               @Param("bedName") String bedName);
 }

+ 1 - 1
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyConsumerVouchersServiceImpl.java

@@ -116,7 +116,7 @@ public class ElderlyConsumerVouchersServiceImpl implements ElderlyConsumerVouche
         orderItem.setEndDate(yearMonth.atEndOfMonth());
         orderItem.setTenantId(createReqVO.getTenantId());
         orderItem.setPayStatus(0);
-        orderItem.setDescription(yearMonth+"消费券抵扣");
+        orderItem.setDescription(StringUtils.isBlank(createReqVO.getRemarks()) ? yearMonth+"消费券抵扣" : createReqVO.getRemarks()) ;
         expenseOrderItemMapper.insert(orderItem);
 
         BigDecimal currentAmount = expenseOrder.getActualAmount() != null ? expenseOrder.getActualAmount() : BigDecimal.ZERO;

+ 6 - 4
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyInfoService.java

@@ -2,10 +2,7 @@ package cn.iocoder.yudao.module.system.service.biz;
 
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.*;
-import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.ElderlyFileImportExcelVO;
-import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.ElderlyImportExcelVO;
-import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.KingdeeElderlyExcelVO;
-import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.KingdeeCustomerExcelVO;
+import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.*;
 import cn.iocoder.yudao.module.system.dal.dataobject.biz.ElderlyCheckInRecordDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.biz.ElderlyInfoDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.biz.MbtiRecordBO;
@@ -92,6 +89,11 @@ public interface ElderlyInfoService {
 
     ElderlyWeeklyOperationSummaryRespVO getWeeklyOperationSummary(Long tenantId);
 
+    InstitutionDashboardRespVO getInstitutionDashboard();
+
     void deleteElderlyAndRelatedData(Long id);
+
+    String importCheckIn(List<ElderlyCheckInImportVO> list);
+    String importDeposit(List<ElderlyDepositImportVO> list);
 }
 

+ 371 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ElderlyInfoServiceImpl.java

@@ -10,9 +10,12 @@ import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
 import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.yudao.module.bpm.api.business.BpmElderlApplyServiceApi;
 import cn.iocoder.yudao.module.system.api.bpm.BpmElderlyApi;
 import cn.iocoder.yudao.module.system.api.bpm.vo.CheckInContractReqVO;
+import cn.iocoder.yudao.module.system.api.bpm.vo.CheckInCreateReqVO;
 import cn.iocoder.yudao.module.system.api.bpm.vo.CheckInExpenseItemReqVo;
+import cn.iocoder.yudao.module.system.api.bpm.vo.CheckInExpenseSaveReqVO;
 import cn.iocoder.yudao.module.system.api.open.OpenApi;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.*;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.*;
@@ -43,6 +46,7 @@ import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.google.gson.Gson;
+import com.google.gson.JsonObject;
 import com.google.gson.reflect.TypeToken;
 import com.mzt.logapi.starter.annotation.LogRecord;
 import lombok.extern.slf4j.Slf4j;
@@ -185,6 +189,15 @@ public class ElderlyInfoServiceImpl implements ElderlyInfoService {
 
     @Autowired
     private RedisTemplate<String, Object> redisTemplate;
+    
+    @Autowired
+    private SysOverheadChargeMapper sysOverheadChargeMapper;
+
+    @Autowired
+    private BpmElderlApplyServiceApi bpmElderlApplyServiceApi;
+
+    @Autowired
+    private DepositService depositService;
 
     // 定义一个静态的线程池
     private static final ExecutorService executorService = Executors.newFixedThreadPool(10);
@@ -1539,6 +1552,95 @@ public class ElderlyInfoServiceImpl implements ElderlyInfoService {
         return respVO;
     }
 
+    @Override
+    @TenantIgnore
+    public InstitutionDashboardRespVO getInstitutionDashboard() {
+        Long tenantId = TenantContextHolder.getTenantId();
+        LocalDate today = LocalDate.now();
+        Date todayStartDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
+        Date todayEndDate = Date.from(today.plusDays(1).atStartOfDay(ZoneId.systemDefault()).minusSeconds(1).toInstant());
+
+        long totalBedCount = Optional.ofNullable(buildBedMapper.selectCount(new LambdaQueryWrapperX<BuildBedDO>()
+                .eq(BuildBedDO::getOrgType, 1)
+                .in(BuildBedDO::getTenantId, tenantId))).orElse(0L);
+
+        long inHospitalCount = Optional.ofNullable(elderlyInfoMapper.selectCount(new LambdaQueryWrapperX<ElderlyInfoDO>()
+                .eq(ElderlyInfoDO::getInStatus, 1)
+                .eq(ElderlyInfoDO::getDeleted, 0)
+                .eq(ElderlyInfoDO::getOrgType, 1)
+                .in(ElderlyInfoDO::getTenantId, tenantId))).orElse(0L);
+
+        long newCheckInCount = Optional.ofNullable(elderlyCheckInRecordMapper.selectCount(new LambdaQueryWrapperX<ElderlyCheckInRecordDO>()
+                .eq(ElderlyCheckInRecordDO::getStatus, 2)
+                .in(ElderlyCheckInRecordDO::getTenantId, tenantId)
+                .between(ElderlyCheckInRecordDO::getCheckInTime, todayStartDate, todayEndDate))).orElse(0L);
+
+        long askLeaveCount = Optional.ofNullable(elderlyAskLeaveMapper.selectCount(new LambdaQueryWrapperX<ElderlyAskLeaveDO>()
+                .in(ElderlyAskLeaveDO::getTenantId, tenantId)
+                .le(ElderlyAskLeaveDO::getOutDate, todayEndDate)
+                .and(w -> w.ge(ElderlyAskLeaveDO::getComeDate, todayStartDate).or().isNull(ElderlyAskLeaveDO::getComeDate)))).orElse(0L);
+
+        long todayAskLeaveCount = Optional.ofNullable(elderlyAskLeaveMapper.selectCount(new LambdaQueryWrapperX<ElderlyAskLeaveDO>()
+                .in(ElderlyAskLeaveDO::getTenantId, tenantId)
+                .between(ElderlyAskLeaveDO::getOutDate, todayStartDate, todayEndDate))).orElse(0L);
+
+        long checkOutCount = Optional.ofNullable(elderlyRetreatRecordMapper.selectCount(new LambdaQueryWrapperX<ElderlyRetreatRecordDO>()
+                .in(ElderlyRetreatRecordDO::getTenantId, tenantId)
+                .between(ElderlyRetreatRecordDO::getRetreatDate, today, today))).orElse(0L);
+
+        List<ElderlyInfoDO> inHospitalElders = elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
+                .select(ElderlyInfoDO::getNurseLevelId)
+                .eq(ElderlyInfoDO::getInStatus, 1)
+                .eq(ElderlyInfoDO::getDeleted, 0)
+                .eq(ElderlyInfoDO::getOrgType, 1)
+                .in(ElderlyInfoDO::getTenantId, tenantId));
+
+        Map<Long, Long> nurseLevelCountMap = inHospitalElders.stream()
+                .map(ElderlyInfoDO::getNurseLevelId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
+
+        long noFeeCount = inHospitalElders.stream().filter(e -> e.getNurseLevelId() == null).count();
+
+        Map<Long, String> levelNameMap = nurseLevelCountMap.isEmpty()
+                ? new HashMap<>()
+                : nurseLevelMapper.selectBatchIds(nurseLevelCountMap.keySet()).stream()
+                .collect(Collectors.toMap(NurseLevelDO::getId, NurseLevelDO::getNurseLevelName, (a, b) -> a));
+
+        List<InstitutionDashboardRespVO.StatisticItemVO> nursingSituation = new ArrayList<>();
+        nurseLevelCountMap.entrySet().stream()
+                .sorted(Map.Entry.comparingByKey())
+                .forEach(entry -> {
+                    String levelName = levelNameMap.get(entry.getKey());
+                    if (StringUtils.isBlank(levelName)) {
+                        levelName = "未知等级";
+                    }
+                    nursingSituation.add(buildStatisticItem(levelName, entry.getValue()));
+                });
+        if (noFeeCount > 0) {
+            nursingSituation.add(buildStatisticItem("无费用", noFeeCount));
+        }
+
+        InstitutionDashboardRespVO respVO = new InstitutionDashboardRespVO();
+        respVO.setHospitalDynamics(Arrays.asList(
+                buildStatisticItem("总床位数", totalBedCount),
+                buildStatisticItem("在院人数", inHospitalCount),
+                buildStatisticItem("新收人数", newCheckInCount),
+                buildStatisticItem("请假人数", askLeaveCount),
+                buildStatisticItem("当天请假人数", todayAskLeaveCount),
+                buildStatisticItem("退院人数", checkOutCount)
+        ));
+        respVO.setNursingSituation(nursingSituation);
+        return respVO;
+    }
+
+    private InstitutionDashboardRespVO.StatisticItemVO buildStatisticItem(String name, Long count) {
+        InstitutionDashboardRespVO.StatisticItemVO item = new InstitutionDashboardRespVO.StatisticItemVO();
+        item.setName(name);
+        item.setCount(count == null ? 0L : count);
+        return item;
+    }
+
 
     private List<TodayUpdate> getTodayUpdate(ElderlyInfoHomeDataReqVO reqVO) {
         Long tenantId = reqVO.getTenantIds()[0];
@@ -2164,6 +2266,52 @@ public class ElderlyInfoServiceImpl implements ElderlyInfoService {
         });
         return list;
     }
+    @Override
+    @Transactional
+    public String importCheckIn(List<ElderlyCheckInImportVO> list){
+        List<CheckInCreateReqVO> checkInList = new ArrayList<>();
+        for (ElderlyCheckInImportVO item : list) {
+            CheckInCreateReqVO checkInCreateReqVO = preCheckIn(item);
+            if(checkInCreateReqVO != null){
+                checkInList.add(checkInCreateReqVO);
+            }
+        }
+        handleImportCheckIn(checkInList);
+        return "success";
+    }
+
+    @Override
+    @Transactional
+    public String importDeposit(List<ElderlyDepositImportVO> list){
+        for (ElderlyDepositImportVO item : list) {
+            ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectOne(new LambdaQueryWrapperX<ElderlyInfoDO>()
+                    .eq(ElderlyInfoDO::getIdCard, item.getIdCard())
+                    .eq(ElderlyInfoDO::getTenantId,TenantContextHolder.getTenantId()));
+            DepositDO depositDO = depositMapper.selectOne(new LambdaQueryWrapperX<DepositDO>().eq(DepositDO::getElderId,elderlyInfoDO.getId()));
+            depositDO.setAmount(item.getDeposit());
+            depositDO.setTenantId(TenantContextHolder.getTenantId());
+            DepositRecordDO depositRecordDO = new DepositRecordDO();
+            OverheadChargeDO overheadChargeDO = sysOverheadChargeMapper.selectOne(new LambdaQueryWrapperX<OverheadChargeDO>()
+                    .like(OverheadChargeDO::getChargeName, "押金")
+                    .eq(OverheadChargeDO::getPrice, item.getDeposit())
+                    .eq(OverheadChargeDO::getTenantId,TenantContextHolder.getTenantId()));
+            if(overheadChargeDO == null){
+                log.info("{},该条记录异常,无该金额的押金:{}",item.getElderName(),item.getDeposit());
+                continue;
+            }
+            depositRecordDO.setItemId(overheadChargeDO.getId());
+            depositRecordDO.setItemName(overheadChargeDO.getChargeName());
+            depositRecordDO.setElderId(elderlyInfoDO.getId());
+            depositRecordDO.setReceiptNumber("系统初始化导入");
+            depositRecordDO.setAmount(item.getDeposit());
+            depositRecordDO.setType(1);
+            depositRecordDO.setPayType("系统初始化导入");
+            depositDO.setRecords(Collections.singletonList(depositRecordDO));
+            depositService.pay(depositDO);
+        }
+
+        return "success";
+    }
 
     ElderlySanChart getSexAndNcdSan(ElderlyInfoHomeDataReqVO reqVO) {
 
@@ -2614,6 +2762,229 @@ public class ElderlyInfoServiceImpl implements ElderlyInfoService {
         }
         return field + " " + order + ", ei.update_time desc";
     }
+
+    private CheckInExpenseItemReqVo processMonthlyBedExpense(ElderlyCheckInImportVO item) {
+        String itemName = item.getBedType();
+        BigDecimal itemPrice = item.getBedFee();
+        OverheadChargeDO overheadChargeDO = sysOverheadChargeMapper.selectOne(new LambdaQueryWrapperX<OverheadChargeDO>()
+                .eq(OverheadChargeDO::getChargeName, itemName)
+                .eq(OverheadChargeDO::getPrice, itemPrice)
+                .eq(OverheadChargeDO::getStatus,1)
+                .eq(OverheadChargeDO::getTenantId,TenantContextHolder.getTenantId()));
+        if (overheadChargeDO == null) {
+            System.out.println("获取床位费项失败: 类型=" + itemName + ", 价格=" + itemPrice + ",长者=" + item.getElderName());
+            return null;
+        }
+        return setMonthlyFee(overheadChargeDO, itemName, itemPrice, 1);
+    }
+
+    private CheckInExpenseItemReqVo processMonthlyNurseExpense(ElderlyCheckInImportVO item) {
+        String itemName = item.getNurseType();
+        BigDecimal itemPrice = item.getNurseFee();
+        OverheadChargeDO overheadChargeDO = sysOverheadChargeMapper.selectOne(new LambdaQueryWrapperX<OverheadChargeDO>()
+                .eq(OverheadChargeDO::getChargeName, itemName)
+                .eq(OverheadChargeDO::getPrice, itemPrice)
+                .eq(OverheadChargeDO::getStatus,1)
+                .eq(OverheadChargeDO::getTenantId,TenantContextHolder.getTenantId()));
+        if (overheadChargeDO == null) {
+            System.out.println("护理费错误: 类型=" + itemName + ",价格=" + itemPrice);
+            return null;
+        }
+
+        return setMonthlyFee(overheadChargeDO, itemName, itemPrice, 2);
+    }
+
+    private CheckInExpenseItemReqVo processMonthlyDietExpense(ElderlyCheckInImportVO item) {
+        String itemName = item.getCateringType();
+        BigDecimal itemPrice = item.getCateringFee();
+        OverheadChargeDO overheadChargeDO = sysOverheadChargeMapper.selectOne(new LambdaQueryWrapperX<OverheadChargeDO>()
+                .eq(OverheadChargeDO::getChargeName, itemName)
+                .eq(OverheadChargeDO::getPrice, itemPrice)
+                .eq(OverheadChargeDO::getStatus,1)
+                .eq(OverheadChargeDO::getTenantId,TenantContextHolder.getTenantId()));
+        if (overheadChargeDO == null) {
+            System.out.println("餐饮费错误: 类型=" + itemName + ",价格=" + itemPrice);
+            return null;
+        }
+        return setMonthlyFee(overheadChargeDO, itemName, itemPrice, 3);
+    }
+
+    private CheckInExpenseItemReqVo processMonthlyServiceFees(ElderlyCheckInImportVO item) {
+        String itemName = item.getServiceType();
+        BigDecimal itemPrice = item.getServiceFee();
+        OverheadChargeDO overheadChargeDO = sysOverheadChargeMapper.selectOne(new LambdaQueryWrapperX<OverheadChargeDO>()
+                .eq(OverheadChargeDO::getChargeName, itemName)
+                .eq(OverheadChargeDO::getPrice, itemPrice)
+                .eq(OverheadChargeDO::getStatus,1)
+                .eq(OverheadChargeDO::getTenantId,TenantContextHolder.getTenantId()));
+        if (overheadChargeDO == null) {
+            System.out.println("服务费错误: 类型=" + itemName + ",价格=" + itemPrice);
+            return null;
+        }
+        return setMonthlyFee(overheadChargeDO, itemName, itemPrice, 7);
+    }
+
+    private CheckInExpenseItemReqVo processMonthlyExaminationFees(ElderlyCheckInImportVO item) {
+        String itemName = "诊查费";
+        BigDecimal itemPrice = item.getExaminationFee();
+        OverheadChargeDO overheadChargeDO = sysOverheadChargeMapper.selectOne(new LambdaQueryWrapperX<OverheadChargeDO>()
+                .eq(OverheadChargeDO::getChargeName, itemName)
+                .eq(OverheadChargeDO::getPrice, itemPrice)
+                .eq(OverheadChargeDO::getStatus,1)
+                .eq(OverheadChargeDO::getTenantId,TenantContextHolder.getTenantId()));
+        if (overheadChargeDO == null) {
+            System.out.println("诊查费错误: 类型=" + itemName + ",价格=" + itemPrice);
+            return null;
+        }
+        return setMonthlyFee(overheadChargeDO, itemName, itemPrice, 7);
+    }
+
+    private CheckInExpenseItemReqVo setMonthlyFee(OverheadChargeDO overheadChargeDO, String itemName, BigDecimal itemPrice, int expenseType) {
+        CheckInExpenseItemReqVo monthlyItem = new CheckInExpenseItemReqVo();
+        long itemCategoryId = Long.parseLong(overheadChargeDO.getSuperiorsId());
+        monthlyItem.setItemCategoryId(itemCategoryId);
+        monthlyItem.setItemCategoryName(overheadChargeDO.getCategoryName());
+        monthlyItem.setItemId(overheadChargeDO.getId());
+        monthlyItem.setItemName(itemName);
+
+        monthlyItem.setCount(1);
+        monthlyItem.setIsOneTimeFee(0);
+        monthlyItem.setIsDiscount(0);
+        monthlyItem.setIsDeposit(0);
+        monthlyItem.setIsFreeGift(0);
+        monthlyItem.setIsHirePurchase(0);
+        monthlyItem.setIsMonthlyExpense(1);
+
+        monthlyItem.setType(expenseType); // 床位费1,护理费2
+        monthlyItem.setTenantId(TenantContextHolder.getTenantId());
+        monthlyItem.setDiscount(null);
+
+        monthlyItem.setAmount(itemPrice);
+        monthlyItem.setDiscountAmount(BigDecimal.valueOf(0.0));
+        monthlyItem.setActualAmount(itemPrice);
+        monthlyItem.setTotalAmount(itemPrice);
+
+        return monthlyItem;
+    }
+
+    private CheckInCreateReqVO preCheckIn(ElderlyCheckInImportVO item){
+        CheckInCreateReqVO checkInCreateReqVO = new CheckInCreateReqVO();
+        ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectOne(new LambdaQueryWrapperX<ElderlyInfoDO>()
+                .eq(ElderlyInfoDO::getIdCard, item.getIdCard())
+                .eq(ElderlyInfoDO::getTenantId,TenantContextHolder.getTenantId()));
+        if(elderlyInfoDO == null){
+            log.info("{},该条记录异常,无该身份证长者",item.getElderName());
+            return null;
+        }
+        CheckInContractReqVO contractDO = new CheckInContractReqVO();
+        contractDO.setElderId(elderlyInfoDO.getId());
+        contractDO.setElderName(elderlyInfoDO.getElderName());
+        contractDO.setBeginTime(item.getContractBeginDate());
+        contractDO.setContractNumber(item.getContractNumber());
+        // 多少年
+        int yearNum = Integer.parseInt(item.getContractYear().replace("年", ""));
+        // Date -> LocalDate
+        LocalDate localDate = item.getContractBeginDate().toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDate();
+        // 增加年份
+        LocalDate newLocalDate = localDate.plusYears(yearNum);
+        contractDO.setExpireTime(Date.from(newLocalDate.atStartOfDay(ZoneId.systemDefault()).toInstant()));
+        contractDO.setStatus(1);
+        contractDO.setTimes(0);
+        contractDO.setInStatusType("1");
+        CheckInExpenseSaveReqVO reqVO = new CheckInExpenseSaveReqVO();
+        List<CheckInExpenseItemReqVo> monthlyExpenseList = new ArrayList<>();
+        // 2.1 床位费
+        monthlyExpenseList.add(processMonthlyBedExpense(item));
+        // 2.1 护理费
+        monthlyExpenseList.add(processMonthlyNurseExpense(item));
+        // 2.2 餐饮
+        monthlyExpenseList.add(processMonthlyDietExpense(item));
+        // 2.3 服务费
+        monthlyExpenseList.add(processMonthlyServiceFees(item));
+        // 2.4 诊查费
+        monthlyExpenseList.add(processMonthlyExaminationFees(item));
+        monthlyExpenseList = monthlyExpenseList.stream().filter(Objects::nonNull).collect(Collectors.toList());
+        BigDecimal total = monthlyExpenseList.stream()
+                .map(CheckInExpenseItemReqVo::getActualAmount)
+                .reduce(BigDecimal.ZERO, BigDecimal::add);
+        reqVO.setMonthlyExpenses(monthlyExpenseList);
+
+        List<CheckInExpenseItemReqVo> oneTimeExpensesList = new ArrayList<>();
+        oneTimeExpensesList.add(processDeposit(item));
+        oneTimeExpensesList = oneTimeExpensesList.stream().filter(Objects::nonNull).collect(Collectors.toList());
+        reqVO.setOneTimeExpenses(oneTimeExpensesList);
+        reqVO.setStageExpenses(new ArrayList<>());
+        // 5. 其他字段
+        String totalBedName = item.getBedName();
+        String[] parts = totalBedName.split("-"); // 按">"分割字符串
+        String buildName = parts[0]; // "3-5号楼"
+        String floorName = parts[1]; // "1F"
+        String roomName = parts[2]; // "110"
+        String bedName = parts[3]; // "01"
+
+        long bedId = buildBedMapper.selectBedIdByFullName(TenantContextHolder.getTenantId(),buildName, floorName, roomName, bedName);
+        if (bedId == -1L) {
+            log.error(item.getElderName()+",bedId=-1:" + buildName + "-" + floorName + "-" + roomName + "-" + bedName);
+            return null;
+        }
+        reqVO.setElderId(elderlyInfoDO.getId());
+        reqVO.setTotalAmount(total);
+        reqVO.setBedId(bedId);
+        reqVO.setCheckInTime(item.getContractBeginDate());
+        reqVO.setCheckInDeadlineTime(contractDO.getExpireTime());
+        NurseLevelDO nurseLevelDO = nurseLevelMapper.selectOne(new LambdaQueryWrapperX<NurseLevelDO>()
+                .eq(NurseLevelDO::getNurseLevelName, item.getNurseLevel())
+                .eq(NurseLevelDO::getTenantId, TenantContextHolder.getTenantId()));
+        if(nurseLevelDO == null){
+            log.info("{},该条记录异常,无该护理等级:{}",item.getElderName(),item.getNurseLevel());
+            return null;
+        }
+
+        reqVO.setNurseLevelId(nurseLevelDO.getId());
+        reqVO.setIsPrivateRoom(item.getIsPrivate().equals("是") ? 1 : 0);
+        reqVO.setSpecialCareNotes("");
+        checkInCreateReqVO.setElderlyId(elderlyInfoDO.getId());
+        checkInCreateReqVO.setElderlyContractDO(contractDO);
+        checkInCreateReqVO.setExpenseBO(reqVO);
+        checkInCreateReqVO.setType(9);
+        checkInCreateReqVO.setTenantId(TenantContextHolder.getTenantId());
+        return checkInCreateReqVO;
+    }
+
+    private CheckInExpenseItemReqVo processDeposit(ElderlyCheckInImportVO item){
+        CheckInExpenseItemReqVo deposit = new CheckInExpenseItemReqVo();
+        OverheadChargeDO depositDO = sysOverheadChargeMapper.selectOne(new LambdaQueryWrapperX<OverheadChargeDO>()
+                .like(OverheadChargeDO::getChargeName, "押金")
+                .eq(OverheadChargeDO::getPrice, item.getDeposit())
+                .eq(OverheadChargeDO::getTenantId,TenantContextHolder.getTenantId()));
+        if(depositDO == null){
+            log.info("{},该条记录异常,无该金额的押金:{}",item.getElderName(),item.getDeposit());
+            return null;
+        }
+        deposit.setItemId(depositDO.getId());
+        deposit.setItemName(depositDO.getChargeName());
+        deposit.setItemCategoryId(Long.valueOf(depositDO.getSuperiorsId()));
+        deposit.setItemCategoryName("押金");
+        deposit.setAmount(item.getDeposit());
+        deposit.setActualAmount(item.getDeposit());
+        deposit.setTotalAmount(item.getDeposit());
+        deposit.setIsOneTimeFee(1);
+        deposit.setCount(1);
+        deposit.setIsDeposit(1);
+        deposit.setTenantId(TenantContextHolder.getTenantId());
+        deposit.setChangeStartDate(LocalDate.now());
+        return deposit;
+    }
+
+    private void handleImportCheckIn(List<CheckInCreateReqVO> checkInList){
+        for (CheckInCreateReqVO checkInCreateReqVO : checkInList) {
+            bpmElderlApplyServiceApi.checkInCreate(SecurityFrameworkUtils.getLoginUserId(), (JSONObject)JSON.toJSON(checkInCreateReqVO));
+        }
+    }
+
+
 }
 
 

+ 1 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/biz/ExpenseSubsidyServiceImpl.java

@@ -439,6 +439,7 @@ public class ExpenseSubsidyServiceImpl implements ExpenseSubsidyService {
                 .eq(ExpenseOrderDO::getElderId, createReqVO.getElderId())
                 .eq(ExpenseOrderDO::getIsShow,BooleanEnum.TRUE.getValue())
                 .eq(ExpenseOrderDO::getBillingMonth, createReqVO.getDeductionBillMonth())
+                .ne(ExpenseOrderDO::getPayStatus,1)
                 .eq(ExpenseOrderDO::getType, 2)); // 月度账单
 
         // 如果账单存在,更新长护险到账单里面

+ 2 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/nursing/NurseLevelServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollectionUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
+import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ItemPageReqVO;
 import cn.iocoder.yudao.module.system.controller.admin.biz.vo.excel.NurseItemImportExcel;
 import cn.iocoder.yudao.module.system.dal.dataobject.biz.*;
@@ -166,6 +167,7 @@ public class NurseLevelServiceImpl implements NurseLevelService {
             nurseItemDO.setCreateTime(new Date());
             nurseItemDO.setStatus(1);
             nurseItemDO.setCategoryId(optional.get().getId());
+            nurseItemDO.setTenantId(TenantContextHolder.getTenantId());
             nurseItemMapper.insert(nurseItemDO);
             i++;
         }

+ 25 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java

@@ -25,12 +25,14 @@ import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.UserSaveReqV
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
+import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
 import cn.iocoder.yudao.module.system.dal.dataobject.user.*;
 import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper;
 import cn.iocoder.yudao.module.system.dal.mysql.user.*;
 import cn.iocoder.yudao.module.system.service.dept.DeptService;
 import cn.iocoder.yudao.module.system.service.dept.PostService;
 import cn.iocoder.yudao.module.system.service.permission.PermissionService;
+import cn.iocoder.yudao.module.system.service.permission.RoleService;
 import cn.iocoder.yudao.module.system.service.tenant.TenantService;
 import com.google.common.annotations.VisibleForTesting;
 import com.mzt.logapi.context.LogRecordContext;
@@ -77,6 +79,8 @@ public class AdminUserServiceImpl implements AdminUserService {
     @Resource
     private PermissionService permissionService;
     @Resource
+    private RoleService roleService;
+    @Resource
     private PasswordEncoder passwordEncoder;
     @Resource
     @Lazy // 延迟,避免循环依赖报错
@@ -636,6 +640,7 @@ public class AdminUserServiceImpl implements AdminUserService {
                 }
                 adminUser.setUsername(adminUser.getMobile());
                 userMapper.insert(adminUser);
+                assignImportUserRole(adminUser.getId(), importUser.getRoleName());
                 respVO.getCreateUsernames().add(importUser.getNickname());
             } else {
                 // 存在则更新
@@ -672,6 +677,7 @@ public class AdminUserServiceImpl implements AdminUserService {
                 // 保持岗位信息不变(如果需要更新岗位,可以在这里处理)
                 updateUser.setPostIds(existUser.getPostIds());
                 userMapper.updateById(updateUser);
+                assignImportUserRole(updateUser.getId(), importUser.getRoleName());
                 respVO.getUpdateUsernames().add(importUser.getNickname());
             }
         });
@@ -714,6 +720,25 @@ public class AdminUserServiceImpl implements AdminUserService {
                 .orderByAsc(AdminUserDO::getId));
     }
 
+    private void assignImportUserRole(Long userId, String roleName) {
+        if (StrUtil.isBlank(roleName)) {
+            return;
+        }
+        List<String> roleNameList = StrUtil.splitTrim(roleName, ',');
+        if (CollUtil.isEmpty(roleNameList)) {
+            return;
+        }
+        List<RoleDO> roleList = roleService.getRoleList();
+        Set<Long> roleIds = roleList.stream()
+                .filter(role -> roleNameList.contains(role.getName()))
+                .map(RoleDO::getId)
+                .collect(java.util.stream.Collectors.toSet());
+        if (CollUtil.isEmpty(roleIds)) {
+            return;
+        }
+        permissionService.assignUserRole(userId, roleIds, Arrays.asList(1, 5));
+    }
+
     /**
      * 对密码进行加密
      *

+ 14 - 1
yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/BuildBedMapper.xml

@@ -28,6 +28,19 @@
         </if>
     </select>
 
-
+    <select id="selectBedIdByFullName" resultType="java.lang.Long">
+        SELECT bed.id AS bed_id
+        FROM org_build AS build
+                 INNER JOIN org_build_floor AS floor ON build.id = floor.build_id AND build.tenant_id = floor.tenant_id
+                 INNER JOIN org_build_room AS room ON floor.id = room.floor_id AND floor.tenant_id = room.tenant_id
+                 INNER JOIN org_build_bed AS bed ON room.id = bed.room_id AND room.tenant_id = bed.tenant_id
+        WHERE build.tenant_id = #{tenantId}
+          AND build.build_name = #{buildName}
+          AND floor.floor_name = #{floorName}
+          AND room.room_name = #{roomName}
+          AND bed.bed_name = #{bedName}
+          AND build.org_type = 1
+        LIMIT 1
+    </select>
 
 </mapper>

BIN
yudao-server/src/main/resources/files/员工导入模板.xls