package cn.iocoder.yudao.module.system.service.biz;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.ChineseDate;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.ReflectUtils;
import cn.iocoder.yudao.framework.common.util.string.StringUtil;
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.*;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.*;
import cn.iocoder.yudao.module.system.dal.dataobject.reservation.VisitRegistrationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.restaurant.CateringPlanDO;
import cn.iocoder.yudao.module.system.dal.dataobject.restaurant.CateringPlanItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.restaurant.DishesOrderStatisticsDO;
import cn.iocoder.yudao.module.system.dal.dataobject.restaurant.DishesOrderItemDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.GroupTenantDO;
import cn.iocoder.yudao.module.system.dal.dataobject.tenant.TenantDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.ElderlyTempOutDO;
import cn.iocoder.yudao.module.system.dal.mysql.biz.*;
import cn.iocoder.yudao.module.system.dal.mysql.biz.ElderlyTempOutMapper;
import cn.iocoder.yudao.module.system.dal.mysql.reservation.VisitRegistrationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.restaurant.CateringPlanItemMapper;
import cn.iocoder.yudao.module.system.dal.mysql.restaurant.CateringPlanMapper;
import cn.iocoder.yudao.module.system.dal.mysql.restaurant.DishesOrderItemMapper;
import cn.iocoder.yudao.module.system.dal.mysql.restaurant.DishesOrderStatisticsMapper;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.GroupTenantMapper;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper;
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
import cn.iocoder.yudao.module.system.enums.VitalSignsEnum;
import cn.iocoder.yudao.module.system.enums.common.BooleanEnum;
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.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;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exceptionCustomMsg;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.COMMON_ERROR;
import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 长者信息
 */
@Service
@Validated
@Slf4j
public class ElderlyInfoServiceImpl implements ElderlyInfoService {

    @Autowired
    private RelativesMapper relativesMapper;
    @Autowired
    private ElderlyInfoMapper elderlyInfoMapper;
    @Autowired
    private ElderlySyntheticAbilityMapper elderlySyntheticAbilityMapper;
    @Autowired
    private ElderlyCheckInRecordMapper elderlyCheckInRecordMapper;
    @Autowired
    private SysEvaluationProcessMapper sysEvaluationProcessMapper;
    @Autowired
    private BuildService buildService;
    @Resource
    private NurseLevelMapper nurseLevelMapper;

    @Autowired
    private TenantMapper tenantMapper;

    @Autowired
    private BuildBedMapper buildBedMapper;

    @Autowired
    private ElderlyContractMapper elderlyContractMapper;

    @Autowired
    private AdminUserMapper userMapper;

    @Resource
    private VisitRegistrationMapper registrationMapper;

    @Resource
    private ElderlyVitalSignsMapper vitalSignsMapper;

    @Resource
    private BpmElderlyApi bpmElderlyApi;

    @Resource
    private GroupTenantMapper groupTenantMapper;

    @Resource
    private GroupsMapper groupsMapper;

    @Autowired
    private MbtiRecordMapper mbtiRecordMapper;

    @Autowired
    private DailyExpensesMapper dailyExpensesMapper;

    @Resource
    private CateringPlanMapper cateringPlanMapper;
    @Resource
    private CateringPlanItemMapper cateringPlanItemMapper;

    @Resource
    private MonthlyActivityMapper monthlyActivityMapper;

    @Resource
    private HomeOverviewSummaryMapper overviewSummaryMapper;

    @Resource
    private CheckInApplyMapper checkInApplyMapper;

    @Resource
    private ExpenseOrderMapper expenseOrderMapper;

    @Resource
    private ExpenseOrderItemMapper expenseOrderItemMapper;

    @Resource
    private ElderlyHealthRecordMapper elderlyHealthRecordMapper;

    @Resource
    private ElderlyRetreatRecordMapper elderlyRetreatRecordMapper;

    @Resource
    private ElderlyTempOutMapper elderlyTempOutMapper;

    @Resource
    private DepositMapper depositMapper;

    @Resource
    private BalanceMapper balanceMapper;

    @Resource
    private ExpenseSubsidyAccountMapper expenseSubsidyAccountMapper;

    @Resource
    private ExpenseSubsidyMapper expenseSubsidyMapper;

    @Resource
    private OpenApi openApi;

    @Resource
    private ElderlyAskLeaveMapper elderlyAskLeaveMapper;

    @Resource
    private DishesOrderStatisticsMapper dishesOrderStatisticsMapper;

    @Resource
    private DishesOrderItemMapper dishesOrderItemMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private SysOverheadChargeMapper sysOverheadChargeMapper;

    @Autowired
    private BpmElderlApplyServiceApi bpmElderlApplyServiceApi;

    @Autowired
    private DepositService depositService;

    @Autowired
    private ElderlyContractService elderlyContractService;

    @Autowired
    private ExpenseOrderService expenseOrderService;

    // 定义一个静态的线程池
    private static final ExecutorService executorService = Executors.newFixedThreadPool(10);
    private static final ScheduledExecutorService timeoutExecutor = Executors.newScheduledThreadPool(10);
    private static final long TIMEOUT_DURATION = 5; // 设置超时时间为5秒

    private static final Map<String, String> SORT_FIELD_MAP;

    static {
        Map<String, String> tempMap = new HashMap<>();
        tempMap.put("checkInTime", "ei.check_in_time");
        tempMap.put("contractNumber", "ec.contract_number");
        SORT_FIELD_MAP = Collections.unmodifiableMap(tempMap);
    }

    @Override
    public PageResult<ElderlyInfoDO> findPage(ElderlyInfoPageReqVO pageVO) {
        Page<ElderlyInfoDO> page = new Page<>(pageVO.getPageNo(), pageVO.getPageSize());
        pageVO.setOrderByClause(buildOrderBy(pageVO.getProp(), pageVO.getOrder()));
        List<ElderlyInfoDO> list = elderlyInfoMapper.findPage(page, pageVO);
        for (ElderlyInfoDO elderlyInfoDO : list) {
            elderlyInfoDO.setBedName(buildService.getFullBedName(elderlyInfoDO.getId()));
            //统计信息完成度
            elderlyInfoStatistics(elderlyInfoDO);
        }
        return new PageResult<>(list, page.getTotal());
    }


    public void elderlyInfoStatistics(ElderlyInfoDO elderlyInfo) {
        Field[] declaredFields = ElderlyInformationStatistics.class.getDeclaredFields();
        int total = declaredFields.length + 1;
        int count = 0;

        //对比基本信息
        for (Field declaredField : declaredFields) {
            Object fieldValue = ReflectUtils.getFieldValue(elderlyInfo, declaredField.getName());
            if (fieldValue != null && !fieldValue.equals("")) {
                count++;
            }
        }


        //健康档案信息
//        List<ElderlyHealthRecord> elderlyHealthRecords = elderlyHealthRecordMapper.selectList(new LambdaQueryWrapper<ElderlyHealthRecord>().eq(ElderlyHealthRecord::getElderId, elderlyInfo.getId()).orderByDesc(ElderlyHealthRecord::getId));
//        if (!elderlyHealthRecords.isEmpty()) {
//            ElderlyHealthRecord elderlyHealthRecord = elderlyHealthRecords.stream().findFirst().get();
//            if (elderlyHealthRecord != null) {
//                for (Field declaredField : declaredFields) {
//                    Object fieldValue = ReflectUtils.getFieldValue(elderlyHealthRecord, declaredField.getName());
//                    if (fieldValue != null && !fieldValue.equals("")) {
//                        count++;
//                    }
//                }
//            }
//        }
//
//
        //获取亲属信息
        List<RelativesDO> relatives = relativesMapper.selectList(new LambdaQueryWrapper<RelativesDO>().eq(RelativesDO::getPeopleId, elderlyInfo.getId()));
        if (relatives != null && !relatives.isEmpty()) {
            count = count + 1;
        }

        //统计结果
        NumberFormat numberFormat = NumberFormat.getInstance();
        //设备到小数点0位,不需要小数点
        numberFormat.setMaximumFractionDigits(0);
        String result = numberFormat.format((float) count / (float) total * 100);
        elderlyInfo.setInfoPercentage(Integer.parseInt(result));
        elderlyInfo.setInfoFieldCount(count);
        elderlyInfo.setTotalInfoFieldCount(total);
    }


    @Override
    public PageResult<ElderlyCheckInRecordDO> elderlyCheckInRecordPage(ElderlyInfoPageReqVO pageVO) {
        Page<ElderlyInfoDO> page = new Page<>(pageVO.getPageNo(), pageVO.getPageSize());
        List<ElderlyCheckInRecordDO> list = elderlyInfoMapper.elderlyCheckInRecordPage(page, pageVO);
        return new PageResult<>(list, page.getTotal());
    }

    @Override
    @LogRecord(type = DMISSION_DISCHARGE_TYPE, subType = DMISSION_ELDER_INSERT_SUB_TYPE, bizNo = "{{#elderlyInfo.id}}",
            success = DMISSION_ELDER_INSERT_SUCCESS)
    public void addElder(ElderlyInfoDO elderlyInfo) {
        elderlyInfo.setCreateTime(new Date());
        elderlyInfo.setUserSign(RandomUtil.randomString(18));
        elderlyInfo.setUpdateTime(new Date());

        StringBuilder fileNumber = new StringBuilder();
        String date = DateUtils.formatDate(new Date(), "yyyyMMdd");
        fileNumber.append(date);

        redisTemplate.opsForValue().increment(RedisKeyConstants.ELDERLY_FILE_INCREMENT_NUMBER_KEY);
        Integer incrementNum = (Integer) redisTemplate.opsForValue().get(RedisKeyConstants.ELDERLY_FILE_INCREMENT_NUMBER_KEY);
        fileNumber.append(String.format("%06d", incrementNum));
        elderlyInfo.setFileNumber(fileNumber.toString());
        elderlyInfo.setSourceType(2);

        if (Objects.equals(elderlyInfo.getIsLunarCalendar(), BooleanEnum.TRUE.getValue())) {
            //将公历日期转成农历日期
            ChineseDate chineseDate = new ChineseDate(elderlyInfo.getBirthdayCareDate());
            String stringNormal = chineseDate.toStringNormal();
            String chineseCalendar = stringNormal.substring(stringNormal.indexOf("-") + 1);
            elderlyInfo.setChineseCalendar(chineseCalendar);
        }
        elderlyInfoMapper.insert(elderlyInfo);

        if (elderlyInfo.getRelativesList() != null) {
            for (RelativesDO relatives : elderlyInfo.getRelativesList()) {
                relatives.setPeopleId(elderlyInfo.getId());
                relatives.setPeopleName(elderlyInfo.getElderName());
                relatives.setStatus("0");
                relatives.setCreateDate(LocalDateTime.now());
                relativesMapper.insert(relatives);
            }
        }

    }


