package com.lz.modules.sys.service.app.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.lz.common.emun.WorkMsgTypeEnum;
import com.lz.common.exception.RRException;
import com.lz.common.utils.*;
import com.lz.modules.app.dao.DepartmentsDao;
import com.lz.modules.app.dao.DepartmentsStaffRelateDao;
import com.lz.modules.app.dto.ApprovalDto;
import com.lz.modules.app.dto.EmployeesDto;
import com.lz.modules.app.dto.GraphicsStatisticalDto;
import com.lz.modules.app.dto.RecordDetailDto;
import com.lz.modules.app.entity.DepartmentsEntity;
import com.lz.modules.app.entity.DepartmentsStaffRelateEntity;
import com.lz.modules.app.entity.StaffEntity;
import com.lz.modules.app.enums.FlowApprovalRoleTypeEnums;
import com.lz.modules.app.enums.FlowRecordStatusEnums;
import com.lz.modules.app.enums.RoleEnums;
import com.lz.modules.app.req.ResultRecordReq;
import com.lz.modules.app.resp.*;
import com.lz.modules.app.service.DepartmentsService;
import com.lz.modules.app.service.DepartmentsStaffRelateService;
import com.lz.modules.app.service.StaffService;
import com.lz.modules.app.utils.t.TwoTuple;
import com.lz.modules.flow.entity.*;
import com.lz.modules.flow.enums.FlowRecordEnum;
import com.lz.modules.flow.model.*;
import com.lz.modules.flow.service.*;
import com.lz.modules.job.business.DingtalkBusiness;
import com.lz.modules.performance.req.OwnResultReq;
import com.lz.modules.performance.res.ChartStatistical;
import com.lz.modules.sys.dao.app.ResultRecordMapper;
import com.lz.modules.sys.entity.SysUserEntity;
import com.lz.modules.sys.entity.app.ResultComment;
import com.lz.modules.sys.entity.app.ResultDetail;
import com.lz.modules.sys.entity.app.ResultRecord;
import com.lz.modules.sys.service.app.ResultCommentService;
import com.lz.modules.sys.service.app.ResultDetailService;
import com.lz.modules.sys.service.app.ResultRecordService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业绩记录表 服务类
 * </p>
 *
 * @author quyixiao
 * @since 2020-08-10
 */

@Service
@Slf4j
public class ResultRecordServiceImpl extends ServiceImpl<ResultRecordMapper, ResultRecord> implements ResultRecordService {


    @Autowired
    private ResultRecordMapper resultRecordMapper;


    private static EmployeesDto employeesDto;

    @Autowired
    private DepartmentsDao departmentsDao;

    @Autowired
    private DepartmentsStaffRelateDao departmentsStaffRelateDao;

    @Autowired
    private StaffService staffService;

    @Autowired
    private FlowDepartmentService flowDepartmentService;

    @Autowired
    private StaffRoleService staffRoleService;

    @Autowired
    private DepartmentsService departmentsService;

    @Autowired
    private RecordAuthService recordAuthService;

    @Autowired
    private FlowRelationService flowRelationService;

    @Autowired
    private FlowService flowService;

    @Autowired
    private FlowRecordService flowRecordService;


    @Autowired
    private StaffRoleDepartmentService staffRoleDepartmentService;

    @Autowired
    private ResultRecordService resultRecordService;

    @Autowired
    private DepartmentsStaffRelateService departmentsStaffRelateService;

    @Autowired
    private ResultDetailService resultDetailService;

    @Autowired
    private ResultCommentService resultCommentService;

    @Autowired
    private DingtalkBusiness dingtalkBusiness;

    @Autowired
    private FlowApprovalRoleService flowApprovalRoleService;

    @Autowired
    private FlowChartService flowChartService;

    @Autowired
    private FlowChangeService flowChangeService;

    @Autowired
    private EvaluationStartStaffService evaluationStartStaffService;

    @Value("${dingtalk.appid}")
    private String appid;

    @Value("${domain.main}")
    private String domain;

    @Autowired
    private ResultScoreService resultScoreService;

    @Override
    public ResultRecord selectResultRecordById(Long id) {
        return resultRecordMapper.selectResultRecordById(id);
    }


    @Override
    public Long insertResultRecord(ResultRecord resultRecord) {
        return resultRecordMapper.insertResultRecord(resultRecord);
    }


    @Override
    public int updateResultRecordById(ResultRecord resultRecord) {
        return resultRecordMapper.updateResultRecordById(resultRecord);
    }


    @Override
    public int updateCoverResultRecordById(ResultRecord resultRecord) {
        return resultRecordMapper.updateCoverResultRecordById(resultRecord);
    }

    @Override
    public int deleteResultRecordById(Long id) {
        return resultRecordMapper.deleteResultRecordById(id);
    }

    @Override
    public int deleteResultRecordById2(Long id) {
        return resultRecordMapper.deleteResultRecordById2(id);
    }

    @Override
    public R queryPage(ResultRecordReq params, SysUserEntity user) {
        List<String> departmentIds = new ArrayList<>();
        List<DepartmentsEntity> tDepartments = departmentsDao.selectAll();
        if (StringUtil.isNotBlank(params.getDepartment1()) || StringUtil.isNotBlank(params.getDepartment2())
                || StringUtil.isNotBlank(params.getDepartment3())) {
            Map<String, List<DepartmentsEntity>> departmentMap = null;
            if (employeesDto == null || employeesDto.getExpire() < new Date().getTime()) {
                departmentMap = getStringListMap(tDepartments);
                Date expire = DateUtils.addMinute(new Date(), 30);
                EmployeesDto newDto = new EmployeesDto(expire.getTime(), departmentMap);
                employeesDto = newDto;
                log.info("使用新数据");
            } else {
                log.info("使用缓存");
                departmentMap = employeesDto.getCacheMap();
            }
            if (StringUtil.isNotBlank(params.getDepartment3())) {
                getChildIds(departmentIds, params.getDepartment3(), departmentMap);
            } else if (StringUtil.isNotBlank(params.getDepartment2())) {
                getChildIds(departmentIds, params.getDepartment2(), departmentMap);
            } else if (StringUtil.isNotBlank(params.getDepartment1())) {
                getChildIds(departmentIds, params.getDepartment1(), departmentMap);
            }
        }

        if (StringUtil.isNotBlank(params.getStatusStr())) {
            String status[] = params.getStatusStr().split(",");
            List<Long> listx = new ArrayList<>();
            if (status != null) {
                for (String l : status) {
                    listx.add(NumberUtil.objToLongDefault(l, -1));
                }
                params.setStatusList(listx);
            }
        }

        params.setDepartmentIds(departmentIds);
        String departmentLevel = Constant.ME;
        if (params.getIsSelf() != 1) { // 表示点击我们审批
            StaffRole staffRole = staffRoleService.selectByStaffId(user.getUserId());
            if (staffRole != null) {
                departmentLevel = staffRole.getDepartmentLevel();
            } else {
                FlowDepartment flowDepartment = flowDepartmentService.selectByStaffId(user.getUserId());
                if (flowDepartment != null) {
                    departmentLevel = flowDepartment.getDepartmentLevel();
                }
            }
        }
        params.setDepartmentLevel(departmentLevel);

        if ("1,2,3,4,5,6,7".equals(params.getStatusStr()) && "HR".equals(departmentLevel)) { //如果是查看全部，并且用户角色是HR 的话，可以推动一切
            params.setDepartmentLevel(null);
        }
        if ("1,2,5".equals(params.getStatusStr()) || "3".equals(params.getStatusStr())) {
            params.setApprovalStaffId(user.getUserId());
        }
        PageUtils pageUtils = PageUtils.startPage(params.getPage(), params.getLimit()).doSelect(
                page -> resultRecordMapper.selectByConditionByLeader(page, params)
        );

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM");
        List<ResultRecord> resultRecords = pageUtils.getList();
        if (CollectionUtils.isNotEmpty(resultRecords)) {
            List<ResultRecordResp> list = new ArrayList<>();
            for (ResultRecord resultRecord : resultRecords) {
                ResultRecordResp resp = new ResultRecordResp();
                BeanUtils.copyProperties(resultRecord, resp);
                Map<Long, Long> staffRoleMap = recordAuthService.selectRoleIdByStaffRoleInfo(resultRecord.getFlowStaffIdRole());
                if (resp.getStatus().equals(5) && staffRoleMap.get(user.getUserId()) == null) {
                    resp.setStatus(1); // 如果不是自己审批，说明自己己经审批完成
                }
                resp.setMonthTimeStr(df.format(resultRecord.getMonthTime()));
                list.add(resp);
            }
            pageUtils.setList(list);
        }
        return R.ok().put("page", pageUtils)
                .put("departmentLevel", departmentLevel);
    }

    @Override
    public Map<String, List<DepartmentsEntity>> getStringListMap(List<DepartmentsEntity> tDepartments) {
        Map<String, List<DepartmentsEntity>> departmentMap = new HashMap<>();
        for (DepartmentsEntity department : tDepartments) {
            List<DepartmentsEntity> list = new ArrayList<>();
            for (DepartmentsEntity child : tDepartments) {
                if (child.getDepartmentParentId().equals(department.getDepartmentId())) {
                    list.add(child);
                }
            }
            departmentMap.put(department.getDepartmentId(), list);
        }
        return departmentMap;
    }

