package com.cpop.oam.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cpop.api.tencent.wxWork.handler.WebHookSendHandler;
import com.cpop.common.constant.Constants;
import com.cpop.common.utils.DateUtils;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.entity.PageDomain;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.base.table.SysConfig;
import com.cpop.core.service.CoreService;
import com.cpop.core.service.RedisService;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.oam.business.bo.*;
import com.cpop.oam.business.entity.DataImport;
import com.cpop.oam.business.entity.Staff;
import com.cpop.oam.business.entity.Task;
import com.cpop.oam.business.entity.TaskStaffGroup;
import com.cpop.oam.business.mapper.TaskMapper;
import com.cpop.oam.business.service.StaffService;
import com.cpop.oam.business.service.TaskService;
import com.cpop.oam.business.service.TaskStaffGroupService;
import com.cpop.oam.business.service.TaskWorkOrderService;
import com.cpop.oam.business.vo.*;
import com.cpop.oam.framework.constant.OamConfigKey;
import com.cpop.oam.framework.constant.OamRedisConstant;
import com.cpop.oam.framework.constant.WebHookKeyConstant;
import com.cpop.oam.framework.enums.OamConfigEnum;
import com.cpop.system.business.entity.DictData;
import com.cpop.system.business.service.DictDataService;
import com.cpop.system.business.service.DictTypeService;
import com.cpop.system.framework.utils.DictUtils;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Db;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

import static com.cpop.core.base.table.table.SysUserTableDef.SYS_USER;
import static com.cpop.oam.business.entity.table.StaffTableDef.STAFF;
import static com.cpop.oam.business.entity.table.TaskStaffGroupTableDef.TASK_STAFF_GROUP;
import static com.cpop.oam.business.entity.table.TaskTableDef.TASK;
import static com.mybatisflex.core.query.QueryMethods.*;

/**
 * OAM-任务表 服务层实现。
 *
 * @author DB
 * @since 2023-09-15
 */