    @Override
    public List<ElderlyInfoDO> findAllList(Integer orgType) {
        return elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .eqIfPresent(ElderlyInfoDO::getOrgType, orgType)
                .orderByDesc(ElderlyInfoDO::getCreateTime));
    }

    @Override
    @LogRecord(type = DMISSION_DISCHARGE_TYPE, subType = DMISSION_ELDER_UPDATE_SUB_TYPE, bizNo = "{{#elderlyInfo.id}}",
            success = DMISSION_ELDER_UPDATE_SUCCESS)
    public void update(ElderlyInfoDO elderlyInfo) {
        elderlyInfo.setUpdateTime(new Date());
        if (Objects.equals(elderlyInfo.getIsLunarCalendar(), BooleanEnum.TRUE.getValue())) {
            //将公历日期转成农历日期
            ChineseDate chineseDate = new ChineseDate(elderlyInfo.getBirthdayCareDate());
            String stringNormal = chineseDate.toStringNormal();
            String chineseCalendar = stringNormal.substring(stringNormal.indexOf("-") + 1);
            elderlyInfo.setChineseCalendar(chineseCalendar);
        }
        elderlyInfoMapper.updateById(elderlyInfo);


        if (elderlyInfo.getRelativesList() != null) {
            for (RelativesDO relatives : elderlyInfo.getRelativesList()) {
                if (relatives.getId() != null){
                    relativesMapper.updateById(relatives);
                }else {
                    relatives.setPeopleId(elderlyInfo.getId());
                    relatives.setPeopleName(elderlyInfo.getElderName());
                    relatives.setStatus("0");
                    relatives.setCreateDate(LocalDateTime.now());
                    relativesMapper.insert(relatives);
                }
            }
        }

    }

    @Override
    @LogRecord(type = DMISSION_DISCHARGE_TYPE, subType = DMISSION_ELDER_DELETE_SUB_TYPE, bizNo = "{{#id}}",
            success = DMISSION_ELDER_DELETE_SUCCESS)
    public void delete(Long id) {
        elderlyInfoMapper.deleteById(id);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteElderlyAndRelatedData(Long id) {
        // 1. 查询长者信息
        ElderlyInfoDO elderlyInfo = elderlyInfoMapper.selectById(id);

        // 2. 释放占用的床位
        if (elderlyInfo != null && elderlyInfo.getBedId() != null) {
            BuildBedDO bed = buildBedMapper.selectById(elderlyInfo.getBedId());
            if (bed != null) {
                bed.setStatus(0); // 设置为0-空闲状态
                buildBedMapper.updateById(bed);
            }
        }

        // 3. 删除入住办理记录表(elderly_check_in_record)
        elderlyCheckInRecordMapper.delete(new LambdaQueryWrapperX<ElderlyCheckInRecordDO>()
                .eq(ElderlyCheckInRecordDO::getElderId, id));

        // 4. 删除入住申请表(check_in_apply)关联的数据
        List<CheckInApplyDO> checkInApplies = checkInApplyMapper.selectList(new LambdaQueryWrapperX<CheckInApplyDO>()
                .eq(CheckInApplyDO::getElderlyId, id));

        for (CheckInApplyDO checkInApply : checkInApplies) {
            // 删除入住申请相关数据
            checkInApplyMapper.deleteById(checkInApply.getId());
        }

        elderlyRetreatRecordMapper.delete(new LambdaQueryWrapperX<ElderlyRetreatRecordDO>()
                .eq(ElderlyRetreatRecordDO::getElderlyId,id));

        // 5. 删除费用账单表(elderly_expense_order)及相关数据
        List<ExpenseOrderDO> expenseOrders = expenseOrderMapper.selectList(new LambdaQueryWrapperX<ExpenseOrderDO>()
                .eq(ExpenseOrderDO::getElderId, id));

        for (ExpenseOrderDO expenseOrder : expenseOrders) {
            // 删除费用订单项等相关数据
            expenseOrderItemMapper.delete(new LambdaQueryWrapperX<ExpenseOrderItemDO>()
                    .eq(ExpenseOrderItemDO::getExpenseOrderId, expenseOrder.getId()));

            // 删除费用订单
            expenseOrderMapper.deleteById(expenseOrder.getId());
        }

        elderlySyntheticAbilityMapper.delete(new LambdaQueryWrapperX<ElderlySyntheticAbilityDO>()
                .eq(ElderlySyntheticAbilityDO::getElderId, id));

       //6.删除健康档案
        elderlyHealthRecordMapper.delete(new LambdaQueryWrapperX<ElderlyHealthRecordDO>()
                .eq(ElderlyHealthRecordDO::getElderId, id));

        //入住押金和长护险以及余额相关的都要删除掉
        // 删除入住押金相关数据
        depositMapper.delete(new LambdaQueryWrapperX<DepositDO>()
                .eq(DepositDO::getElderId, id));

        // 删除长护险补贴账户数据
        expenseSubsidyAccountMapper.delete(new LambdaQueryWrapperX<ExpenseSubsidyAccountDO>()
                .eq(ExpenseSubsidyAccountDO::getElderId, id));

        // 删除长护险补贴记录数据
        expenseSubsidyMapper.delete(new LambdaQueryWrapperX<ExpenseSubsidyDO>()
                .eq(ExpenseSubsidyDO::getElderId, id));

        balanceMapper.delete(new LambdaQueryWrapperX<BalanceDO>()
                .eq(BalanceDO::getElderId, id));


        // 7. 删除长者信息
        elderlyInfoMapper.deleteById(id);
    }


    @Override
    @TenantIgnore
    public ElderlyInfoDO findDetailById(Long id) {
        ElderlyInfoDO elderlyInfo = elderlyInfoMapper.selectById(id);
        if (elderlyInfo != null) {
            elderlyInfo.setBedName(buildService.getFullBedName(id));
            List<RelativesDO> relatives = relativesMapper.selectList(new LambdaQueryWrapper<RelativesDO>().eq(RelativesDO::getPeopleId, elderlyInfo.getId()));
            elderlyInfo.setRelativesList(relatives);
            //统计信息完成度
            elderlyInfoStatistics(elderlyInfo);

            if (elderlyInfo.getCheckInTime() != null) {
                LocalDate startDay = elderlyInfo.getCheckInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                LocalDate now = LocalDate.now();
                long daysBetween = ChronoUnit.DAYS.between(startDay, now) + 1;
                elderlyInfo.setStayDay((int) daysBetween);
            }

            //更新农历生日到公历日期上
            if (StringUtils.isNotBlank(elderlyInfo.getChineseCalendar()) && elderlyInfo.getIsLunarCalendar().equals(BooleanEnum.TRUE.getValue())) {
                String chineseCalendar = elderlyInfo.getChineseCalendar();
                String[] split = chineseCalendar.replaceAll("(?<=^|-)0+", "").split("-");

                ChineseDate chineseDate = new ChineseDate(YearMonth.now().getYear(), Integer.parseInt(split[0]), Integer.parseInt(split[1]));
                //公历日期
                LocalDate localDate = chineseDate.getGregorianDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                elderlyInfo.setBirthdayCareDate(localDate);
                elderlyInfoMapper.updateById(elderlyInfo);
            }
        }
        return elderlyInfo;
    }

    @Override
    @LogRecord(type = DMISSION_DISCHARGE_TYPE, subType = DMISSION_ELDER_APPLY_SUB_TYPE, bizNo = "{{#elderId}}",
            success = DMISSION_ELDER_APPLY_SUCCESS)
    @Deprecated
    public void generateAdmissionAssessment(Long elderId) {
        //查询入院评估
        List<SysEvaluationProcessDO> sysEvaluationProcessEntities = sysEvaluationProcessMapper.selectList(new LambdaQueryWrapper<SysEvaluationProcessDO>()
                .eq(SysEvaluationProcessDO::getType, 1));


        if (sysEvaluationProcessEntities != null && !sysEvaluationProcessEntities.isEmpty()) {
            SysEvaluationProcessDO sysEvaluationProcess = sysEvaluationProcessEntities.stream().findFirst().get();


            ElderlySyntheticAbilityDO elderlySyntheticAbility = new ElderlySyntheticAbilityDO();
            elderlySyntheticAbility.setElderId(elderId);
            elderlySyntheticAbility.setQuestionnaireId(sysEvaluationProcess.getId().toString());
            elderlySyntheticAbility.setQuestionnaireName(sysEvaluationProcess.getProcessName());
            elderlySyntheticAbility.setStatus("0");
            elderlySyntheticAbility.setEvaluationAgency("1");
            elderlySyntheticAbility.setQuestionnaireType(sysEvaluationProcess.getType());
            elderlySyntheticAbility.setCreateDate(LocalDateTime.now());

            String redisKey = "REDIS_EVALUATION_CODE:" + TenantContextHolder.getTenantId();
            redisTemplate.opsForValue().increment(redisKey, 1);
            Integer incrementalCode = (Integer) redisTemplate.opsForValue().get(redisKey);
            String evaluationCode = "NLPG" + DateUtils.getYear() + DateUtils.getMonth() + DateUtils.getDay() + String.format("%04d", incrementalCode);
            elderlySyntheticAbility.setEvaluationCode(evaluationCode);
            elderlySyntheticAbility.setSignType(0);
            elderlySyntheticAbilityMapper.insert(elderlySyntheticAbility);
        }

        //生成入住申请
        ElderlyCheckInRecordDO elderlyCheckInRecord = new ElderlyCheckInRecordDO();
        elderlyCheckInRecord.setCreatedTime(new Date());
        elderlyCheckInRecord.setStatus(1);
        elderlyCheckInRecord.setElderId(elderId);
        elderlyCheckInRecordMapper.insert(elderlyCheckInRecord);
    }

    @Override
    public BpmCheckInRecordRespVO findBpmRecord(Long elderId) {
        return elderlyCheckInRecordMapper.findBpmRecord(elderId);
    }


    @Override
    public List<ElderlyInfoDO> getElderListByBuild(Long buildId, Long floorId, Long roomId, Long[] tenantIds) {
        List<ElderlyInfoDO> elderList = elderlyInfoMapper.getElderListByBuild(buildId, floorId, roomId, tenantIds);
        for (ElderlyInfoDO elderlyInfoDO : elderList) {
            elderlyInfoDO.setBedName(buildService.getFullBedName(elderlyInfoDO.getId()));
        }
        return elderList;
    }


    @Override
    @Transactional
    public Map<String, Object> importElder(List<ElderlyImportExcelVO> dataList) {
        List<ElderlyImportExcelVO> errorList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        int i = 0;
        for (ElderlyImportExcelVO elderlyImportExcelVO : dataList) {
            checkImportData(elderlyImportExcelVO);
            if (StringUtils.isNotBlank(elderlyImportExcelVO.getErrorMsg())) {
                errorList.add(elderlyImportExcelVO);
                continue;
            }
            ElderlyInfoDO elderlyInfo = new ElderlyInfoDO();
            BeanUtils.copyProperties(elderlyImportExcelVO, elderlyInfo);
            elderlyInfo.setCreateBy(SecurityFrameworkUtils.getLoginUserNickname());
            elderlyInfo.setCreateTime(new Date());
            elderlyInfo.setTenantId(TenantContextHolder.getTenantId());
            elderlyInfoMapper.insert(elderlyInfo);

            bpmElderlyApi.generateApplyAccommodationData(elderlyInfo.getId(), elderlyInfo.getTenantId());

            //创建亲属
            if (StringUtil.isNotEmptyORNull(elderlyImportExcelVO.getFirstName()) &&
                    StringUtil.isNotEmptyORNull(elderlyImportExcelVO.getFirstIdCard())) {
                List<RelativesDO> relativesDOS = relativesMapper.selectList(new LambdaQueryWrapperX<RelativesDO>()
                        .eqIfPresent(RelativesDO::getPeopleId, elderlyInfo.getId())
                        .eqIfPresent(RelativesDO::getName, elderlyImportExcelVO.getFirstName())
                        .eqIfPresent(RelativesDO::getIdCard, elderlyImportExcelVO.getFirstIdCard())
                        .eq(RelativesDO::getTenantId, TenantContextHolder.getTenantId()));
                if (null != relativesDOS && !relativesDOS.isEmpty()) {
                    RelativesDO relativesDO = relativesDOS.get(0);
                    relativesDO.setRelation(elderlyImportExcelVO.getFirstRelation());
                    relativesDO.setPhone(elderlyImportExcelVO.getFirstPhone());
                    relativesDO.setAddress(elderlyImportExcelVO.getFirstAddress());
                    relativesDO.setNowAddress(elderlyImportExcelVO.getFirstAddress());
                    relativesMapper.updateById(relativesDO);
                } else if (StringUtil.isNotEmptyORNull(elderlyImportExcelVO.getFirstName())
                        && StringUtil.isNotEmptyORNull(elderlyImportExcelVO.getFirstIdCard())) {
                    RelativesDO relativesDO = new RelativesDO();
                    relativesDO.setName(elderlyImportExcelVO.getFirstName());
                    relativesDO.setIdCard(elderlyImportExcelVO.getFirstIdCard());
                    relativesDO.setPeopleId(elderlyInfo.getId());
                    relativesDO.setPeopleName(elderlyInfo.getElderName());
                    relativesDO.setRelation(elderlyImportExcelVO.getFirstRelation());
                    relativesDO.setPhone(elderlyImportExcelVO.getFirstPhone());
                    relativesDO.setNowAddress(elderlyImportExcelVO.getFirstAddress());
                    relativesDO.setAddress(elderlyImportExcelVO.getFirstAddress());
                    relativesMapper.insert(relativesDO);
                }
            }


            if (StringUtil.isNotEmptyORNull(elderlyImportExcelVO.getSecondName()) &&
                    StringUtil.isNotEmptyORNull(elderlyImportExcelVO.getSecondIdCard())) {
                List<RelativesDO> relativesDOS = relativesMapper.selectList(new LambdaQueryWrapperX<RelativesDO>()
                        .eqIfPresent(RelativesDO::getPeopleId, elderlyInfo.getId())
                        .eqIfPresent(RelativesDO::getName, elderlyImportExcelVO.getSecondName())
                        .eqIfPresent(RelativesDO::getIdCard, elderlyImportExcelVO.getSecondIdCard())
                        .eq(RelativesDO::getTenantId, TenantContextHolder.getTenantId()));
                if (null != relativesDOS && !relativesDOS.isEmpty()) {
                    RelativesDO relativesDO = relativesDOS.get(0);
                    relativesDO.setRelation(elderlyImportExcelVO.getSecondRelation());
                    relativesDO.setPhone(elderlyImportExcelVO.getSecondPhone());
                    relativesDO.setNowAddress(elderlyImportExcelVO.getSecondAddress());
                    relativesDO.setAddress(elderlyImportExcelVO.getSecondAddress());
                    relativesMapper.updateById(relativesDO);
                } else if (StringUtil.isNotEmptyORNull(elderlyImportExcelVO.getSecondName())
                        && StringUtil.isNotEmptyORNull(elderlyImportExcelVO.getSecondIdCard())) {
                    RelativesDO relativesDO = new RelativesDO();
                    relativesDO.setName(elderlyImportExcelVO.getSecondName());
                    relativesDO.setIdCard(elderlyImportExcelVO.getSecondIdCard());
                    relativesDO.setPeopleId(elderlyInfo.getId());
                    relativesDO.setPeopleName(elderlyInfo.getElderName());
                    relativesDO.setRelation(elderlyImportExcelVO.getSecondRelation());
                    relativesDO.setTelephone(elderlyImportExcelVO.getSecondPhone());
                    relativesDO.setPhone(elderlyImportExcelVO.getSecondPhone());
                    relativesDO.setNowAddress(elderlyImportExcelVO.getSecondAddress());
                    relativesDO.setAddress(elderlyImportExcelVO.getSecondAddress());
                    relativesMapper.insert(relativesDO);
                }
            }
            i++;
        }
        map.put("successCount", i);
        map.put("failCount", errorList.size());
        map.put("errorList", errorList);
        return map;
    }

    private void checkImportData(ElderlyImportExcelVO elderlyImportExcelVO) {
        if (StringUtils.isBlank(elderlyImportExcelVO.getElderName())) {
            elderlyImportExcelVO.setErrorMsg("[长者名称]未填写,请仔细检查");
        }
//        if (StringUtils.isBlank(elderlyImportExcelVO.getPapersType())) {
//            elderlyImportExcelVO.setErrorMsg("有必填项未填写,请仔细检查");
//        }
        if (elderlyImportExcelVO.getElderSex() == null) {
            elderlyImportExcelVO.setErrorMsg("[性别]未填写,请仔细检查");
        }
        if (StringUtils.isBlank(elderlyImportExcelVO.getIdCard())) {
            elderlyImportExcelVO.setErrorMsg("[身份证号]未填写,请仔细检查");
        }
        if (elderlyImportExcelVO.getInStatusType() == null) {
            elderlyImportExcelVO.setErrorMsg("[入住类型]未填写,请仔细检查");
        }
        if (elderlyImportExcelVO.getIdCard() != null) {
            ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectOne(new LambdaQueryWrapperX<ElderlyInfoDO>()
                    .eq(ElderlyInfoDO::getIdCard, elderlyImportExcelVO.getIdCard())
                    .eq(ElderlyInfoDO::getTenantId, TenantContextHolder.getTenantId()));

            if (elderlyInfoDO != null) {
                elderlyImportExcelVO.setErrorMsg("数据重复,请仔细检查");
            }
        }
    }

    @Override
    public Map<String, Object> importElderFile(List<ElderlyFileImportExcelVO> dataList) {
        List<ElderlyFileImportExcelVO> errorList = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        int i = 0;
        for (ElderlyFileImportExcelVO elderlyFileImportExcelVO : dataList) {
            checkImportElderFileData(elderlyFileImportExcelVO);
            if (StringUtils.isNotBlank(elderlyFileImportExcelVO.getErrorMsg())) {
                errorList.add(elderlyFileImportExcelVO);
                continue;
            }
            ElderlyInfoDO elderlyInfoDO = null;
            if (elderlyFileImportExcelVO.getIdCard() != null) {
                elderlyInfoDO = elderlyInfoMapper.selectOne(new LambdaQueryWrapperX<ElderlyInfoDO>()
                        .eq(ElderlyInfoDO::getIdCard, elderlyFileImportExcelVO.getIdCard())
                        .eq(ElderlyInfoDO::getElderName, elderlyFileImportExcelVO.getElderName())
                        .eq(ElderlyInfoDO::getTenantId, TenantContextHolder.getTenantId()));

                if (elderlyInfoDO == null) {
                    elderlyFileImportExcelVO.setErrorMsg("长者不存在,请仔细检查长者姓名和身份证号码");
                    continue;
                }
            }

            ElderlyInfoDO elderlyInfo = new ElderlyInfoDO();
            BeanUtils.copyProperties(elderlyFileImportExcelVO, elderlyInfo);
            elderlyInfo.setCreateBy(SecurityFrameworkUtils.getLoginUserNickname());
            elderlyInfo.setCreateTime(new Date());
            elderlyInfo.setTenantId(TenantContextHolder.getTenantId());
            elderlyInfo.setId(elderlyInfoDO.getId());
            elderlyInfoMapper.updateById(elderlyInfo);

            if (StringUtil.isNotEmptyORNull(elderlyFileImportExcelVO.getFirstName()) &&
                    StringUtil.isNotEmptyORNull(elderlyFileImportExcelVO.getFirstIdCard())) {
                List<RelativesDO> relativesDOS = relativesMapper.selectList(new LambdaQueryWrapperX<RelativesDO>()
                        .eqIfPresent(RelativesDO::getPeopleId, elderlyInfo.getId())
                        .eqIfPresent(RelativesDO::getName, elderlyFileImportExcelVO.getFirstName())
                        .eqIfPresent(RelativesDO::getIdCard, elderlyFileImportExcelVO.getFirstIdCard())
                        .eq(RelativesDO::getTenantId, TenantContextHolder.getTenantId()));
                if (null != relativesDOS && relativesDOS.size() > 0) {
                    RelativesDO relativesDO = relativesDOS.get(0);
                    relativesDO.setRelation(elderlyFileImportExcelVO.getFirstRelation());
                    relativesDO.setGender(elderlyFileImportExcelVO.getFirstGender());
                    relativesDO.setTelephone(elderlyFileImportExcelVO.getFirstTelephone());
                    relativesDO.setPhone(elderlyFileImportExcelVO.getFirstPhone());
                    relativesDO.setWorkUnit(elderlyFileImportExcelVO.getFirstWorkUnit());
                    relativesDO.setNowAddress(elderlyFileImportExcelVO.getFirstNowAddress());
                    relativesDO.setAddress(elderlyFileImportExcelVO.getFirstAddress());
                    relativesMapper.updateById(relativesDO);
                } else if (StringUtil.isNotEmptyORNull(elderlyFileImportExcelVO.getFirstName())
                        && StringUtil.isNotEmptyORNull(elderlyFileImportExcelVO.getFirstIdCard())) {
                    RelativesDO relativesDO = new RelativesDO();
                    relativesDO.setName(elderlyFileImportExcelVO.getFirstName());
                    relativesDO.setIdCard(elderlyFileImportExcelVO.getFirstIdCard());
                    relativesDO.setPapersType(elderlyFileImportExcelVO.getFirstPapersType().toString());
                    relativesDO.setPeopleId(elderlyInfo.getId());
                    relativesDO.setPeopleName(elderlyInfo.getElderName());
                    relativesDO.setRelation(elderlyFileImportExcelVO.getFirstRelation());
                    relativesDO.setGender(elderlyFileImportExcelVO.getFirstGender());
                    relativesDO.setTelephone(elderlyFileImportExcelVO.getFirstTelephone());
                    relativesDO.setPhone(elderlyFileImportExcelVO.getFirstPhone());
                    relativesDO.setWorkUnit(elderlyFileImportExcelVO.getFirstWorkUnit());
                    relativesDO.setNowAddress(elderlyFileImportExcelVO.getFirstNowAddress());
                    relativesDO.setAddress(elderlyFileImportExcelVO.getFirstAddress());
                    relativesMapper.insert(relativesDO);
                }
            }


            if (StringUtil.isNotEmptyORNull(elderlyFileImportExcelVO.getSecondName()) &&
                    StringUtil.isNotEmptyORNull(elderlyFileImportExcelVO.getSecondIdCard())) {
                List<RelativesDO> relativesDOS = relativesMapper.selectList(new LambdaQueryWrapperX<RelativesDO>()
                        .eqIfPresent(RelativesDO::getPeopleId, elderlyInfo.getId())
                        .eqIfPresent(RelativesDO::getName, elderlyFileImportExcelVO.getSecondName())
                        .eqIfPresent(RelativesDO::getIdCard, elderlyFileImportExcelVO.getSecondIdCard())
                        .eq(RelativesDO::getTenantId, TenantContextHolder.getTenantId()));
                if (null != relativesDOS && relativesDOS.size() > 0) {
                    RelativesDO relativesDO = relativesDOS.get(0);
                    relativesDO.setRelation(elderlyFileImportExcelVO.getSecondRelation());
                    relativesDO.setGender(elderlyFileImportExcelVO.getSecondGender());
                    relativesDO.setTelephone(elderlyFileImportExcelVO.getSecondTelephone());
                    relativesDO.setPhone(elderlyFileImportExcelVO.getSecondPhone());
                    relativesDO.setWorkUnit(elderlyFileImportExcelVO.getSecondWorkUnit());
                    relativesDO.setNowAddress(elderlyFileImportExcelVO.getSecondNowAddress());
                    relativesDO.setAddress(elderlyFileImportExcelVO.getSecondAddress());
                    relativesMapper.updateById(relativesDO);
                } else if (StringUtil.isNotEmptyORNull(elderlyFileImportExcelVO.getSecondName())
                        && StringUtil.isNotEmptyORNull(elderlyFileImportExcelVO.getSecondIdCard())) {
                    RelativesDO relativesDO = new RelativesDO();
                    relativesDO.setName(elderlyFileImportExcelVO.getSecondName());
                    relativesDO.setIdCard(elderlyFileImportExcelVO.getSecondIdCard());
                    relativesDO.setPapersType(elderlyFileImportExcelVO.getSecondPapersType().toString());
                    relativesDO.setPeopleId(elderlyInfo.getId());
                    relativesDO.setPeopleName(elderlyInfo.getElderName());
                    relativesDO.setRelation(elderlyFileImportExcelVO.getSecondRelation());
                    relativesDO.setGender(elderlyFileImportExcelVO.getSecondGender());
                    relativesDO.setTelephone(elderlyFileImportExcelVO.getSecondTelephone());
                    relativesDO.setPhone(elderlyFileImportExcelVO.getSecondPhone());
                    relativesDO.setWorkUnit(elderlyFileImportExcelVO.getSecondWorkUnit());
                    relativesDO.setNowAddress(elderlyFileImportExcelVO.getSecondNowAddress());
                    relativesDO.setAddress(elderlyFileImportExcelVO.getSecondAddress());
                    relativesMapper.insert(relativesDO);
                }
            }
            i++;
        }
        map.put("successCount", i);
        map.put("failCount", errorList.size());
        map.put("errorList", errorList);
        return map;
    }


    private void checkImportElderFileData(ElderlyFileImportExcelVO excelVO) {
        if (StringUtils.isBlank(excelVO.getElderName())) {
            excelVO.setErrorMsg("[长者名称]未填写,请仔细检查");
        }
//        if (StringUtils.isBlank(elderlyImportExcelVO.getPapersType())) {
//            elderlyImportExcelVO.setErrorMsg("有必填项未填写,请仔细检查");
//        }
        if (excelVO.getElderSex() == null) {
            excelVO.setErrorMsg("[性别]未填写,请仔细检查");
        }
        if (StringUtils.isBlank(excelVO.getIdCard())) {
            excelVO.setErrorMsg("[身份证号]未填写,请仔细检查");
        }
//        if (excelVO.getIdCard() != null){
//            ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectOne(new LambdaQueryWrapperX<ElderlyInfoDO>()
//                    .eq(ElderlyInfoDO::getIdCard, excelVO.getIdCard())
//                    .eq(ElderlyInfoDO::getElderName, excelVO.getElderName())
//                    .eq(ElderlyInfoDO::getTenantId,TenantContextHolder.getTenantId()));
//
//            if (elderlyInfoDO == null){
//                excelVO.setErrorMsg("长者不存在,请仔细检查长者姓名和身份证号码");
//            }
//        }
    }

    @Override
    @TenantIgnore
    public ElderlyInfoDO selectByIdTenantIgnore(Long elderlyId) {
        return elderlyInfoMapper.selectById(elderlyId);
    }

    @Override
    public List<ElderlyInfoDO> queryUngroupedElderlyList(Integer orgType, Long tenantId) {
        List<ElderlyInfoDO> elderlyInfoList = elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .eqIfPresent(ElderlyInfoDO::getOrgType, orgType)
                .eqIfPresent(ElderlyInfoDO::getTenantId, tenantId)
                .eq(ElderlyInfoDO::getInStatus, 1)
                .isNull(ElderlyInfoDO::getNurseGroupId));
        for (ElderlyInfoDO elderlyInfoDO : elderlyInfoList) {
            elderlyInfoDO.setBedName(buildService.getFullBedName(elderlyInfoDO.getId()));
        }
        return elderlyInfoList;
    }

    @Override
    public Map<String, Object> selectExportElderData(ElderlyInfoPageReqVO pageVO) {
        Page<ElderlyInfoDO> page = new Page<>(pageVO.getPageNo(), pageVO.getPageSize());
        List<ElderlyInfoDO> list = elderlyInfoMapper.findPage(page, pageVO);
        AtomicInteger atomicInteger = new AtomicInteger(1);
        List<ElderlyBaseInfoExportExcelVO> baseInfoExportExcelList = list.stream().map(e -> {
            ElderlyBaseInfoExportExcelVO baseInfoExportExcelVO = new ElderlyBaseInfoExportExcelVO();
            BeanUtils.copyProperties(e, baseInfoExportExcelVO);
            baseInfoExportExcelVO.setNum(atomicInteger.getAndIncrement());
            baseInfoExportExcelVO.setBirthdayCareDate(e.getBirthday() == null ? null : e.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate());
            baseInfoExportExcelVO.setBedName(buildService.getFullBedName(e.getId()));
            if (e.getNurseLevelId() != null) {
                NurseLevelDO nurseLevelDO = nurseLevelMapper.selectById(e.getNurseLevelId());
                baseInfoExportExcelVO.setNurseLevelName(nurseLevelDO == null ? null : nurseLevelDO.getNurseLevelName());
            }
            //查询亲属信息（取最早创建的两条：第一托养人、第二托养人）
            List<RelativesDO> relativesList = relativesMapper.selectList(new LambdaQueryWrapperX<RelativesDO>()
                    .eq(RelativesDO::getPeopleId, e.getId())
                    .orderByAsc(RelativesDO::getId));
            if (relativesList != null && !relativesList.isEmpty()) {
                RelativesDO first = relativesList.get(0);
                BeanUtils.copyProperties(first, baseInfoExportExcelVO, "idCard", "address", "papersType");
                baseInfoExportExcelVO.setRelativesPapersType(first.getPapersType());
                baseInfoExportExcelVO.setRelativesIdCard(first.getIdCard());
                baseInfoExportExcelVO.setRelativeAddress(first.getAddress());
            }
            if (relativesList != null && relativesList.size() >= 2) {
                RelativesDO second = relativesList.get(1);
                baseInfoExportExcelVO.setSecondName(second.getName());
                baseInfoExportExcelVO.setSecondRelation(second.getRelation());
                baseInfoExportExcelVO.setSecondGender(second.getGender());
                baseInfoExportExcelVO.setSecondPhone(second.getPhone());
                baseInfoExportExcelVO.setSecondRelativesPapersType(second.getPapersType());
                baseInfoExportExcelVO.setSecondRelativesIdCard(second.getIdCard());
                baseInfoExportExcelVO.setSecondTelephone(second.getTelephone());
                baseInfoExportExcelVO.setSecondWorkUnit(second.getWorkUnit());
                baseInfoExportExcelVO.setSecondNowAddress(second.getNowAddress());
                baseInfoExportExcelVO.setSecondRelativeAddress(second.getAddress());
            }
            return baseInfoExportExcelVO;
        }).collect(Collectors.toList());

        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("baseInfo", baseInfoExportExcelList);
        dataMap.put("contractInfo", new ArrayList<ElderlyContractInfoExportExcelVO>());
        return dataMap;
    }

    @Override
    @TenantIgnore
    public CheckInRecordDetailRespVO getCheckInDetail(Long id) {
        CheckInRecordDetailRespVO detailRespVO = elderlyInfoMapper.getCheckInDetail(id);
        List<RelativesDO> relatives = relativesMapper.selectList(new LambdaQueryWrapper<RelativesDO>().eq(RelativesDO::getPeopleId, detailRespVO.getElderId()));
        detailRespVO.setRelativesList(relatives);
        Gson gson = new Gson();
        String contractJson = detailRespVO.getContractJson();
        CheckInContractReqVO contractReqVO = gson.fromJson(contractJson, CheckInContractReqVO.class);
        Type listType = new TypeToken<List<CheckInExpenseItemReqVo>>() {
        }.getType();
        List<CheckInExpenseItemReqVo> monthlyExpenses = gson.fromJson(detailRespVO.getMonthlyExpensesJson(), listType);
        List<CheckInExpenseItemReqVo> oneTimeExpenses = gson.fromJson(detailRespVO.getOneTimeExpensesJson(), listType);
        List<CheckInExpenseItemReqVo> stageExpenses = gson.fromJson(detailRespVO.getStageExpensesJson(), listType);
        detailRespVO.setMonthlyExpenses(monthlyExpenses);
        detailRespVO.setOneTimeExpenses(oneTimeExpenses);
        detailRespVO.setStageExpenses(stageExpenses);
        detailRespVO.setElderlyContractDO(contractReqVO);
        NurseLevelDO nurseLevelDO = nurseLevelMapper.selectById(detailRespVO.getNurseLevelId());
        detailRespVO.setNurseLevelName(nurseLevelDO == null ? null : nurseLevelDO.getNurseLevelName());
        detailRespVO.setContractJson("");
        detailRespVO.setMonthlyExpensesJson("");
        detailRespVO.setOneTimeExpensesJson("");
        detailRespVO.setStageExpensesJson("");
        return detailRespVO;
    }

    @Override
    @TenantIgnore
    public ElderlyHomeRespVO getHomeDataElderlyPortrait(ElderlyInfoHomeDataReqVO reqVO) {
        ElderlyHomeTAgeBarChart elderlyHomeTAgeBarChart = new ElderlyHomeTAgeBarChart();
        elderlyHomeTAgeBarChart.setYAxis(new String[]{"50岁以下", "51-60岁", "61-70岁", "71-80岁", "81-90岁", "90岁以上"});
        List<ElderlyInfoDO> elderlyList = elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .eq(ElderlyInfoDO::getInStatus, 1)
                .in(ElderlyInfoDO::getTenantId, reqVO.getTenantIds()));
        BigDecimal count = new BigDecimal(elderlyList.size());
        List<String> series = new ArrayList<>();
        AtomicInteger count50 = new AtomicInteger();
        AtomicInteger count60 = new AtomicInteger();
        AtomicInteger count70 = new AtomicInteger();
        AtomicInteger count80 = new AtomicInteger();
        AtomicInteger count90 = new AtomicInteger();
        AtomicInteger countLast = new AtomicInteger();


        elderlyList.forEach(e -> {
            Integer elderAge = e.getElderAge();
            if (null == elderAge) return;
            if (elderAge <= 50) {
                count50.set(count50.get() + 1);
            }
            if (elderAge > 50 && elderAge <= 60) {
                count60.set(count60.get() + 1);
            }
            if (elderAge > 60 && elderAge <= 70) {
                count70.set(count70.get() + 1);
            }
            if (elderAge > 70 && elderAge <= 80) {
                count80.set(count80.get() + 1);
            }
            if (elderAge > 80 && elderAge <= 90) {
                count80.set(count80.get() + 1);
            }
            if (elderAge > 90) {
                countLast.set(countLast.get() + 1);
            }
        });
        BigDecimal decimal50 = new BigDecimal(count50.get());
        BigDecimal proportion50 = decimal50.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimal60 = new BigDecimal(count60.get());
        BigDecimal proportion60 = decimal60.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimal70 = new BigDecimal(count70.get());
        BigDecimal proportion70 = decimal70.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimal80 = new BigDecimal(count80.get());
        BigDecimal proportion80 = decimal80.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimal90 = new BigDecimal(count90.get());
        BigDecimal proportion90 = decimal90.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimalLast = new BigDecimal(countLast.get());
        BigDecimal proportionLast = decimalLast.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        series.add(String.valueOf(count50) + "(" + proportion50 + "%)");
        series.add(String.valueOf(count60) + "(" + proportion60 + "%)");
        series.add(String.valueOf(count70) + "(" + proportion70 + "%)");
        series.add(String.valueOf(count80) + "(" + proportion80 + "%)");
        series.add(String.valueOf(count90) + "(" + proportion90 + "%)");
        series.add(String.valueOf(countLast) + "(" + proportionLast + "%)");
        elderlyHomeTAgeBarChart.setSeries(series.toArray(new String[series.size() - 1]));
        elderlyHomeTAgeBarChart.setElderlyTotal(elderlyList.size());

        List<ElderlyHomeGenderRespVO> genderList = new ArrayList<>();
        ElderlyHomeGenderRespVO maleGenderRespVO = new ElderlyHomeGenderRespVO();
        ElderlyHomeGenderRespVO femaleGenderRespVO = new ElderlyHomeGenderRespVO();
        long maleCount = elderlyList.stream().filter(e -> e.getElderSex() == 1) == null ? 0 :
                elderlyList.stream().filter(e -> e.getElderSex() == 1).count();
        BigDecimal decimalMale = new BigDecimal(maleCount);
        BigDecimal proportionMale = decimalMale.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        maleGenderRespVO.setName("男");
        maleGenderRespVO.setValue(maleCount + "(" + proportionMale + "%)");

        long femaleCount = elderlyList.stream().filter(e -> e.getElderSex() == 2) == null ? 0 :
                elderlyList.stream().filter(e -> e.getElderSex() == 2).count();
        BigDecimal decimalFemale = new BigDecimal(femaleCount);
        BigDecimal proportionFemale = decimalFemale.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        femaleGenderRespVO.setName("女");
        femaleGenderRespVO.setValue(femaleCount + "(" + proportionFemale + "%)");


        genderList.add(maleGenderRespVO);
        genderList.add(femaleGenderRespVO);

        return new ElderlyHomeRespVO().setElderlyHomeTAgeBarChart(elderlyHomeTAgeBarChart).setGenderList(genderList);
    }

    @Override
    @TenantIgnore
    public ElderlyHomeRespVO getHomeDataCheckInAnalysis(ElderlyInfoHomeDataReqVO reqVO) {
        ElderlyHomeCheckInBarChart elderlyHomeCheckInYearBarChart = new ElderlyHomeCheckInBarChart();
        ElderlyHomeCheckInBarChart elderlyHomeCheckInMonthBarChart = new ElderlyHomeCheckInBarChart();

        List<ElderlyInfoDO> elderlyList = elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .eq(ElderlyInfoDO::getInStatus, 1)
                .in(ElderlyInfoDO::getTenantId, reqVO.getTenantIds()));

        Map<String, Integer> yearMap = new HashMap<>();
        Map<String, Integer> monthMap = new HashMap<>();
        LocalDateTime now = LocalDateTime.now();

        // 获取当前年限，和往前5年的年份
        List<String> xYearList = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            String s = String.valueOf(now.minusYears(i).getYear());
            xYearList.add(s);
            yearMap.put(s, 0);
        }
        // xList 转 数组
        String[] xArray = xYearList.toArray(new String[xYearList.size() - 1]);
        elderlyHomeCheckInYearBarChart.setXAxis(xArray);

        // 获取当前年月，和往前6个月的年月
        List<String> xMonthList = new ArrayList<>();
        for (int i = 0; i < 7; i++) {
            String format = now.minusMonths(i).format(DateTimeFormatter.ofPattern("yyyy-MM"));
            xMonthList.add(format);
            monthMap.put(format, 0);
        }
        elderlyHomeCheckInMonthBarChart.setXAxis(xMonthList.toArray(new String[xMonthList.size() - 1]));


        //  nianlin
        ElderlyHomeTAgeBarChart elderlyHomeTAgeBarChart = new ElderlyHomeTAgeBarChart();
        elderlyHomeTAgeBarChart.setYAxis(new String[]{"50岁以下", "51-60岁", "61-70岁", "71-80岁", "81-90岁", "90岁以上"});
        BigDecimal count = new BigDecimal(elderlyList.size());
        List<String> series = new ArrayList<>();
        AtomicInteger count50 = new AtomicInteger();
        AtomicInteger count60 = new AtomicInteger();
        AtomicInteger count70 = new AtomicInteger();
        AtomicInteger count80 = new AtomicInteger();
        AtomicInteger count90 = new AtomicInteger();
        AtomicInteger countLast = new AtomicInteger();


        elderlyList.forEach(elderlyInfoDO -> {
            String yearValue = "";
            String monthValue = "";
            LocalDate localDate = elderlyInfoDO.getCheckInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            yearValue = localDate.getYear() + "";
            monthValue = localDate.getYear() + "-" + String.format("%02d", localDate.getMonthValue());
            if (yearMap.containsKey(yearValue)) {
                yearMap.put(yearValue, yearMap.get(yearValue) + 1);
            }
            if (monthMap.containsKey(monthValue)) {
                monthMap.put(monthValue, monthMap.get(monthValue) + 1);
            }

            Integer elderAge = elderlyInfoDO.getElderAge();
            if (null == elderAge) return;
            if (elderAge <= 50) {
                count50.set(count50.get() + 1);
            }
            if (elderAge > 50 && elderAge <= 60) {
                count60.set(count60.get() + 1);
            }
            if (elderAge > 60 && elderAge <= 70) {
                count70.set(count70.get() + 1);
            }
            if (elderAge > 70 && elderAge <= 80) {
                count80.set(count80.get() + 1);
            }
            if (elderAge > 80 && elderAge <= 90) {
                count80.set(count80.get() + 1);
            }
            if (elderAge > 90) {
                countLast.set(countLast.get() + 1);
            }

        });
        // map的值转数组
        elderlyHomeCheckInYearBarChart.setSeries(yearMap.values().toArray(new Integer[yearMap.size()]));
        elderlyHomeCheckInMonthBarChart.setSeries(monthMap.values().toArray(new Integer[monthMap.size()]));
        ElderlyHomeRespVO elderlyHomeRespVO = new ElderlyHomeRespVO();
        elderlyHomeRespVO.setElderlyTrendsYearBarChart(elderlyHomeCheckInYearBarChart);
        elderlyHomeRespVO.setElderlyTrendsMonthBarChart(elderlyHomeCheckInMonthBarChart);

        BigDecimal decimal50 = new BigDecimal(count50.get());
        BigDecimal proportion50 = decimal50.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimal60 = new BigDecimal(count60.get());
        BigDecimal proportion60 = decimal60.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimal70 = new BigDecimal(count70.get());
        BigDecimal proportion70 = decimal70.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimal80 = new BigDecimal(count80.get());
        BigDecimal proportion80 = decimal80.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimal90 = new BigDecimal(count90.get());
        BigDecimal proportion90 = decimal90.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        BigDecimal decimalLast = new BigDecimal(countLast.get());
        BigDecimal proportionLast = decimalLast.multiply(new BigDecimal(100)).divide(count, 2, BigDecimal.ROUND_HALF_UP);
        series.add(String.valueOf(count50) + "(" + proportion50 + "%)");
        series.add(String.valueOf(count60) + "(" + proportion60 + "%)");
        series.add(String.valueOf(count70) + "(" + proportion70 + "%)");
        series.add(String.valueOf(count80) + "(" + proportion80 + "%)");
        series.add(String.valueOf(count90) + "(" + proportion90 + "%)");
        series.add(String.valueOf(countLast) + "(" + proportionLast + "%)");
        elderlyHomeTAgeBarChart.setSeries(series.toArray(new String[series.size() - 1]));
        elderlyHomeTAgeBarChart.setElderlyTotal(elderlyList.size());
        elderlyHomeRespVO.setElderlyHomeTAgeBarChart(elderlyHomeTAgeBarChart);
        return elderlyHomeRespVO;
    }

    @Override
    @TenantIgnore
    public ElderlyVitalSignsStatisticsMainRespVO getElderlyVitalSigns(ElderlyVitalSignsMainPageReqVO pageReqVO) {

        ElderlyVitalSignsStatisticsMainRespVO mainRespVO = new ElderlyVitalSignsStatisticsMainRespVO();


        Page<BedChangeRecordRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<ElderlyVitalSignsStatisticsRespVO> statisticsRespVOList = elderlyInfoMapper.selectVitalSignsList(page, pageReqVO);

        statisticsRespVOList.forEach(vitalSignsRespVO -> {

            vitalSignsRespVO.setBedName(buildService.getFullBedName(vitalSignsRespVO.getElderId()));

            // 查询所有的统计数据
            List<ElderlyVitalSignsDO> elderlyVitalSignsDOList = vitalSignsMapper.selectList(new LambdaQueryWrapperX<ElderlyVitalSignsDO>()
                    .eq(ElderlyVitalSignsDO::getElderId, vitalSignsRespVO.getElderId())
                    .orderByDesc(ElderlyVitalSignsDO::getCreatedTime));
//            if (null == elderlyVitalSignsDOList || elderlyVitalSignsDOList.size() == 0) return;
            ElderlyVitalSignsStatisticsRespVO assembleValue = assembleVitalSigns(elderlyVitalSignsDOList);
            vitalSignsRespVO.setBodyTemperatureData(assembleValue.getBodyTemperatureData());
            vitalSignsRespVO.setBloodPressureData(assembleValue.getBloodPressureData());
            vitalSignsRespVO.setInRoomStatus(1);
        });

//        PageResult<ElderlyVitalSignsRespVO> elderlyVitalSignsRespVOPageResult = new PageResult<>(vitalSignsList, page.getTotal());

        Long bedCount = buildBedMapper.selectCount(new LambdaQueryWrapperX<BuildBedDO>()
                .in(BuildBedDO::getTenantId, pageReqVO.getTenantIds()));
        Long freeBedCount = buildBedMapper.selectCount(new LambdaQueryWrapperX<BuildBedDO>()
                .eq(BuildBedDO::getStatus, 0)
                .in(BuildBedDO::getTenantId, pageReqVO.getTenantIds()));
        Long checkInBedCount = buildBedMapper.selectCount(new LambdaQueryWrapperX<BuildBedDO>()
                .eq(BuildBedDO::getStatus, 1)
                .in(BuildBedDO::getTenantId, pageReqVO.getTenantIds()));
        mainRespVO.setTotalBed(bedCount.intValue());
        mainRespVO.setEmptyBed(freeBedCount.intValue());
        mainRespVO.setCheckInBed(checkInBedCount.intValue());
        mainRespVO.setVitalSignsList(statisticsRespVOList);
        return mainRespVO;
    }

    @Override
    @TenantIgnore
    public PageResult<ElderlyVitalSignsStatisticsTodayRespVO> getElderlyVitalSignsToday(ElderlyVitalSignsMainPageReqVO pageReqVO) {
        Page<BedChangeRecordRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        pageReqVO.setSystolicPressureMin(VitalSignsEnum.SYSTOLIC_PRESSURE.getMinValue());
        pageReqVO.setSystolicPressureMax(VitalSignsEnum.SYSTOLIC_PRESSURE.getMaxValue());
        pageReqVO.setDiastolicPressureMin(VitalSignsEnum.DIASTOLIC_PRESSURE.getMinValue());
        pageReqVO.setDiastolicPressureMax(VitalSignsEnum.DIASTOLIC_PRESSURE.getMaxValue());
        List<ElderlyVitalSignsStatisticsTodayRespVO> statisticsRespVOList = elderlyInfoMapper.selectVitalSignsTodayList(page, pageReqVO);

        statisticsRespVOList.forEach(vitalSignsRespVO -> {
            vitalSignsRespVO.setBedName(buildService.getFullBedName(vitalSignsRespVO.getElderId()));
            String systolicPressurePrompt = "";
            String diastolicPressurePrompt = "";

            if (StringUtils.isNotBlank(vitalSignsRespVO.getSystolicPressure())) {
                VitalSignsEnum vitalSignsEnum = VitalSignsEnum.SYSTOLIC_PRESSURE;
                double v = Double.parseDouble(vitalSignsRespVO.getSystolicPressure());
                if (v >= vitalSignsEnum.getMaxValue()) {
                    systolicPressurePrompt = "收缩压偏高";
                } else if (v < vitalSignsEnum.getMinValue()) {
                    systolicPressurePrompt = "收缩压偏低";
                } else {
                    systolicPressurePrompt = "收缩压正常";
                }
            }

            if (StringUtils.isNotBlank(vitalSignsRespVO.getDiastolicPressure())) {
                VitalSignsEnum vitalSignsEnum = VitalSignsEnum.DIASTOLIC_PRESSURE;
                double v = Double.parseDouble(vitalSignsRespVO.getDiastolicPressure());

                if (v >= vitalSignsEnum.getMaxValue()) {
                    diastolicPressurePrompt = "舒张压偏高";
                } else if (v < vitalSignsEnum.getMinValue()) {
                    diastolicPressurePrompt = "舒张压偏高";
                } else {
                    diastolicPressurePrompt = "舒张压正常";
                }
            }
            vitalSignsRespVO.setSystolicPressurePrompt(systolicPressurePrompt);
            vitalSignsRespVO.setDiastolicPressurePrompt(diastolicPressurePrompt);
        });


        PageResult<ElderlyVitalSignsStatisticsTodayRespVO> pageResult = new PageResult<>(statisticsRespVOList, page.getTotal());
        return pageResult;
    }


    @Override
    @TenantIgnore
    public ElderlyHomeRespVO getElderlyInfoHomeData(ElderlyInfoHomeDataReqVO reqVO) {
        ElderlyHomeRespVO elderlyHomeRespVO = new ElderlyHomeRespVO();

        if (null == reqVO.getTenantIds() || reqVO.getTenantIds().length == 0 || 0 == reqVO.getTenantIds()[0]) {
            List<GroupTenantDO> groupTenantDOS = groupTenantMapper.selectList(new LambdaQueryWrapperX<GroupTenantDO>()
                    .eq(GroupTenantDO::getGroupTenantId, 1l));
            if (null == groupTenantDOS || groupTenantDOS.size() == 0) {
                return null;
            }
            // 获取groupTenantDOS下所有的orgTenantId转为list
            List<Long> orgTenantIds = groupTenantDOS.stream().map(GroupTenantDO::getOrgTenantId).collect(Collectors.toList());
            reqVO.setTenantIds(orgTenantIds.toArray(new Long[0]));
        }

        // 异步处理 getElderlyHomeOverviewSummary
        CompletableFuture<ElderlyHomeOverviewSummary> overviewSummaryFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getElderlyHomeOverviewSummary(reqVO);
            } catch (Exception e) {
                log.error("getElderlyHomeOverviewSummary 执行异常", e);
                return null; // 返回空值作为默认值
            }
        }, executorService);

        // 异步处理 getBusiness
        CompletableFuture<ElderlyHomeBusiness> businessFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getBusiness(reqVO);
            } catch (Exception e) {
                log.error("getBusiness 执行异常", e);
                return null; // 返回空值作为默认值
            }
        }, executorService);

        // 异步处理 getHouseholdAndEconomic
        CompletableFuture<ElderlyHomeRespVO> householdAndEconomicFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getHouseholdAndEconomic(reqVO);
            } catch (Exception e) {
                log.error("getHouseholdAndEconomic 执行异常", e);
                return null; // 返回空值作为默认值
            }
        }, executorService);

        // 异步处理 tenantMapper.selectByHomeData(reqVO) 并增加超时处理
        CompletableFuture<List<ElderlyHomeTenantRespVO>> tenantFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return tenantMapper.selectByHomeData(reqVO);
            } catch (Exception e) {
                log.error("tenantMapper.selectByHomeData 执行异常", e);
                return Collections.emptyList(); // 返回空列表作为默认值
            }
        }, executorService);


        // 异步处理 getHouseholdAndEconomic
        CompletableFuture<ElderlyHomeRespVO> elderlyTrendsFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getHomeDataCheckInAnalysis(reqVO);
            } catch (Exception e) {
                log.error("getHomeDataCheckInAnalysis 执行异常", e);
                return null; // 返回空值作为默认值
            }
        }, executorService);

        // 异步处理 diseaseTypeFuture
        CompletableFuture<List<ElderlyHomeDiseaseType>> diseaseTypeFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getHomeDataDiseaseTypeFuture(reqVO);
            } catch (Exception e) {
                log.error("getHomeDataDiseaseTypeFuture 执行异常", e);
                return Collections.emptyList(); // 返回空列表作为默认值
            }
        }, executorService);


        // 设置超时处理
        CompletableFuture<ElderlyHomeOverviewSummary> overviewSummaryTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> overviewSummaryTimeoutFuture.completeExceptionally(new TimeoutException("getElderlyHomeOverviewSummary 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<ElderlyHomeBusiness> businessTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> businessTimeoutFuture.completeExceptionally(new TimeoutException("getBusiness 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<ElderlyHomeRespVO> householdAndEconomicTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> householdAndEconomicTimeoutFuture.completeExceptionally(new TimeoutException("getHouseholdAndEconomic 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<List<ElderlyHomeTenantRespVO>> tenantTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> tenantTimeoutFuture.completeExceptionally(new TimeoutException("tenantMapper.selectByHomeData 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<ElderlyHomeRespVO> elderlyTrendsTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> elderlyTrendsTimeoutFuture.completeExceptionally(new TimeoutException("elderlyTrendsFuture 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<List<ElderlyHomeDiseaseType>> diseaseTypeTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> diseaseTypeTimeoutFuture.completeExceptionally(new TimeoutException("diseaseTypeFuture 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        // 合并异步任务和超时任务
        CompletableFuture<ElderlyHomeOverviewSummary> combinedOverviewSummaryFuture = overviewSummaryFuture.applyToEither(overviewSummaryTimeoutFuture, Function.identity());
        CompletableFuture<ElderlyHomeBusiness> combinedBusinessFuture = businessFuture.applyToEither(businessTimeoutFuture, Function.identity());
        CompletableFuture<ElderlyHomeRespVO> combinedHouseholdAndEconomicFuture = householdAndEconomicFuture.applyToEither(householdAndEconomicTimeoutFuture, Function.identity());
        CompletableFuture<List<ElderlyHomeTenantRespVO>> combinedTenantFuture = tenantFuture.applyToEither(tenantTimeoutFuture, Function.identity());
        CompletableFuture<ElderlyHomeRespVO> combinedTrendsFuture = elderlyTrendsFuture.applyToEither(elderlyTrendsTimeoutFuture, Function.identity());
        CompletableFuture<List<ElderlyHomeDiseaseType>> combinedDiseaseTypeFuture = diseaseTypeFuture.applyToEither(diseaseTypeTimeoutFuture, Function.identity());

        // 等待异步任务完成并获取结果
        ElderlyHomeOverviewSummary overviewSummary = null;
        ElderlyHomeBusiness business = null;
        ElderlyHomeRespVO householdAndEconomic = null;
        ElderlyHomeRespVO elderlyTrends = null;
        List<ElderlyHomeDiseaseType> elderlyHomeDiseaseTypes = null;
        List<ElderlyHomeTenantRespVO> tenantList = Collections.emptyList();
        try {
            overviewSummary = combinedOverviewSummaryFuture.get(); // 获取异步任务结果
            business = combinedBusinessFuture.get(); // 获取异步任务结果
            householdAndEconomic = combinedHouseholdAndEconomicFuture.get(); // 获取异步任务结果
            tenantList = combinedTenantFuture.get(); // 获取异步任务结果
            elderlyTrends = combinedTrendsFuture.get();
            elderlyHomeDiseaseTypes = combinedDiseaseTypeFuture.get();

        } catch (Exception e) {
            log.error("异步处理异常", e);
        }

        elderlyHomeRespVO.setOverviewSummary(overviewSummary);
        elderlyHomeRespVO.setBusiness(business);
        if (householdAndEconomic != null) {
            elderlyHomeRespVO.setEconomic(householdAndEconomic.getEconomic());
            elderlyHomeRespVO.setHousehold(householdAndEconomic.getHousehold());
        }
        elderlyHomeRespVO.setTenantList(tenantList);
        elderlyHomeRespVO.setElderlyTrendsYearBarChart(elderlyTrends.getElderlyTrendsYearBarChart());
        elderlyHomeRespVO.setElderlyTrendsMonthBarChart(elderlyTrends.getElderlyTrendsMonthBarChart());
        elderlyHomeRespVO.setElderlyHomeTAgeBarChart(elderlyTrends.getElderlyHomeTAgeBarChart());
        elderlyHomeRespVO.setDiseaseType(elderlyHomeDiseaseTypes);
        return elderlyHomeRespVO;
    }


    @Override
    @TenantIgnore
    public ElderlyHomeRespVO getTenantHomeData(ElderlyInfoHomeDataReqVO reqVO) {
        ElderlyHomeRespVO elderlyHomeRespVO = new ElderlyHomeRespVO();

        if (null == reqVO.getTenantIds() || reqVO.getTenantIds().length == 0 || 0 == reqVO.getTenantIds()[0]) {
            List<GroupTenantDO> groupTenantDOS = groupTenantMapper.selectList(new LambdaQueryWrapperX<GroupTenantDO>()
                    .eq(GroupTenantDO::getGroupTenantId, 1l));
            if (null == groupTenantDOS || groupTenantDOS.size() == 0) {
                return null;
            }

            // 获取groupTenantDOS下所有的orgTenantId转为list
            List<Long> orgTenantIds = groupTenantDOS.stream().map(GroupTenantDO::getOrgTenantId).collect(Collectors.toList());
            reqVO.setTenantIds(orgTenantIds.toArray(new Long[0]));
        }

        // 异步处理 getElderlyHomeOverviewSummary
        CompletableFuture<ElderlyHomeOverviewSummary> overviewSummaryFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getElderlyHomeOverviewSummary(reqVO);
            } catch (Exception e) {
                log.error("getElderlyHomeOverviewSummary 执行异常", e);
                return null; // 返回空值作为默认值
            }
        }, executorService);


        // 异步处理 getHouseholdAndEconomic
        CompletableFuture<ElderlyHomeRespVO> householdAndEconomicFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getHouseholdAndEconomic(reqVO);
            } catch (Exception e) {
                log.error("getHouseholdAndEconomic 执行异常", e);
                return null; // 返回空值作为默认值
            }
        }, executorService);


        // 异步处理 tenantMapper.selectByHomeData(reqVO) 并增加超时处理
        CompletableFuture<List<ElderlyHomeTenantRespVO>> tenantFuture = CompletableFuture.supplyAsync(() -> {
            try {

                List<ElderlyHomeTenantRespVO> elderlyHomeTenantRespVOS = tenantMapper.selectByHomeData(reqVO);

                if (null != elderlyHomeTenantRespVOS && elderlyHomeTenantRespVOS.size() > 0) {
                    elderlyHomeTenantRespVOS.forEach(elderlyHomeTenantRespVO -> {
                        String picture = elderlyHomeTenantRespVO.getPicture();
                        if (null != picture) {
                            picture = picture.replace("\\", "");
                            // 解析JSON数组
                            JSONArray jsonArray = JSONObject.parseArray(picture);

                            // 获取第一个JSON对象
                            JSONObject jsonObject = jsonArray.getJSONObject(0);

                            // 提取fileUrl的值
                            String fileUrl = jsonObject.getString("fileUrl");
                            elderlyHomeTenantRespVO.setPicture(fileUrl);
                        }
                    });
                }

                return elderlyHomeTenantRespVOS;
            } catch (Exception e) {
                log.error("tenantMapper.selectByHomeData 执行异常", e);
                return Collections.emptyList(); // 返回空列表作为默认值
            }
        }, executorService);


        // 异步处理 getHouseholdAndEconomic
        CompletableFuture<ElderlyHomeRespVO> elderlyTrendsFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getHomeDataCheckInAnalysis(reqVO);
            } catch (Exception e) {
                log.error("getHomeDataCheckInAnalysis 执行异常", e);
                return null; // 返回空值作为默认值
            }
        }, executorService);


        CompletableFuture<List<ElderlyHomeService>> serviceFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return getHomeDataService(reqVO);
            } catch (Exception e) {
                log.error("getHomeDataCheckInAnalysis 执行异常", e);
                return null; // 返回空值作为默认值
            }
        }, executorService);


        // 异步处理 getHouseholdAndEconomic