    @Override
    public ResultRecord selectResultRecordByStaffIdStatus(Long staffId, int status) {
        return resultRecordMapper.selectResultRecordByStaffIdStatus(staffId, status);
    }

    public void getChildIds(List<String> childDepartIds, String parentId, Map<String, List<DepartmentsEntity>> departmentMap) {
        childDepartIds.add(parentId);
        List<DepartmentsEntity> tDepartments = departmentMap.get(parentId);
        if (CollectionUtils.isNotEmpty(tDepartments)) {
            for (DepartmentsEntity tDepartment : tDepartments) {
                getChildIds(childDepartIds, tDepartment.getDepartmentId(), departmentMap);
            }
        }
    }


    @Override
    public void deleteBatchIds(List<Long> asList) {

    }

    @Override
    public ResultRecord selectResultRecordByStaffId(Long staffId) {

        return resultRecordMapper.selectResultRecordByStaffId(staffId);
    }

    @Override
    public void updateFlowStaffIdRoleToNull(Long id, Integer status) {
        resultRecordMapper.updateFlowStaffIdRoleToNull(id, status);
    }

    @Override
    public TwoTuple getFlowInfo(Long staffId, Integer type) {
        FlowDepartment flowDepartment = flowDepartmentService.selectByStaffId(staffId);
        List<FlowDepartment> list = new ArrayList<>();
        Long flowId = flowDepartment != null ? TypeFlowDto.getFlowId(flowDepartment.getFlowIds(), Constant.SELF, type) : 0l;       // 表示是部门主管自己
        if (flowDepartment == null) {
            DepartmentsStaffRelateEntity leader = getLeaderDepartmentsStaffRelateEntity(staffId);
            flowDepartment = flowDepartmentService.selectByStaffId(leader.getStaffId());
            flowId = TypeFlowDto.getFlowId(flowDepartment.getFlowIds(), Constant.CHILD, type);//表示是部门下的普通员工
            list.add(flowDepartment);
        }
        for (int i = 0; i < 10; i++) {
            if (flowDepartment.getParentId() != null && flowDepartment.getParentId() > 0) {
                flowDepartment = flowDepartmentService.selectFlowDepartmentById(flowDepartment.getParentId());
                list.add(flowDepartment);
            } else {
                break;
            }
        }
        return new TwoTuple(flowId, list);
    }

    @Override
    public DepartmentsStaffRelateEntity getLeaderDepartmentsStaffRelateEntity(Long staffId) {
        DepartmentsStaffRelateEntity departmentsStaffRelateEntity = departmentsStaffRelateService.selectLastDepartmentByStaffId(staffId);
        DepartmentsStaffRelateEntity leader = departmentsStaffRelateService.selectLeaderByDepartmentId(departmentsStaffRelateEntity.getDepartmentId());
        if (leader == null) {
            Map<String, String> map = departmentsService.selectUserAllDepartmentInFo(departmentsStaffRelateEntity.getDepartmentId());
            if (StringUtil.isNotBlank(map.get("dd2"))) {
                leader = departmentsStaffRelateService.selectLeaderByDepartmentId(map.get("dd2"));
                if (leader == null && StringUtil.isNotBlank(map.get("dd3"))) {
                    leader = departmentsStaffRelateService.selectLeaderByDepartmentId(map.get("dd3"));
                    return leader;

                }
            }
        }
        return leader;
    }

    @Override
    public ResultRecord selectLastResultRecordByStaffIdType(Long staffId, int type) {
        return resultRecordMapper.selectLastResultRecordByStaffIdType(staffId, type);
    }

    @Override
    public ResultRecord selectCurrentMonthResultRecordByStaffIdType(Long staffId, int type) {
        return resultRecordMapper.selectCurrentMonthResultRecordByStaffIdType(staffId, type);
    }

    @Override
    public List<ResultRecord> selectResultRecordAllByStaffId(Long staffId) {

        return resultRecordMapper.selectResultRecordAllByStaffId(staffId);
    }


    @Override
    public ResultRecord createResultRecord(Long staffId, int type, Long roleId) {
        StaffEntity staffEntity = staffService.selectStaffById(staffId);
        ResultRecord resultRecord = new ResultRecord();
        resultRecord.setMonthTime(new Date());
        resultRecord.setFlowStaffIdRole(resultDetailService.initRole(staffId, roleId));
        resultRecord.setStaffId(staffId);
        resultRecord.setStatus(0);
        resultRecord.setType(type);
        resultRecord.setGmtCreate(new Date());
        resultRecord.setGmtModified(new Date());
        resultRecord.setStaffName(staffEntity.getName());
        DepartmentsStaffRelateEntity relateEntity = departmentsStaffRelateService.selectLastDepartmentByStaffId(staffId);
        Map<String, String> map = departmentsService.selectUserAllDepartmentIds(relateEntity.getDepartmentId());
        resultRecord.setDepartmentId(relateEntity.getDepartmentId());
        resultRecord.setDepartmentName(map.get(relateEntity.getDepartmentId()));
        resultRecordService.insertResultRecord(resultRecord);
        return resultRecord;
    }

    @Override
    public ResultRecord initResult(Long staffId, Integer recordType, Long roleId) {
        ResultRecord resultRecordOld = resultRecordService.selectLastResultRecordByStaffIdType(staffId, 1);
        ResultRecord resultRecordNew = null;
        if (resultRecordOld != null) {
            Long oldResultRecordId = resultRecordOld.getId();
            Long recordId = resultRecordOld.getId();
            resultRecordOld.setId(null);
            resultRecordOld.setType(Constant.TWO);                      // 1 表示是目标，2 表示是业绩
            resultRecordOld.setStatus(0);
            resultRecordOld.setCurrentApprovalStaffId(staffId);
            resultRecordOld.setScoreLevel("0");
            StaffEntity staffEntity = staffService.selectStaffById(staffId);
            resultRecordOld.setCurrentApprovalStaffName(staffEntity.getName());
            resultRecordOld.setFlowStaffIdRole(resultDetailService.initRole(resultRecordOld.getStaffId(), roleId));
            resultRecordService.insertResultRecord(resultRecordOld);
            //删除月初目标
            resultRecordService.deleteResultRecordById2(oldResultRecordId);
            List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByResultRecordIdFlowId(oldResultRecordId);

            for (FlowRecord flowRecord : flowRecords) {
                flowRecord.setRecordId(resultRecordOld.getId());
                flowRecord.setId(null);
                flowRecord.setType(Constant.ONE);
                //新增record
                flowRecordService.copyFlowRecord(flowRecord);
            }

            flowRecordService.initFlowRecord(resultRecordOld, roleId, recordType, "月未总结");
            resultRecordNew = resultRecordOld;
            List<ResultDetail> resultDetails = resultDetailService.selectByRecordId(recordId);
            if (CollectionUtils.isNotEmpty(resultDetails)) {
                // 保存业绩相关
                for (ResultDetail resultDetail : resultDetails) {
                    resultDetail.setRecordId(resultRecordNew.getId());
                    resultDetail.setId(null);
                    resultDetail.setType(1);                    // 表示业绩
                    resultDetailService.insertResultDetail(resultDetail);
                }
            }
        } else {
            resultRecordNew = resultRecordService.createResultRecord(staffId, recordType, roleId);
        }
        //保存文件价值观
        resultDetailService.insertWenHuaJiaZhiGua(Constant.WENHUAJIAZHIGUAN, resultRecordNew.getId(), staffId, new BigDecimal(0.3));
        return resultRecordNew;
    }

    @Override
    public R checkApproval(ResultRecord resultRecord, Long userId) {
        Long recordId = resultRecord.getId();
        List<ResultDetail> resultDetails = resultDetailService.selectByRecordId(recordId);
        if (CollectionUtils.isEmpty(resultDetails)) {
            return R.error("请先添加绩效。");
        }
        double sum = resultDetails.stream().filter(p -> p.getType() == 1).mapToDouble(p -> NumberUtil.objToDoubleWithDefault(p.getCheckWeight(), 0d)).sum();
        if (sum < 0.7) {
            return R.error("recordId为[" + recordId + "]绩效权重之和必需等于0.7。");
        }

        Map<Long, Long> staffRoleMap = recordAuthService.selectRoleIdByStaffRoleInfo(resultRecord.getFlowStaffIdRole());
        List<RecordAuth> listAuth = recordAuthService.selectAuthInfo(staffRoleMap.get(userId));
        Auth auth = recordAuthService.getAuth(listAuth);
        // 如果是评分，查看是不是所有内容都己经评分
        if (auth.getEditScore() == 1) {
            for (ResultDetail resultDetail : resultDetails) {
                if (resultDetail.getAcquireScore().compareTo(BigDecimal.ZERO) <= 0) {
                    return R.error("resultDetail[" + resultDetail.getId() + "] 评分必需 > 0 ");
                }
            }
        }
        return R.ok();
    }