@Service("oamTaskService")
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {

    /**
     * 技术模块-任务归档-获取任务归档分页
     * @author DB
     * @param bo 请求
     * @since 2023-11-30 21:11:47
     */
    @Override
    public Page<TaskArchivingPagVo> getTaskArchivingPage(TaskArchivingPagBo bo) {
        // 获取当前员工
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(), pageDomain.getPageSize()),
                QueryWrapper.create()
                        .select(TASK.ID,
                                TASK.RESPONSIBLE_STAFF_ID,
                                TASK.TASK_CONTENT,
                                TASK.TASK_TYPE,
                                TASK.TASK_RATING,
                                TASK.TASK_WEIGHT,
                                TASK.TASK_RECEIPT_TIME,
                                TASK.TEST_TO_FINISH_URL,
                                TASK.TO_TEST_TIME,
                                TASK.TO_DEPLOY_TIME,
                                TASK.COMPLETION_DATE,
                                TASK.SUBJECT)
                        .from(TASK)
                        .where(TASK.TASK_TYPE.in(0, 1))
                        .and(TASK.TASK_STATUS.eq(bo.getIsFinish() ? 9 : 8).and(TASK.TASK_CONTENT.like(bo.getTaskContent())))
                        .and(TASK.SUBJECT.like(bo.getSubject()))
                        .orderBy(TASK.UPDATE_TIME.desc()),
                TaskArchivingPagVo.class,
                // 负责人
                item -> item.field(TaskArchivingPagVo::getResponsibleStaffName)
                        .queryWrapper(recordStaff -> queryChain().select(STAFF.NAME.as(TaskArchivingPagVo::getResponsibleStaffName))
                                        .from(STAFF)
                                        .where(STAFF.ID.eq(recordStaff.getResponsibleStaffId()))),
                // 小组成员
                item -> item.field(TaskArchivingPagVo::getTaskGroupStaffs)
                        .queryWrapper(taskGroupStaffs -> queryChain()
                                .select(groupConcat(STAFF.NAME).as(TaskArchivingPagVo::getTaskGroupStaffs))
                                .from(STAFF)
                                .leftJoin(TASK_STAFF_GROUP)
                                .on(TASK_STAFF_GROUP.STAFF_ID.eq(STAFF.ID))
                                .leftJoin(TASK)
                                .on(TASK.ID.eq(TASK_STAFF_GROUP.TASK_ID))
                                .where(TASK.ID.eq(taskGroupStaffs.getId()))
                                .groupBy(TASK.ID)));
    }

    /**
     * 技术模块-任务归档-设置任务归档
     *
     * @param taskId 任务id
     * @author DB
     * @since 2023-11-30 21:49:05
     */
    @Override
    public void setTaskArchiving(String taskId) {
        //获取任务
        Task task = this.getById(taskId);
        this.updateChain()
                .set(TASK.TASK_STATUS, 9)
                .set(TASK.TASK_ITEM, 3)
                .set(TASK.COMPLETION_DATE, LocalDate.now())
                .where(TASK.ID.eq(taskId))
                .update();
        // 企微通知手机号
        List<String> phoneList = new ArrayList<String>();
        StaffInfoVo responsibleStaff = SpringUtils.getBean(StaffService.class).getStaffInfo(task.getResponsibleStaffId());
        //字符串数组
        String testStaffPhone = SpringUtils.getBean(RedisService.class).getCacheObject(OamConfigKey.OAM_CONFIG_KEY + OamConfigEnum.TEST_STAFF_PHONE.getKey());
        phoneList.add(responsibleStaff.getPhoneNumber());
        List<String> testPhoneList = Arrays.asList(testStaffPhone.split(","));
        phoneList.addAll(testPhoneList);
        try {
            SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
                    phoneList,
                    "==========开发任务更新==========" + "\n" + task.getTaskContent() + "\n" + "任务归档",
                    false);
        } catch (IOException e) {
            throw new ServiceException("发送任务通知失败!");
        }
    }

    /**
     * 技术模块-任务领取-获取领取任务分页
     *
     * @param subject       主体
     * @param taskContent   任务内容
     * @param taskGetStatus 任务领取状态(0:待领取;1:待评估;10:审核不通过)
     * @author DB
     * @since 2023-11-30 22:21:58
     */
    @Override
    public Page<TaskToBeClaimedPageVo> getToBeClaimedPage(String subject, String taskContent, Integer taskGetStatus) {
        // 获取当前员工
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(), pageDomain.getPageSize()),
                QueryWrapper.create()
                        .select(TASK.ID,
                                TASK.TASK_TYPE,
                                TASK.SUBJECT,
                                TASK.TASK_CONTENT,
                                TASK.ATTACHMENT_URL,
                                TASK.TASK_RATING,
                                TASK.CREATE_TIME,
                                TASK.RECORD_STAFF_ID,
                                TASK.TASK_WEIGHT)
                        .select(TASK_STAFF_GROUP.GRADE_POINT)
                        .from(TASK)
                        .leftJoin(TASK_STAFF_GROUP)
                        .on(TASK_STAFF_GROUP.TASK_ID.eq(TASK.ID))
                        .where(TASK.TASK_STATUS.eq(taskGetStatus))
                        .and(TASK.TASK_CONTENT.like(taskContent))
                        .and(TASK.SUBJECT.like(subject))
                        .and(TASK.TASK_TYPE.in(0, 1))
                        .orderBy(TASK.IS_URGENT.desc(), TASK.CREATE_TIME.desc()),
                TaskToBeClaimedPageVo.class,
                // 对接人
                item -> item.field(TaskToBeClaimedPageVo::getDockingStaff).queryWrapper(dockingStaff ->
                        queryChain().select(STAFF.NAME.as(TaskToBeClaimedPageVo::getDockingStaff))
                                .from(STAFF)
                                .where(STAFF.ID.eq(dockingStaff.getRecordStaffId()))
                ));
    }

    /**
     * 技术模块-任务领取-新增迭代任务
     *
     * @param bo 请求
     * @author DB
     * @since 2023-12-01 09:45:08
     */
    @Override
    public void insertIterationTask(TaskIterationBo bo) {
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        Task entity = BeanUtils.mapToClass(bo, Task.class);
        // 默认待审核 默认开发中
        entity.setTaskStatus(0).setTaskItem(0).setTaskType(0).setRecordStaffId(loginUserInfo.getString("id"));
        this.save(entity);
        // 获取审核管理员手机号
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        String auditStaffPhone = redisService.getCacheObject(OamConfigEnum.AUDIT_STAFF_PHONE.getKey());
        if (StringUtils.isBlank(auditStaffPhone)) {
            CoreService coreService = SpringUtils.getBean(CoreService.class);
            SysConfig sysConfig = coreService.selectConfigByKey(OamConfigEnum.AUDIT_STAFF_PHONE.getKey());
            auditStaffPhone = sysConfig.getConfigValue();
            if (StringUtils.isBlank(auditStaffPhone)) {
                throw new ServiceException("尚未配置审核管理员信息!");
            }
        }
        // 企微通知审核管理员
        List<String> phoneList = new ArrayList<String>();
        phoneList.add(auditStaffPhone);
        try {
            SpringUtils.getBean(WebHookSendHandler.class)
                    .webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
                            phoneList,
                            "==========您有一条新的迭代任务需要审核==========" + "\n" + entity.getTaskContent(),
                            false);
        } catch (IOException e) {
            throw new ServiceException("发送迭代任务通知失败!");
        }
    }

    /**
     * 任务评级
     */
    private final String OAM_TASK_RATING = "oam_task_rating";

    /**
     * 技术模块-任务领取-技术人员领取任务
     *
     * @param id 任务id
     * @author DB
     * @since 2023-12-01 10:15:28
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void claimTask(String id) {
        //分布式锁进行幂等处理
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        //分布式锁进行幂等处理
        Lock userIdLock = redisService.distributedLock(OamRedisConstant.TASK_CLAIM_LOCK + id);
        if (userIdLock.tryLock()) {
            try {
                // 查询任务
                Task task = this.getById(id);
                if (task.getTaskStatus() == 2){
                    throw new ServiceException("任务已领取,请刷新页面");
                }
                // 进行中 接受时间
                task.setTaskStatus(2).setTaskReceiptTime(LocalDateTime.now());
                // 如果任务没有设置预期完成时间，则按照任务评级进行设置默认
                if (task.getExpectedCompletionDate() == null) {
                    // 获取任务评级
                    String taskRating = task.getTaskRating();
                    LocalDate now = LocalDate.now();
                    String dictValue = DictUtils.getDictValue(OAM_TASK_RATING, taskRating);
                    task.setExpectedCompletionDate(now.plusDays(Integer.parseInt(dictValue.split(",")[1]) - 1));
                }
                // 获取当前用户
                JSONObject loginUser = SecurityUtils.getInstance().getLoginUserInfo();
                if (!Constants.SUPER_ADMIN.equals(loginUser.getString("userName"))) {
                    // 获取当前员工
                    Staff staff = SpringUtils.getBean(StaffService.class).getOne(QueryWrapper.create().where(STAFF.USER_ID.eq(loginUser.getString("userId"))));
                    task.setResponsibleStaffId(staff.getId());
                }
                this.updateById(task);
                // 添加主要负责人组
                TaskStaffGroup taskStaffGroup = new TaskStaffGroup();
                taskStaffGroup.setStaffId(task.getResponsibleStaffId()).setTaskId(id).setGradePoint(task.getTaskWeight());
                SpringUtils.getBean(TaskStaffGroupService.class).save(taskStaffGroup);
                // 通知所有人
                try {
                    SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
                                    Collections.singletonList(loginUser.getString("phoneNumber")),
                                    "==========任务领取==========" + "\n" + task.getTaskContent(),
                                    false);
                } catch (IOException e) {
                    throw new ServiceException("发送任务领取通知失败!");
                }
            } catch (Exception e) {
                throw new ServiceException(e.getMessage());
            } finally {
                //释放锁
                userIdLock.unlock();
            }
        } else {
            //获取锁失败，直接返回空
            throw new ServiceException("请勿重复领取");
        }
    }

    /**
     * 技术模块-任务领取-任务审核
     *
     * @param bo 请求参数
     * @author DB
     * @since 2023-12-01 10:35:31
     */
    @Override
    public void setTaskAuditComments(TaskAuditCommentsBo bo) {
        Task entity = BeanUtils.mapToClass(bo, Task.class);
        if (bo.getIsPass()) {
            entity.setTaskStatus(1);
            this.updateById(entity);
            // 通知所有人
            try {
                SpringUtils.getBean(WebHookSendHandler.class)
                        .webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
                                new ArrayList<>(),
                                "==========任务审核通过==========" + "\n" + this.getById(bo.getId()).getTaskContent(),
                                true);
            } catch (IOException e) {
                throw new ServiceException("发送任务审核通过通知失败!");
            }
        } else {
            entity.setTaskStatus(10);
            this.updateById(entity);
        }
    }

    /**
     * 技术模块-今日事务-个人任务分页列表
     *
     * @return Page<PersonTaskPageVo>
     * @author DB
     * @since 2023/12/04
     */
    @Override
    public Page<PersonTaskPageVo> getPersonTaskPage(String staffId, LocalDate startDate, LocalDate endDate) {
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        String testStaffPhones = SpringUtils.getBean(RedisService.class).getCacheObject(OamConfigKey.OAM_CONFIG_KEY + OamConfigEnum.TEST_STAFF_PHONE.getKey());
        if (StringUtils.isBlank(testStaffPhones)) {
            throw new ServiceException("测试员工手机号未配置,请联系相关人员配置");
        }
        QueryWrapper queryWrapper = QueryWrapper.create();
        if (StringUtils.isNotBlank(staffId)){
            Row staff = Db.selectOneByQuery(SYS_USER.getTableName(), QueryWrapper.create().select(SYS_USER.PHONE_NUMBER)
                    .leftJoin(STAFF).on(STAFF.USER_ID.eq(SYS_USER.ID))
                    .where(STAFF.ID.eq(staffId)));
            //对比当前员工是否是测试管理员
            if (!Arrays.asList(testStaffPhones.split(",")).contains(staff.getString("phoneNumber"))) {
                queryWrapper.and(TASK.TASK_STATUS.in(2, 3, 8, 9))
                        .and(TASK_STAFF_GROUP.STAFF_ID.eq(staffId));
            } else {
                //测试人员
                queryWrapper.and(TASK.TASK_STATUS.in(3, 8, 9))
                        .groupBy(TASK.ID);
            }
        } else {
            JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
            //对比当前员工是否是测试管理员
            if (!Arrays.asList(testStaffPhones.split(",")).contains(loginUserInfo.getString("phoneNumber"))) {
                queryWrapper.and(TASK.TASK_STATUS.in(2, 3, 8, 9))
                        .and(TASK_STAFF_GROUP.STAFF_ID.eq(loginUserInfo.getString("id")));
            } else {
                //测试人员
                queryWrapper.and(TASK.TASK_STATUS.in(3, 8, 9))
                        .groupBy(TASK.ID);
            }
        }
        if (startDate != null && endDate != null) {
            queryWrapper.and(dateFormat(TASK.TASK_RECEIPT_TIME, "%Y-%m-%d").between(startDate, endDate));
        } else {
            LocalDate date = LocalDate.now();
            // 获取当前月的第一天
            LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
            // 获取当前月的最后一天
            LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
            queryWrapper.and(dateFormat(TASK.TASK_RECEIPT_TIME, "%Y-%m-%d").between(firstDay, lastDay));
        }
        return this.mapper.paginateAs(pageDomain.getPageNum(),
                pageDomain.getPageSize(),
                queryWrapper
                        .select(TASK.ID, TASK.TASK_STATUS, TASK.TASK_CONTENT, TASK.TASK_ITEM, TASK.TASK_RATING, TASK.TASK_RECEIPT_TIME, TASK.EXPECTED_COMPLETION_DATE, TASK.TASK_PROGRESS, TASK.SUBJECT)
                        .select(STAFF.NAME.as(PersonTaskPageVo::getResponsibleStaffName))
                        //个人绩点
                        .select(TASK_STAFF_GROUP.GRADE_POINT)
                        .from(TASK)
                        // 任务员工组
                        .leftJoin(TASK_STAFF_GROUP)
                        .on(TASK_STAFF_GROUP.TASK_ID.eq(TASK.ID))
                        // 员工表
                        .leftJoin(STAFF)
                        .on(STAFF.ID.eq(TASK.RESPONSIBLE_STAFF_ID))
                        .where(TASK.TASK_TYPE.in(0, 1))
                        .orderBy(TASK.TASK_ITEM.asc(), TASK.EXPECTED_COMPLETION_DATE.asc()),
                PersonTaskPageVo.class);
    }

    /**
     * "技术模块-今日事务-转交任务
     *
     * @param bo 请求参数
     * @author DB
     * @since 2023/12/04
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTaskItem(TaskItemBo bo) {
        //查询任务进度
        Task task = this.getById(bo.getId());
        //进行中转测试
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        switch (bo.getTaskItem()) {
            //逾期
            case -1:
                //判断当前任务状态
                if (task.getTaskStatus() == 2) {
                    if (!StringUtils.equals(task.getResponsibleStaffId(), loginUserInfo.getString("id"))) {
                        throw new ServiceException("当前操作员工不是当前任务主要负责人，不允许操作当前任务！");
                    }
                    if (task.getTaskProgress() == null || task.getTaskProgress().split(",").length < 5) {
                        throw new ServiceException("当前任务的进度尚未完全完成,不允许转交");
                    }
                    task.setToTestTime(LocalDateTime.now()).setTaskStatus(3);
                } else {
                    //测试转部署
                    if (StringUtils.isBlank(bo.getTestToFinishUrl())) {
                        throw new ServiceException("当前任务未提交测试部署相关文件,不允许转交");
                    }
                    task.setToDeployTime(LocalDateTime.now()).setTestToFinishUrl(bo.getTestToFinishUrl()).setTaskStatus(8);
                    testStaffAddPoint(task, loginUserInfo);
                    LocalDate now = LocalDate.now();
                    LocalDate expectedCompletionDate = task.getExpectedCompletionDate();
                    //测试任务延期一天
                    long day = now.compareTo(expectedCompletionDate.plusDays(1));
                    // 逾期完成
                    if (day > 0) {
                        //扣除绩点
                        deductGradePoint(day, bo.getId());
                    }
                }
                break;
            //转测试
            case 0:
                if (!StringUtils.equals(task.getResponsibleStaffId(), loginUserInfo.getString("id"))) {
                    throw new ServiceException("当前操作员工不是当前任务主要负责人，不允许操作当前任务！");
                }
                if (task.getTaskProgress() == null || task.getTaskProgress().split(",").length < 5) {
                    throw new ServiceException("当前任务的进度尚未完全完成,不允许转交");
                }
                task.setToTestTime(LocalDateTime.now()).setTaskItem(1).setTaskStatus(3);
                break;
            //转部署
            case 1:
                if (StringUtils.isBlank(bo.getTestToFinishUrl())) {
                    throw new ServiceException("当前任务未提交测试部署相关文件,不允许转交");
                }
                task.setToDeployTime(LocalDateTime.now()).setTestToFinishUrl(bo.getTestToFinishUrl()).setTaskStatus(8).setTaskItem(2);
                testStaffAddPoint(task, loginUserInfo);
                break;
            default:
        }
        this.updateById(task);
        // 企微通知手机号
        List<String> phoneList = new ArrayList<String>();
        StaffInfoVo responsibleStaff = SpringUtils.getBean(StaffService.class).getStaffInfo(task.getResponsibleStaffId());
        //字符串数组
        String testStaffPhone = SpringUtils.getBean(RedisService.class).getCacheObject(OamConfigKey.OAM_CONFIG_KEY + OamConfigEnum.TEST_STAFF_PHONE.getKey());
        phoneList.add(responsibleStaff.getPhoneNumber());
        List<String> testPhoneList = Arrays.asList(testStaffPhone.split(","));
        phoneList.addAll(testPhoneList);
        try {
            SpringUtils.getBean(WebHookSendHandler.class).webHookSendText(WebHookKeyConstant.PRODUCT_BOT,
                    phoneList,
                    "==========开发任务更新==========" + "\n" + task.getTaskContent() + "\n" +
                            (bo.getTaskItem() == 0 ? "开发转测试" : "测试转待部署"),
                    false);
        } catch (IOException e) {
            throw new ServiceException("发送任务通知失败!");
        }
    }

    /**
     * 测试员工添加绩点
     * @author DB
     * @since 2023/12/21
     * @param task 任务
     */
    private void testStaffAddPoint(Task task, JSONObject loginUserInfo) {
        //计算绩点
        double v = task.getTaskWeight() * 0.2;
        TaskStaffGroup taskStaffGroup = new TaskStaffGroup();
        taskStaffGroup.setTaskId(task.getId()).setStaffId(loginUserInfo.getString("id")).setGradePoint((int) v).setRemark("测试员工获取绩点");
        SpringUtils.getBean(TaskStaffGroupService.class).save(taskStaffGroup);
    }

    /**
     * 逾期扣除绩点
     *
     * @param day    逾期日期
     * @param taskId 任务id
     * @author DB
     * @since 2023/12/04
     */
    private void deductGradePoint(Long day, String taskId) {
        //获取所有参与员工的绩点列表
        TaskStaffGroupService taskStaffGroupService = SpringUtils.getBean(TaskStaffGroupService.class);
        List<TaskStaffGroup> taskStaffGroups = taskStaffGroupService.queryChain().where(TASK_STAFF_GROUP.TASK_ID.eq(taskId)).list();
        //逾期完成3天内只计算有效绩点的80%
        if (day <= 3) {
            //3天以上50%
            taskStaffGroups.forEach(item -> {
                //向下取整
                Integer oldGradePoint = item.getGradePoint();
                Double deductGradePoint = Math.floor(item.getGradePoint() * 0.2);
                item.setGradePoint(oldGradePoint - deductGradePoint.intValue()).setRemark("任务完成超时扣除绩点:" + deductGradePoint);
            });
        } else {
            //3天以上50%
            taskStaffGroups.forEach(item -> {
                //向下取整
                Integer oldGradePoint = item.getGradePoint();
                Double deductGradePoint = Math.floor(item.getGradePoint() * 0.5);
                item.setGradePoint(oldGradePoint - deductGradePoint.intValue()).setRemark("任务完成超时扣除绩点:" + deductGradePoint);
            });
        }
        taskStaffGroupService.updateBatch(taskStaffGroups);
    }

    /**
     * 技术模块-今日事务-修改任务负责人
     *
     * @param bo 请求参数
     * @author DB
     * @since 2023/12/04
     */
    @Override
    public void updateTaskResponsibleStaff(TransferTaskBo bo) {
        isTaskResponsibleStaff(bo.getId());
        // 新负责人在不在任务组内
        TaskStaffGroupService taskStaffGroupService = SpringUtils.getBean(TaskStaffGroupService.class);
        long count = taskStaffGroupService.count(QueryWrapper.create()
                .where(TASK_STAFF_GROUP.TASK_ID.eq(bo.getId()))
                .and(TASK_STAFF_GROUP.STAFF_ID.eq(bo.getNewResponsibleStaffId())));
        // 获取旧员工绩点
        TaskStaffGroup oldStaffGroup = taskStaffGroupService.getOne(QueryWrapper.create()
                .where(TASK_STAFF_GROUP.TASK_ID.eq(bo.getId()))
                .and(TASK_STAFF_GROUP.STAFF_ID.eq(bo.getResponsibleStaffId())));
        if (count == 0) {
            // 不在
            TaskStaffGroup taskStaffGroup = new TaskStaffGroup();
            taskStaffGroup.setStaffId(bo.getNewResponsibleStaffId())
                    .setTaskId(bo.getId())
                    .setGradePoint(oldStaffGroup.getGradePoint());
            taskStaffGroupService.save(taskStaffGroup);
        } else {
            // 在，直接添加绩点
            TaskStaffGroup newStaffGroup = taskStaffGroupService.getOne(QueryWrapper.create()
                    .where(TASK_STAFF_GROUP.TASK_ID.eq(bo.getId()))
                    .and(TASK_STAFF_GROUP.STAFF_ID.eq(bo.getNewResponsibleStaffId())));
            newStaffGroup.setGradePoint(newStaffGroup.getGradePoint() + oldStaffGroup.getGradePoint());
            taskStaffGroupService.updateById(newStaffGroup);
        }
        taskStaffGroupService.removeById(oldStaffGroup.getId());
        // 替换任务负责人
        this.updateChain()
                .set(TASK.RESPONSIBLE_STAFF_ID, bo.getNewResponsibleStaffId())
                .where(TASK.ID.eq(bo.getId()))
                .update();
    }

    /**
     * @param taskId 任务id
     * @Description: 是否是任务主要负责员工
     * @return: Boolean
     * @Author: DB
     * @Date: 2023/5/30 9:48
     **/
    private void isTaskResponsibleStaff(String taskId) {
        // 获取任务
        Task task = this.getById(taskId);
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        if (!StringUtils.equals(task.getResponsibleStaffId(), loginUserInfo.getString("id"))) {
            throw new ServiceException("当前操作员工不是当前任务主要负责人，不允许操作当前任务！");
        }
    }

    /**
     * 技术模块-数据统计-获取月度任务统计列表
     *
     * @param bo 请求参数
     * @return R<TaskMonthStatisticsVo>
     * @author DB
     * @since 2023/12/04
     */
    @Override
    public TaskMonthStatisticsVo getTaskMonthStatistics(TaskMonthStatisticsBo bo) {
        QueryWrapper queryWrapper = QueryWrapper.create();
        if(StringUtils.isNotBlank(bo.getTechnologyStaffId())){
            queryWrapper.and(TASK_STAFF_GROUP.STAFF_ID.eq(bo.getTechnologyStaffId()));
        }
        LocalDate firstDay;
        if (StringUtils.isNotBlank(bo.getTaskMoth())) {
            DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            LocalDate date = LocalDate.parse(bo.getTaskMoth() + "-15", df);
            // 获取目标月的第一天
            firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
        } else {
            // 查询当月
            DateUtils.getDate();
            LocalDate now = LocalDate.now();
            firstDay = now.with(TemporalAdjusters.firstDayOfMonth());
        }
        //查询当月所有任务
        List<Task> taskList = this.list(queryWrapper.select(distinct(TASK.TASK_STATUS, TASK.ID, TASK.TASK_RECEIPT_TIME, TASK.TASK_CONTENT, TASK.EXPECTED_COMPLETION_DATE))
                .leftJoin(TASK_STAFF_GROUP).on(TASK_STAFF_GROUP.TASK_ID.eq(TASK.ID))
                .and(TASK.EXPECTED_COMPLETION_DATE.ge(firstDay))
                .and(TASK.TASK_TYPE.in(0, 1))
                .and(TASK.TASK_STATUS.in(2, 3, 4, 6, 8, 9))
                .groupBy(TASK.ID)
                .orderBy(TASK.EXPECTED_COMPLETION_DATE.asc()));
        if (taskList.isEmpty()) {
            return new TaskMonthStatisticsVo();
        }
        List<TaskStaffGroup> taskStaffGroups = SpringUtils.getBean(TaskStaffGroupService.class).queryChain()
                .where(TASK_STAFF_GROUP.TASK_ID.in(taskList.stream().map(Task::getId).collect(Collectors.toSet()))).list();
        return buildMonthTaskStatistics(taskList, bo, taskStaffGroups);
    }

    /**
     * @param taskList 任务列表
     * @Description: 构建月统计数据
     * @return: List<TaskMonthStatisticsVo>
     * @Author: DB
     * @Date: 2023/5/15 17:54
     **/
    private TaskMonthStatisticsVo buildMonthTaskStatistics(List<Task> taskList, TaskMonthStatisticsBo bo, List<TaskStaffGroup> taskStaffGroups) {
        TaskMonthStatisticsVo statisticsVo = new TaskMonthStatisticsVo();
        List<TaskMonthStatisticsVo.DataStatisticsVo> vos = new ArrayList<>();
        // 统计数据
        statisticsVo.setVos(vos);
        // 进行中(进行中)
        statisticsVo.setInProgress(taskList.stream().filter(s -> s.getTaskStatus() == 2).count());
        // 已完成(待部署或已归档)
        Set<String> finishTaskSet = taskList.stream().filter(s -> s.getTaskStatus() == 8 || s.getTaskStatus() == 9).map(Task::getId).collect(Collectors.toSet());
        statisticsVo.setHaveCompleted(Long.parseLong(String.valueOf(finishTaskSet.size())));
        // 已逾期(正常逾期与接收逾期)
        statisticsVo.setOverdue(taskList.stream().filter(s -> s.getTaskStatus() == 4 || s.getTaskStatus() == 7).count());
        // 测试中(正常测试与逾期完成)
        statisticsVo.setInTest(taskList.stream().filter(s -> s.getTaskStatus() == 3 || s.getTaskStatus() == 6).count());
        if (null != taskStaffGroups) {
            // 已完成(待部署或已归档)
            Long finishGpa = statisticalGpa(taskStaffGroups.stream().filter(s -> finishTaskSet.contains(s.getTaskId())).collect(Collectors.toList()));
            statisticsVo.setGpaOfTheMonth(finishGpa);
        }
        List<Date> allTheDateOfMonth;
        // 有传入月份
        if (StringUtils.isNotBlank(bo.getTaskMoth())) {
            allTheDateOfMonth = DateUtils.getAllTheDateOfTheMonth(DateUtils.parseDate(bo.getTaskMoth() + "-15"));
        } else {
            // 获取当月日期数组并遍历
            allTheDateOfMonth = DateUtils.getAllTheDateOfTheMonth(new Date());
        }
        allTheDateOfMonth.forEach(item -> {
            LocalDate localDate = item.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            List<String> taskContents = new ArrayList<>();
            TaskMonthStatisticsVo.DataStatisticsVo dataStatisticsVo = statisticsVo.new DataStatisticsVo();
            // 如果日期大于等于接受任务日期,并且小于等于预期完成日期,则插入
            taskList.forEach(task -> {
                // 接受时间
                LocalDate date = task.getTaskReceiptTime().toLocalDate();
                if (!localDate.isBefore(date) && !localDate.isAfter(task.getExpectedCompletionDate())) {
                    taskContents.add(task.getTaskContent());
                }
            });
            dataStatisticsVo.setDate(localDate);
            dataStatisticsVo.setTaskContents(taskContents);
            statisticsVo.getVos().add(dataStatisticsVo);
        });
        return statisticsVo;
    }

    /**
     * @param taskStaffGroups 绩点列表
     * @Description: 统计绩点
     * @return: Long
     * @Author: DB
     * @Date: 2023/5/29 18:24
     **/
    private Long statisticalGpa(List<TaskStaffGroup> taskStaffGroups) {
        // 获取任务
        if (null != taskStaffGroups) {
            return taskStaffGroups.stream().mapToLong(TaskStaffGroup::getGradePoint).sum();
        } else {
            return 0L;
        }
    }

    /**
     * 技术模块-今日事务-更新任务进度
     *
     * @param bo 请求参数
     * @author DB
     * @since 2023/12/04
     */
    @Override
    public void updateTaskProgress(TaskProgressBo bo) {
        this.updateChain().set(TASK.TASK_PROGRESS, bo.getTaskProgress()).where(TASK.ID.eq(bo.getId())).update();
    }

    /**
     * 技术模块-数据统计-获取任务日报
     * @author DB
     * @since 2023/12/05
     * @param bo 请求参数
     * @return String
     */
    @Override
    public String getTaskDailyPaper(TaskDailyPaperBo bo) {
        //获取当前日期的任务
        List<Task> taskList = this.list(QueryWrapper.create().select(distinct(TASK.TASK_STATUS,TASK.RESPONSIBLE_STAFF_ID,TASK.TASK_PROGRESS, TASK.ID, TASK.TASK_RECEIPT_TIME, TASK.TASK_CONTENT, TASK.EXPECTED_COMPLETION_DATE))
                .leftJoin(TASK_STAFF_GROUP).on(TASK_STAFF_GROUP.TASK_ID.eq(TASK.ID))
                .and(dateFormat(TASK.TASK_RECEIPT_TIME, "%Y-%m-%d").le(bo.getDate()))
                .and(TASK.EXPECTED_COMPLETION_DATE.ge(bo.getDate()))
                .and(TASK.TASK_TYPE.in(0, 1))
                .and(TASK.TASK_STATUS.in(2, 3, 4, 6, 8, 9))
                .groupBy(TASK.ID)
                .orderBy(TASK.EXPECTED_COMPLETION_DATE.asc()));
        if (taskList.isEmpty()){
            return "";
        }
        //获取任务所属成员
        Map<String, List<TaskStaffGroup>> taskStaffGroupMap = SpringUtils.getBean(TaskStaffGroupService.class).queryChain()
                .where(TASK_STAFF_GROUP.TASK_ID.in(taskList.stream().map(Task::getId).collect(Collectors.toSet())))
                .list()
                .stream().collect(Collectors.groupingBy(TaskStaffGroup::getTaskId));
        return createDailyPaper(taskList, taskStaffGroupMap);
    }

    /**
     * 创建日报
     * @author DB
     * @since 2023/12/05
     * @param taskList 任务列表
     * @param taskStaffGroupMap 任务员工组map
     * @return String
     */
    private String createDailyPaper(List<Task> taskList, Map<String, List<TaskStaffGroup>> taskStaffGroupMap) {
        //所有技术员工信息
        Map<String, Staff> staffMap = SpringUtils.getBean(StaffService.class).queryChain()
                .leftJoin(SYS_USER).on(SYS_USER.ID.eq(STAFF.USER_ID))
                .where(STAFF.STAFF_TYPE.in(0, 2))
                .and(SYS_USER.STATUS.eq(1))
                .list()
                .stream().collect(Collectors.toMap(Staff::getId, item -> item));
        StringBuilder dailyPaper = new StringBuilder();
        dailyPaper.append("开发:\n");
        AtomicReference<Integer> start = new AtomicReference<>(1);
        DateTimeFormatter yyyyMMddHHmmss = DateTimeFormatter.ofPattern("yyyy-MM-dd HH-mm-ss");
        DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        taskList.forEach(item -> {
            //负责员工信息
            String staffGroupInfo = taskStaffGroupMap.get(item.getId()).stream().map(inner -> staffMap.get(inner.getStaffId()).getName()).collect(Collectors.joining(","));
            //首行
            dailyPaper.append(start.get()).append(":").append(item.getTaskContent()).append("\n")
                    //负责人
                    .append("负责人:").append(staffMap.get(item.getResponsibleStaffId()).getName()).append("(").append(staffGroupInfo).append(")").append("\n")
                    //进度
                    .append("目前进度:").append(item.getTaskProgress() == null ? 0 : item.getTaskProgress().split(",").length * 20).append("%\n")
                    //开始时间
                    .append("开始时间:").append(item.getTaskReceiptTime().format(yyyyMMddHHmmss)).append("\n")
                    //预计完成日期
                    .append("预计完成日期:").append(item.getExpectedCompletionDate().format(yyyyMMdd)).append("\n");
            start.getAndSet(start.get() + 1);
        });
        return dailyPaper.toString();
    }

    /**
     * 技术模块-今日事务-个人绩点
     * @author DB
     * @since 2023/12/05
     * @return TaskIndividualGpaVo
     */
    @Override
    public TaskIndividualGpaVo getIndividualGpa(String staffId, LocalDate startDate, LocalDate endDate) {
        QueryWrapper queryWrapper = QueryWrapper.create();
        if (StringUtils.isNotBlank(staffId)) {
            queryWrapper.and(TASK_STAFF_GROUP.STAFF_ID.eq(staffId));
        } else {
            //获取当前用户信息
            JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
            queryWrapper.and(TASK_STAFF_GROUP.STAFF_ID.eq(loginUserInfo.getString("id")));
        }
        if (startDate != null && endDate != null) {
            queryWrapper.and(dateFormat(TASK.TASK_RECEIPT_TIME, "%Y-%m-%d").between(startDate, endDate));
        } else {
            LocalDate now = LocalDate.now();
            // 获取目标月的第一天
            LocalDate firstDay = now.with(TemporalAdjusters.firstDayOfMonth());
            // 获取目标月的最后一天
            LocalDate lastDay = now.with(TemporalAdjusters.lastDayOfMonth());
            //获取当月绩点
            queryWrapper.and(dateFormat(TASK.TASK_RECEIPT_TIME, "%Y-%m-%d").between(firstDay, lastDay));
        }
        List<TaskIndividualGpaDetailVo> individualGpas = this.listAs(queryWrapper
                        .select(TASK.ID, TASK.TASK_CONTENT, TASK.TASK_STATUS)
                        .select(TASK_STAFF_GROUP.GRADE_POINT, TASK_STAFF_GROUP.REMARK)
                        .leftJoin(TASK_STAFF_GROUP).on(TASK_STAFF_GROUP.TASK_ID.eq(TASK.ID))
                        .where(TASK.TASK_STATUS.in(2, 3, 5, 6, 7, 8, 9))
                , TaskIndividualGpaDetailVo.class);
        TaskIndividualGpaVo vo = new TaskIndividualGpaVo();
        if (individualGpas.isEmpty()) {
            return vo;
        }
        //绩点详情
        vo.setGpa(individualGpas);
        //获取当天值班信息
        WorkOrderDutyVo workOrderDuty = SpringUtils.getBean(TaskWorkOrderService.class).getWorkOrderDutyStaff();
        vo.setDutyVo(workOrderDuty);
        //已完成
        vo.setHaveFinished(individualGpas.stream().filter(item -> item.getTaskStatus() == 8 || item.getTaskStatus() == 9)
                .mapToInt(TaskIndividualGpaDetailVo::getGradePoint).sum());
        //待完成
        vo.setToBeCompleted(individualGpas.stream().filter(item -> item.getTaskStatus() != 8 && item.getTaskStatus() != 9)
                .mapToInt(TaskIndividualGpaDetailVo::getGradePoint).sum());
        return vo;
    }
}