//        CompletableFuture<ElderlySanChart> sexAndNcdSanFuture = CompletableFuture.supplyAsync(() -> {
//            try {
//                return getSexAndNcdSan(reqVO);
//            } catch (Exception e) {
//                log.error("getHomeDataCheckInAnalysis 执行异常", e);
//                return null; // 返回空值作为默认值
//            }
//        }, executorService);


        // 设置超时处理
        CompletableFuture<ElderlyHomeOverviewSummary> overviewSummaryTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> overviewSummaryTimeoutFuture.completeExceptionally(new TimeoutException("getElderlyHomeOverviewSummary 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<ElderlyHomeBusiness> businessTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> businessTimeoutFuture.completeExceptionally(new TimeoutException("getBusiness 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<ElderlyHomeRespVO> householdAndEconomicTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> householdAndEconomicTimeoutFuture.completeExceptionally(new TimeoutException("getHouseholdAndEconomic 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<List<ElderlyHomeTenantRespVO>> tenantTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> tenantTimeoutFuture.completeExceptionally(new TimeoutException("tenantMapper.selectByHomeData 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<ElderlyHomeRespVO> elderlyTrendsTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> elderlyTrendsTimeoutFuture.completeExceptionally(new TimeoutException("elderlyTrendsFuture 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);

        CompletableFuture<ElderlyHomeRespVO> sexAndNcdSanTimeoutFuture = new CompletableFuture<>();
        timeoutExecutor.schedule(() -> sexAndNcdSanTimeoutFuture.completeExceptionally(new TimeoutException("sexAndNcdSanFuture 超时")), TIMEOUT_DURATION, TimeUnit.SECONDS);


        // 合并异步任务和超时任务
        CompletableFuture<ElderlyHomeOverviewSummary> combinedOverviewSummaryFuture = overviewSummaryFuture.applyToEither(overviewSummaryTimeoutFuture, Function.identity());
        CompletableFuture<ElderlyHomeRespVO> combinedHouseholdAndEconomicFuture = householdAndEconomicFuture.applyToEither(householdAndEconomicTimeoutFuture, Function.identity());
        CompletableFuture<List<ElderlyHomeTenantRespVO>> combinedTenantFuture = tenantFuture.applyToEither(tenantTimeoutFuture, Function.identity());

        // 等待异步任务完成并获取结果
        ElderlyHomeOverviewSummary overviewSummary = null;
        ElderlyHomeBusiness business = null;
        ElderlyHomeRespVO householdAndEconomic = null;
        ElderlyHomeRespVO elderlyTrends = null;
        ElderlySanChart elderlySanChart = null;
        List<ElderlyHomeService> elderlyHomeServices = null;
        List<ElderlyHomeTenantRespVO> tenantList = Collections.emptyList();
        try {
            overviewSummary = combinedOverviewSummaryFuture.get(); // 获取异步任务结果
            householdAndEconomic = combinedHouseholdAndEconomicFuture.get(); // 获取异步任务结果
            tenantList = combinedTenantFuture.get(); // 获取异步任务结果
            elderlyTrends = elderlyTrendsFuture.get();
            //elderlySanChart = sexAndNcdSanFuture.get();
            elderlyHomeServices = serviceFuture.get();
        } catch (Exception e) {
            log.error("异步处理异常", e);
        }

        elderlyHomeRespVO.setOverviewSummary(overviewSummary);
        if (householdAndEconomic != null) {
            elderlyHomeRespVO.setEconomic(householdAndEconomic.getEconomic());
            elderlyHomeRespVO.setHousehold(householdAndEconomic.getHousehold());
        }
        elderlyHomeRespVO.setTenantList(tenantList);
        elderlyHomeRespVO.setElderlyTrendsYearBarChart(elderlyTrends == null ? null : elderlyTrends.getElderlyTrendsYearBarChart());
        elderlyHomeRespVO.setElderlyTrendsMonthBarChart(elderlyTrends == null ? null : elderlyTrends.getElderlyTrendsMonthBarChart());
        elderlyHomeRespVO.setElderlyHomeTAgeBarChart(elderlyTrends == null ? null : elderlyTrends.getElderlyHomeTAgeBarChart());


        List<TodayUpdate> todayUpdateList = getTodayUpdate(reqVO);
        elderlyHomeRespVO.setTodayUpdate(todayUpdateList);
        elderlyHomeRespVO.setServiceList(elderlyHomeServices);
        elderlyHomeRespVO.setWeekDishes(getCateringPlan(reqVO.getTenantIds()[0]));
        elderlyHomeRespVO.setWeekActivity(getActivity(reqVO));
        return elderlyHomeRespVO;

    }

    @Override
    public String getMonitorUrl(Long tenantId) {
        return openApi.getOpenAddress(tenantId);
    }

    @Override
    @TenantIgnore
    public ElderlyWeeklyOperationSummaryRespVO getWeeklyOperationSummary(Long tenantId) {
        Long targetTenantId = tenantId;
        if (targetTenantId == null) {
            targetTenantId = Optional.ofNullable(SecurityFrameworkUtils.getLoginUser())
                    .map(user -> user.getTenantId())
                    .orElse(TenantContextHolder.getTenantId());
        }

        LocalDate today = LocalDate.now();
        LocalDate weekStart = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.SATURDAY));
        LocalDate weekEnd = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY));
        LocalDate monthStart = today.withDayOfMonth(1);

        LocalDateTime weekStartDateTime = weekStart.atStartOfDay();
        LocalDateTime weekEndDateTime = weekEnd.plusDays(1).atStartOfDay();

        ElderlyWeeklyOperationSummaryRespVO respVO = new ElderlyWeeklyOperationSummaryRespVO();

        TenantDO tenantDO = tenantMapper.selectById(targetTenantId);
        respVO.setInstitutionName(tenantDO != null ? tenantDO.getName() : "");

        Long periodEndCount = elderlyInfoMapper.selectCount(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .eq(ElderlyInfoDO::getTenantId, targetTenantId)
                .eq(ElderlyInfoDO::getDeleted, 0)
                .eq(ElderlyInfoDO::getOrgType, 1)
                .eq(ElderlyInfoDO::getInStatus, 1));
        respVO.setPeriodEndCount(periodEndCount == null ? 0L : periodEndCount);

        Long weeklyCheckInCount = elderlyCheckInRecordMapper.selectCount(new LambdaQueryWrapperX<ElderlyCheckInRecordDO>()
                .eq(ElderlyCheckInRecordDO::getTenantId, targetTenantId)
                .eq(ElderlyCheckInRecordDO::getStatus, 2)
                .ge(ElderlyCheckInRecordDO::getCheckInTime, weekStartDateTime)
                .lt(ElderlyCheckInRecordDO::getCheckInTime, weekEndDateTime));
        respVO.setWeeklyCheckInCount(weeklyCheckInCount == null ? 0L : weeklyCheckInCount);

        Long weeklyCheckOutCount = elderlyRetreatRecordMapper.selectCount(new LambdaQueryWrapperX<ElderlyRetreatRecordDO>()
                .eq(ElderlyRetreatRecordDO::getTenantId, targetTenantId)
                .ge(ElderlyRetreatRecordDO::getRetreatDate, weekStart)
                .le(ElderlyRetreatRecordDO::getRetreatDate, weekEnd));
        respVO.setWeeklyCheckOutCount(weeklyCheckOutCount == null ? 0L : weeklyCheckOutCount);

        Long monthlyCheckInCount = elderlyCheckInRecordMapper.selectCount(new LambdaQueryWrapperX<ElderlyCheckInRecordDO>()
                .eq(ElderlyCheckInRecordDO::getTenantId, targetTenantId)
                .eq(ElderlyCheckInRecordDO::getStatus, 2)
                .ge(ElderlyCheckInRecordDO::getCheckInTime, monthStart.atStartOfDay())
                .lt(ElderlyCheckInRecordDO::getCheckInTime, today.plusDays(1).atStartOfDay()));
        Long monthlyCheckOutCount = elderlyRetreatRecordMapper.selectCount(new LambdaQueryWrapperX<ElderlyRetreatRecordDO>()
                .eq(ElderlyRetreatRecordDO::getTenantId, targetTenantId)
                .ge(ElderlyRetreatRecordDO::getRetreatDate, monthStart)
                .le(ElderlyRetreatRecordDO::getRetreatDate, today));

        long safeWeekIn = weeklyCheckInCount == null ? 0L : weeklyCheckInCount;
        long safeWeekOut = weeklyCheckOutCount == null ? 0L : weeklyCheckOutCount;
        long safeMonthIn = monthlyCheckInCount == null ? 0L : monthlyCheckInCount;
        long safeMonthOut = monthlyCheckOutCount == null ? 0L : monthlyCheckOutCount;

        respVO.setMonthlyCheckInCount(safeMonthIn);
        respVO.setMonthlyCheckOutCount(safeMonthOut);

        long weeklyNetGrowth = safeWeekIn - safeWeekOut;
        respVO.setWeeklyNetGrowthCount(weeklyNetGrowth);
        respVO.setPeriodBeginCount(Math.max(0L, respVO.getPeriodEndCount() - weeklyNetGrowth));
        respVO.setMonthlyNetGrowthCount(safeMonthIn - safeMonthOut);

        Long periodEndEmptyBedCount = buildBedMapper.selectCount(new LambdaQueryWrapperX<BuildBedDO>()
                .eq(BuildBedDO::getTenantId, targetTenantId)
                .eq(BuildBedDO::getOrgType, 1)
                .eq(BuildBedDO::getStatus, 0));
        respVO.setPeriodEndEmptyBedCount(periodEndEmptyBedCount == null ? 0L : periodEndEmptyBedCount);

        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.gt(ElderlyAskLeaveDO::getUpdateDate, LocalDateTime.now()).or().isNull(ElderlyAskLeaveDO::getUpdateDate)))).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];
        List<TodayUpdate> updates = new ArrayList<>();
        LocalDate today = LocalDate.now();

        // 1. 未来一个月长者生日提醒
        LocalDate oneMonthLater = today.plusMonths(1);
        List<ElderlyInfoDO> allElderly = elderlyInfoMapper.selectList(new LambdaQueryWrapper<ElderlyInfoDO>()
                .eq(ElderlyInfoDO::getTenantId, tenantId));
        allElderly.stream()
                .filter(e -> e.getBirthday() != null)
                .map(e -> {
                    LocalDate birthday = e.getBirthday().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
                    LocalDate thisYearBirthday = birthday.withYear(today.getYear());
                    if (thisYearBirthday.isBefore(today)) {
                        thisYearBirthday = thisYearBirthday.plusYears(1);
                    }
                    return new AbstractMap.SimpleEntry<>(e.getElderName(), thisYearBirthday);
                })
                .filter(entry -> !entry.getValue().isBefore(today) && !entry.getValue().isAfter(oneMonthLater))
                .sorted(Map.Entry.comparingByValue())
                .forEach(entry -> {
                    String content = String.format("%s的生日是 %s", entry.getKey(), entry.getValue().format(DateTimeFormatter.ofPattern("MM-dd")));
                    updates.add(TodayUpdate.builder().content(content).build());
                });

        // 2. 过去一个星期入住长者、退住长者
        LocalDateTime oneWeekAgo = LocalDateTime.now().minusDays(7);
        List<ElderlyCheckInRecordDO> checkIns = elderlyCheckInRecordMapper.selectList(
                new LambdaQueryWrapperX<ElderlyCheckInRecordDO>().ge(ElderlyCheckInRecordDO::getCheckInTime, oneWeekAgo)
                        .eq(ElderlyCheckInRecordDO::getTenantId,tenantId));
        checkIns.forEach(r -> {
            ElderlyInfoDO elder = elderlyInfoMapper.selectById(r.getElderId());
            String name = elder != null ? elder.getElderName() : "未知长者";
            String dateStr = r.getCheckInTime() == null ? "" : r.getCheckInTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().toString();
            updates.add(TodayUpdate.builder().content(name + " 于 " + dateStr + " 入住").build());
        });

        List<ElderlyRetreatRecordDO> checkOuts = elderlyRetreatRecordMapper.selectList(
                new LambdaQueryWrapperX<ElderlyRetreatRecordDO>().ge(ElderlyRetreatRecordDO::getRetreatDate, oneWeekAgo.toLocalDate())
                        .eq(ElderlyRetreatRecordDO::getTenantId,tenantId));
        checkOuts.forEach(r -> {
            ElderlyInfoDO elder = elderlyInfoMapper.selectById(r.getElderlyId());
            String name = elder != null ? elder.getElderName() : "未知长者";
            updates.add(TodayUpdate.builder().content(name + " 于 " + r.getRetreatDate() + " 退住").build());
        });

        // 3. 当天外出（即不在院）人数
        Date todayStartDate = Date.from(today.atStartOfDay(ZoneId.systemDefault()).toInstant());
        Date todayEndDate = Date.from(today.atTime(23, 59, 59).atZone(ZoneId.systemDefault()).toInstant());
        Long outOfOfficeCount = elderlyAskLeaveMapper.selectCount(new LambdaQueryWrapperX<ElderlyAskLeaveDO>()
                .eq(ElderlyAskLeaveDO::getTenantId, tenantId)
                .le(ElderlyAskLeaveDO::getOutDate, todayEndDate)
                .and(w -> w.ge(ElderlyAskLeaveDO::getComeDate, todayStartDate).or().isNull(ElderlyAskLeaveDO::getComeDate)));
        updates.add(TodayUpdate.builder().content("当天外出人数: " + outOfOfficeCount).build());

        // 4. 餐单更新提醒
        List<CateringPlanDO> activeMenus = cateringPlanMapper.selectList(new LambdaQueryWrapperX<CateringPlanDO>()
                .le(CateringPlanDO::getScheduledStartDate, today)
                .ge(CateringPlanDO::getScheduledEndDate, today)
                .eq(CateringPlanDO::getTenantId,tenantId));
        activeMenus.forEach(menu -> updates.add(TodayUpdate.builder().content("餐单更新: " + menu.getPlanName()).build()));

        // 5. 活动更新提醒
        List<MonthlyActivityDO> activities = monthlyActivityMapper.selectList(new LambdaQueryWrapperX<MonthlyActivityDO>()
                .eq(MonthlyActivityDO::getActivityDate, today)
                .eq(MonthlyActivityDO::getTenantId,tenantId));
        activities.forEach(activity -> updates.add(TodayUpdate.builder().content("活动提醒: " + activity.getActivityTitle()).build()));

        // 6 & 7. 今日订餐信息（按创建时间筛选，去重后输出）
        List<DishesOrderStatisticsDO> meals = dishesOrderStatisticsMapper.selectList(new LambdaQueryWrapperX<DishesOrderStatisticsDO>()
                .eq(DishesOrderStatisticsDO::getTenantId, tenantId)
                .between(DishesOrderStatisticsDO::getCreatedTime, todayStartDate, todayEndDate));

        if (!meals.isEmpty()) {
            // 每个长者只保留一条（按创建时间升序）
            Map<Long, DishesOrderStatisticsDO> mealByElder = meals.stream()
                    .filter(m -> m.getElderId() != null)
                    .sorted(Comparator.comparing(DishesOrderStatisticsDO::getCreatedTime))
                    .collect(Collectors.toMap(DishesOrderStatisticsDO::getElderId, m -> m, (a, b) -> a));

            // 准备查询菜品明细
            List<Long> orderIds = mealByElder.values().stream().map(DishesOrderStatisticsDO::getId).collect(Collectors.toList());
            Map<Long, List<DishesOrderItemDO>> itemsByOrder = dishesOrderItemMapper.selectList(
                    new LambdaQueryWrapperX<DishesOrderItemDO>().in(DishesOrderItemDO::getOrderStatisticsId, orderIds))
                    .stream()
                    .collect(Collectors.groupingBy(DishesOrderItemDO::getOrderStatisticsId));

            updates.add(TodayUpdate.builder().content("今日订餐人数: " + mealByElder.size()).build());

            mealByElder.values().forEach(meal -> {
                ElderlyInfoDO elder = elderlyInfoMapper.selectById(meal.getElderId());
                if (elder == null) {
                    return;
                }
                List<DishesOrderItemDO> items = itemsByOrder.get(meal.getId());
                if (items == null || items.isEmpty()) {
                    return;
                }
                String foodNames = items.stream()
                        .map(DishesOrderItemDO::getFoodName)
                        .filter(StringUtils::isNotBlank)
                        .collect(Collectors.joining("、"));
                String createdTimeStr = meal.getCreatedTime().toInstant().atZone(ZoneId.systemDefault())
                        .toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm"));
                String orderDateStr = meal.getOrderDate() != null
                        ? meal.getOrderDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate().toString()
                        : today.toString();
                String content = String.format("%s %s订了%s的 %s", createdTimeStr, elder.getElderName(), orderDateStr, foodNames);
                updates.add(TodayUpdate.builder().content(content).build());
            });
        }

        return updates;
    }


    ElderlyHomeOverviewSummary getElderlyHomeOverviewSummary(ElderlyInfoHomeDataReqVO reqVO) {
        ElderlyHomeOverviewSummary overviewSummary = new ElderlyHomeOverviewSummary();
        HomeOverviewSummaryDO homeOverviewSummaryDO = null;
        List<HomeOverviewSummaryDO> homeOverviewSummaryDOS = overviewSummaryMapper.selectList();
        if (null != homeOverviewSummaryDOS && !homeOverviewSummaryDOS.isEmpty()) {
            homeOverviewSummaryDO = homeOverviewSummaryDOS.get(0);
        } else {
            homeOverviewSummaryDO = new HomeOverviewSummaryDO();
        }

        // 总床位数量
        String bedCount = null;
        if (StringUtil.isNotEmptyORNull(homeOverviewSummaryDO.getOpenBedCount()) && reqVO.getQueryFlag() == 1) {
            bedCount = homeOverviewSummaryDO.getOpenBedCount();
        } else {
            Long resultCount = buildBedMapper.selectCount(new LambdaQueryWrapperX<BuildBedDO>()
                    .eq(BuildBedDO::getOrgType, 1)
                    .in(BuildBedDO::getTenantId, reqVO.getTenantIds()));
            bedCount = resultCount == null ? "0" : resultCount.toString();
        }

        // 入住数（剔除离住未返院）
        String checkInBedCount = null;
        if (StringUtil.isNotEmptyORNull(homeOverviewSummaryDO.getCheckInCount()) && reqVO.getQueryFlag() == 1) {
            checkInBedCount = homeOverviewSummaryDO.getCheckInCount();
        } else {
            Long resultCount = elderlyInfoMapper.selectCount(new LambdaQueryWrapperX<ElderlyInfoDO>()
                    .eq(ElderlyInfoDO::getInStatus, 1)
                    .eq(ElderlyInfoDO::getDeleted, 0)
                    .eq(ElderlyInfoDO::getOrgType, 1)
                    .in(ElderlyInfoDO::getTenantId, reqVO.getTenantIds()));

            Long tempOutCount = elderlyTempOutMapper.selectCount(new LambdaQueryWrapperX<ElderlyTempOutDO>()
                    .eq(ElderlyTempOutDO::getOutStatus, 1)
                    .in(ElderlyTempOutDO::getTenantId, reqVO.getTenantIds()));

            long checkInCount = (resultCount == null ? 0L : resultCount) - (tempOutCount == null ? 0L : tempOutCount);
            checkInBedCount = String.valueOf(Math.max(checkInCount, 0L));
        }

        // 离住数（未返院）
        String tempOutCountStr;
        Long resultCount = elderlyTempOutMapper.selectCount(new LambdaQueryWrapperX<ElderlyTempOutDO>()
                .eq(ElderlyTempOutDO::getOutStatus, 1)
                .in(ElderlyTempOutDO::getTenantId, reqVO.getTenantIds()));
        tempOutCountStr = resultCount == null ? "0" : resultCount.toString();

        // 退住数
        String retreatCountStr = null;
        if (StringUtil.isNotEmptyORNull(homeOverviewSummaryDO.getRetreatCount()) && reqVO.getQueryFlag() == 1) {
            retreatCountStr = homeOverviewSummaryDO.getRetreatCount();
        } else {
            // 计算过去一个月的时间范围
            LocalDate today = LocalDate.now();
            LocalDateTime endDate = today.atStartOfDay();
            LocalDateTime startDate = endDate.minusMonths(1);

            Long retreatCount = elderlyInfoMapper.selectCount(new LambdaQueryWrapperX<ElderlyInfoDO>()
                    .eq(ElderlyInfoDO::getInStatus, 2)
                    .eq(ElderlyInfoDO::getDeleted, 0)
                    .eq(ElderlyInfoDO::getOrgType, 1)
                    .ge(ElderlyInfoDO::getCheckOutTime, startDate)
                    .lt(ElderlyInfoDO::getCheckOutTime, endDate)
                    .in(ElderlyInfoDO::getTenantId, reqVO.getTenantIds()));
            retreatCountStr = retreatCount == null ? "0" : retreatCount.toString();
        }

        if (reqVO.getQueryFlag() == 2) {
            // 空床位数量
            Long freeBedCount = buildBedMapper.selectCount(new LambdaQueryWrapperX<BuildBedDO>()
                    .eq(BuildBedDO::getStatus, 0)
                    .in(BuildBedDO::getTenantId, reqVO.getTenantIds())
                    .eq(BuildBedDO::getOrgType, 1));
            // 预定数
            Long presetBedCount = buildBedMapper.selectCount(new LambdaQueryWrapperX<BuildBedDO>()
                    .eq(BuildBedDO::getStatus, 2)
                    .in(BuildBedDO::getTenantId, reqVO.getTenantIds())
                    .eq(BuildBedDO::getOrgType, 1));

            // 入住率
            BigDecimal checkInRate = BigDecimal.valueOf(Long.valueOf(checkInBedCount))
                    .divide(BigDecimal.valueOf(Long.valueOf(bedCount)), 2, BigDecimal.ROUND_HALF_UP).multiply(BigDecimal.valueOf(100));

            // 员工数
            Long employeeCount = userMapper.selectCount(new LambdaQueryWrapperX<AdminUserDO>()
                    .in(AdminUserDO::getTenantId, reqVO.getTenantIds()));

            // 护工数
            Long caregiverCount = userMapper.selectCount(new LambdaQueryWrapperX<AdminUserDO>()
                    .eq(AdminUserDO::getUserType, 4)
                    .in(AdminUserDO::getTenantId, reqVO.getTenantIds()));

            overviewSummary.setBedCount(bedCount);
            overviewSummary.setPresetCount("0");
            overviewSummary.setEmptyBedCount(freeBedCount.toString());
            overviewSummary.setOccupancyRate(checkInRate.toString() + "%");
            overviewSummary.setUserCount(employeeCount.toString());
            overviewSummary.setCaregiverCount(caregiverCount.toString());
        }

        // 机构数
        Long tenantCount = groupTenantMapper.selectCount(new LambdaQueryWrapperX<GroupTenantDO>()
                .eq(GroupTenantDO::getGroupTenantId, 1l));

        // 包房数
        Long privateRoomCount = elderlyInfoMapper.selectCount(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .eq(ElderlyInfoDO::getInStatus, 1)
                .eq(ElderlyInfoDO::getDeleted, 0)
                .eq(ElderlyInfoDO::getOrgType, 1)
                .eq(ElderlyInfoDO::getIsPrivateRoom, 1)
                .in(ElderlyInfoDO::getTenantId, reqVO.getTenantIds()));

        overviewSummary.setOpenBedCount(bedCount);
        overviewSummary.setCheckInCount(checkInBedCount);
        overviewSummary.setServiceCount(homeOverviewSummaryDO.getServiceCount());
        overviewSummary.setPlanBedCount(homeOverviewSummaryDO.getPlanBedCount());
        overviewSummary.setTenantCount(tenantCount.toString());
        overviewSummary.setRetreatCount(retreatCountStr);
        overviewSummary.setLeaveCount(tempOutCountStr);
        overviewSummary.setCommunityCount(homeOverviewSummaryDO.getCommunityCount());
        overviewSummary.setHomeBasedServiceCount(homeOverviewSummaryDO.getHomeBasedServiceCount());
        overviewSummary.setHomeBasedCateringCount(homeOverviewSummaryDO.getHomeBasedCateringCount());
        overviewSummary.setPrivateRoomCount(privateRoomCount == null ? "0" : privateRoomCount.toString());


        return overviewSummary;
    }

    ElderlyHomeBusiness getBusiness(ElderlyInfoHomeDataReqVO reqVO) {
        ElderlyHomeBusiness business = new ElderlyHomeBusiness();

        reqVO.setCurrentDate(LocalDate.now());

        // 咨询入住
        Long consultationCheckInCount = registrationMapper.selectCount(new LambdaQueryWrapperX<VisitRegistrationDO>()
                .eq(VisitRegistrationDO::getPurposeVisit, 6)
                .in(VisitRegistrationDO::getTenantId, reqVO.getTenantIds()));
        // 家属探访
        Long visitCount = registrationMapper.selectCount(new LambdaQueryWrapperX<VisitRegistrationDO>()
                .eq(VisitRegistrationDO::getPurposeVisit, 4)
                .in(VisitRegistrationDO::getTenantId, reqVO.getTenantIds()));

        // 本月预订
        Integer presetBedCount = buildBedMapper.selectCurrentPresetCount(reqVO);

        // 本月试住
        Integer tryStayCount = elderlyInfoMapper.selectTryStayCount(reqVO);

        // 本月外出
        Integer goOutCount = elderlyInfoMapper.selectGoOutCount(reqVO);

        // 本月入住
        Integer checkInCount = elderlyInfoMapper.selectCurrentCheckInCount(reqVO);

        business.setConsultationCheckInCount(consultationCheckInCount.intValue());
        business.setVisitCount(visitCount.intValue());
        business.setPresetCount(presetBedCount.intValue());
        business.setTryStayCount(tryStayCount);
        business.setGoOutCount(goOutCount);
        business.setCheckInCount(checkInCount);
        return business;
    }
    ElderlyHomeRespVO getHouseholdAndEconomic(ElderlyInfoHomeDataReqVO reqVO) {
        ElderlyHomeRespVO respVO = new ElderlyHomeRespVO();
        ElderlyHomeHousehold household = new ElderlyHomeHousehold();

        Integer queryFlag = reqVO.getQueryFlag();

        Integer householdTotal = 0;
        Integer nonHouseholdTotal = 0;
        Integer unknownTotal = 0;

        Integer endowmentInsurance = 0;
        BigDecimal endowmentInsuranceRatio = BigDecimal.ZERO;

        Integer cityLowIncome = 0;
        BigDecimal cityLowIncomeRatio = BigDecimal.ZERO;

        Integer childrenSupport = 0;
        BigDecimal childrenSupportRatio = BigDecimal.ZERO;

        Integer familyDeposit = 0;
        BigDecimal familyDepositRatio = BigDecimal.ZERO;

        Integer retirementPay = 0;
        BigDecimal retirementPayRatio = BigDecimal.ZERO;

        Integer fiveGuarantees = 0;
        BigDecimal fiveGuaranteesRatio = BigDecimal.ZERO;

        Integer pension = 0;
        BigDecimal pensionRatio = BigDecimal.ZERO;

        Integer commercialInsurance = 0;
        BigDecimal commercialInsuranceRatio = BigDecimal.ZERO;

        Integer other = 0;
        BigDecimal otherRatio = BigDecimal.ZERO;


        List<ElderlyInfoDO> elderlyList = elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .eq(ElderlyInfoDO::getInStatus, 1)
                .in(ElderlyInfoDO::getTenantId, reqVO.getTenantIds()));

        for (int i = 0; i < elderlyList.size(); i++) {
            ElderlyInfoDO elderlyInfoDO = elderlyList.get(i);
            String economySource = elderlyInfoDO.getEconomySource() == null ? "" : elderlyInfoDO.getEconomySource();
            if ("户籍".equals(elderlyInfoDO.getCensusRegister())) {
                householdTotal++;
            } else if ("非户籍".equals(elderlyInfoDO.getCensusRegister())) {
                nonHouseholdTotal++;
            } else {
                unknownTotal++;
            }


            // 养老保险,城市低保,子女供养.家庭存款,离退休金,五保,抚恤金,商业保险,其他
            switch (economySource) {
                case "养老保险":
                    endowmentInsurance++;
                    break;
                case "城市低保":
                    cityLowIncome++;
                    break;
                case "子女供养":
                    childrenSupport++;
                    break;
                case "家庭存款":
                    familyDeposit++;
                    break;
                case "离退休金":
                    retirementPay++;
                    break;
                case "五保":
                    fiveGuarantees++;
                    break;
                case "抚恤金":
                    pension++;
                    break;
                case "商业保险":
                    commercialInsurance++;
                    break;
                default:
                    other++;
                    break;
            }


        }
        BigDecimal count = BigDecimal.valueOf(elderlyList.size());

        BigDecimal decimal = new BigDecimal(100);

        ElderlyHomeEconomic economic = null;

        if (1 == queryFlag) {
            endowmentInsuranceRatio = BigDecimal.valueOf(endowmentInsurance).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);
            cityLowIncomeRatio = BigDecimal.valueOf(cityLowIncome).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);
            childrenSupportRatio = BigDecimal.valueOf(childrenSupport).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);
            familyDepositRatio = BigDecimal.valueOf(familyDeposit).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);
            retirementPayRatio = BigDecimal.valueOf(retirementPay).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);
            fiveGuaranteesRatio = BigDecimal.valueOf(fiveGuarantees).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);
            pensionRatio = BigDecimal.valueOf(pension).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);
            commercialInsuranceRatio = BigDecimal.valueOf(commercialInsurance).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);
            otherRatio = BigDecimal.valueOf(other).multiply(decimal).divide(count, 2, RoundingMode.HALF_UP);

            economic = ElderlyHomeEconomic.builder().endowmentInsurance(endowmentInsurance).endowmentInsuranceRatio(endowmentInsuranceRatio)
                    .cityLowIncome(cityLowIncome).cityLowIncomeRatio(cityLowIncomeRatio)
                    .childrenSupport(childrenSupport).childrenSupportRatio(childrenSupportRatio)
                    .familyDeposit(familyDeposit).familyDepositRatio(familyDepositRatio)
                    .retirementPay(retirementPay).retirementPayRatio(retirementPayRatio)
                    .fiveGuarantees(fiveGuarantees).fiveGuaranteesRatio(fiveGuaranteesRatio)
                    .pension(pension).pensionRatio(pensionRatio)
                    .commercialInsurance(commercialInsurance).commercialInsuranceRatio(commercialInsuranceRatio)
                    .other(other).otherRatio(otherRatio)
                    .build();
        }


        household.setHouseholdTotal(householdTotal);
        household.setNonHouseholdTotal(nonHouseholdTotal);
        household.setUnknownTotal(unknownTotal);

        respVO.setEconomic(economic);
        respVO.setHousehold(household);
        return respVO;
    }

    private static ElderlyVitalSignsStatisticsRespVO assembleVitalSigns(List<ElderlyVitalSignsDO> list) {
        Integer listSize = 0;
        if (null != list && list.size() > 0) {
            listSize = list.size() - 1;
        }

        ElderlyVitalSignsStatisticsRespVO respVO = new ElderlyVitalSignsStatisticsRespVO();
        int numberOfCycles = 7;

        List<String> bloodPressureDataList = new ArrayList<>();
        List<String> bodyTemperatureDataList = new ArrayList<>();

        for (int i = 0; i < numberOfCycles; i++) {
            String temperature = "0";
            String bloodOxygenSaturation = "0";
            if (i > listSize || (i == 0 && listSize == 0)) {
                bodyTemperatureDataList.add(temperature);
                bloodPressureDataList.add(bloodOxygenSaturation);
            } else {
                ElderlyVitalSignsDO elderlyVitalSigns = list.get(i);
                temperature = elderlyVitalSigns.getTemperature() == null ? "0" : elderlyVitalSigns.getTemperature();
                bloodOxygenSaturation = elderlyVitalSigns.getBloodOxygenSaturation() == null ? "0" : elderlyVitalSigns.getBloodOxygenSaturation();
                bodyTemperatureDataList.add(temperature);
                bloodPressureDataList.add(bloodOxygenSaturation);
            }
        }
        // list 转 数组
        String[] bodyTemperatureDataArray = bodyTemperatureDataList.toArray(new String[6]);
        String[] bloodPressureDataArray = bloodPressureDataList.toArray(new String[6]);
        respVO.setBodyTemperatureData(bodyTemperatureDataArray);
        respVO.setBloodPressureData(bloodPressureDataArray);
        return respVO;
    }


    @Override
    public void addElderlyAtHome(ElderlyInfoSaveReqVO reqVO) {
        ElderlyInfoDO elderlyInfoDO = new ElderlyInfoDO();
        BeanUtils.copyProperties(reqVO, elderlyInfoDO);
        elderlyInfoMapper.insert(elderlyInfoDO);
    }

    @Override
    public void updateElderlyAtHome(ElderlyInfoDO elderlyInfoDO) {
        elderlyInfoMapper.updateById(elderlyInfoDO);
    }

    @Override
    public void enableOrDisabled(Long elderId, Integer status) {
        ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectById(elderId);
        if (elderlyInfoDO != null) {
            elderlyInfoDO.setServiceStatus(status);
            elderlyInfoMapper.updateById(elderlyInfoDO);
        }
    }

    @Override
    public void deleteElderlyAtHome(List<Long> ids) {
        elderlyInfoMapper.deleteBatchIds(ids);
    }

    @Override
    public ElderlyInfoDO getElderlyAtHome(Long elderId) {
        return elderlyInfoMapper.selectById(elderId);
    }

    @Override
    @TenantIgnore
    public Map<String, Object> importKingdeeElderlyExcel(List<KingdeeElderlyExcelVO> list) {
        List<KingdeeElderlyExcelVO> errorList = new ArrayList<>();
        int i = 0;
        for (KingdeeElderlyExcelVO excelVO : list) {
            //查询老人信息
            ElderlyInfoDO elderlyInfo = elderlyInfoMapper.selectOne(new LambdaQueryWrapperX<ElderlyInfoDO>()
                    .eq(ElderlyInfoDO::getElderName, excelVO.getElderName())
                    .eq(ElderlyInfoDO::getTenantId, excelVO.getTenantId()));

            if (elderlyInfo == null) {
                errorList.add(excelVO);
                continue;
            }
            ElderlyInfoDO updateInfo = new ElderlyInfoDO();
            updateInfo.setId(elderlyInfo.getId());
            updateInfo.setKingdeeCustomerNumber(excelVO.getKingdeeCustomerNumber());
            elderlyInfoMapper.updateById(updateInfo);
            i += 1;

        }
        Map<String, Object> map = new HashMap<>();
        map.put("successCount", i);
        map.put("failCount", errorList.size());
        map.put("errorList", errorList);
        return map;
    }

    @Override
    @TenantIgnore
    public Map<String, Object> importKingdeeCustomerExcel(Long tenantId, List<KingdeeCustomerExcelVO> list) {
        // 失败明细：原样返回 + 在 errorList 每条里写入失败原因，便于前端展示
        List<KingdeeCustomerExcelVO> errorList = new ArrayList<>();
        int successCount = 0;

        Map<String, Object> map = new HashMap<>();

        if (list == null || list.isEmpty()) {
            map.put("successCount", 0);
            map.put("failCount", 0);
            map.put("errorList", errorList);
            return map;
        }

        if (tenantId == null) {
            map.put("successCount", 0);
            map.put("failCount", list.size());
            // 写入失败原因到每一条，便于前端直接展示 errorList
            for (KingdeeCustomerExcelVO vo : list) {
                if (vo != null) {
                    vo.setError("tenantId(机构id)不能为空");
                }
            }
            map.put("errorList", list);
            map.put("message", "tenantId(机构id)不能为空");
            return map;
        }

        int row = 1;
        for (KingdeeCustomerExcelVO excelVO : list) {
            row++;
            if (excelVO == null) {
                // 无法写入具体行数据，跳过
                continue;
            }

            String customerName = excelVO.getCustomerName();
            String customerNumber = excelVO.getCustomerNumber();

            // 必填校验：客户名称、客户编码
            if (StringUtil.isEmpty(customerName) || StringUtil.isEmpty(customerNumber)) {
                excelVO.setError("第" + row + "行：客户名称/客户编码不能为空");
                errorList.add(excelVO);
                continue;
            }

            try {
                // 仅按接口传入的 tenantId(机构id) 精确匹配
                List<ElderlyInfoDO> elderlyInfos = elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
                        .eq(ElderlyInfoDO::getElderName, customerName)
                        .eq(ElderlyInfoDO::getTenantId, tenantId));

                ElderlyInfoDO elderlyInfo = null;
                if (elderlyInfos != null) {
                    if (elderlyInfos.size() == 1) {
                        elderlyInfo = elderlyInfos.get(0);
                    } else if (elderlyInfos.size() > 1) {
                        // 同一机构内同名多条，无法确定要更新哪条，计入失败
                        excelVO.setError("第" + row + "行：机构内存在多条同名长者[" + customerName + "]，无法匹配");
                        errorList.add(excelVO);
                        continue;
                    }
                }

                if (elderlyInfo == null) {
                    excelVO.setError("第" + row + "行：未找到长者[" + customerName + "]（tenantId=" + tenantId + "）");
                    errorList.add(excelVO);
                    continue;
                }

                ElderlyInfoDO updateInfo = new ElderlyInfoDO();
                updateInfo.setId(elderlyInfo.getId());
                updateInfo.setKingdeeCustomerNumber(customerNumber);
                elderlyInfoMapper.updateById(updateInfo);
                successCount += 1;
            } catch (Exception e) {
                excelVO.setError("第" + row + "行：处理异常 - " + (e.getMessage() == null ? e.getClass().getSimpleName() : e.getMessage()));
                errorList.add(excelVO);
                log.error("importKingdeeCustomerExcel error, tenantId={}, row={}, data={}", tenantId, row, JSON.toJSONString(excelVO), e);
            }
        }

        map.put("successCount", successCount);
        map.put("failCount", errorList.size());
        map.put("errorList", errorList);
        return map;
    }

    @Override
    public Boolean saveResult(MbtiRecordBO reqVO) {
        int insert = mbtiRecordMapper.insert(reqVO);
        if (insert > 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public PageResult<MbtiRecordBO> findMbtiPage(MbtiRecordPageReqVO pageVO) {
        Page<MbtiRecordBO> page = new Page<>(pageVO.getPageNo(), pageVO.getPageSize());
        List<MbtiRecordBO> list = mbtiRecordMapper.findPage(page, pageVO);
        return new PageResult<>(list, page.getTotal());
    }

    @Override
    public List<GroupTenantRespVO> getGroupTenant(Long groupId) {
        if (null == groupId) {
            groupId = 1l;
        }
        List<GroupTenantDO> groupTenantDOS = groupTenantMapper.selectList(new LambdaQueryWrapperX<GroupTenantDO>()
                .eq(GroupTenantDO::getGroupTenantId, groupId));
        if (null == groupTenantDOS || groupTenantDOS.size() == 0) {
            return null;
        }
        // 获取groupTenantDOS下所有的orgTenantId转为list
        List<Long> orgTenantIds = groupTenantDOS.stream().map(GroupTenantDO::getOrgTenantId).collect(Collectors.toList());
        List<TenantDO> tenantDOS = tenantMapper.selectList(new LambdaQueryWrapperX<TenantDO>().in(TenantDO::getId, orgTenantIds));
        List<GroupTenantRespVO> list = new ArrayList<>();

        groupTenantDOS.get(0).getOrgTenantId();
        GroupsDO groupsDO = groupsMapper.selectById(groupId);
        GroupTenantRespVO groupTenantRespVO = new GroupTenantRespVO();
        groupTenantRespVO.setTentantId(0l);
        groupTenantRespVO.setTentantName(groupsDO.getName());
        groupTenantRespVO.setGroupFlag(1);
        list.add(groupTenantRespVO);
        tenantDOS.forEach(tenantDO -> {
            GroupTenantRespVO tenantRespVO = new GroupTenantRespVO();
            tenantRespVO.setTentantId(tenantDO.getId());
            tenantRespVO.setTentantName(tenantDO.getName());
            tenantRespVO.setGroupFlag(0);
            list.add(tenantRespVO);
        });
        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";
    }

    @Override
    public String miniGetElderInfo(String elderName, Long tenantId) {
        List<ElderlyInfoDO> elderlyInfoDOS = elderlyInfoMapper.selectList(new LambdaQueryWrapperX<ElderlyInfoDO>()
                .like(ElderlyInfoDO::getElderName, elderName)
                .eq(ElderlyInfoDO::getTenantId, tenantId));
        if(CollectionUtil.isEmpty(elderlyInfoDOS)){
            throw exceptionCustomMsg(COMMON_ERROR,"不存在该长者：" + elderName);
        }
        if(elderlyInfoDOS.size() > 1){
            String multiName = elderlyInfoDOS.stream().map(e -> e.getElderName()).collect(Collectors.joining(","));
            throw exceptionCustomMsg(COMMON_ERROR,"该长者名称存在多个：" + multiName);
        }
        ElderlyInfoDO elderlyInfo = elderlyInfoDOS.get(0);
        Long elderId = elderlyInfo.getId();
        JSONObject data = new JSONObject();
        ElderlyInfoDO detailById = findDetailById(elderId);
        ElderlyContractResVO contractByElderId = elderlyContractService.getContractByElderId(elderId);
        ExpenseBillPageReqVO expenseBillPageReqVO = new ExpenseBillPageReqVO();
        expenseBillPageReqVO.setPageSize(1000);
        expenseBillPageReqVO.setElderId(elderId);
        PageResult<ExpenseOrderDO> expenseOrderPageByElderId = expenseOrderService.getExpenseOrderPageByElderId(expenseBillPageReqVO);
        Map<String, Object> expenseOrderAmountByElderId = expenseOrderService.getExpenseOrderAmountByElderId(elderId);
        data.put("elderInfo",detailById);
        data.put("contractInfo",contractByElderId);
        data.put("expenseOrder",expenseOrderPageByElderId);
        data.put("ExpenseOrderAmount",expenseOrderAmountByElderId);
        return data.toString();
    }

    ElderlySanChart getSexAndNcdSan(ElderlyInfoHomeDataReqVO reqVO) {

        ElderlySanChart elderlySanChart = new ElderlySanChart();
        ElderlySanSourceRespVO sexSource1 = ElderlySanSourceRespVO.builder().name("男性").build();
        ElderlySanSourceRespVO sexSource2 = ElderlySanSourceRespVO.builder().name("女性").build();
        elderlySanChart.setSexData(Arrays.asList(sexSource1, sexSource2));
        ElderlySanLinksRespVO sexLinks1 = ElderlySanLinksRespVO.builder().source("男性").target("90岁以上").value(3).build();
        ElderlySanLinksRespVO sexLinks2 = ElderlySanLinksRespVO.builder().source("女性").target("86至90岁").value(7).build();
        ElderlySanLinksRespVO sexLinks3 = ElderlySanLinksRespVO.builder().source("女性").target("81至85岁").value(8).build();
        ElderlySanLinksRespVO sexLinks4 = ElderlySanLinksRespVO.builder().source("男性").target("76至80岁").value(2).build();
        ElderlySanLinksRespVO sexLinks5 = ElderlySanLinksRespVO.builder().source("男性").target("70至75岁").value(4).build();
        ElderlySanLinksRespVO sexLinks6 = ElderlySanLinksRespVO.builder().source("男性").target("60至69岁").value(10).build();
        ElderlySanLinksRespVO sexLinks7 = ElderlySanLinksRespVO.builder().source("女性").target("59岁以上").value(8).build();
        elderlySanChart.setSexLinks(Arrays.asList(sexLinks1, sexLinks2, sexLinks3, sexLinks4, sexLinks5, sexLinks6, sexLinks7));

        ElderlySanSourceRespVO ncdSource1 = ElderlySanSourceRespVO.builder().name("59至60岁").build();
        ElderlySanSourceRespVO ncdSource2 = ElderlySanSourceRespVO.builder().name("70至80岁").build();
        ElderlySanSourceRespVO ncdSource3 = ElderlySanSourceRespVO.builder().name("81至90岁").build();
        ElderlySanSourceRespVO ncdSource4 = ElderlySanSourceRespVO.builder().name("90岁以上").build();
        elderlySanChart.setNcdData(Arrays.asList(ncdSource1, ncdSource2, ncdSource3, ncdSource4));
        ElderlySanLinksRespVO ncdLinks1 = ElderlySanLinksRespVO.builder().source("59至60岁").target("高血压").value(7).build();
        ElderlySanLinksRespVO ncdLinks2 = ElderlySanLinksRespVO.builder().source("59至60岁").target("高血脂").value(6).build();
        ElderlySanLinksRespVO ncdLinks3 = ElderlySanLinksRespVO.builder().source("59至60岁").target("糖尿病").value(11).build();
        ElderlySanLinksRespVO ncdLinks4 = ElderlySanLinksRespVO.builder().source("59至60岁").target("支气管炎").value(2).build();
        ElderlySanLinksRespVO ncdLinks5 = ElderlySanLinksRespVO.builder().source("59至60岁").target("骨关节").value(5).build();
        ElderlySanLinksRespVO ncdLinks6 = ElderlySanLinksRespVO.builder().source("59至60岁").target("慢性胃病").value(3).build();
        ElderlySanLinksRespVO ncdLinks7 = ElderlySanLinksRespVO.builder().source("59至60岁").target("老年痴呆").value(6).build();
        ElderlySanLinksRespVO ncdLinks8 = ElderlySanLinksRespVO.builder().source("59至60岁").target("通风").value(7).build();
        elderlySanChart.setNcdLinks(Arrays.asList(ncdLinks1, ncdLinks2, ncdLinks3, ncdLinks4, ncdLinks5, ncdLinks6, ncdLinks7, ncdLinks8));

        return elderlySanChart;
    }


    private List<ElderlyHomeDiseaseType> getHomeDataDiseaseTypeFuture(ElderlyInfoHomeDataReqVO reqVO) {

        Long elderCount = 10000l;

        List<ElderlyHomeDiseaseType> list = new ArrayList<>();
        ElderlyHomeDiseaseType type1 = ElderlyHomeDiseaseType.builder().typeName("高血压").typeCount(40)
                .typeRatio(new BigDecimal("40")).elderCount(elderCount.intValue()).build();
        ElderlyHomeDiseaseType type2 = ElderlyHomeDiseaseType.builder().typeName("糖尿病").typeCount(40)
                .typeRatio(new BigDecimal("40")).elderCount(elderCount.intValue()).build();
        ElderlyHomeDiseaseType type3 = ElderlyHomeDiseaseType.builder().typeName("冠心病").typeCount(25)
                .typeRatio(new BigDecimal("25")).elderCount(elderCount.intValue()).build();
        ElderlyHomeDiseaseType type4 = ElderlyHomeDiseaseType.builder().typeName("脑卒中").typeCount(20)
                .typeRatio(new BigDecimal("20")).elderCount(elderCount.intValue()).build();
        list = Arrays.asList(type1, type2, type3, type4);
        return list;
    }

    private List<ElderlyHomeService> getHomeDataService(ElderlyInfoHomeDataReqVO reqVO) {

        Long[] tenantIds = reqVO.getTenantIds();
        Long tenantId = tenantIds[0];
        TenantDO tenantDO = tenantMapper.selectById(tenantId);

        List<ElderlyHomeService> list = dailyExpensesMapper.selectServiceList(tenantDO.getId(), tenantDO.getChargeCategoryId());

        return list;

    }

    private List<List<String>> getCateringPlan(Long tenantId) {
        LocalDate currentDate = LocalDate.now();
        List<CateringPlanDO> cateringPlans = cateringPlanMapper.selectList(new LambdaQueryWrapperX<CateringPlanDO>()
                .eq(CateringPlanDO::getTenantId, tenantId)
                .le(CateringPlanDO::getScheduledStartDate, currentDate)
                .ge(CateringPlanDO::getScheduledEndDate, currentDate));

        if (cateringPlans.isEmpty()) {
            return Collections.emptyList();
        }
        CateringPlanDO cateringPlanDO = cateringPlans.get(0);
        // 查询对应的餐饮计划项

        List<CateringPlanItemDO> cateringPlanItemDOS = cateringPlanItemMapper.selectList(new LambdaQueryWrapperX<CateringPlanItemDO>()
                .in(CateringPlanItemDO::getCateringPlanId, cateringPlanDO.getId()));
        List<List<String>> result = new ArrayList<>();

        List<String> nameList = new ArrayList<>();
        nameList.add("");
        List<String> mondayList = new ArrayList<>();
        mondayList.add("周一");
        List<String> tuesdayList = new ArrayList<>();
        tuesdayList.add("周二");

        List<String> wednesdayList = new ArrayList<>();
        wednesdayList.add("周三");

        List<String> thursdayList = new ArrayList<>();
        thursdayList.add("周四");

        List<String> fridayList = new ArrayList<>();
        fridayList.add("周五");

        List<String> saturdayList = new ArrayList<>();
        saturdayList.add("周六");

        List<String> sundayList = new ArrayList<>();
        sundayList.add("周日");

        if (null != cateringPlanItemDOS) {
            cateringPlanItemDOS.forEach(item -> {
                List<String> mondayValueList = JSON.parseArray(item.getMonday() == null ? "" : item.getMonday(), String.class);
                List<String> tuesdayValueList = JSON.parseArray(item.getTuesday() == null ? "" : item.getTuesday(), String.class);
                List<String> wednesdayValueList = JSON.parseArray(item.getWednesday() == null ? "" : item.getWednesday(), String.class);
                List<String> thursdayValueList = JSON.parseArray(item.getThursday() == null ? "" : item.getThursday(), String.class);
                List<String> fridayValueList = JSON.parseArray(item.getFriday() == null ? "" : item.getFriday(), String.class);
                List<String> saturdayValueList = JSON.parseArray(item.getSaturday() == null ? "" : item.getSaturday(), String.class);
                List<String> sundayValueList = JSON.parseArray(item.getSunday() == null ? "" : item.getSunday(), String.class);
                String monday = "";
                String tuesday = "";
                String wednesday = "";
                String thursday = "";
                String friday = "";
                String saturday = "";
                String sunday = "";

                if (null != mondayValueList) {
                    monday = String.join("、", mondayValueList);
                }
                if (null != tuesdayValueList) {
                    tuesday = String.join("、", tuesdayValueList);
                }
                if (null != wednesdayValueList) {
                    wednesday = String.join("、", wednesdayValueList);
                }
                if (null != thursdayValueList) {
                    thursday = String.join("、", thursdayValueList);
                }
                if (null != fridayValueList) {
                    friday = String.join("、", fridayValueList);
                }
                if (null != saturdayValueList) {
                    saturday = String.join("、", saturdayValueList);
                }
                if (null != sundayValueList) {
                    sunday = String.join("、", sundayValueList);
                }

                nameList.add(item.getMealTimes());
                mondayList.add(monday);
                tuesdayList.add(tuesday);
                wednesdayList.add(wednesday);
                thursdayList.add(thursday);
                fridayList.add(friday);
                saturdayList.add(saturday);
                sundayList.add(sunday);
            });
        }


        result.add(nameList);
        result.add(mondayList);
        result.add(tuesdayList);
        result.add(wednesdayList);
        result.add(thursdayList);
        result.add(fridayList);
        result.add(saturdayList);
        result.add(sundayList);


        return result;
    }


    List<WeekActivityRespVO> getActivity(ElderlyInfoHomeDataReqVO reqVO) {
        LocalDate currentDate = LocalDate.now();
        LocalDate startDate = currentDate.with(java.time.temporal.TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY));
        LocalDate endDate = currentDate.with(java.time.temporal.TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY));

        List<MonthlyActivityDO> monthlyActivityDOS = monthlyActivityMapper.selectList(new LambdaQueryWrapperX<MonthlyActivityDO>()
                .eq(MonthlyActivityDO::getTenantId, reqVO.getTenantIds()[0])
                .between(MonthlyActivityDO::getActivityDate, startDate, endDate));

        if (monthlyActivityDOS.isEmpty()) {
            return Collections.emptyList();
        }

        // 创建一周七天的活动列表
        List<WeekActivityRespVO> weekActivities = new ArrayList<>();

        // 初始化周一到周日
        for (int i = 0; i < 7; i++) {
            LocalDate day = startDate.plusDays(i);
            WeekActivityRespVO activity = new WeekActivityRespVO();
            activity.setWeekday(getWeekdayChinese(day.getDayOfWeek()));
            activity.setMorning("无活动");
            activity.setAfternoon("无活动");
            weekActivities.add(activity);
        }

        // 按日期和时间段分组活动
        Map<LocalDate, Map<String, List<String>>> activityMap = new HashMap<>();

        // 填充实际活动数据
        for (MonthlyActivityDO activityDO : monthlyActivityDOS) {
            LocalDate activityDate = activityDO.getActivityDate();
            if (activityDate == null) continue;

            activityMap.putIfAbsent(activityDate, new HashMap<>());
            activityMap.get(activityDate).putIfAbsent("morning", new ArrayList<>());
            activityMap.get(activityDate).putIfAbsent("afternoon", new ArrayList<>());

            String activityTitle = activityDO.getActivityTitle() != null ? activityDO.getActivityTitle() : "活动";

            // 根据时间判断是上午还是下午活动 (假设上午是6:00-12:00，下午是12:00-18:00)
            int hour = 12; // 默认下午
            if (activityDO.getActivityStartTime() != null) {
                hour = ZonedDateTime.ofInstant(activityDO.getActivityStartTime().toInstant(), ZoneId.systemDefault()).getHour();
            }

            if (hour >= 6 && hour < 12) {
                // 上午活动
                activityMap.get(activityDate).get("morning").add(activityTitle);
            } else if (hour >= 12 && hour < 18) {
                // 下午活动
                activityMap.get(activityDate).get("afternoon").add(activityTitle);
            }
        }

        // 将分组后的活动填充到对应的星期中
        for (int i = 0; i < 7; i++) {
            LocalDate day = startDate.plusDays(i);
            int dayIndex = (int) ChronoUnit.DAYS.between(startDate, day);

            if (dayIndex >= 0 && dayIndex < 7) {
                WeekActivityRespVO activity = weekActivities.get(dayIndex);

                Map<String, List<String>> dailyActivities = activityMap.get(day);
                if (dailyActivities != null) {
                    List<String> morningActivities = dailyActivities.get("morning");
                    List<String> afternoonActivities = dailyActivities.get("afternoon");

                    if (morningActivities != null && !morningActivities.isEmpty()) {
                        // 将多个活动用顿号连接
                        activity.setMorning(String.join("、", morningActivities));
                    }

                    if (afternoonActivities != null && !afternoonActivities.isEmpty()) {
                        // 将多个活动用顿号连接
                        activity.setAfternoon(String.join("、", afternoonActivities));
                    }
                }
            }
        }

        return weekActivities;


    }

    private String getWeekdayChinese(java.time.DayOfWeek dayOfWeek) {
        switch (dayOfWeek) {
            case MONDAY:
                return "周一";
            case TUESDAY:
                return "周二";
            case WEDNESDAY:
                return "周三";
            case THURSDAY:
                return "周四";
            case FRIDAY:
                return "周五";
            case SATURDAY:
                return "周六";
            case SUNDAY:
                return "周日";
            default:
                return "";
        }
    }

    /**
     * 合并指定日期的菜品项
     *
     * @param target    目标对象
     * @param source    源对象
     * @param dayOfWeek 日期字段名
     */
    private void mergeDayItems(CateringPlanItemDO target, CateringPlanItemDO source, String dayOfWeek) {
        try {
            // 获取源和目标的菜品列表
            String sourceDayValue = getDayValue(source, dayOfWeek);
            String targetDayValue = getDayValue(target, dayOfWeek);

            // 解析JSON数组
            List<String> sourceList = parseJsonArray(sourceDayValue);
            List<String> targetList = parseJsonArray(targetDayValue);

            // 合并列表（去重）
            Set<String> uniqueItems = new LinkedHashSet<>(targetList);
            uniqueItems.addAll(sourceList);

            // 更新目标对象
            List<String> mergedList = new ArrayList<>(uniqueItems);
            setDayValue(target, dayOfWeek, JSON.toJSONString(mergedList));

            // 设置显示用的字符串（用<br />分隔）
            if (!mergedList.isEmpty()) {
                String displayValue = String.join("<br />", mergedList);
                setDayValueForDisplay(target, dayOfWeek, displayValue);
            }
        } catch (Exception e) {
            // 出现异常时保留原有逻辑
            copyDayValue(target, source, dayOfWeek);
        }
    }


    /**
     * 获取指定日期字段的值
     */
    private String getDayValue(CateringPlanItemDO item, String dayOfWeek) {
        switch (dayOfWeek) {
            case "monday":
                return item.getMonday();
            case "tuesday":
                return item.getTuesday();
            case "wednesday":
                return item.getWednesday();
            case "thursday":
                return item.getThursday();
            case "friday":
                return item.getFriday();
            case "saturday":
                return item.getSaturday();
            case "sunday":
                return item.getSunday();
            default:
                return "[]";
        }
    }

    /**
     * 设置指定日期字段的值（JSON格式）
     */
    private void setDayValue(CateringPlanItemDO item, String dayOfWeek, String value) {
        switch (dayOfWeek) {
            case "monday":
                item.setMonday(value);
                break;
            case "tuesday":
                item.setTuesday(value);
                break;
            case "wednesday":
                item.setWednesday(value);
                break;
            case "thursday":
                item.setThursday(value);
                break;
            case "friday":
                item.setFriday(value);
                break;
            case "saturday":
                item.setSaturday(value);
                break;
            case "sunday":
                item.setSunday(value);
                break;
        }
    }

    /**
     * 设置指定日期字段的显示值（HTML格式）
     */
    private void setDayValueForDisplay(CateringPlanItemDO item, String dayOfWeek, String value) {
        switch (dayOfWeek) {
            case "monday":
                item.setMonday(value);
                break;
            case "tuesday":
                item.setTuesday(value);
                break;
            case "wednesday":
                item.setWednesday(value);
                break;
            case "thursday":
                item.setThursday(value);
                break;
            case "friday":
                item.setFriday(value);
                break;
            case "saturday":
                item.setSaturday(value);
                break;
            case "sunday":
                item.setSunday(value);
                break;
        }
    }

    /**
     * 复制指定日期字段的值
     */
    private void copyDayValue(CateringPlanItemDO target, CateringPlanItemDO source, String dayOfWeek) {
        switch (dayOfWeek) {
            case "monday":
                target.setMonday(source.getMonday());
                break;
            case "tuesday":
                target.setTuesday(source.getTuesday());
                break;
            case "wednesday":
                target.setWednesday(source.getWednesday());
                break;
            case "thursday":
                target.setThursday(source.getThursday());
                break;
            case "friday":
                target.setFriday(source.getFriday());
                break;
            case "saturday":
                target.setSaturday(source.getSaturday());
                break;
            case "sunday":
                target.setSunday(source.getSunday());
                break;
        }
    }

    /**
     * 解析JSON数组字符串
     */
    private List<String> parseJsonArray(String json) {
        if (json == null || json.trim().isEmpty()) {
            return new ArrayList<>();
        }

        try {
            return JSON.parseArray(json, String.class);
        } catch (Exception e) {
            return new ArrayList<>();
        }
    }


    private String buildOrderBy(String prop, String order) {
        if (prop == null) return "ei.update_time desc"; // 默认排序
        String field = SORT_FIELD_MAP.get(prop);
        if (field == null) {
            return "ei.update_time desc"; // 非法字段用默认
        }
        if (!"asc".equalsIgnoreCase(order) && !"desc".equalsIgnoreCase(order)) {
            order = "asc";
        }
        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));
        }
    }


}