    @Override
    public R approval(Long resultRecordId, Long userId, Integer status, boolean flagEnd) {
        ResultRecord resultRecord = resultRecordService.selectResultRecordById(resultRecordId);
        R r = resultRecordService.checkApproval(resultRecord, userId);
        if (!r.isSuccess()) {
            return r;
        }
        StaffEntity mySelf = staffService.selectStaffById(userId);
        TwoTuple<Long, List<FlowDepartment>> flowInfo = getFlowInfo(resultRecord.getStaffId(), resultRecord.getType());
        Long flowId = flowInfo.getFirst();
        List<FlowDepartment> list = flowInfo.getSecond();
        List<FlowRelation> flowRelations = flowRelationService.selectFlowRelationAll();
        Map<String, FlowDepartment> staffEntityMap = list.stream().collect(Collectors.toMap(FlowDepartment::getDepartmentLevel, p -> p));
        //approvalList = [ME,ONE_D,TWO_D,HR,BOSS]
        List<String> approvalList = new ArrayList<>();
        approvalList.add("ME");
        for (FlowRelation flowRelation : flowRelations) {
            if (staffEntityMap.get(flowRelation.getChild()) != null || flowRelation.getCanReplace() == 0) {
                approvalList.add(flowRelation.getChild());
            }
        }
        log.info("approvalList approval : " + Arrays.toString(approvalList.toArray()));
        List<Flow> flows = flowService.selectByFlowId(flowId, 0l);
        FlowRecord lastFlowRecord = flowRecordService.selectLastFlowRecordByRecordId(resultRecordId);
        FlowRecord notFlowRecord = flowRecordService.selectNotApprovalStaffIdFlowRecords(resultRecord.getId());
        if (notFlowRecord != null) {
            notFlowRecord.setApprovalStaffId(userId);
        }
        StaffEntity staff = staffService.selectStaffById(resultRecord.getStaffId());
        int flowIndex = lastFlowRecord != null ? lastFlowRecord.getFlowIndex() + 1 : 1;
        int index = getDepartmentLevelIndex(flows, flowIndex);
        if (index < 0 || index >= approvalList.size() || flagEnd) {             //表示流程己经结束
            lastFlowRecord.setFlowName(mySelf.getName() + "-审批通过");
            lastFlowRecord.setStatusName(FlowRecordEnum.END.getName());
            flowRecordService.updateCoverFlowRecordById(lastFlowRecord);
            resultRecordService.updateFlowStaffIdRoleToNull(resultRecord.getId(), status != null ? status : 4);// 更新状态
            if (flagEnd) {
                return R.ok("流程终止")
                        .put("from", staff)
                        .put("to", staff)
                        .put("type", WorkMsgTypeEnum.END);
            } else {
                return R.ok("流程审批结束")
                        .put("from", staff)
                        .put("to", staff)
                        .put("type", WorkMsgTypeEnum.PASS);
            }
        }
        FlowRecord flowRecord = new FlowRecord();
        flowRecord.setRecordId(resultRecordId);
        flowRecord.setRecordStaffId(resultRecord.getStaffId());
        flowRecord.setFlowIndex(flowIndex);
        flowRecord.setFlowId(flowId);
        String departmentLevel = approvalList.get(index);
        StaffEntity approvalStaff = null;
        List<StaffRoleDto> staffRoleDtos = new ArrayList<>();
        Long roleId = flows.get(flowIndex - 1).getRoleId();
        if (Constant.ME.equals(departmentLevel)) {                  //如果是自己
            approvalStaff = staff; // 是自己进行审批
            StaffRoleDto staffRoleDto = new StaffRoleDto(staff.getId(), roleId);
            staffRoleDtos.add(staffRoleDto);
        } else {
            FlowDepartment flowD = staffEntityMap.get(departmentLevel);
            if (flowD == null) {
                approvalStaff = getApprovalStaff(resultRecord, departmentLevel, staffRoleDtos, roleId);
            } else {
                approvalStaff = staffService.selectStaffById(flowD.getStaffId());
                StaffRoleDto staffRoleDto = new StaffRoleDto(approvalStaff.getId(), roleId);
                staffRoleDtos.add(staffRoleDto);
            }
        }
        flowRecord.setFlowName((approvalStaff != null ? approvalStaff.getName() + "-" : "") + flows.get(flowIndex - 1).getOptDesc());
        flowRecord.setApprovalStaffId(approvalStaff != null ? approvalStaff.getId() : null);
        flowRecord.setApprovalStaffName(approvalStaff != null ? approvalStaff.getName() : null);
        // 如果用户有 HR 的权限，又在 flow_department 表中有记录，则记录为 HR
        if (approvalStaff != null) {
            StaffRole staffRole = staffRoleService.selectByStaffId(approvalStaff.getId());
            if (staffRole != null) {
                departmentLevel = staffRole.getDepartmentLevel();
            }
        }
        flowRecord.setDepartmentLevel(departmentLevel);
        String staffRoles = JSON.toJSONString(staffRoleDtos);
        flowRecord.setFlowStaffIdRole(staffRoles);

        flowRecord.setStatusName(FlowRecordEnum.APPROVALING.getName());
        flowRecord.setType(resultRecord.getType());

        FlowRecord lastFlowRecordNoStatus = flowRecordService.selectLastFlowNoStatusRecordByRecordId(resultRecordId);
        // 如果上一步是开始，则不进行修改，如果上一步是确认中，改成提交，如果上一点是审批中，将上一步改成通过
        if (lastFlowRecordNoStatus != null) {
            if (!StringUtil.equals(lastFlowRecordNoStatus.getStatusName(), FlowRecordEnum.START.getName())
                    && !StringUtil.equals(lastFlowRecordNoStatus.getStatusName(), FlowRecordEnum.CONFIRM.getName())) {
                lastFlowRecordNoStatus.setStatusName(FlowRecordEnum.APPROVAL.getName());
                lastFlowRecordNoStatus.setGmtCreate(new Date());
            } else if (StringUtil.equals(lastFlowRecordNoStatus.getStatusName(), FlowRecordEnum.CONFIRM.getName())) {
                lastFlowRecordNoStatus.setStatusName(FlowRecordEnum.COMMIT.getName());
                lastFlowRecordNoStatus.setGmtCreate(new Date());
            }
            flowRecordService.updateFlowRecordById(lastFlowRecordNoStatus);
        }
        flowRecordService.insertFlowRecord(flowRecord);
        resultRecord.setFlowStaffIdRole(staffRoles);
        resultRecord.setStatus(status != null ? status : 1); //如果状态不为空，则使用传入进来的状态，如果状态为空，则默认1,审批中
        resultRecord.setCurrentApprovalStaffId(approvalStaff != null ? approvalStaff.getId() : null);
        resultRecord.setCurrentApprovalStaffName(approvalStaff != null ? approvalStaff.getName() : null);
        resultRecordService.updateResultRecordById(resultRecord);// 更新用户权限
        return R.ok("提交审批成功")
                .put("from", staff)
                .put("to", approvalStaff)
                .put("type", WorkMsgTypeEnum.SUBMIT);
    }

    @Override
    public StaffEntity getApprovalStaff(ResultRecord resultRecord, String departmentLevel, List<StaffRoleDto> staffRoleDtos, Long roleId) {
        StaffEntity approvalStaff = null;
        List<StaffRole> staffRoles = staffRoleService.selectByRole(departmentLevel);
        for (StaffRole staffRole : staffRoles) {
            List<StaffRoleDepartment> staffRoleDepartments = staffRoleDepartmentService.selectStaffRoleDepartmentByStaffRoleId(staffRole.getId());
            Map<String, String> departmentIdMap = departmentsService.selectUserAllDepartmentIds(resultRecord.getDepartmentId());
            for (StaffRoleDepartment staffRoleDepartment : staffRoleDepartments) {
                String value = departmentIdMap.get(staffRoleDepartment.getDepartmentId());
                if (StringUtil.isNotBlank(value)) {
                    StaffRoleDto staffRoleDto = new StaffRoleDto(staffRole.getStaffId(), roleId != null && roleId > 0 ? roleId :
                            TypeRoleDto.getRoleId(staffRole.getTypeRoleIds(), resultRecord.getType()));
                    staffRoleDtos.add(staffRoleDto);
                }
            }
        }
        if (staffRoleDtos.size() >= 1) { //表示只有一个审批的用户
            approvalStaff = staffService.selectStaffById(staffRoleDtos.get(0).getStaffId());
        }
        return approvalStaff;
    }

    @Override
    public List<ResultRecord> selectResultRecordByIds(List<Long> recordIds) {
        return resultRecordMapper.selectResultRecordByIds(recordIds);
    }


    @Override
    public int getDepartmentLevelIndex(List<Flow> list, int flowIndex) {
        if (flowIndex > list.size()) {
            return -1;
        }
        List<Flow> flows = new ArrayList<>();
        for (int i = 0; i < flowIndex; i++) {
            flows.add(list.get(i));
        }
        int index = 0;
        for (Flow flow : flows) {
            String opt = flow.getOpt();
            String opts[] = opt.split("");
            for (String p : opts) {
                if ("+".equals(p)) {
                    index++;
                } else {
                    index--;
                }
            }
        }
        return index;
    }

    @Override
    public R commitApproval(ResultRecordReq req, Long userId) {
        ResultRecord resultRecord = resultRecordService.selectResultRecordById(req.getRecordResultId());
        if (req.getStatus() == 2 || req.getStatus() == 3 || req.getStatus() == 5) {
            if (resultRecord.getCurrentApprovalStaffId() != null && !userId.equals(resultRecord.getCurrentApprovalStaffId())) {
                return R.error("请勿重复提交");
            }
        }

        R r = null;
        int status = 1;
        FlowRecord lastUsedFlowRecord = flowRecordService.selectLastFlowRecordByRecordId(req.getRecordResultId());
        if (req.getStatus() == 2) {
            r = resultRecordService.approval(req.getRecordResultId(), userId, null, false);
        } else if (req.getStatus() == 3) {      //侍提交
            resultRecord.setStatus(Constant.STATUS_3);
            resultRecordService.updateResultRecordById(resultRecord);
        } else if (req.getStatus() == 5) { // 驳回
            status = 5;
            r = reject(resultRecord, status);
        } else if (req.getStatus() == 7) {
            List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByResultRecordIdType(req.getRecordResultId(), resultRecord.getType());
            if (flowRecords != null && flowRecords.size() == 2) {       // 表示可以撤回
                r = reject(resultRecord, 5);
            } else if (flowRecords != null && flowRecords.size() > 2) {
                return R.error("你的领导己经审批，不能撤回了");
            }
        } else if (req.getStatus() == 8) {
            Long staffId = resultRecord.getStaffId();
            Long approvalStaffId = resultRecord.getCurrentApprovalStaffId();
            StaffEntity mySelf = staffService.selectStaffById(staffId);
            StaffEntity approvalStaff = staffService.selectStaffById(approvalStaffId);
            r = R.ok("成功")
                    .put("from", mySelf)
                    .put("to", approvalStaff)
                    .put("type", WorkMsgTypeEnum.URGING);
        } else if (req.getStatus() == 6) {
            status = 6;
            // 回滚代码
            resultRecordService.reject(resultRecord, req.getStatus());
        }
        resultCommentService.addOrUpdateComment(req, userId, status, lastUsedFlowRecord);
        if (r != null) {//下面推送消息
            if (r.isSuccess()) {
                StaffEntity mySelf = (StaffEntity) r.get("from");
                StaffEntity toSelf = (StaffEntity) r.get("to");
                WorkMsgTypeEnum workMsgTypeEnum = (WorkMsgTypeEnum) r.get("type");
                sendWorkMSG(mySelf, toSelf, workMsgTypeEnum, req.getRecordResultId(), 1);
                return R.ok("成功");
            }
            return r;
        }
        return R.ok("成功");
    }

    @Override
    public R reject(ResultRecord resultRecord, Integer status) {
        List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByResultRecordIdFlowId(resultRecord.getId());
        StaffEntity mySelf = staffService.selectStaffById(resultRecord.getStaffId());
        StaffEntity approvalStaff = mySelf;
        if (flowRecords.size() >= 2) {
            FlowRecord secondFlowRecord = flowRecords.get(flowRecords.size() - 2);
            resultRecord.setFlowStaffIdRole(secondFlowRecord.getFlowStaffIdRole());
            resultRecord.setStatus(status);                          //更新驳回状态为5
            List<StaffRoleDto> list = JSONObject.parseArray(resultRecord.getFlowStaffIdRole(), StaffRoleDto.class);
            if (CollectionUtils.isNotEmpty(list)) {
                StaffRoleDto staffRoleDto = list.get(0);
                approvalStaff = staffService.selectStaffById(staffRoleDto.getStaffId());
                resultRecord.setCurrentApprovalStaffId(approvalStaff != null ? approvalStaff.getId() : null);
                resultRecord.setCurrentApprovalStaffName(approvalStaff != null ? approvalStaff.getName() : null);
            }
            resultRecordService.updateResultRecordById(resultRecord);

            FlowRecord lastFlowRecord = flowRecords.get(flowRecords.size() - 1);
            lastFlowRecord.setStatus(1);
            flowRecordService.updateFlowRecordById(lastFlowRecord);

            FlowRecord lastFlowRecordNoStatus = flowRecordService.selectLastFlowNoStatusRecordByRecordId(resultRecord.getId());
            lastFlowRecordNoStatus.setStatusName(FlowRecordEnum.REJECT.getName());
            lastFlowRecordNoStatus.setGmtCreate(new Date());    //更新驳回时间
            flowRecordService.updateFlowRecordById(lastFlowRecordNoStatus);


            // 可能会被删除
            FlowRecord lastUsedFlowRecord = flowRecordService.selectLastFlowRecordByRecordId(resultRecord.getId());
            lastUsedFlowRecord.setId(null);
            lastUsedFlowRecord.setStatus(1);
            lastUsedFlowRecord.setStatusName(FlowRecordEnum.CONFIRM.getName());
            flowRecordService.insertFlowRecord(lastUsedFlowRecord);// 新插入一条提交记录

            if (mySelf.getId().longValue() == approvalStaff.getId().longValue()) {//同一个人
                mySelf.setName("你");//用于替换消息中的@符号。无其他任何作用，不保存
            }
            return R.ok("成功")
                    .put("from", mySelf)
                    .put("to", approvalStaff)
                    .put("type", WorkMsgTypeEnum.REJECT);
        }
        return R.error("驳回失败");
    }

    public void sendWorkMSG(StaffEntity mySelf, StaffEntity toSelf, WorkMsgTypeEnum workMsgTypeEnum
            , Long recordResultId, int count) {
        String url = domain + "/management/dingtalklogin?url=";//免登接口
        String jump;
        if (count == 1) {//一个提交
            log.info("单个提交推送消息");
            jump = domain + "/management/recorddetail?id=" + recordResultId
                    + "&recordType=3";//跳转接口
        } else {//批量提交
            log.info("批量提交推送消息");
            jump = domain + "/management/result-record-lzresultrecordapp";//跳转接口
        }

        jump = URLEncoder.encode(jump);
        String msg = dingtalkBusiness.sendWorkMSGByEntity(appid, mySelf, toSelf, workMsgTypeEnum, url + jump);
        log.info("发送钉钉工作消息{}", msg);
    }


    @Override
    public List<OwnResultResp> ownResult(OwnResultReq req) {
        return resultRecordMapper.ownResult(req);
    }

    @Override
    public List<GraphicsStatisticalDto> staffDistribution(String monthTime, List<String> staffIds) {

        return resultRecordMapper.staffDistribution(monthTime, staffIds);
    }

    @Override
    public List<ChartStatistical> countNumByFlowProcess(Long startId, List<Long> evaluationIds, List<String> departmentIds) {
        return resultRecordMapper.countNumByFlowProcess(startId, evaluationIds, departmentIds);
    }

    @Override
    public List<ChartStatistical> countNumByScoreLevel(Long startId, List<Long> evaluationIds, List<String> departmentIds) {
        return resultRecordMapper.countNumByScoreLevel(startId, evaluationIds, departmentIds);
    }

    @Override
    public void batchDeleteByStaffIds(List<String> staffIds) {

    }

    @Override
    public R initFlowRecord(Long resultRecordId) {
        ResultRecord resultRecord = resultRecordMapper.selectResultRecordById(resultRecordId);
        List<Flow> flows = flowService.selectByFlowId(resultRecord.getEvaluationId(), resultRecord.getStartId());
        List<Long> flowIds = new ArrayList<>();
        for (Flow flow : flows) {
            flowIds.add(flow.getId());
        }
        List<FlowApprovalRole> flowApprovalRoles = flowApprovalRoleService.selectFlowApprovalRoleList(flowIds);

        return initFlowRecord(resultRecord, flows, flowApprovalRoles);
    }

    @Override
    public R initFlowRecord(ResultRecord resultRecord, List<Flow> flows, List<FlowApprovalRole> flowApprovalRoles) {
        int i = 0;
        for (FlowApprovalRole flowApprovalRole : flowApprovalRoles) {
            FlowRecord flowRecord = new FlowRecord();
            flowRecord.setRecordId(resultRecord.getId());
            StaffEntity approvalStaff = new StaffEntity();
            if (FlowApprovalRoleTypeEnums.ME.getType().equals(flowApprovalRole.getType())) {
                approvalStaff = staffService.selectStaffById(resultRecord.getStaffId());
            } else if (FlowApprovalRoleTypeEnums.STAFF.getType().equals(flowApprovalRole.getType())) {
                approvalStaff = staffService.selectStaffById(flowApprovalRole.getApprovalId());
            } else if (FlowApprovalRoleTypeEnums.ONE_SUPPER.getType().equals(flowApprovalRole.getType())) {
                approvalStaff = getDepartmentStaff(resultRecord.getStaffId(), 1);
            } else if (FlowApprovalRoleTypeEnums.TWO_SUPPER.getType().equals(flowApprovalRole.getType())) {
                approvalStaff = getDepartmentStaff(resultRecord.getStaffId(), 2);
            } else if (FlowApprovalRoleTypeEnums.THREE_SUPPER.getType().equals(flowApprovalRole.getType())) {
                approvalStaff = getDepartmentStaff(resultRecord.getStaffId(), 3);
            } else if (FlowApprovalRoleTypeEnums.FOUR_SUPPER.getType().equals(flowApprovalRole.getType())) {
                approvalStaff = getDepartmentStaff(resultRecord.getStaffId(), 4);
            } else if (FlowApprovalRoleTypeEnums.FOUR_SUPPER.getType().equals(flowApprovalRole.getType())) {
                approvalStaff = getDepartmentStaff(resultRecord.getStaffId(), 5);
            }
            if (approvalStaff != null && StringUtil.isNotBlank(approvalStaff.getName())) {
                insertFlowRecord(flowRecord, approvalStaff, flows, flowApprovalRole, resultRecord, i, null);
            } else {
                List<StaffRole> staffRoles = staffRoleService.selectAllStaffRoleByDepartmentLevel(Arrays.asList(new String[]{RoleEnums.MASTER_PM.getName(), RoleEnums.CHILD_PM.getName()}));
                for (StaffRole staffRole : staffRoles) {
                    approvalStaff = staffService.selectStaffById(staffRole.getStaffId());
                    if (staffRole.getDepartmentId() == 0) {    //如果是管理所有部门
                        insertFlowRecord(flowRecord, approvalStaff, flows, flowApprovalRole, resultRecord, i, 1);
                    } else {
                        DepartmentsStaffRelateEntity relateEntity = departmentsStaffRelateService.selectLastDepartmentByStaffId(resultRecord.getStaffId());
                        Map<String, String> map = departmentsService.selectUserAllDepartmentIds(relateEntity.getDepartmentId());
                        List<StaffRoleDepartment> staffRoleDepartments = staffRoleDepartmentService.selectStaffRoleDepartmentByStaffRoleId(staffRole.getId());
                        boolean flag = false;
                        for (StaffRoleDepartment staffRoleDepartment : staffRoleDepartments) {
                            String departmentName = map.get(staffRoleDepartment.getDepartmentId());
                            if (StringUtil.isNotBlank(departmentName)) {
                                flag = true;
                                break;
                            }
                        }
                        if (flag) {                   //如果管理员是管理特定部门
                            insertFlowRecord(flowRecord, approvalStaff, flows, flowApprovalRole, resultRecord, i, 1);
                        }
                    }
                }
            }
            i++;
        }

        resultRecordService.updateResultRecordById(resultRecord);
        return R.ok();
    }


    public void insertFlowRecord(FlowRecord flowRecord, StaffEntity approvalStaff, List<Flow> flows, FlowApprovalRole flowApprovalRole, ResultRecord resultRecord, int i, Integer stepType) {
        flowRecord.setApprovalStaffName(approvalStaff.getName());
        flowRecord.setApprovalStaffId(approvalStaff.getId());
        Flow flow = getFlow(flows, flowApprovalRole.getFlowId());
        flowRecord.setFlowName(flow.getOptDesc());
        flowRecord.setRecordStaffId(resultRecord.getStaffId());
        flowRecord.setFlowId(flowApprovalRole.getFlowId());
        FlowChart flowChart = flowService.selectFlowChartByFlow(flow);
        flowRecord.setProcessId(flowChart.getProcessId());
        flowRecord.setFlowProcess(flowChart.getFlowProcess());
        String staffRole = StaffRoles.getStaffRole(approvalStaff.getId(), StringUtil.strToLongs(flowApprovalRole.getRoleId()));
        if (i == 0) {
            flowRecord.setStatus(FlowRecordStatusEnums.CURRENT_FLOW_STATUS.getStatus());
            resultRecord.setFlowStaffIdRole(staffRole);
            resultRecord.setFlowProcess(flowChart.getFlowProcess());
        } else {
            flowRecord.setStatus(FlowRecordStatusEnums.UN_TO_STATUS.getStatus());
            if (new Integer(4).equals(flowChart.getFlowProcess())) {
                EvaluationStartStaff evaluationStartStaff = evaluationStartStaffService.selectEvaluationStartById(resultRecord.getEvaluationId(), resultRecord.getStartId());
                if (evaluationStartStaff != null && new Integer(1).equals(evaluationStartStaff.getScore())) {
                    flowRecord.setStatus(FlowRecordStatusEnums.SKIP_STATUS.getStatus());
                } else {
                    log.info("evaluationStartStaff is null evaluationId :" + resultRecord.getEvaluationId() + ", startId : " + resultRecord.getStartId());
                }
            }
        }
        flowRecord.setFlowStaffIdRole(staffRole);
        flowRecord.setFlowIndex(flowApprovalRole.getStepIndex());
        flowRecord.setType(stepType != null ? stepType : flowApprovalRole.getStepType());         //步骤类型0：依次，1：或签（同时通知，一人通过或拒绝即可），2会签（同时通知，所有人同意才可）
        flowRecordService.insertFlowRecord(flowRecord);

    }

    @Override
    ////1 提交审批,审批通过,2 撤回,3 催办,4 跳过,5 驳回，6 申述，7 流程终止，8 转交
    public R newApproval(ApprovalDto approvalDto) throws Exception {
        log.info("newApproval args :" + JSON.toJSONString(approvalDto));
        if (approvalDto.getResultRecordId() == null) {
            throw new RRException("resultRecordId 不能为空");
        }
        if (approvalDto.getStatus() == null) {
            throw new RRException("status 不能为空");
        }
        if (StringUtil.isBlank(approvalDto.getMenuName())) {
            throw new RRException("menuName 不能为空");
        }

        List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByRecordIdStatus(approvalDto.getResultRecordId(), 2);
        Long commentId = 0l;
        if (CollectionUtils.isNotEmpty(flowRecords)) {
            FlowRecord preFlowRecord = flowRecords.get(0);
            // 评论内容
            FlowChart flowChart = flowService.selectFlowChartByChartId(preFlowRecord.getFlowId());
            commentId = comment(approvalDto, flowChart);
        }
        R r = apply(approvalDto);
        return r.put("commentId",commentId);
    }

    public R apply( ApprovalDto approvalDto){
        switch (approvalDto.getStatus()) {
            case 1: //1 提交审批,审批通过
                return newSubmit(approvalDto, null);
            case 2:     //2 撤回
                return reSubmit(approvalDto);
            case 3:     //3 催办
                return urge(approvalDto);
            case 4:     //4 跳过
                if (approvalDto.getFlowRecordId() == null) {
                    throw new RRException("currentStaffId 不能为空");
                }
                return skip(approvalDto);
            case 5:     //5 驳回
                return newReject(approvalDto);
            case 6:     //6 申述
                return explain(approvalDto);
            case 8:     //6 转交
                if (approvalDto.getTransferStaffId() == null) {
                    throw new RRException("transferStaffId 不能为空");
                }
                if (approvalDto.getFlowRecordId() == null) {
                    throw new RRException("flowRecordId 不能为空");
                }
                return transfer(approvalDto);
            case 9:
                return reset(approvalDto);
            default:
                break;
        }
        return R.ok();
    }


    private R reset(ApprovalDto approvalDto) {
        switch (approvalDto.getResetFlag()) {
            case 0:     //0 重置到制定节点,所有数据会保留,重置到制定节点的后面跳过的节点需要重新执行
                return resetNode(approvalDto);
            case 1:     //重新读取考核流程,添加的指标信息根据选择是否清空,后面跳过的节点需要重新执行
                return resetAll(approvalDto);
        }
        return R.ok();
    }

    private R resetNode(ApprovalDto approvalDto) {
        FlowRecord f = flowRecordService.selectFlowRecordById(approvalDto.getFlowRecordId());
        ResultRecord resultRecord = resultRecordService.selectResultRecordById(f.getRecordId());
        List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByRecordIdGeFlowIndex(f.getRecordId(),f.getFlowIndex());
        boolean flag = false ;
        for(FlowRecord flowRecord:flowRecords){
            // 如果结果录入己经走了
            if (new Integer(2).equals(flowRecord.getFlowProcess()) && (flowRecord.getStatus() == 1 || flowRecord.getStatus() == 4) ) {
                flowRecord.setStatus(4);        //表示流程己经被重置
                flag = true;
            }else{
                flowRecord.setStatus(0);        //表示流程己经被重置
            }
            flowRecordService.updateFlowRecordById(flowRecord);
        }

        FlowRecord preFlowRecord = flowRecordService.selectPreFlowRecordByRecordIdMinIdStatusList(f.getRecordId(), f.getFlowIndex(), Arrays.asList(1, 2,4));
        List<FlowRecord> runing = new ArrayList<>();
        if (preFlowRecord != null) {
            runing = flowRecordService.selectFlowRecordByRecordIdFlowIndex(f.getRecordId(), preFlowRecord.getFlowIndex());
        } else {
            runing = flowRecordService.selectFlowRecordByRecordIdFlowIndex(f.getRecordId(), 0);
        }
        for (FlowRecord r : runing) {
            r.setStatus(2);
            resultRecord.setFlowProcess(r.getFlowProcess());
            flowRecordService.updateFlowRecordById(r);
        }
        resultRecordService.updateResultRecordById(resultRecord);
        if(flag) {  //如果录入己经走了，设置新的数据，结果录入己走
            List<FlowRecord> newflowRecords = flowRecordService.selectFlowRecordByRecordId(f.getRecordId());
            for(int i = 0 ;i < newflowRecords.size() ; i ++){
                FlowRecord newFlowRecord = newflowRecords.get(i) ;
                if (new Integer(2).equals(newFlowRecord.getFlowProcess()) ) {
                    newFlowRecord.setStatus(4);
                    flowRecordService.updateFlowRecordById(newFlowRecord);
                }
            }
        }
        resultRecordService.resetData(resultRecord.getId(),2);
        return R.ok();
    }


    private R resetAll(ApprovalDto approvalDto) {
        FlowRecord flowRecord = flowRecordService.selectFlowRecordById(approvalDto.getFlowRecordId());
        Long resultRecordId = approvalDto.getResultRecordId();

        if(flowRecord != null ){
            resultRecordId  = flowRecord.getRecordId();
        }
        List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByRecordId(resultRecordId);
        List<Long> flowRecordIds =new ArrayList<>();
        boolean flag = false ;
        for(FlowRecord f: flowRecords){
            flowRecordIds.add(f.getId());
            //如果录入己经走了，则重置数据后，结果录入还是默认己走
            if (new Integer(2).equals(f.getFlowProcess()) && (f.getStatus() == 1  || f.getStatus() == 4 )) {
                flag = true;
            }
        }
        flowRecordService.deleteFlowRecordByRecordId(resultRecordId);
        initFlowRecord(resultRecordId);
        List<FlowRecord> newflowRecords = flowRecordService.selectFlowRecordByRecordId(resultRecordId);
        for(int i = 0 ;i < newflowRecords.size() ; i ++){
            flowRecordService.updateFlowRecordIdById(newflowRecords.get(i).getId(),flowRecordIds.get(i));
            if(flag ){  //如果录入己经走了，设置新的数据，结果录入己走
                FlowRecord newFlowRecord = newflowRecords.get(i) ;
                if (new Integer(2).equals(newFlowRecord.getFlowProcess()) ) {
                    newFlowRecord.setStatus(4);
                    flowRecordService.updateFlowRecordById(newFlowRecord);
                }
            }
        }

        //更新flowProcess为0
        ResultRecord resultRecord = resultRecordService.selectResultRecordById(resultRecordId);
        resultRecord.setFlowProcess(0);
        resultRecordService.updateResultRecordById(resultRecord);


        resultRecordService.resetData(resultRecordId,approvalDto.getClearFlag());
        return R.ok();
    }

    private R skip(ApprovalDto approvalDto) {
        FlowRecord flowRecord = flowRecordService.selectFlowRecordById(approvalDto.getFlowRecordId());
        if (flowRecord.getStatus().equals(FlowRecordStatusEnums.FINISHED_STATUS.getStatus())
                || flowRecord.getStatus().equals(FlowRecordStatusEnums.OTHER_APPROVAL.getStatus())) {
            return R.ok("流程己经走了，无法跳过 ");
        }

        if (flowRecord.getStatus().equals(FlowRecordStatusEnums.UN_TO_STATUS.getStatus())) {      // 如果当前没有审批
            flowRecord.setStatus(FlowRecordStatusEnums.SKIP_STATUS.getStatus());
            flowRecordService.updateFlowRecordById(flowRecord);
        } else if (flowRecord.getStatus().equals(FlowRecordStatusEnums.CURRENT_FLOW_STATUS.getStatus())) { //如果当前正在审批中
            approvalDto.setLoginUserId(flowRecord.getApprovalStaffId());
            newSubmit(approvalDto, FlowRecordStatusEnums.SKIP_STATUS.getStatus());
        }
        flowChangeService.saveChange(approvalDto, flowRecord, 0);
        dingtalkBusiness.sendWorkMSGWithAsyn(flowRecord.getRecordId(), flowRecord.getId(), WorkMsgTypeEnum.SKIP.getType());
        return R.ok("恭喜您，跳过成功。");
    }

    private R transfer(ApprovalDto approvalDto) {
        FlowRecord flowRecord = flowRecordService.selectFlowRecordById(approvalDto.getFlowRecordId());
        flowChangeService.saveChange(approvalDto, flowRecord, 1);
        StaffEntity staffEntity = staffService.selectStaffById(approvalDto.getTransferStaffId());
        flowRecord.setApprovalStaffId(staffEntity.getId());
        flowRecord.setApprovalStaffName(staffEntity.getName());
        flowRecordService.updateFlowRecordById(flowRecord);
        dingtalkBusiness.sendWorkMSGWithAsyn(flowRecord.getRecordId(), flowRecord.getId(), WorkMsgTypeEnum.TRANSFER.getType());
        return R.ok("转交成功");
    }


    private R reSubmit(ApprovalDto approvalDto) {
        List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByRecordIdStatus(approvalDto.getResultRecordId(), 1);
        if (flowRecords != null && flowRecords.size() > 0) {
            return R.error("领导己经审批，不能撤回");
        }
        return newReject(approvalDto);
    }

    public Long comment(ApprovalDto approvalDto, FlowChart flowChart) {
        StaffEntity staffEntity = staffService.selectStaffById(approvalDto.getLoginUserId());
        if (staffEntity != null) {
            ResultComment resultComment = new ResultComment();
            resultComment.setComment(approvalDto.getComment());
            resultComment.setStaffName(staffEntity.getName());
            resultComment.setStaffId(staffEntity.getId());
            resultComment.setRecordId(approvalDto.getResultRecordId());
            resultComment.setOptDesc(approvalDto.getMenuName() + flowChart.getName());
            resultCommentService.insertResultComment(resultComment);
            return resultComment.getId();
        }
        return 0l;
    }

    private R newSubmit(ApprovalDto approvalDto, Integer finishedStatus) {
        ResultRecord resultRecord = resultRecordMapper.selectResultRecordById(approvalDto.getResultRecordId());
        if (approvalDto.getLoginUserId() == null) {
            approvalDto.setLoginUserId(resultRecord.getCurrentApprovalStaffId());
        }
        List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByRecordIdStatus(approvalDto.getResultRecordId(), 2);
        if (CollectionUtils.isEmpty(flowRecords)) {
            log.info("流程己经结束");
            return R.ok("流程己经结束");
        }
        if (finishedStatus == null) {
            finishedStatus = FlowRecordStatusEnums.FINISHED_STATUS.getStatus();
        }
        FlowRecord preFlowRecord = flowRecords.get(0);
        int stepType = preFlowRecord.getType();
        if (flowRecords.size() > 1) {
            if (stepType == 0 || stepType == 1) {           //表示只要一个人通过就可以了
                for (FlowRecord flowRecord : flowRecords) {
                    if (flowRecord.getApprovalStaffId().equals(approvalDto.getLoginUserId())) {
                        flowRecord.setStatus(finishedStatus);//当前审批己经完成
                    } else {
                        flowRecord.setStatus(FlowRecordStatusEnums.OTHER_APPROVAL.getStatus()); //其他审批
                    }
                    flowRecordService.updateFlowRecordById(flowRecord);
                }
            } else {
                boolean flag = false;
                FlowRecord currentFlowRecord = null;
                for (FlowRecord flowRecord : flowRecords) {
                    if (!flowRecord.getApprovalStaffId().equals(approvalDto.getLoginUserId())
                            && flowRecord.getStatus().equals(FlowRecordStatusEnums.CURRENT_FLOW_STATUS.getStatus())) {
                        flag = true;
                    } else {
                        currentFlowRecord = flowRecord;//当前流程 id
                    }
                }
                currentFlowRecord.setStatus(finishedStatus);//当前审批己经完成
                flowRecordService.updateFlowRecordById(currentFlowRecord);
                if (flag) {                         //流程未向下走
                    return R.ok("恭喜您，审批成功");
                }
            }
        } else {
            preFlowRecord.setStatus(finishedStatus);//流程己走
            flowRecordService.updateFlowRecordById(preFlowRecord);
        }
        // 找到当前下一个节点为0的 flowIndex
        FlowRecord nextFlowRecord = flowRecordService.selectFlowRecordByRecordIdMinIdStatus(approvalDto.getResultRecordId(), preFlowRecord.getId(), 0);
        if (nextFlowRecord == null) {
            dingtalkBusiness.sendWorkMSGWithAsyn(resultRecord.getId(), WorkMsgTypeEnum.PROCESS.getType()); //流程己经结束调用
            log.info("流程己经结束2");
            return R.ok("流程己经结束");
        }
        List<FlowRecord> nextFlowRecords = flowRecordService.selectFlowRecordByRecordIdStatusFlowIndex(approvalDto.getResultRecordId(), 0, nextFlowRecord.getFlowIndex());
        if (CollectionUtils.isEmpty(nextFlowRecords)) {
            dingtalkBusiness.sendWorkMSGWithAsyn(resultRecord.getId(), WorkMsgTypeEnum.PROCESS.getType());//流程己经结束调用
            log.info("流程己经结束3");
            return R.ok("流程己经结束");
        }
        FlowRecord currentFlowRecord = nextFlowRecords.get(0);
        for (FlowRecord flowRecord : nextFlowRecords) {
            flowRecord.setStatus(FlowRecordStatusEnums.CURRENT_FLOW_STATUS.getStatus());
            flowRecordService.updateFlowRecordById(flowRecord);
        }
        resultRecord.setFlowProcess(currentFlowRecord.getFlowProcess());
        log.info("resultRecordId = " + resultRecord.getId() + ",currentFlowRecordId" + currentFlowRecord.getId() + " , 当前 flowProcess :  " + resultRecord.getFlowProcess());
        resultRecord.setFlowStaffIdRole(nextFlowRecords.size() == 1 ? currentFlowRecord.getFlowStaffIdRole() : null);
        resultRecord.setCurrentApprovalStaffId(nextFlowRecords.size() == 1 ? currentFlowRecord.getApprovalStaffId() : null);
        resultRecord.setCurrentApprovalStaffName(nextFlowRecords.size() == 1 ? currentFlowRecord.getApprovalStaffName() : null);
        resultRecordService.updateCoverResultRecordById(resultRecord);
        dingtalkBusiness.sendWorkMSGWithAsyn(resultRecord.getId(), WorkMsgTypeEnum.PROCESS.getType());
        return R.ok();
    }

    private R newReject(ApprovalDto approvalDto) {
        List<FlowRecord> currentflowRecords = flowRecordService.selectFlowRecordByRecordIdStatus(approvalDto.getResultRecordId(), FlowRecordStatusEnums.CURRENT_FLOW_STATUS.getStatus());
        if (currentflowRecords != null && currentflowRecords.size() > 0) {
            FlowRecord currentFlowRecord = currentflowRecords.get(0);
            // 更新当前数据
            // 获取当前审批结点组
            List<FlowRecord> currentFlowRecords = flowRecordService.selectFlowRecordByRecordIdFlowIndex(approvalDto.getResultRecordId(), currentFlowRecord.getFlowIndex());
            for (FlowRecord flowRecord : currentFlowRecords) {
                flowRecord.setStatus(FlowRecordStatusEnums.UN_TO_STATUS.getStatus());
                flowRecordService.updateFlowRecordById(flowRecord);
            }
            // 恢复之前数据
            // 获取之前审批过的结点
            FlowRecord preFlowRecord = flowRecordService.selectPreFlowRecordByRecordIdMaxIdStatus(approvalDto.getResultRecordId(),
                    currentFlowRecord.getId(), FlowRecordStatusEnums.FINISHED_STATUS.getStatus());
            if (preFlowRecord != null) {
                // 获取之前审批结点组
                List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByRecordIdFlowIndex(approvalDto.getResultRecordId(), preFlowRecord.getFlowIndex());
                for (FlowRecord flowRecord : flowRecords) {
                    flowRecord.setStatus(FlowRecordStatusEnums.CURRENT_FLOW_STATUS.getStatus());
                    flowRecordService.updateFlowRecordById(flowRecord);
                }
                FlowRecord lastFlowRecord = flowRecords.get(0);
                ResultRecord resultRecord = resultRecordMapper.selectResultRecordById(approvalDto.getResultRecordId());
                resultRecord.setCurrentApprovalStaffId(flowRecords.size() == 1 ? lastFlowRecord.getApprovalStaffId() : null);
                resultRecord.setCurrentApprovalStaffName(flowRecords.size() == 1 ? lastFlowRecord.getApprovalStaffName() : null);
                resultRecord.setFlowStaffIdRole(flowRecords.size() == 1 ? lastFlowRecord.getFlowStaffIdRole() : null);

                FlowChart flowChart = flowService.selectFlowChartByChartId(lastFlowRecord.getFlowId());
                resultRecord.setFlowProcess(flowChart.getFlowProcess());
                resultRecordService.updateCoverResultRecordById(resultRecord);
                dingtalkBusiness.sendWorkMSGWithAsyn(resultRecord.getId(), WorkMsgTypeEnum.REJECT.getType());
            }
        }
        return R.ok();
    }


    private R urge(ApprovalDto approvalDto) {
        ResultRecord resultRecord = resultRecordMapper.selectResultRecordById(approvalDto.getResultRecordId());
        if (!resultRecord.getCurrentApprovalStaffId().equals(approvalDto.getLoginUserId())) {
            log.info("催办" + resultRecord.getCurrentApprovalStaffId());
            dingtalkBusiness.urging(resultRecord.getId());
        }
        return R.ok();
    }

    private R explain(ApprovalDto approvalDto) {

        return R.ok();
    }

    @Override
    public R newResultRecordList(RecordDetailDto recordDetailDto) {
        List<FlowRecord> flowRecords = flowRecordService.selectFlowRecordByResultRecordId(recordDetailDto.getResultRecordId());
        List<FlowRecordResp> flowRecordList = new ArrayList<>();
        int flowIndex = -1;
        Long flowRecordId = 0l;
        ResultRecord resultRecord = resultRecordService.selectResultRecordById(recordDetailDto.getResultRecordId());
        for (FlowRecord flowRecord : flowRecords) {
            if (flowRecord.getFlowIndex().equals(flowIndex)) { //表示有重复数据
                FlowRecordResp lastResp = flowRecordList.get(flowRecordList.size() - 1);
                List<FlowRecord> mulFlowRecord = flowRecordService.selectFlowRecordByRecordIdFlowIndex(recordDetailDto.getResultRecordId(), flowIndex);
                FlowRecord fisrt = mulFlowRecord.get(0);
                int stepIndex = fisrt.getType();
                boolean flag0 = false;
                boolean flag1 = false;
                boolean flag2 = false;
                boolean flag4 = false;
                List<FlowDetailResp> flowDetailRespList = lastResp.getFlowDetailRespList();
                mySetFlowDetailRespList(flowDetailRespList, flowRecord, recordDetailDto.getLoginUserId(), resultRecord.getStaffId());
                for (FlowRecord mul : mulFlowRecord) {
                    if (mul.getStatus().equals(FlowRecordStatusEnums.UN_TO_STATUS.getStatus())) {
                        flag0 = true;
                    } else if (mul.getStatus().equals(FlowRecordStatusEnums.FINISHED_STATUS.getStatus())) {
                        flag1 = true;
                    } else if (mul.getStatus().equals(FlowRecordStatusEnums.CURRENT_FLOW_STATUS.getStatus())) {
                        flag2 = true;
                    } else if (mul.getStatus().equals(FlowRecordStatusEnums.SKIP_STATUS.getStatus())) {
                        flag4 = true;
                    }
                    if (mul.getApprovalStaffId().equals(recordDetailDto.getLoginUserId())) {
                        lastResp.setStaffName(mul.getApprovalStaffName());
                    }
                }
                if (stepIndex == 0 || stepIndex == 1) { // 依次
                    if (flag0) {
                        lastResp.setStatus(0);
                    } else if (flag1) {
                        lastResp.setStatus(1);
                    } else if (flag2) {
                        lastResp.setStatus(1);
                    } else if (flag4) {
                        lastResp.setStatus(4);
                    }
                } else {            //所有
                    if (flag0) {      //只要有 0 表示当前节点所有的为0
                        lastResp.setStatus(0);
                    } else if (flag2) {   // 只要有 2 表示所有的结点停留在当前
                        lastResp.setStatus(1);
                    } else if (flag1) {
                        lastResp.setStatus(1);  // 当前步骤中只存在1和4 ，那么当前结点肯定通过了
                    } else if (flag4) {
                        lastResp.setStatus(4);  // 当前步骤中所有的结点都跳过了
                    }
                }
                continue;
            }
            FlowRecordResp resp = new FlowRecordResp();
            resp.setFlowName(flowRecord.getFlowName());
            resp.setRealStatus(flowRecord.getStatus());
            resp.setStaffName(flowRecord.getApprovalStaffName());
            resp.setStatus(flowRecord.getStatus() == 2 ? 1 : flowRecord.getStatus());

            List<FlowDetailResp> flowDetailRespList = new ArrayList<>();
            mySetFlowDetailRespList(flowDetailRespList, flowRecord, recordDetailDto.getLoginUserId(), resultRecord.getStaffId());
            resp.setFlowDetailRespList(flowDetailRespList);
            flowRecordList.add(resp);
            flowIndex = flowRecord.getFlowIndex();
        }

        boolean flag = true;
        for (FlowRecord flowRecord : flowRecords) {
            if (flowRecord.getStatus() == 2) {
                flag = false;
                break;
            }
        }

        FlowRecordResp end = new FlowRecordResp();
        end.setFlowName("结束");
        end.setStatus(flag ? 1 : 0);
        flowRecordList.add(end);
        List<ResultComment> resultCommentList = resultCommentService.selectByRecordId(recordDetailDto.getResultRecordId());
        for (ResultComment resultComment : resultCommentList) {
            StaffEntity staffEntity = staffService.selectStaffById(resultComment.getStaffId());
            resultComment.setAvatar(staffEntity.getAvatar());
        }
        Map<String, Integer> auth = new HashMap<>();
        auth.put("showResult", 1);
        auth.put("showScore", 1);
        List<FlowRecord> currentResultRecords = flowRecordService.selectFlowRecordByRecordIdStatus(recordDetailDto.getResultRecordId(), 2);
        log.info("当前用户登陆用户 id :" + recordDetailDto.getLoginUserId());
        if (currentResultRecords != null && currentResultRecords.size() > 0) {
            FlowRecord currentFlowRecord = currentResultRecords.get(0);
            int flowProcess = currentFlowRecord.getFlowProcess();
            if (flowProcess <= 3) {
                auth.put("showResult", 0);
            }
            if (flowProcess <= 4) {
                auth.put("showScore", 0);
            }
            FlowRecord currentResultRecord = null;
            for (FlowRecord flowRecord : currentResultRecords) {
                if (flowRecord.getApprovalStaffId().equals(recordDetailDto.getLoginUserId())) {
                    currentResultRecord = flowRecord;
                    log.info("当前审批用户 id id :" + currentResultRecord.getApprovalStaffId());
                    break;
                }
            }
            if (currentResultRecord != null) {
                if (StringUtil.isNotBlank(currentResultRecord.getFlowStaffIdRole())) {
                    auth = getAuth(currentResultRecord.getFlowStaffIdRole());
                    flowRecordId = currentResultRecord.getId();
                }
            }
        }
        //如果是绩效管理员有一键催办功能
        StaffRole staffRole = staffRoleService.selectStaffRolesByStaffIdDepartmentLevelList(recordDetailDto.getLoginUserId(),
                Arrays.asList(new String[]{RoleEnums.CHILD_PM.getName(), RoleEnums.MASTER_PM.getName()}));
        if (staffRole != null) {
            auth.put("toFast", 1);
            auth.put("toReset", 1);
        }
        auth.put("tiaozhuang", 0);
        Map<String, Object> map = new HashMap<>();
        map.put("flowRecordList", flowRecordList);
        map.put("resultCommentList", resultCommentList);
        map.put("auth", auth);
        map.put("flowRecordId", flowRecordId);
        return R.ok().put("data", map);
    }

    public Map<String, Integer> getAuth(String flowStaffIdRole) {
        Map<String, Integer> auth = Maps.newHashMap();
        Map<String, Object> map = JSONObject.parseObject(flowStaffIdRole, Map.class);
        List<Long> roleIds = null;
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (entry.getValue() != null) {
                roleIds = JSON.parseArray(entry.getValue().toString(), Long.class);
            }
        }
        if (roleIds != null && roleIds.size() > 0) {
            auth = recordAuthService.selectAuthByRoleIds(roleIds);
        }
        return auth;
    }

    public void mySetFlowDetailRespList(List<FlowDetailResp> flowDetailRespList, FlowRecord flowRecord, Long loginUserId, Long recordStaffId) {
        FlowDetailResp flowDetailResp = new FlowDetailResp();
        flowDetailResp.setCurrentStaffId(flowRecord.getApprovalStaffId());
        flowDetailResp.setStaffName(flowRecord.getApprovalStaffName());
        flowDetailResp.setFlowRecordId(flowRecord.getId());
        int status = flowRecord.getStatus();
        if (flowRecord.getStatus() == 3) {
            status = 0;
        }
        if (flowRecord.getStatus() == 2) {
            status = 0;
        }
        flowDetailResp.setStatus(status);
        StaffEntity staffEntity = staffService.selectStaffById(flowRecord.getApprovalStaffId());
        DepartmentsStaffRelateEntity departmentsStaffRelateEntity = departmentsStaffRelateService.selectLastDepartmentByStaffId(flowRecord.getApprovalStaffId());
        flowDetailResp.setAvatar(staffEntity.getAvatar());
        DepartmentsEntity departmentsEntity = departmentsDao.selectByDepartmentId(departmentsStaffRelateEntity.getDepartmentId());
        flowDetailResp.setDepartName(departmentsEntity.getDepartmentName());
        if (new Integer(0).equals(flowRecord.getStatus()) || new Integer(2).equals(flowRecord.getStatus())) {
            int position = getRole(loginUserId, departmentsStaffRelateEntity);
            /**
             1：绩效管理员的权限只在里面
             2：流程节点的授权只展示在外面（里面不展示）
             3：既是绩效管理员和审批节点人员，里面展示，外面根据节点授权情况来确定是否展示
             */
            if (position == 1) {     //如果是绩效管理员
                initTiaoZhuangZhuangJiao(flowDetailResp, 1, 1);
                if (flowRecord.getFlowProcess() == 0) {//目标制定有转交，但是没有跳过
                    initTiaoZhuangZhuangJiao(flowDetailResp, 0, 1);
                }
            }
        }//如果流程节点己经走了，直接返回不可跳转，不可转交
        flowDetailRespList.add(flowDetailResp);
    }


    public int getRole(Long loginUserId, DepartmentsStaffRelateEntity departmentsStaffRelateEntity) {
        int position = 0;
        StaffRole staffRole = staffRoleService.selectStaffRolesByStaffIdDepartmentLevelList(loginUserId,
                Arrays.asList(new String[]{RoleEnums.CHILD_PM.getName(), RoleEnums.MASTER_PM.getName()}));
        if (staffRole != null) {
            boolean flag = false;
            if (staffRole.getDepartmentId() == 0) {
                flag = true;
            } else {
                Map<String, String> map = departmentsService.selectUserAllDepartmentIds(departmentsStaffRelateEntity.getDepartmentId());
                List<StaffRoleDepartment> staffRoleDepartments = staffRoleDepartmentService.selectStaffRoleDepartmentByStaffRoleId(staffRole.getId());
                for (StaffRoleDepartment staffRoleDepartment : staffRoleDepartments) {
                    String departmentName = map.get(staffRoleDepartment.getDepartmentId());
                    if (StringUtil.isNotBlank(departmentName)) {
                        flag = true;
                        break;
                    }
                }
            }
            if (flag) {
                log.info("当前 loginUserId : " + loginUserId + "，是管理员");
                position = 1;//表示当前是绩效管理员
            }
        }
        return position;
    }

    public void initTiaoZhuangZhuangJiao(FlowDetailResp flowDetailResp, int tiaoZhuang, int transfer) {
        flowDetailResp.setTiaozhuang(tiaoZhuang);
        flowDetailResp.setTransfer(transfer);
    }

    public StaffEntity getDepartmentStaff(Long staffId, int level) {
        DepartManagers departManagers = staffService.findLeader(staffId, level);
        List<StaffEntity> staffEntities = departManagers.getManagers();
        if (CollectionUtils.isNotEmpty(staffEntities)) {
            return staffEntities.get(0);
        }
        return new StaffEntity();

    }

    public Flow getFlow(List<Flow> flows, Long flowId) {
        for (Flow flow : flows) {
            if (flow.getId().equals(flowId)) {
                return flow;
            }
        }
        return new Flow();
    }

    @Override
    public ResultRecord selectLastResultRecordByUserId(Long userId) {
        return resultRecordMapper.selectLastResultRecordByUserId(userId);
    }

    @Override
    public ResultRecord selectResultRecordByStaffIdAndStartId(Long userId, Long startId) {
        return resultRecordMapper.selectResultRecordByStaffIdAndStartId(userId, startId);
    }

    @Override
    public List<ResultRecord> selectResultRecordsByStartId(Long startId) {
        return resultRecordMapper.selectResultRecordsByStartId(startId);
    }

    @Override
    public List<Long> selectResultRecordIdsByStartId(Long startId) {
        return resultRecordMapper.selectIdsByStartId(startId);
    }

    @Override
    public R getResetData(RecordDetailDto recordDetailDto) {
        List<FlowRecord> flowRecordRunning = flowRecordService.selectFlowRecordByRecordIdStatus(recordDetailDto.getResultRecordId(),2);
        List<FlowRecord> flowRecords = new ArrayList<>();
        if(CollectionUtils.isEmpty(flowRecordRunning) ){
            flowRecords = flowRecordService.selectFlowRecordByResultRecordId(recordDetailDto.getResultRecordId());
        }else{
            flowRecords = flowRecordService.selectFlowRecordByRecordIdLeFlowIndex(recordDetailDto.getResultRecordId(),flowRecordRunning.get(0).getFlowIndex() -1 );
        }
        int flowIndex = 0;
        List<ResetDataResp> resetDataResps = new ArrayList<>();
        for (FlowRecord flowRecord : flowRecords) {
            if(new Integer(2).equals(flowRecord.getFlowProcess())){ //过虑掉flowProcess
                continue;
            }
            if (flowRecord.getFlowIndex().equals(flowIndex - 1)) { //表示有重复数据
                ResetDataResp resetDataResp = resetDataResps.get(flowIndex - 1);
                resetDataResp.getStaffNames().add(flowRecord.getApprovalStaffName());
                continue;
            }
            ResetDataResp resetDataResp = new ResetDataResp();
            resetDataResp.setFlowName(flowRecord.getFlowName());
            resetDataResp.setId(flowRecord.getId());
            List<String> staffNames = new ArrayList<>();
            staffNames.add(flowRecord.getApprovalStaffName());
            resetDataResp.setStaffNames(staffNames);
            resetDataResps.add(resetDataResp);
            flowIndex ++ ;
        }
        return R.ok().put("data",resetDataResps);
    }

    //删除指标信息
    /**
     * clearFlag == 0 全清 1 部分清包括评分标志 2只清楚评分标志
     *
     * */
    @Override
    public R resetData(Long recordId, int clearFlag) {
        List<ResultDetail> resultDetails = resultDetailService.selectByRecordId(recordId);

        log.info("需要删除指标个数{}", resultDetails.size());
        if(resultDetails.size() > 0){
            if(clearFlag == 0){
                log.info("全部清空，删除所有指标即可");
                resultDetailService.deleteResultDetailByRecordId(recordId);
                for(ResultDetail detail : resultDetails){
                    resultScoreService.deleteResultScoreByDetailId(detail.getId());
                }
                return R.ok();
            }
            //删除指标以外的所有数据，评分、评分说明、结果

            for(ResultDetail detail : resultDetails){
                if(clearFlag == 1){
                    detail.setCheckResult(null);
                    detail.setAcquireScore(null);
                    detail.setSuperScore(null);
                    resultScoreService.deleteResultScoreByDetailId(detail.getId());
                }else{
                    resultScoreService.setNoEditScoreByDetailId(detail.getId());
                }

            }
            resultDetailService.updateBatchById(resultDetails);

            return R.ok();
        }
        return R.error("无数据删除");

    }


    @Override
    public List<Long> selectStaffIdsByFlowProcess(List<Integer> flowProcess) {
        return resultRecordMapper.selectStaffIdsByFlowProcess(flowProcess);
    }
}
