using AutoMapper;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using Performance.Services.ExtractExcelService;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Performance.Services
{
    public partial class SecondAllotService : IAutoInjection
    {
        private readonly IMapper _mapper;
        private readonly ILogger logger;
        private readonly IServiceScopeFactory _serviceScopeFactory;
        private readonly DapperService _service;
        private readonly Application application;
        private readonly PerforAgsecondallotRepository agsecondallotRepository;
        private readonly PerforAgtempRepository agtempRepository;
        private readonly PerforAgtempitemRepository agtempitemRepository;
        private readonly PerforAgusetempRepository agusetempRepository;
        private readonly PerforAgworkloadRepository agworkloadRepository;
        private readonly PerforAgworkloadtypeRepository agworkloadtypeRepository;
        private readonly PerforAgbodysourceRepository agbodysourceRepository;
        private readonly PerforAgheadsourceRepository agheadsourceRepository;
        private readonly PerforAgworktypesourceRepository agworktypesourceRepository;
        private readonly PerforAgworkloadsourceRepository agworkloadsourceRepository;
        private readonly PerforPerallotRepository perallotRepository;
        private readonly PerforUserRepository userRepository;
        private readonly PerforHospitalRepository hospitalRepository;
        private readonly PerforUserhospitalRepository userhospitalRepository;
        private readonly PerforRoleRepository roleRepository;
        private readonly PerforUserroleRepository userroleRepository;
        private readonly PerforImemployeeclinicRepository imemployeeclinicRepository;
        private readonly PerforPeremployeeRepository peremployeeRepository;
        private readonly PerforResaccountRepository resaccountRepository;
        private readonly PerforRescomputeRepository rescomputeRepository;
        private readonly PerforResspecialunitRepository resspecialunitRepository;
        private readonly PerforPerapramountRepository perapramountRepository;

        private readonly PerforAgfixatitemRepository agfixatitemRepository;
        private readonly PerforAgothersourceRepository agothersourceRepository;
        //private readonly PerforAgcomputeRepository agcomputeRepository;
        private readonly PerforCofagainRepository cofagainRepository;

        private readonly ComputeService computeService;
        private readonly IWebHostEnvironment _evn;
        private readonly PersonService personService;
        private readonly List<ag_tempitem> tempitems = new List<ag_tempitem>();

        public SecondAllotService(
            IMapper mapper,
            ILogger<SecondAllotService> logger,
            IOptions<Application> application,
            IServiceScopeFactory serviceScopeFactory,
            DapperService service,
            PerforAgsecondallotRepository agsecondallotRepository,
            PerforAgtempRepository agtempRepository,
            PerforAgtempitemRepository agtempitemRepository,
            PerforAgusetempRepository agusetempRepository,
            PerforAgworkloadRepository agworkloadRepository,
            PerforAgworkloadtypeRepository agworkloadtypeRepository,
            PerforAgbodysourceRepository agbodysourceRepository,
            PerforAgheadsourceRepository agheadsourceRepository,
            PerforAgworktypesourceRepository agworktypesourceRepository,
            PerforAgworkloadsourceRepository agworkloadsourceRepository,
            PerforPerallotRepository perallotRepository,
            PerforUserRepository userRepository,
            PerforHospitalRepository hospitalRepository,
            PerforUserhospitalRepository userhospitalRepository,
            PerforRoleRepository roleRepository,
            PerforUserroleRepository userroleRepository,
            PerforImemployeeclinicRepository imemployeeclinicRepository,
            PerforPeremployeeRepository peremployeeRepository,
            PerforResaccountRepository resaccountRepository,
            PerforRescomputeRepository rescomputeRepository,
            PerforResspecialunitRepository resspecialunitRepository,
            PerforPerapramountRepository perapramountRepository,
            PerforAgfixatitemRepository agfixatitemRepository,
            PerforAgothersourceRepository agothersourceRepository,
            //PerforAgcomputeRepository agcomputeRepository,
            PerforCofagainRepository cofagainRepository,
            PersonService personService,
            ComputeService computeService,
            IWebHostEnvironment evn
            )
        {
            _mapper = mapper;
            this.logger = logger;
            _serviceScopeFactory = serviceScopeFactory;
            _service = service;
            this.application = application.Value;
            this.agsecondallotRepository = agsecondallotRepository;
            this.agtempRepository = agtempRepository;
            this.agtempitemRepository = agtempitemRepository;
            this.agusetempRepository = agusetempRepository;
            this.agworkloadRepository = agworkloadRepository;
            this.agworkloadtypeRepository = agworkloadtypeRepository;
            this.agbodysourceRepository = agbodysourceRepository;
            this.agheadsourceRepository = agheadsourceRepository;
            this.agworktypesourceRepository = agworktypesourceRepository;
            this.agworkloadsourceRepository = agworkloadsourceRepository;
            this.perallotRepository = perallotRepository;
            this.userRepository = userRepository;
            this.hospitalRepository = hospitalRepository;
            this.userhospitalRepository = userhospitalRepository;
            this.roleRepository = roleRepository;
            this.userroleRepository = userroleRepository;
            this.imemployeeclinicRepository = imemployeeclinicRepository;
            this.peremployeeRepository = peremployeeRepository;
            this.resaccountRepository = resaccountRepository;
            this.rescomputeRepository = rescomputeRepository;
            this.resspecialunitRepository = resspecialunitRepository;
            this.perapramountRepository = perapramountRepository;
            this.agfixatitemRepository = agfixatitemRepository;
            this.agothersourceRepository = agothersourceRepository;
            //this.agcomputeRepository = agcomputeRepository;
            this.cofagainRepository = cofagainRepository;
            this.computeService = computeService;
            _evn = evn;
            this.personService = personService;
        }

        #region 二次绩效列表与数据保存
        //public List<ag_secondallot> GetSeconds(int userId)
        //{
        //    var userInfo = userRepository.GetUser(userId);
        //    if (userInfo?.User == null) throw new NotImplementedException("当前用户不存在");

        //    if (userInfo?.URole == null) throw new NotImplementedException("当前用户暂未分配角色");

        //    if (userInfo?.Hospitals == null) throw new NotImplementedException("当前用户暂未分配医院");

        //    // 查询当前角色下科室的绩效
        //    UnitTypeUtil.Maps.TryGetValue(userInfo?.URole.Type ?? 0, out string[] unitType);

        //    var secondList = agsecondallotRepository.Get(userInfo.HospitalIds.ToArray(), unitType, userInfo.User.Department);

        //}


        /// <summary>
        /// 获取二次绩效列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<SecondListResponse> GetSecondList(int userId)
        {
            var userInfo = userRepository.GetUser(userId);
            if (userInfo?.User == null) throw new NotImplementedException("当前用户不存在");

            if (userInfo?.URole == null) throw new NotImplementedException("当前用户暂未分配角色");

            if (userInfo?.Hospitals == null) throw new NotImplementedException("当前用户暂未分配医院");

            var status = new List<int> { (int)AllotStates.绩效下发, (int)AllotStates.归档, (int)AllotStates.绩效结果解析成功 };
            var allotList = perallotRepository.GetEntities(t => userInfo.HospitalIds.Contains(t.HospitalId) && status.Contains(t.States));
            if (allotList == null || allotList.Count == 0) return new List<SecondListResponse>();

            var allotListId = allotList.Select(t => t.ID).ToList();

            // 查询当前角色下科室的绩效
            UnitTypeUtil.Maps.TryGetValue(userInfo?.URole.Type ?? 0, out string[] unitType);
            var secondList = agsecondallotRepository.GetEntities(t => allotListId.Contains(t.AllotId.Value) && unitType.Contains(t.UnitType) && t.Department == userInfo.User.Department);

            // 查询过往科室的绩效 
            var histroys = agsecondallotRepository.GetEntities(t => allotListId.Contains(t.AllotId.Value) && unitType.Contains(t.NewUnitType) && t.NewAccountingUnit == userInfo.User.Department);
            if (histroys != null && histroys.Any())
            {
                var sids = secondList.Select(w => w.Id).ToArray();
                secondList.AddRange(histroys.Where(w => !sids.Contains(w.Id)));
            }

            foreach (var item in allotList)
            {
                if (!secondList.Any(w => w.AllotId == item.ID && w.Year == item.Year && w.Month == item.Month))
                {
                    secondList.Add(new ag_secondallot
                    {
                        AllotId = item.ID,
                        UseTempId = null,
                        Year = item.Year,
                        Month = item.Month,
                        UnitType = unitType.FirstOrDefault(),
                        Department = userInfo.User.Department,
                        RealGiveFee = 0,
                        PreRealGiveFee = 0,
                        Status = 0,
                    });
                }
            }

            var list = _mapper.Map<List<SecondListResponse>>(secondList);
            // 二次分配只支持单医院
            var hospital = userInfo.Hospitals.First();
            list?.ForEach(t =>
            {
                var allot = allotList.FirstOrDefault(a => a.ID == t.AllotId);
                if (allot != null)
                {
                    t.IsArchive = allot.States == 8 ? 1 : 0;
                    t.States = allot.States;
                    t.ShowFormula = allot.ShowFormula;
                    t.Name = allot.Name;
                }
                t.IsShowManageButton = hospital?.IsShowManageButton ?? (int)States.Disabled;
            });

            if (secondList != null && secondList.Any())
            {
                // 暂时在加载列表时补充信息
                var worktypes = agworkloadtypeRepository.GetEntities(t => t.HospitalId == hospital.ID && t.Department == secondList.First().Department && t.UnitType == secondList.First().UnitType);
                if (worktypes != null && worktypes.Any())
                {
                    worktypes.ForEach(t => AddWorkTypeDefaultValues(t));
                }

                // 补充默认工作量项
                CheckDefaultWorkload(hospital.ID, secondList.First().Department, secondList.First().UnitType);
            }

            return list.OrderByDescending(w => w.Year).ThenByDescending(w => w.Month).ToList();
        }

        #region 二次绩效详情

        ///// <summary>
        ///// 二次绩效详情
        ///// </summary>
        ///// <returns></returns>
        //public SecondResponse GetSecondDetail(UseTempRequest request)
        //{
        //    var usetemp = perforAgusetempRepository.GetEntity(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
        //    if (usetemp == null)
        //        throw new PerformanceException("当前科室暂未配置绩效模板");

        //    var second = perforAgsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
        //    //获取固定模板列 + 工作量列
        //    var headItems = GetHeadItems(usetemp.UseTempId.Value, usetemp.HospitalId.Value, usetemp.Department, usetemp.UnitType);

        //    var result = new SecondResponse { HeadItems = headItems, BodyItems = new List<BodyItem>() };
        //    //获取已录入数据
        //    var fixatList = agfixatitemRepository.GetEntities(t => t.SecondId == request.SecondId && t.RowNumber.HasValue);
        //    if (request.IsArchive == 1 || new List<int> { 2, 3 }.Contains(second.Status ?? 1))     //归档  等待审核、审核通过
        //    {
        //        #region 已归档数据，根据数据获取 列
        //        if (fixatList == null || fixatList.Where(t => t.RowNumber != -1).Count() == 0)
        //            throw new PerformanceException("提交时未添加数据。");
        //        else
        //        {
        //            var existHead = fixatList.Select(t => new { FiledName = t.ItemName, Sort = t.Sort.Value, SourceType = t.SourceType.Value, Type = t.Type.Value, FactorValue = t.FactorValue.Value }).Distinct().ToList();
        //            headItems = existHead.Select(t => new HeadItem
        //            {
        //                FiledId = headItems.FirstOrDefault(h => h.FiledName == t.FiledName && h.Type == t.Type)?.FiledId ?? "无FiledId",
        //                FiledName = t.FiledName,
        //                Sort = headItems.FirstOrDefault(h => h.FiledName == t.FiledName && h.Type == t.Type)?.Sort ?? 0,
        //                SourceType = t.SourceType,
        //                Type = t.Type,
        //                FactorValue = headItems.FirstOrDefault(h => h.FiledName == t.FiledName && h.Type == t.Type)?.FactorValue ?? 0
        //            }).ToList();
        //            result.HeadItems = headItems;
        //        }
        //        #endregion
        //    }
        //    //未归档
        //    if (fixatList != null && fixatList.Where(t => t.RowNumber != -1).Count() > 0)
        //    {
        //        var rows = fixatList.Select(t => t.RowNumber.Value).Distinct();
        //        foreach (var row in rows)
        //        {
        //            var header = row == -1 ? headItems.Where(t => t.Type == 1).ToList() : headItems.Where(t => t.Type != 1).ToList();
        //            result.BodyItems.AddRange(GetBodyItems(header, 2, fixatitems: fixatList, row: row));
        //        }
        //    }
        //    else if (fixatList == null || (fixatList != null && fixatList.Where(t => t.RowNumber != -1).Count() == 0))
        //    {
        //        #region 补充历史绩效需要带出的数据
        //        var bringhead = headItems.Where(t => t.IsBring == 1).ToList();
        //        if (bringhead != null && bringhead.Count > 0)
        //        {
        //            var allotIds = perforPerallotRepository.GetEntities(t => t.HospitalId == request.HospitalId).Select(a => a.ID);
        //            var secondIdList = perforAgsecondallotRepository.GetEntities(t => allotIds.Contains(t.AllotId.Value)
        //            && t.Department == request.Department && t.UnitType == request.UnitType)
        //                .OrderBy(t => t.Year).ThenBy(t => t.Month).Select(t => t.Id).ToList();
        //            var index = secondIdList.IndexOf(request.SecondId);
        //            if (index != 0)
        //                fixatList = agfixatitemRepository.GetEntities(t => t.SecondId == secondIdList.ElementAt(index - 1) && t.RowNumber.HasValue);

        //            fixatList = fixatList?.Where(t => bringhead.Select(h => h.FiledName).Contains(t.ItemName)).ToList();
        //            if (fixatList != null && fixatList.Count > 0)
        //            {
        //                var rows = fixatList.Select(t => t.RowNumber.Value).Distinct();
        //                foreach (var row in rows)
        //                {
        //                    var header = row == -1 ? bringhead.Where(t => t.Type == 1).ToList() : bringhead.Where(t => t.Type != 1).ToList();
        //                    result.BodyItems.AddRange(GetBodyItems(header, 2, fixatitems: fixatList, row: row));
        //                }
        //            }
        //        }
        //        #endregion
        //    }
        //    if (fixatList == null || (fixatList != null && fixatList.Where(t => t.RowNumber == -1).Count() == 0))
        //    {
        //        var config = perforCofagainRepository.GetEntities(t => t.AllotID == second.AllotId && t.Department == request.Department) ?? new List<cof_again>();

        //        #region 补充顶部数据
        //        config.Add(new cof_again { TypeName = "绩效合计(考核后)", Value = second.RealGiveFee });
        //        result.BodyItems.AddRange(GetBodyItems(headItems.Where(t => t.Type == 1).ToList(), 1, configs: config));
        //        result.BodyItems.FirstOrDefault(t => t.FiledName == "发放月份").Value = $"{second.Year}年{second.Month}月";
        //        #endregion
        //    }
        //    return new SecondResponse
        //    {
        //        HeadItems = result.HeadItems.OrderBy(t => t.Type).ThenBy(t => t.Sort).ThenBy(t => t.FiledName).ToList(),
        //        BodyItems = result.BodyItems.OrderBy(t => t.RowNumber).ThenBy(t => t.Type).ThenBy(t => t.Sort).ToList(),
        //    };
        //}

        ///// <summary>
        ///// 二次绩效详情
        ///// </summary>
        ///// <returns></returns>
        //public List<ag_othersource> GetSecondDetail(int secondid)
        //{
        //    var others = perforAgothersourceRepository.GetEntities(t => t.SecondId == secondid);
        //    return others;
        //}

        #endregion 二次绩效详情

        /// <summary>
        /// 二次绩效分配录入人员自动补全信息
        /// </summary>
        /// <param name="request"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<BodyItem> AutoComplete(SecondEmpRequest request, int userId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
            if (second == null)
                throw new PerformanceException("当前科室二次分配绩效信息无效");

            var allot = perallotRepository.GetEntity(w => w.ID == second.AllotId);
            if (allot == null)
                throw new PerformanceException("当前绩效信息无效");

            var usetemp = agusetempRepository.GetEntity(
                t => t.HospitalId == allot.HospitalId && t.Department == second.Department && t.UnitType == second.UnitType);
            if (usetemp == null)
                throw new PerformanceException("当前科室暂未配置绩效模板");

            //获取固定模板列 + 工作量列
            var headItems = GetHeadItems(request.TempId, usetemp.HospitalId.Value, usetemp.Department, usetemp.UnitType);

            //var employees = personService.GetPerEmployee(second.AllotId.Value);
            var bodyItems = GetEmployees(second, userId, headItems, second.UnitType, request.EmployeeName, request.JobNumber);

            return bodyItems;
        }

        #region 二次绩效详情-使用中

        /// <summary>
        /// 二次绩效详情
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public SecondResponse GetSecondDetail(UseTempRequest request, int userId)
        {
            var usetemp = agusetempRepository.GetEntity(t => t.HospitalId == request.HospitalId
            && t.Department == request.Department && t.UnitType == request.UnitType);   //获取科室二次绩效费用分配使用的模板
            if (usetemp == null)
                throw new PerformanceException("当前科室暂未配置绩效模板");

            var temp = agtempRepository.GetEntity(t => t.Id == usetemp.UseTempId);
            if (temp == null || temp.IsEnable != 1)
                throw new PerformanceException("模板无效，请重新选择");

            var second = agsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
            //获取固定模板列 + 工作量列
            var headItems = GetHeadItems(request.TempId, usetemp.HospitalId.Value, usetemp.Department, usetemp.UnitType);

            var result = new SecondResponse();

            var fixatList = agfixatitemRepository.GetEntities(t => t.SecondId == request.SecondId && t.RowNumber.HasValue && !string.IsNullOrEmpty(t.ItemName));
            //归档 或 等待审核、审核通过时，headItems不会随选择模板改动，带出已填写数据中的headItems
            if (request.IsArchive == 1 || new List<int> { 2, 3 }.Contains(second.Status ?? 1))
            {
                if (fixatList == null || fixatList.Where(t => t.RowNumber != -1).Count() == 0)
                    throw new PerformanceException("提交时未添加数据。");

                result = SubmittedData(fixatList, headItems);
                // 补充 医院其他绩效
                SupplementOtherPerfor(result, second.AllotId ?? -99);
            }
            else
            {
                result = new SecondResponse { HeadItems = headItems };
                //判断是否有数据
                //有数据 带出历史数据
                if (fixatList != null && fixatList.Any())
                {
                    result.BodyItems = GetBodyItems(fixatList, headItems);
                    // 补充 医院其他绩效
                    SupplementOtherPerfor(result, second.AllotId ?? -99);
                    if (fixatList.Where(t => t.RowNumber != -1) == null || !fixatList.Where(t => t.RowNumber != -1).Any())
                    {
                        //更换模板时，会自动保存顶部数据
                        //var employees = personService.GetPersons(second.AllotId.Value, userId);
                        result.BodyItems.AddRange(GetEmployees(second, userId, headItems, second.UnitType));
                    }
                }
                else
                {
                    //无数据 根据IsBring带出历史二次绩效中需要带出的数据
                    //result.BodyItems = GetBringItems(request, headItems);
                    //var employees = personService.GetPersons(second.AllotId.Value, userId);
                    result.BodyItems = GetEmployees(second, userId, headItems, second.UnitType);

                    var bodys = _mapper.Map<List<BodyItem>>(headItems.Where(t => t.Type == 1));
                    if (bodys != null && bodys.Any())
                        bodys.ForEach(t => t.RowNumber = -1);
                    result.BodyItems.AddRange(bodys);
                }
            }

            //检验 二次绩效配置 数据是否 有值，无则补充带出
            FillData(second, result.BodyItems);

            SupplyHeaderByWorkItem(request, result, second, fixatList?.Where(t => t.RowNumber == -1));

            return new SecondResponse
            {
                HeadItems = result.HeadItems.OrderBy(t => t.Type).ThenBy(t => t.Sort).ThenBy(t => t.FiledName).ToList(),
                BodyItems = result.BodyItems.OrderBy(t => t.RowNumber).ThenBy(t => t.Type).ThenBy(t => t.Sort).ToList(),
            };
        }

        /// <summary>
        /// 补充 医院其他绩效
        /// </summary>
        /// <param name="result"></param>
        private void SupplementOtherPerfor(SecondResponse result, int allotId)
        {
            if (result?.BodyItems != null && result.BodyItems.Any())
            {
                var second = agsecondallotRepository.GetEntity(t => t.AllotId == allotId);
                var perapramounts = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Status == 3);

                foreach (var rownum in result.BodyItems.Where(w => w.RowNumber > -1).Select(w => w.RowNumber).Distinct())
                {
                    var rowData = result.BodyItems.Where(w => w.RowNumber == rownum);
                    var personnelNumber = rowData.FirstOrDefault(w => w.FiledId == "PersonnelNumber")?.Value;
                    var fullName = rowData.FirstOrDefault(w => w.FiledId == "FullName")?.Value;

                    var amount = perapramounts
                       ?.Where(w => w.DoctorName?.Trim() == fullName?.Trim() && w.PersonnelNumber?.Trim() == personnelNumber?.Trim())
                       ?.Sum(w => w.Amount);
                    var otherPerfor = rowData.FirstOrDefault(w => w.FiledId == "OtherPerformance");
                    if (otherPerfor != null)
                        otherPerfor.Value = amount?.ToString();
                }
            }
        }

        private List<BodyItem> GetEmployees(ag_secondallot second, int userId, List<HeadItem> heads, string unittype, string empName = "", string jobNumber = "")
        {
            #region 接口响应速度优化
            var employees = new List<per_employee>();

            if (string.IsNullOrEmpty(empName) && string.IsNullOrEmpty(jobNumber))
                employees = peremployeeRepository.GetEntities(w => w.AllotId == second.AllotId.Value && w.UnitType == unittype);
            if (!string.IsNullOrEmpty(empName))
                employees = peremployeeRepository.GetEntities(w => w.AllotId == second.AllotId.Value && w.DoctorName == empName);
            if (!string.IsNullOrEmpty(jobNumber))
                employees = peremployeeRepository.GetEntities(w => w.AllotId == second.AllotId.Value && w.PersonnelNumber == jobNumber);
            #endregion

            if (employees == null || !employees.Any()) return new List<BodyItem>();

            var perapramounts = perapramountRepository.GetEntities(t => t.AllotId == second.AllotId && t.Status == 3);
            Func<per_employee, decimal?> getAprAmount = (t) => second.Department == t.AccountingUnit && second.UnitType == t.UnitType
                ? perapramounts?.Where(w => w.PersonnelNumber?.Trim() == t.PersonnelNumber?.Trim())?.Sum(w => w.Amount)
                : 0;

            Dictionary<(string, string), Func<per_employee, object>> dict = new Dictionary<(string, string), Func<per_employee, object>>
            {
                { ("人员工号", "PersonnelNumber"), (t) => t.PersonnelNumber },
                { ("姓名", "FullName"), (t) => t.DoctorName },
                { ("岗位", "Post"), (t) => !string.IsNullOrEmpty(t.Duty) && (t.Duty.IndexOf("主任") > -1 || t.Duty.IndexOf("护士长") > -1) ? "主任" : "其他" },
                { ("出勤", "ActualAttendance"), (t) => t.AttendanceDay },
                { ("职称", "JobTitle"), (t) => t.JobTitle },
                { ("预留比例", "ReservedRatio"), (t) => t.ReservedRatio },
                { ("医院其他绩效","OtherPerformance"), (t) => getAprAmount(t)},
            };

            var list = new List<BodyItem>();
            int rowNumber = 1;
            foreach (var employee in employees)
            {
                foreach (var item in dict)
                {
                    var head = heads.FirstOrDefault(t => t.FiledName == item.Key.Item1 && t.FiledId == item.Key.Item2);
                    if (head != null)
                    {
                        var body = _mapper.Map<BodyItem>(head);
                        body.Value = item.Value.Invoke(employee)?.ToString();
                        body.RowNumber = rowNumber;
                        list.Add(body);
                    }
                }
                rowNumber++;
            }

            var hospital = hospitalRepository.GetEntity(t => t.ID == employees.First().HospitalId);
            if (hospital == null) return list;
            if (hospital.IsShowSecondDirector == 2)
                list = list.Where(t => t.FiledName == "岗位" && t.FiledId == "Post" && t.Value == "其他")?.ToList();

            return list;
        }

        /// <summary>
        /// 根据已保存的数据返回
        /// </summary>
        /// <param name="fixatitems">已保存的数据</param>
        /// <param name="headItems">列的名称、系数等值</param>
        /// <returns></returns>
        private SecondResponse SubmittedData(List<ag_fixatitem> fixatitems, List<HeadItem> headItems)
        {
            var header = fixatitems.Select(t => new { t.ItemName, t.Type, t.Sort }).ToDistinct().ToList();

            var result = new SecondResponse
            {
                HeadItems = header.Select(t => new HeadItem
                {
                    FiledId = headItems.FirstOrDefault(h => h.FiledName == t.ItemName && h.Type == t.Type)?.FiledId ?? t.ItemName + t.Type,
                    FiledName = t.ItemName,
                    Sort = t.Sort.Value,
                    Type = t.Type.Value,
                    FactorValue = headItems.FirstOrDefault(h => h.FiledName == t.ItemName && h.Type == t.Type)?.FactorValue ?? 0
                }).ToList()
            };
            result.BodyItems = GetBodyItems(fixatitems, headItems);
            return result;
        }

        /// <summary>
        /// 获取历史数据
        /// </summary>
        /// <param name="fixatitems"></param>
        /// <param name="headItems"></param>
        /// <returns></returns>
        private List<BodyItem> GetBodyItems(List<ag_fixatitem> fixatitems, List<HeadItem> headItems)
        {
            var bodyItems = new List<BodyItem>();
            if (fixatitems != null && fixatitems.Any())
            {
                bodyItems = fixatitems.Select(t => new BodyItem
                {
                    RowNumber = t.RowNumber.Value,
                    FiledId = tempitems.FirstOrDefault(h => h.FiledName == t.ItemName && h.Type == t.Type)?.FiledId ??
                    headItems.FirstOrDefault(h => h.FiledName == t.ItemName && h.Type == t.Type)?.FiledId,
                    FiledName = t.ItemName,
                    SourceType = t.SourceType ?? 0,
                    Type = t.Type ?? 0,
                    Value = t.ItemValue,
                    Sort = t.Sort ?? 0,
                    SpecialAttr = t.SpecialAttr ?? headItems.FirstOrDefault(h => h.FiledName == t.ItemName && h.Type == t.Type)?.SpecialAttr,
                }).ToList();
            }
            // 删除多余的headvalue
            bodyItems.RemoveAll(t => !headItems.Select(h => h.FiledId).Contains(t.FiledId) && t.RowNumber == -1);
            return bodyItems;
        }

        /// <summary>
        /// 补充须带出的历史数据，如姓名、职称等
        /// </summary>
        /// <param name="request"></param>
        /// <param name="headItems"></param>
        /// <returns></returns>
        private List<BodyItem> GetBringItems(UseTempRequest request, List<HeadItem> headItems)
        {
            var bodyItems = new List<BodyItem>();
            var bringhead = headItems.Where(t => t.IsBring == 1).ToList();
            if (bringhead != null && bringhead.Count > 0)
            {
                var allotIds = perallotRepository.GetEntities(t => t.HospitalId == request.HospitalId).Select(a => a.ID);
                var secondIdList = agsecondallotRepository.GetEntities(t => allotIds.Contains(t.AllotId.Value)
                && t.Department == request.Department && t.UnitType == request.UnitType)
                    .OrderBy(t => t.Year).ThenBy(t => t.Month).Select(t => t.Id).ToList();
                var index = secondIdList.IndexOf(request.SecondId);
                var fixatList = new List<ag_fixatitem>();
                if (index != 0)
                    fixatList = agfixatitemRepository.GetEntities(t => t.SecondId == secondIdList.ElementAt(index - 1)
                    && t.RowNumber.HasValue && t.RowNumber != -1 && bringhead.Select(s => s.FiledName).Contains(t.ItemName));

                if (fixatList != null && fixatList.Any())
                    bodyItems = GetBodyItems(fixatList, headItems);
            }
            return bodyItems;
        }

        /// <summary>
        /// 补充二次绩效配置数据
        /// </summary>
        /// <param name="second"></param>
        /// <param name="bodyItems"></param>
        private void FillData(ag_secondallot second, List<BodyItem> bodyItems)
        {
            if (bodyItems == null || !bodyItems.Any()) return;
            var unitType = UnitTypeUtil.GetUnitTypeValue(second.UnitType);
            var account = resaccountRepository.GetEntity(t => t.AllotID == second.AllotId && t.AccountingUnit == second.Department && t.UnitType == unitType);

            var keyValue = new Dictionary<string, string>
            {
                {"发放月份",  $"{second.Year}年{second.Month.ToString().PadLeft(2, '0')}月"},
                //{"可分配绩效",  second.RealGiveFee.ToString()},
                //{"主任基础绩效", account?.Avg?.ToString()}
            };

            if (new int[] { 1, 4 }.Contains(second.Status ?? 0))
                keyValue.Add("可分配绩效", second.RealGiveFee.ToString());

            //二次绩效配置 列头数据始终用最新分配结果
            foreach (var item in keyValue)
            {
                var kfp = bodyItems.FirstOrDefault(w => w.RowNumber == -1 && w.FiledName == item.Key);
                if (kfp != null)
                    kfp.Value = item.Value;
            }

            var pairs = new Dictionary<string, string>
            {
                {  "职称绩效", "年资职称绩效占比" },
                {  "工作量绩效", "工作量绩效占比" },
            };
            var config = cofagainRepository.GetEntities(t => t.AllotID == second.AllotId);
            if (config != null && config.Any())
            {
                foreach (var item in config)
                {
                    var key = pairs.ContainsKey(item.TypeName) ? pairs[item.TypeName] : item.TypeName;
                    if (!keyValue.Keys.Contains(key))
                        keyValue.Add(key, item.Value.ToString());
                }
            }

            foreach (var item in keyValue)
            {
                var header = bodyItems.FirstOrDefault(t => t.FiledName == item.Key);
                if (header != null && (string.IsNullOrEmpty(header.Value) /*|| header.Value == "0"*/))
                    bodyItems.FirstOrDefault(t => t.FiledName == item.Key).Value = item.Value;
            }
        }

        /// <summary>
        /// 根绝添加工作量类型判断是否添加
        /// </summary>
        /// <param name="request"></param>
        /// <param name="result"></param>
        private void SupplyHeaderByWorkItem(UseTempRequest request, SecondResponse result, ag_secondallot second, IEnumerable<ag_fixatitem> fixatitems)
        {
            //var workitem = perforAgworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department
            //&& t.UnitType == request.UnitType && t.WorkTypeId != (int)AgWorkloadType.SingleAwards);

            //if (workitem == null || !workitem.Any(t => t.Id > 0))
            //    return;

            //不包含工作量绩效
            if (!result.HeadItems.Select(t => t.FiledId).Contains("PerformanceShareTheWorkload"))
                return;

            var maxSortValue = result.HeadItems.Where(t => t.Type == 1).Max(t => t.Sort);

            var headers = new HeadItem[] {
                new HeadItem
                {
                    FiledId = "ThePerformanceOf",
                    Type =  1,
                    SourceType = 1,
                    IsBring =  2,
                    SpecialAttr = 1,
                },
                new HeadItem
                {
                    FiledId = "ThePerformanceAmountOf",
                    Type =  1,
                    SourceType = 1,
                    IsBring =  2,
                    SpecialAttr = 2,
                }
            };

            var headerItems = new List<HeadItem>();

            var unit = second.UnitType == UnitType.医技组.ToString() ? UnitType.医生组.ToString() : second.UnitType;
            var deptHeader = agworkloadtypeRepository.GetEntities(t => request.HospitalId == t.HospitalId && t.Department == second.Department && t.UnitType == unit);
            if (deptHeader != null && deptHeader.Any())
            {
                int sortindex = 1;
                foreach (var item in deptHeader)
                {
                    if (item.HospitalId == 0) continue;

                    for (int i = 0; i < headers.Length; i++)
                    {
                        var headItem = (HeadItem)headers[i].Clone();
                        headItem.FiledName = (i % 2 == 0) ? item.TypeName : item.TypeName.Replace("占比", "金额");
                        if (i % 2 != 0 && !headItem.FiledName.EndsWith("金额"))
                            headItem.FiledName += "金额";
                        headItem.FiledId += item.Id;
                        headItem.Sort = maxSortValue + sortindex;
                        headerItems.Add(headItem);
                        sortindex++;
                    }
                }
            }
            var defauleHeader = new List<ag_workload_type>
            {
                new ag_workload_type { Id = (int)AgWorkloadType.Workload, TypeName = "工作量绩效占比", },
                new ag_workload_type { Id = (int)AgWorkloadType.Workload, TypeName = "工作量分配绩效金额" },
            };
            foreach (var item in defauleHeader)
            {
                result.HeadItems.Where(t => t.FiledName == item.TypeName).ToList()?.ForEach(t =>
                {
                    t.SpecialAttr = item.TypeName.IndexOf("占比") > -1 ? 1 : 2;
                });
                result.BodyItems.Where(t => t.FiledName == item.TypeName).ToList()?.ForEach(t =>
                {
                    t.SpecialAttr = item.TypeName.IndexOf("占比") > -1 ? 1 : 2;
                });
            }

            var rownumber = result.BodyItems.Any(t => t.RowNumber == -1) ? -1 : 0;
            foreach (var item in headerItems)
            {
                if (!result.HeadItems.Select(t => t.FiledId).Contains(item.FiledId))
                {
                    result.HeadItems.Add(item);
                    var body = _mapper.Map<BodyItem>(item);
                    body.RowNumber = rownumber;
                    if (fixatitems != null && fixatitems.Any(t => t.ItemName == item.FiledName))
                        body.Value = fixatitems.FirstOrDefault(t => t.ItemName == item.FiledName).ItemValue;
                    result.BodyItems.Add(body);
                }
            }
        }

        #endregion 二次绩效详情-使用中

        /// <summary>
        /// 二次绩效项录入保存
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool SaveValue(List<ag_fixatitem> request, int secondId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null)
                throw new PerformanceException("二次绩效ID不存在");

            var fixatitems = agfixatitemRepository.GetEntities(t => t.SecondId == secondId);

            #region old

            //var result = DelValue(secondId, fixatitems, request);
            //List<ag_fixatitem> update = new List<ag_fixatitem>(), insert = new List<ag_fixatitem>();
            //if (fixatitems != null && fixatitems.Any())
            //{
            //    foreach (var item in request.Where(w => !string.IsNullOrEmpty(w.ItemName)))
            //    {
            //        var cellItem = fixatitems.FirstOrDefault(t => t.RowNumber == item.RowNumber && t.ItemName == item.ItemName);
            //        if (cellItem != null)
            //        {
            //            cellItem.ItemValue = item.ItemValue;
            //            cellItem.Sort = item.Sort;
            //            cellItem.SourceType = item.SourceType;
            //            cellItem.Type = item.Type;
            //            cellItem.UnitType = item.UnitType;
            //            cellItem.SpecialAttr = item.SpecialAttr;
            //            update.Add(cellItem);
            //        }
            //        else
            //        {
            //            insert.Add(item);
            //        }
            //    }
            //}
            //else
            //    insert = request;
            //result = agfixatitemRepository.UpdateRange(update.ToArray());
            //result = agfixatitemRepository.AddRange(insert.ToArray());

            #endregion

            bool result = false;
            if (fixatitems != null && fixatitems.Any())
                result = agfixatitemRepository.RemoveRange(fixatitems.ToArray());

            result = agfixatitemRepository.AddRange(request.ToArray());

            return result;
        }

        /// <summary>
        /// 删除未保存的历史数据
        /// </summary>
        /// <param name="oldFixatItems">数据库中查询到的值</param>
        /// <param name="newFixatItems">需要保存的数据</param>
        /// <returns></returns>
        public bool DelValue(int secondId, List<ag_fixatitem> oldFixatItems, List<ag_fixatitem> newFixatItems)
        {
            var result = true;
            // 提交数据为空时，删除所有数据
            if (newFixatItems == null || newFixatItems.Count == 0)
            {
                if (oldFixatItems != null && oldFixatItems.Any())
                {
                    result = agfixatitemRepository.RemoveRange(oldFixatItems.ToArray());
                    logger.LogError($"删除二次分配录入数据：{oldFixatItems.Count()}");
                    logger.LogError($"删除二次分配录入数据：{JsonHelper.Serialize(oldFixatItems.Select(w => w.ID))}");
                }
                return result;
            }

            if (oldFixatItems != null && oldFixatItems.Any())
            {
                var groupData = oldFixatItems.GroupBy(t => new { t.RowNumber, t.ItemName }).Select(t => new
                {
                    t.Key.RowNumber,
                    t.Key.ItemName,
                    Count = t.Count(),
                    Id = t.Max(group => group.ID)
                });
                // 删除重复数据
                if (groupData.Any(t => t.Count > 1))
                {
                    var delData = oldFixatItems.Where(t => t.SecondId == secondId && !groupData.Select(w => w.Id).Contains(t.ID));
                    int flag = oldFixatItems.RemoveAll(t => t.SecondId == secondId && !groupData.Select(w => w.Id).Contains(t.ID));
                    logger.LogError($"删除二次分配录入数据：{delData.Count()}");
                    result = agfixatitemRepository.RemoveRange(delData.ToArray());
                }

                // 删除行号不存在的数据
                var saveRows = newFixatItems.Where(t => t.SecondId == secondId).Select(t => t.RowNumber).Distinct();
                var delRows = oldFixatItems.Where(t => t.SecondId == secondId).Select(t => t.RowNumber).Distinct().Except(saveRows);
                if (delRows != null && delRows.Count() > 0)
                {
                    result = agfixatitemRepository.RemoveRange(oldFixatItems.Where(t => delRows.Contains(t.RowNumber)).ToArray());
                    logger.LogError($"删除二次分配录入数据 删除行号不存在的数据：{oldFixatItems.Count()}");
                }
            }

            return result;
        }

        ///// <summary>
        ///// 二次绩效分配结果保存
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public bool SaveCompute(List<ag_compute> request)
        //{
        //    var secondId = request.First().SecondId;
        //    var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
        //    if (second == null)
        //        throw new PerformanceException("二次绩效ID不存在");
        //    if (second.Status == 2)
        //        throw new PerformanceException("二次绩效已提交，无法重复提交");

        //    var compute = agcomputeRepository.GetEntities(t => t.SecondId == secondId);
        //    foreach (var item in request)
        //    {
        //        if (compute != null && compute.Any(t => t.SecondId == secondId && t.Department == item.Department && t.PersonName == item.PersonName))
        //        {
        //            var cellItem = compute.First(t => t.SecondId == secondId && t.Department == item.Department && t.PersonName == item.PersonName);
        //            cellItem.RealGiveFee = item.RealGiveFee;
        //            agcomputeRepository.Update(cellItem);
        //        }
        //        else
        //        {
        //            agcomputeRepository.Add(item);
        //        }
        //    }
        //    return true;
        //}

        #endregion 二次绩效列表与数据保存

        #region 模板

        /// <summary>
        /// 获取模板列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<SecondTempResponse> GetTemp(int hospitalid, string unitType, string department, int userId)
        {
            var temps = agtempRepository.GetEntities(t => t.IsEnable == 1);
            if (temps != null && temps.Any())
            {
                ag_usetemp useTemp = null;
                if (string.IsNullOrEmpty(unitType))
                {
                    var userCenter = userRepository.GetUser(userId);
                    var unitTypes = UnitTypeUtil.GetMaps(userCenter?.URole.Type ?? 0);
                    Expression<Func<ag_usetemp, bool>> exp = t => t.HospitalId == hospitalid && t.Department == department;

                    if (userCenter?.URole != null && userCenter.URole.Type.HasValue)
                        exp = exp.And(t => unitTypes.Contains(t.UnitType));

                    useTemp = agusetempRepository.GetEntity(exp);
                }
                else
                {
                    var useTemps = agusetempRepository.GetEntities(t => t.HospitalId == hospitalid);
                    useTemp = useTemps.FirstOrDefault(t => UnitTypeUtil.IsEqualsUnitType(t.UnitType, unitType) && t.Department == department);
                }

                var secondTemps = _mapper.Map<List<SecondTempResponse>>(temps);
                if (useTemp != null)
                    secondTemps.ForEach(t => t.IsSelected = t.Id == useTemp.UseTempId);
                return secondTemps;
            }
            return new List<SecondTempResponse>();
        }

        /// <summary>
        /// 使用模板
        /// </summary>
        /// <param name="tempId"></param>
        /// <returns></returns>
        public bool UseTemp(UseTempRequest request)
        {
            var result = false;
            var entities = agusetempRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department);
            var entity = entities.FirstOrDefault(w => UnitTypeUtil.IsEqualsUnitType(w.UnitType, request.UnitType));
            if (entity == null)
            {
                entity = _mapper.Map<ag_usetemp>(request);
                result = agusetempRepository.Add(entity);
            }
            else
            {
                entity.UseTempId = request.TempId;
                result = agusetempRepository.Update(entity);
                if (result)
                {
                    //获取固定模板列 + 工作量列
                    var headItems = GetHeadItems(request.TempId, request.HospitalId, request.Department, request.UnitType);

                    List<ag_fixatitem> list = new List<ag_fixatitem>();
                    var addList = new List<ag_fixatitem>();

                    var allotList = perallotRepository.GetEntities(t => t.HospitalId == request.HospitalId);
                    var seconds = agsecondallotRepository.GetEntities(t => allotList.Select(a => a.ID).Contains(t.AllotId.Value) && new List<int> { 1, 4 }.Contains(t.Status ?? 1));
                    var secondList = _mapper.Map<List<SecondListResponse>>(seconds);
                    secondList?.ForEach(t => t.IsArchive = allotList.FirstOrDefault(a => a.ID == t.AllotId).States == 8 ? 1 : 0);

                    //获取未归档  未提交  驳回 的二次绩效
                    var secondId = secondList?.Where(s => s.IsArchive == 0).Select(s => s.Id);
                    if (secondId == null || secondId.Count() <= 0)
                        return result;

                    var fixatList = agfixatitemRepository.GetEntities(t => secondId.Contains(t.SecondId.Value));

                    #region 获取需要添加的数据 和 无需操作的数据

                    //var update_second_usetemps = new List<ag_secondallot>();
                    foreach (var second in secondList)
                    {
                        if (second.IsArchive == 0 && new List<int> { 1, 4 }.Contains(second.Status ?? 1))
                        {
                            //var update_second_usetemp = seconds.FirstOrDefault(t => t.Id == second.Id);
                            //update_second_usetemp.UseTempId = request.TempId;
                            //update_second_usetemps.Add(update_second_usetemp);

                            foreach (var head in headItems)
                            {
                                var exist = fixatList?.Where(t => t.ItemName == head.FiledName && t.Type == head.Type && t.SecondId == second.Id);
                                if (exist != null && exist.Count() > 0)
                                    list.AddRange(exist);
                                else if (head.Type == 1)
                                {
                                    var configs = cofagainRepository.GetEntities(t => t.AllotID == second.AllotId && t.Department == request.Department) ?? new List<cof_again>();
                                    addList.Add(new ag_fixatitem
                                    {
                                        ItemName = head.FiledName,
                                        RowNumber = -1,
                                        Type = head.Type,
                                        SourceType = head.SourceType,
                                        Sort = head.Sort,
                                        FactorValue = head.FactorValue,
                                        UnitType = second.UnitType,
                                        AllotId = second.AllotId,
                                        SecondId = second.Id,
                                        ItemValue = head.FiledName == "绩效合计(考核后)" ? second.RealGiveFee?.ToString()
                                        : head.FiledName == "发放月份" ? $"{second.Year}年{second.Month.ToString().PadLeft(2, '0')}月"
                                        : configs.FirstOrDefault(t => t.TypeName == head.FiledName)?.Value.ToString()
                                    });
                                }
                            }
                        }
                    }

                    #endregion 获取需要添加的数据 和 无需操作的数据

                    ////perforAgsecondallotRepository.UpdateRange(update_second_usetemps.ToArray());
                    //if (list != null && list.Count > 0)
                    //{
                    //    var delList = fixatList.Except(list);
                    //    agfixatitemRepository.RemoveRange(delList.Where(w => w.SecondId == request.SecondId).ToArray());

                    //    if (addList != null && addList.Count > 0)
                    //        agfixatitemRepository.AddRange(addList.ToArray());
                    //}
                }
            }
            return result;
        }

        /// <summary>
        /// 应用模板
        /// </summary>
        /// <returns></returns>
        public void RefreshTemp(UseTempRequest request)
        {
            var usetemp = agusetempRepository.GetEntity(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
            if (usetemp == null)
                throw new PerformanceException("参数usetempId 无效");
            //获取工作量列头
            var workItem = agworkloadRepository.GetEntities(t => t.HospitalId == usetemp.HospitalId && t.Department == usetemp.Department && t.UnitType == usetemp.UnitType);
            //获取固定模板列头
            var tempItem = agtempitemRepository.GetEntities(t => t.TempId == usetemp.UseTempId);
            var tempHeader = workItem == null ? tempItem.Select(t => t.FiledName) : tempItem.Select(t => t.FiledName).Union(workItem?.Select(t => t.ItemName));

            //获取数据
            var fixatList = agfixatitemRepository.GetEntities(t => t.SecondId == request.SecondId);
            if (fixatList == null || fixatList.Count == 0)
                throw new PerformanceException("未录入数据");

            //更新系数、排序
            fixatList.ForEach(t =>
            {
                t.Sort = workItem?.FirstOrDefault(w => w.ItemName == t.ItemName)?.Sort;
                t.FactorValue = workItem?.FirstOrDefault(w => w.ItemName == t.ItemName)?.FactorValue;
            });
            agfixatitemRepository.UpdateRange(fixatList.ToArray());
            //删除  列 不存在的数据
            var header = fixatList.Select(t => t.ItemName).Distinct();
            var delItems = header.Except(tempHeader);
            if (delItems != null && delItems.Count() > 0)
                agfixatitemRepository.RemoveRange(fixatList.Where(t => delItems.Contains(t.ItemName)).ToArray());
            //添加  新增列 的数据
            var addItems = new List<ag_fixatitem>();
            fixatList.Select(t => t.RowNumber).Distinct().ToList().ForEach(t =>
            {
                addItems.AddRange(tempHeader.Except(header)?.Select(s => new ag_fixatitem
                {
                    ItemName = s,
                    RowNumber = t,
                    AllotId = fixatList.First().AllotId,
                    SecondId = fixatList.First().SecondId,
                    UnitType = fixatList.First().UnitType,
                    Sort = tempItem?.FirstOrDefault(w => w.FiledName == s)?.Sort ?? workItem?.FirstOrDefault(w => w.ItemName == s)?.Sort,
                    FactorValue = workItem?.FirstOrDefault(w => w.ItemName == s)?.FactorValue,
                    Type = tempItem?.FirstOrDefault(w => w.FiledName == s)?.Type ?? 3,
                    SourceType = tempItem?.FirstOrDefault(w => w.FiledName == s)?.SourceType ?? 1,
                }));
            });
            if (addItems != null && addItems.Count() > 0)
                agfixatitemRepository.AddRange(addItems.ToArray());
        }

        #endregion 模板

        #region 工作量绩效配置

        /// <summary>
        /// 获取工作量类型列表
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public List<TitleValue<int>> WorkTypeList(WorkloadRequest request, int secondId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null) throw new PerformanceException("参数错误");

            var worktypes = agworkloadtypeRepository.GetEntities(t => request.HospitalId.Value == t.HospitalId && t.Department == second.Department && t.UnitType == second.UnitType);
            if (worktypes != null && worktypes.Any())
            {
                return worktypes.Select(t => new TitleValue<int>
                {
                    Title = t.TypeName,
                    Value = t.Id
                }).ToList();
            }
            return null;
        }

        /// <summary>
        /// 获取二次分配 提取工作量带出字典
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public List<string> WorkloadMap(int secondId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null) throw new PerformanceException("参数错误");

            var allot = perallotRepository.GetEntity(t => t.ID == second.AllotId);
            if (allot == null) throw new PerformanceException("参数错误");

            var worktypes = perallotRepository.GetSecondWorkloadMaps(allot.HospitalId);
            return (worktypes != null && worktypes.Any()) ? worktypes.ToList() : new List<string>();
        }

        /// <summary>
        /// 保存工作量类型
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public ag_workload_type SaveWorkType(ag_workload_type request, int secondId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null) throw new PerformanceException("参数错误");

            var entity = agworkloadtypeRepository.GetEntity(t => request.HospitalId == t.HospitalId && t.Department == second.Department
                && t.UnitType == second.UnitType && t.TypeName == request.TypeName);
            if (entity == null)
            {
                if (request.Id > 0)
                {
                    entity = agworkloadtypeRepository.GetEntity(t => t.Id == request.Id);
                    entity.HospitalId = request.HospitalId;
                    entity.TypeName = request.TypeName;
                    entity.TypeName = request.TypeName;

                    agworkloadtypeRepository.Update(entity);
                }
                else
                {
                    entity = new ag_workload_type
                    {
                        HospitalId = request.HospitalId,
                        TypeName = request.TypeName,
                        Department = second.Department,
                        UnitType = second.UnitType,
                    };
                    agworkloadtypeRepository.Add(entity);
                }
                AddWorkTypeDefaultHeadValue(request.HospitalId, entity);
                AddWorkTypeDefaultValues(entity);
                return entity;
            }
            else if (request.Id != entity.Id)
                throw new PerformanceException("类型已存在");
            else
                return request;
        }

        /// <summary>
        /// 添加工作量类型默认项工作量得分、考核得分、工作量绩效工资
        /// </summary>
        /// <param name="type"></param>
        private void AddWorkTypeDefaultValues(ag_workload_type type)
        {
            var workItems = agworkloadRepository.GetEntities(t => t.WorkTypeId == type.Id);

            List<(string, string, int)> addItems = new List<(string, string, int)>();
            if (workItems != null && workItems.Any())
            {
                foreach (var item in defaultValues)
                {
                    if (!workItems.Any(t => t.ItemId == $"{item.Item2}_{type.Id}"))
                        addItems.Add(item);
                }
            }
            else
                addItems = defaultValues;

            if (addItems == null || !addItems.Any()) return;

            var insertData = addItems.Select(t => new ag_workload
            {
                HospitalId = type.HospitalId,
                Department = type.Department,
                UnitType = type.UnitType,
                ItemId = $"{t.Item2}_{type.Id}",
                ItemName = t.Item1,
                FactorValue = null,
                Sort = 100 + t.Item3,
                WorkTypeId = type.Id
            });
            agworkloadRepository.AddRange(insertData.ToArray());
        }

        /// <summary>
        /// 添加工作量类型默认配置 - 顶部数据中的占比、金额
        /// </summary>
        /// <param name="hospitalId"></param>
        /// <param name="type"></param>
        private void AddWorkTypeDefaultHeadValue(int hospitalId, ag_workload_type type)
        {
            List<ag_worktype_source> insertData = new List<ag_worktype_source>();
            var seconds = GetNotAuditSeconds(hospitalId, type);
            if (seconds == null || !seconds.Any())
                return;

            var worktypeSources = agworktypesourceRepository.GetEntities(t => t.WorkTypeId == type.Id);
            if (worktypeSources == null || !worktypeSources.Any())
            {
                insertData = seconds.Select(t => new ag_worktype_source
                {
                    WorkTypeId = type.Id,
                    SecondId = t.Id,
                    FieldId = $"{AgWorkloadType.Workload}_Ratio_{type.Id}",
                    FieldName = type.TypeName.EndsWith("占比") ? type.TypeName : type.TypeName + "占比"
                }).ToList();
            }
            else
            {
                var existedSeconds = worktypeSources.Select(t => t.SecondId);
                var except = seconds.Select(t => t.Id).Except(existedSeconds);
                if (except != null && except.Any())
                {
                    insertData = except.Select(t => new ag_worktype_source
                    {
                        WorkTypeId = type.Id,
                        SecondId = t,
                        FieldId = $"{AgWorkloadType.Workload}_Ratio_{type.Id}",
                        FieldName = type.TypeName.EndsWith("占比") ? type.TypeName : type.TypeName + "占比"
                    }).ToList();
                }
                worktypeSources.ForEach(t =>
                {
                    t.FieldName = type.TypeName + t.FieldName.Substring(t.FieldName.Length - 2);
                });
                agworktypesourceRepository.UpdateRange(worktypeSources.ToArray());
            }
            var amounts = insertData.Select(t => new ag_worktype_source
            {
                WorkTypeId = type.Id,
                SecondId = t.SecondId,
                FieldId = $"{AgWorkloadType.Workload.ToString()}_Amount_{type.Id}",
                FieldName = t.FieldName.Substring(0, t.FieldName.Length - 2) + "金额"
            }).ToList();
            insertData.AddRange(amounts);
            agworktypesourceRepository.AddRange(insertData.OrderBy(t => t.SecondId).ThenBy(t => t.FieldName).ToArray());
        }

        /// <summary>
        /// 添加工作量类型默认配置 - 顶部数据中的占比、金额
        /// </summary>
        /// <param name="hospitalId"></param>
        /// <param name="second"></param>
        private void AddWorkTypeDefaultHeadValue(int hospitalId, ag_secondallot second)
        {
            /**
             * 
             * 二次绩效提交时，跳过该绩效新增工作量类型
             * 防止在二次绩效审核期间新增工作量类型，进行数据补充
             * 
             */
            if (second == null || IsAudit(second.Status)) return;

            var worktypeSources = agworktypesourceRepository.GetEntities(t => t.SecondId == second.Id);

            var worktypes = agworkloadtypeRepository.GetEntities(t => t.HospitalId == hospitalId && t.Department == second.Department && t.UnitType == second.UnitType);
            if (worktypes == null || !worktypes.Any())
            {
                if (worktypeSources != null && worktypeSources.Any())
                    agworktypesourceRepository.RemoveRange(worktypeSources.ToArray());
                return;
            }

            List<ag_worktype_source> insertData = new List<ag_worktype_source>(), updateData = new List<ag_worktype_source>();
            foreach (var type in worktypes)
            {
                var sources = worktypeSources?.Where(t => t.WorkTypeId == type.Id).ToList();
                if (sources != null && sources.Any())
                {
                    sources.ForEach(t => t.FieldName = type.TypeName + t.FieldName.Substring(t.FieldName.Length - 2));
                    updateData.AddRange(sources);
                }
                else
                {
                    insertData.Add(new ag_worktype_source
                    {
                        WorkTypeId = type.Id,
                        SecondId = second.Id,
                        FieldId = $"{AgWorkloadType.Workload}_Ratio_{type.Id}",
                        FieldName = type.TypeName.EndsWith("占比") ? type.TypeName : type.TypeName + "占比"
                    });
                }
            }

            if (insertData != null && insertData.Any())
            {
                var amounts = insertData.Select(t => new ag_worktype_source
                {
                    WorkTypeId = t.WorkTypeId,
                    SecondId = second.Id,
                    FieldId = $"{AgWorkloadType.Workload}_Amount_{t.WorkTypeId}",
                    FieldName = t.FieldName.Substring(0, t.FieldName.Length - 2) + "金额"
                }).ToList();
                insertData.AddRange(amounts);
                agworktypesourceRepository.AddRange(insertData.OrderBy(t => t.WorkTypeId).ThenBy(t => t.FieldName).ToArray());
            }
            if (updateData != null && updateData.Any())
            {
                agworktypesourceRepository.UpdateRange(updateData.ToArray());
            }
        }

        /// <summary>
        /// 检查默认工作量项是否已添加，添加默认的工作量得分、考核得分、工作量绩效工资
        /// </summary>
        /// <param name="hospitalId"></param>
        /// <param name="department"></param>
        /// <param name="unitType"></param>
        private void CheckDefaultWorkload(int hospitalId, string department, string unitType)
        {
            var workloads = agworkloadRepository.GetEntities(t => t.HospitalId == hospitalId && t.Department == department && t.UnitType == unitType);

            List<(string, string, int)> addItems = new List<(string, string, int)>();
            if (workloads != null && workloads.Any())
            {
                foreach (var item in defaultValues)
                {
                    if (!workloads.Any(t => t.ItemId == item.Item2 + "_Default"))
                        addItems.Add(item);
                }
            }
            else
                addItems = defaultValues;

            if (addItems == null || !addItems.Any()) return;

            var insertData = addItems.Select(t => new ag_workload
            {
                HospitalId = hospitalId,
                Department = department,
                UnitType = unitType,
                ItemId = t.Item2 + "_Default",
                ItemName = t.Item1,
                FactorValue = null,
                Sort = 100 + t.Item3,
                WorkTypeId = (int)AgWorkloadType.Workload
            });
            agworkloadRepository.AddRange(insertData.ToArray());
        }

        internal static List<(string, string, int)> defaultValues = new List<(string, string, int)>
        {
            ( "工作量得分", "WorkloadScore" , 1 ),
            ( "考核得分", "AssessmentScore", 2 ),
            ( "工作量绩效工资", "WorkPerformance", 3 )
        };

        /// <summary>
        /// 删除工作量类型
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public bool DeleteWorkType(WorkloadRequest request)
        {
            var entity = agworkloadtypeRepository.GetEntity(t => t.Id == request.Id);
            if (entity != null)
            {
                var items = agworkloadRepository.GetEntities(t => t.WorkTypeId == request.Id);
                if (items != null && items.Any())
                    agworkloadRepository.RemoveRange(items.ToArray());

                var seconds = GetNotAuditSeconds(entity.HospitalId, entity);
                if (seconds != null && seconds.Any())
                {
                    // 删除未提交驳回的二次绩效的数据
                    var sources = agworktypesourceRepository.GetEntities(t => t.WorkTypeId == request.Id && seconds.Select(w => w.Id).Contains(t.SecondId));
                    if (sources != null && sources.Any())
                        agworktypesourceRepository.RemoveRange(sources.ToArray());
                }

                return agworkloadtypeRepository.Remove(entity);
            }
            else
                return false;
        }

        /// <summary>
        /// 获取工作量列表
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public List<ag_workload> GetWorkloadList(WorkloadRequest request)
        {
            return agworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department
            && t.UnitType == request.UnitType && t.ItemId.StartsWith($"{AgWorkloadType.Workload}_"));
        }

        /// <summary>
        /// 新增工作量绩效配置
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool WorkloadAdd(WorkloadRequest request)
        {
            Expression<Func<ag_workload, bool>> exp = (t) => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType && t.ItemId.StartsWith($"{request.AgWorkloadType}_");
            var workloadList = agworkloadRepository.GetEntities(exp);
            if (workloadList != null && workloadList.Any(t => t.ItemName == request.ItemName))
                throw new PerformanceException("项目名称重复");
            ag_workload workload = new ag_workload
            {
                HospitalId = request.HospitalId,
                Department = request.Department,
                UnitType = request.UnitType,
                FactorValue = request.FactorValue ?? 1,
                ItemName = request.ItemName,
                Sort = request.Sort ?? 1,
                SourceCategory = request.SourceCategory,
                WorkTypeId = request.AgWorkloadType == AgWorkloadType.Workload ? request.WorkTypeId : (int)request.AgWorkloadType
            };
            var result = agworkloadRepository.Add(workload);
            if (result)
            {
                workload.ItemId = getWorkloadItemId.Invoke(request.AgWorkloadType, request.WorkTypeId, workload.Id);
                agworkloadRepository.Update(workload);
            }

            return result;
        }

        /// <summary>
        /// 修改工作量绩效配置
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool WorkloadUpdate(WorkloadRequest request)
        {
            Expression<Func<ag_workload, bool>> exp = (t) => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType && t.ItemId.StartsWith($"{request.AgWorkloadType}_");
            var workloadList = agworkloadRepository.GetEntities(exp);
            if (workloadList != null && workloadList.Any(t => t.Id != request.Id && t.ItemName == request.ItemName))
                throw new PerformanceException("项目名称重复");

            var workload = workloadList.FirstOrDefault(t => t.Id == request.Id);
            workload.HospitalId = request.HospitalId;
            workload.Department = request.Department;
            workload.UnitType = request.UnitType;
            workload.FactorValue = request.FactorValue;
            workload.ItemName = request.ItemName;
            workload.SourceCategory = request.SourceCategory;
            workload.Sort = request.Sort;
            workload.ItemId = getWorkloadItemId.Invoke(request.AgWorkloadType, request.WorkTypeId, workload.Id);
            workload.WorkTypeId = request.AgWorkloadType == AgWorkloadType.Workload ? request.WorkTypeId : (int)request.AgWorkloadType;

            return agworkloadRepository.Update(workload);
        }

        /// <summary>
        /// 获取工作量绩效配置的ItemId
        /// </summary>
        readonly Func<AgWorkloadType, int, int, string> getWorkloadItemId = (agWorkloadType, workTypeId, workloadId) =>
        {
            /**
             * 单项奖励 - SingleAwards_WorkloadId
             * 默认工作量类型WorkTypeId=0 - Workload_Default_WorkloadId
             * 自定义工作量类型WorkTypeId>0 - Workload_WorkTypeId_WorkloadId
             */
            if (agWorkloadType == AgWorkloadType.Workload)
            {
                return workTypeId == (int)AgWorkloadType.Workload ? $"{AgWorkloadType.Workload}_Default_{workloadId}"
                   : $"{AgWorkloadType.Workload}_{workTypeId}_{workloadId}";
            }
            else
            {
                return $"{agWorkloadType}_{workloadId}";
            }
        };

        /// <summary>
        /// 获取等待提交或驳回的二次绩效（同一医院同一科室）
        /// </summary>
        private List<ag_secondallot> GetNotAuditSeconds(int hospitalId, ag_workload_type type)
        {
            List<ag_secondallot> seconds = new List<ag_secondallot>();
            var allots = perallotRepository.GetEntities(t => t.HospitalId == hospitalId);
            if (allots == null || !allots.Any()) return seconds;

            /**
             * 添加数据时注意避免给已经提交过的数据添加，否则会造成提交时的数据和显示数据不一致 
             */
            return agsecondallotRepository.GetEntities(t => allots.Select(w => w.ID).Contains(t.AllotId.Value) && t.Department == type.Department && t.UnitType == type.UnitType && !new int[] { 2, 3 }.Contains(t.Status ?? 1)) ?? seconds;
        }

        /// <summary>
        /// 删除工作量绩效配置
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool WorkloadDelete(int id)
        {
            var workload = agworkloadRepository.GetEntity(t => t.Id == id);
            return agworkloadRepository.Remove(workload);
        }

        /// <summary>
        /// 获取单行奖励列表
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public List<ag_workload> GetSingleList(WorkloadRequest request)
        {
            return agworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department
            && t.UnitType == request.UnitType && t.ItemId.StartsWith(request.AgWorkloadType.ToString()));
        }

        //public (string, string) GetDeptAndUnit(int userId)
        //{
        //    var user = userRepository.GetEntity(t => t.ID == userId);
        //    var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
        //    var role = roleRepository.GetEntity(t => t.ID == userrole.RoleID);

        //    if (role.Type == application.DirectorRole)
        //    {
        //        return (UnitType.医生组.ToString(), user.Department);
        //    }
        //    else if (role.Type == application.NurseRole)
        //        return (UnitType.护理组.ToString(), user.Department);
        //    if (role.Type == application.SpecialRole)
        //        return (UnitType.特殊核算组.ToString(), user.Department);
        //    if (role.Type == application.OfficeRole)
        //        return (UnitType.行政后勤.ToString(), user.Department);
        //    else
        //        return ("", user.Department);
        //}

        #endregion 工作量绩效配置

        #region 二次绩效考核

        /// <summary>
        /// 二次绩效考核列表
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <returns></returns>
        public List<ag_secondallot> AuditList(int allotId)
        {
            var allot = perallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null)
                throw new PerformanceException("所选绩效不存在！");

            var types = new List<int> { (int)UnitType.行政高层, (int)UnitType.行政中层, (int)UnitType.行政工勤 };
            var accountUnit = resaccountRepository.GetEntities(t => t.AllotID == allot.ID && !types.Contains(t.UnitType.Value));
            // 查询需要进行二次分配的行政后勤科室
            var xzAccountUnit = resaccountRepository.GetEntities(t => t.AllotID == allot.ID && t.UnitType.Value == (int)UnitType.行政工勤 && t.NeedSecondAllot == "是");
            if (xzAccountUnit != null && xzAccountUnit.Count > 0)
                (accountUnit ?? new List<res_account>()).AddRange(xzAccountUnit);

            var specialunit = resspecialunitRepository.GetEntities(t => t.AllotID == allot.ID);

            return SecondList(allot, accountUnit, specialunit);
        }

        private List<ag_secondallot> SecondList(per_allot allot, List<res_account> accountUnit, List<res_specialunit> specialunit)
        {
            List<res_account> temps = new List<res_account>();
            if (accountUnit != null)
                accountUnit.ForEach(w => temps.Add(new res_account { UnitType = w.UnitType, AccountingUnit = w.AccountingUnit, RealGiveFee = w.RealGiveFee }));
            if (specialunit != null)
                specialunit.ForEach(w =>
                {
                    if (!temps.Any(t => t.UnitType == (int)UnitType.特殊核算组 && t.AccountingUnit == w.AccountingUnit))
                        temps.Add(new res_account { UnitType = (int)UnitType.特殊核算组, AccountingUnit = w.AccountingUnit, RealGiveFee = w.RealGiveFee });
                });

            var secondList = agsecondallotRepository.GetEntities(t => t.AllotId == allot.ID && t.Year == allot.Year && t.Month == allot.Month);
            var result = temps.Select(t =>
            {
                var second = secondList?.FirstOrDefault(f => UnitTypeUtil.IsEqualsUnitType(f.UnitType, t.UnitType) && f.Department == t.AccountingUnit);
                if (second != null) return second;
                return new ag_secondallot
                {
                    AllotId = allot.ID,
                    Year = allot.Year,
                    Month = allot.Month,
                    UnitType = ((UnitType)t.UnitType).ToString(),
                    Department = t.AccountingUnit,
                    RealGiveFee = t.RealGiveFee,
                    Status = 1,
                };
            });
            var enums = UnitTypeUtil.GetUnitTypeFromEnum();
            return result.Where(w => w.RealGiveFee.HasValue && w.RealGiveFee != 0)
                .OrderBy(t => t.Status == 4 ? 2 : t.Status)
                .ThenBy(t => enums.FirstOrDefault(f => f.Name == t.UnitType)?.Value)
                .ThenBy(t => t.Department)
                .ToList();
        }

        /// <summary>
        /// 护理部二次绩效考核列表
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <returns></returns>
        public List<ag_secondallot> NursingDeptlist(int allotId)
        {
            var allot = perallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null)
                throw new PerformanceException("所选绩效不存在！");
            var types = new int[] { (int)UnitType.其他护理组, (int)UnitType.护理组 };
            var accountUnit = resaccountRepository.GetEntities(t => t.AllotID == allotId && types.Contains(t.UnitType.Value));
            var specialunit = resspecialunitRepository.GetEntities(t => t.AllotID == allot.ID);
            return SecondList(allot, accountUnit, specialunit);
        }

        /// <summary>
        /// 提交审核
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <param name="secondId">二次绩效ID</param>
        /// <returns></returns>
        public bool AuditSubmit(ag_secondallot second, int userId)
        {
            var allot = perallotRepository.GetEntity(t => t.ID == second.AllotId);
            if (allot == null)
                throw new PerformanceException("二次绩效无效！");

            var userCenter = userRepository.GetUser(userId);
            var unitType = UnitTypeUtil.GetMaps(userCenter?.URole.Type ?? 0);
            Expression<Func<ag_usetemp, bool>> exp = t => t.HospitalId == allot.HospitalId && t.Department == second.Department;
            if (userCenter?.URole != null && userCenter.URole.Type.HasValue)
                exp = exp.And(t => unitType.Contains(t.UnitType));

            var temp = agusetempRepository.GetEntity(exp);
            if (temp == null)
                throw new PerformanceException("选择模板不可用，请确定模板及数据是否存在！");

            bool VerifySubmissioAmount(decimal? leftAmount, decimal? rightAmount)
            {
                decimal floatValue = 0m;
                return Math.Abs((rightAmount ?? 0) - (leftAmount ?? 0)) <= floatValue;
            }

            if (temp.UseTempId == 6)
            {
                var data = agothersourceRepository.GetEntities(t => t.SecondId == second.Id);
                if (data == null || !data.Any())
                    throw new PerformanceException("提交时未检测到数据!");

                var total = data.Sum(t => (t.DistPerformance ?? 0) + (t.NightWorkPerformance ?? 0));   // 其他模板 = 可分配绩效 + 夜班绩效
                if (!VerifySubmissioAmount(total, second.RealGiveFee))
                    throw new PerformanceException($"总金额与考核后金额不一致！可分配金额：{second.RealGiveFee}，提交金额：{total}");

                var submitType = temp.UseTempId == 6 ? 2 : 1;
                var res = agsecondallotRepository.Submit(second.Id, temp.UseTempId ?? 0, total, submitType);
                if (res == 0)
                    throw new PerformanceException($"提交失败，当前绩效分配可能发生改变！");
                return true;
            }
            else if (new int[] { 7, 8 }.Contains(temp.UseTempId.Value))
            {
                var data = agfixatitemRepository.GetEntities(t => t.SecondId == second.Id);
                if (data == null || !data.Any())
                    throw new PerformanceException("提交时未检测到数据!");

                var total = data.Where(t => new string[] { "可分配绩效", "夜班工作量绩效" }.Contains(t.ItemName) && t.RowNumber > -1).GroupBy(t => t.RowNumber)
                    .Sum(t => t.Sum(item => ConvertHelper.To<decimal>(item.ItemValue)));
                if (!VerifySubmissioAmount(total, second.RealGiveFee))
                    throw new PerformanceException($"总金额与考核后金额不一致！可分配金额：{second.RealGiveFee}，提交金额：{total}");

                var submitType = temp.UseTempId == 6 ? 2 : 1;
                var res = agsecondallotRepository.Submit(second.Id, temp.UseTempId ?? 0, total, submitType);
                if (res == 0)
                    throw new PerformanceException($"提交失败，当前绩效分配可能发生改变请刷新后重试！");
                return true;
            }
            else /*if (new int[] { 9, 10 }.Contains(temp.UseTempId.Value))*/
            {
                var data = agbodysourceRepository.GetEntities(t => t.SecondId == second.Id);
                if (data == null || !data.Any())
                    throw new PerformanceException("提交时未检测到数据!");
                else
                {
                    var nightShiftWorkPerforFee = data.Sum(w => w.NightWorkPerformance ?? 0);
                    var total = data.Sum(t => (t.DistPerformance ?? 0) + (t.NightWorkPerformance ?? 0));
                    if (!VerifySubmissioAmount(nightShiftWorkPerforFee, second.NightShiftWorkPerforFee))
                        throw new PerformanceException($"专项绩效金额不一致！专项绩效金额：{second.NightShiftWorkPerforFee ?? 0:0.####}，提交金额：{nightShiftWorkPerforFee:0.####}");
                    else if (!VerifySubmissioAmount(total, second.RealGiveFee))
                        throw new PerformanceException($"总金额与考核后金额不一致！可分配金额：{second.RealGiveFee:0.####}，提交金额：{total:0.####}");
                    else
                    {
                        var submitType = temp.UseTempId == 6 ? 2 : 1;
                        var res = agsecondallotRepository.Submit(second.Id, temp.UseTempId ?? 0, total, submitType);
                        if (res == 0)
                            throw new PerformanceException($"提交失败，当前绩效分配可能发生改变，请刷新后重试！");
                        return true;
                    }
                }
            }
            //logger.LogCritical("程序虽然抛出异常但是还是执行了后续代码");
        }

        /// <summary>
        /// 二次绩效撤回提交
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        /// <exception cref="PerformanceException"></exception>
        public bool RollbackSubmit(int secondId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null)
                throw new PerformanceException("二次分配记录不存在，请确认后重试");

            if (second.Status != 2)
                throw new PerformanceException("该绩效未提交至审核，请确认后重试");

            second.UseTempId = null;
            second.Status = 1;
            second.NursingDeptStatus = 1;
            second.SubmitType = null;
            second.SubmitTime = null;

            return agsecondallotRepository.Update(second);
        }
        /// <summary>
        /// 审核
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <param name="secondId">二次绩效ID</param>
        /// <param name="ispass">1、审核通过 2、驳回</param>
        /// <returns></returns>
        public bool ConfirmAudit(int userId, SecondAuditRequest request)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == request.SecondId);

            if (request.IsPass == 1)
            {
                second.Status = 3;
            }
            else
            {
                second.UseTempId = null;
                second.Status = 4;
            }
            second.AuditUser = userId;
            second.AuditTime = DateTime.Now;
            second.Remark = request.Remark;
            var result = agsecondallotRepository.Update(second);

            // 无论驳回还是通过，都需要清空该科室历史数据
            agsecondallotRepository.DeleteComputeHistory(request.SecondId);
            if (request.IsPass == 1)
                _service.FreezeAllotSync(second.AllotId.Value);
            _service.SecondUseTempRestore();
            _service.RestoreSecondAllot();
            return result;
        }

        /// <summary>
        /// 审计
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="secondIds"></param>
        /// <returns></returns>
        public bool SecondMark(int userId, int[] secondIds)
        {
            var seconds = agsecondallotRepository.GetEntities(t => secondIds.Contains(t.Id));
            if (seconds == null || !seconds.Any())
                throw new PerformanceException("未能找到二次分配核算记录！");

            foreach (var item in seconds)
            {
                item.MarkStatus = 1;
                item.MarkUser = userId;
                item.MarkTime = DateTime.Now;
            }
            return agsecondallotRepository.UpdateRange(seconds.ToArray());
        }
        ///// <summary>
        ///// 审核结束 添加至二次绩效汇总
        ///// </summary>
        ///// <param name="second"></param>
        ///// <param name="isPass"></param>
        ///// <returns></returns>
        //private bool SyncSecondComputeData(ag_secondallot second)
        //{
        //    // 护理部及二次分配审核同时审核完成
        //    var allot = perallotRepository.GetEntity(w => w.ID == second.AllotId);
        //    if (allot == null) return true;

        //    var hospital = hospitalRepository.GetEntity(w => w.ID == allot.HospitalId);
        //    if (hospital == null) return true;

        //    if (hospital.IsOpenNursingDeptAudit == 1 && second.NursingDeptStatus != 3 && new string[] { UnitType.护理组.ToString(), UnitType.其他护理组.ToString() }.Contains(second.UnitType))
        //        return true;

        //    if (second.Status != 3)
        //        return true;

        //    var computes = new List<ag_compute>();

        //    var (tempId, name) = GetUsingTempId(hospital.ID, second);

        //    if (new int[] { (int)Temp.crosswise, (int)Temp.lengthways }.Contains(tempId))
        //    {
        //        var items = agfixatitemRepository.GetEntities(t => t.SecondId == second.Id);
        //        if (items != null && items.Any())
        //        {
        //            var rowNumbers = items.Select(t => t.RowNumber).Where(t => t >= 0)?.Distinct();
        //            if (rowNumbers != null && rowNumbers.Any())
        //            {
        //                foreach (var item in rowNumbers)
        //                {
        //                    var perforsumfee = ConvertHelper.TryDecimal(items.FirstOrDefault(t => t.RowNumber == item && t.ItemName == "可分配绩效")?.ItemValue, 0);
        //                    var nightworkperfor = ConvertHelper.TryDecimal(items.FirstOrDefault(t => t.RowNumber == item && t.ItemName == "夜班工作量绩效")?.ItemValue, 0);
        //                    computes.Add(new ag_compute
        //                    {
        //                        AllotId = second.AllotId,
        //                        SecondId = second.Id,
        //                        UnitType = second.UnitType,
        //                        Department = second.Department,
        //                        JobNumber = items.FirstOrDefault(t => t.RowNumber == item && t.ItemName == "人员工号")?.ItemValue,
        //                        WorkPost = items.FirstOrDefault(t => t.RowNumber == item && t.ItemName == "岗位")?.ItemValue,
        //                        PersonName = items.FirstOrDefault(t => t.RowNumber == item && t.ItemName == "姓名")?.ItemValue,
        //                        PerforSumFee = perforsumfee,
        //                        OthePerfor = ConvertHelper.TryDecimal(items.FirstOrDefault(t => t.RowNumber == item && t.ItemName == "医院其他绩效")?.ItemValue, 0),
        //                        NightWorkPerfor = nightworkperfor,
        //                        RealGiveFee = perforsumfee + nightworkperfor,
        //                    });
        //                }
        //            }
        //        }
        //    }
        //    else if (tempId == (int)Temp.other)
        //    {
        //        var others = agothersourceRepository.GetEntities(t => t.SecondId == second.Id);
        //        if (others != null && others.Any())
        //        {
        //            foreach (var item in others)
        //            {
        //                computes.Add(new ag_compute
        //                {
        //                    AllotId = second.AllotId,
        //                    SecondId = second.Id,
        //                    UnitType = second.UnitType,
        //                    Department = second.Department,
        //                    WorkPost = item.WorkPost,
        //                    JobNumber = item.WorkNumber,
        //                    PersonName = item.Name,
        //                    PerforSumFee = item.DistPerformance,
        //                    OthePerfor = item.OtherPerformance,
        //                    NightWorkPerfor = item.NightWorkPerformance,
        //                    RealGiveFee = item.RealAmount,
        //                });
        //            }
        //        }
        //    }
        //    else
        //    {
        //        var bodys = agbodysourceRepository.GetEntities(t => t.SecondId == second.Id);
        //        if (bodys != null && bodys.Any())
        //        {
        //            foreach (var item in bodys)
        //            {
        //                computes.Add(new ag_compute
        //                {
        //                    AllotId = second.AllotId,
        //                    SecondId = second.Id,
        //                    UnitType = second.UnitType,
        //                    Department = second.Department,
        //                    WorkPost = item.JobTitle,
        //                    JobNumber = item.WorkNumber,
        //                    PersonName = item.Name,
        //                    PerforSumFee = item.DistPerformance,
        //                    OthePerfor = item.OtherPerformance,
        //                    NightWorkPerfor = item.NightWorkPerformance,
        //                    RealGiveFee = item.RealAmount,
        //                });
        //            }
        //        }
        //    }
        //    agcomputeRepository.AddRange(computes.ToArray());

        //    return true;
        //}

        /// <summary>
        /// 护理部审核
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <param name="secondId">二次绩效ID</param>
        /// <param name="ispass">1、审核通过 2、驳回</param>
        /// <returns></returns>
        public bool NursingDeptAudit(int userId, SecondAuditRequest request)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
            if (second == null)
                throw new PerformanceException("二次分配绩效无效");
            if (request.IsPass == 1)
            {
                second.NursingDeptStatus = 3;
                second.NursingDeptRemark = $"{request.Remark}";
            }
            else
            {
                // 护理部审核 不修改 模板信息 20210926 zry
                //second.UseTempId = null;
                second.NursingDeptStatus = 4;
                second.NursingDeptRemark = $"{request.Remark}";
            }
            second.NursingDeptAuditUser = userId;
            second.NursingDeptAuditTime = DateTime.Now;

            //if (request.IsPass == 1)
            //    SyncSecondComputeData(second);

            return agsecondallotRepository.Update(second);
        }

        #endregion 二次绩效考核

        #region common

        /// <summary>
        /// 获取二次绩效
        /// </summary>
        /// <param name="secondId">二次绩效Id</param>
        /// <returns></returns>
        public ag_secondallot GetSecondAllot(int secondId)
        {
            return agsecondallotRepository.GetEntity(t => t.Id == secondId);
        }


        /// <summary>
        /// 获取 列
        /// </summary>
        /// <param name="tempId">模板Id</param>
        /// <param name="hospitalId">医院Id</param>
        /// <param name="department">科室</param>
        /// <param name="unitType">核算单元类型</param>
        /// <returns></returns>
        public List<HeadItem> GetHeadItems(int tempId, int hospitalId, string department, string unitType)
        {
            var tempItem = agtempitemRepository.GetEntities(t => t.TempId == tempId);

            var headItems = _mapper.Map<List<HeadItem>>(tempItem) ?? new List<HeadItem>();

            var temp = agtempRepository.GetEntity(w => w.Id == tempId);

            // 其他来源不考虑工作量
            if (temp?.Id == 6)
                return headItems;

            //获取工作量列头
            var workItem = agworkloadRepository.GetEntities(t => t.HospitalId == hospitalId && t.Department == department && t.UnitType == unitType);
            if (workItem != null && workItem.Count > 0)
            {
                var workDtos = _mapper.Map<List<HeadItem>>(workItem.Where(t => t.WorkTypeId != (int)AgWorkloadType.SingleAwards));
                workDtos.ForEach(t => { t.Type = 3; });
                headItems.AddRange(workDtos);

                workDtos = _mapper.Map<List<HeadItem>>(workItem.Where(t => t.WorkTypeId == (int)AgWorkloadType.SingleAwards));
                workDtos.ForEach(t => { t.Type = 4; });
                headItems.AddRange(workDtos);
            }
            return headItems;
        }

        /// <summary>
        /// 获取 展示数据
        /// </summary>
        /// <param name="headItems">列</param>
        /// <param name="source">数据来源 1. 二次绩效配置 2. 保存数据 </param>
        /// <param name="configs">二次绩效配置</param>
        /// <param name="fixatitems">保存数据</param>
        /// <param name="row">行号</param>
        /// <returns></returns>
        public List<BodyItem> GetBodyItems(List<HeadItem> headItems, int source, List<cof_again> configs = null, List<ag_fixatitem> fixatitems = null, int? row = null)
        {
            var bodyItems = new List<BodyItem>();
            foreach (var item in headItems)
            {
                var bodyItem = new BodyItem
                {
                    RowNumber = source == 1 ? -1 : row.Value,
                    FiledId = item.FiledId,
                    FiledName = item.FiledName,
                    FactorValue = item.FactorValue,
                    SourceType = item.SourceType,
                    Type = item.Type,
                    Sort = item.Sort,
                    Value = source == 1 ? configs.FirstOrDefault(t => t.TypeName == item.FiledName)?.Value.ToString()
                                : fixatitems.FirstOrDefault(t => t.RowNumber == row && t.ItemName == item.FiledName)?.ItemValue
                };
                bodyItems.Add(bodyItem);
            }
            return bodyItems;
        }

        #endregion common

        #region 二次绩效其他来源

        public List<ag_othersource> OtherList(int secondId, int userId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null) throw new PerformanceException("二次绩效信息无效！");

            var employees = personService.GetPersons(second.AllotId.Value, userId);
            employees = employees?.Where(t => t.UnitType == second.UnitType).ToList();

            List<ag_othersource> result = null;
            var otherSecondList = agothersourceRepository.GetEntities(t => t.SecondId == secondId);
            if (otherSecondList != null && otherSecondList.Any())
            {
                result = otherSecondList.OrderBy(t => t.Id).ToList();
            }
            else
            {
                if (employees == null || !employees.Any(t => t.UnitType == second.UnitType))
                    return new List<ag_othersource>();
                result = employees.Select(t => new ag_othersource
                {
                    SecondId = secondId,
                    WorkNumber = t.PersonnelNumber,
                    Name = t.DoctorName,
                    Department = t.Department,
                    WorkPost = t.JobTitle,
                }).ToList();
            }
            var isSupplementTitlePerformance = otherSecondList == null || !otherSecondList.Any();
            SupplementSecondDetail(second, employees, result, isSupplementTitlePerformance);

            return result;
        }

        /// <summary>
        /// 二次绩效录入页面其他模板自动补全
        /// </summary>
        /// <param name="secondId"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<ag_othersource> OtherAutoComplete(SecondEmpRequest request, int userId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
            if (second == null)
                throw new PerformanceException("当前科室二次分配绩效信息无效");

            var allot = perallotRepository.GetEntity(w => w.ID == second.AllotId);
            if (allot == null)
                throw new PerformanceException("当前绩效信息无效");

            var usetemp = agusetempRepository.GetEntity(
                t => t.HospitalId == allot.HospitalId && t.Department == second.Department && t.UnitType == second.UnitType);
            if (usetemp == null)
                throw new PerformanceException("当前科室暂未配置绩效模板");

            //获取固定模板列 + 工作量列
            var headItems = GetHeadItems(request.TempId, usetemp.HospitalId.Value, usetemp.Department, usetemp.UnitType);

            #region 接口响应速度优化
            var employees = new List<per_employee>();

            if (!string.IsNullOrEmpty(request?.EmployeeName))
                employees = peremployeeRepository.GetEntities(w => w.AllotId == second.AllotId.Value && w.DoctorName == request.EmployeeName);
            if (!string.IsNullOrEmpty(request?.JobNumber))
                employees = peremployeeRepository.GetEntities(w => w.AllotId == second.AllotId.Value && w.PersonnelNumber == request.JobNumber);
            #endregion

            if (employees == null) return new List<ag_othersource>();


            List<ag_othersource> result = employees
                .Select(t => new ag_othersource
                {
                    SecondId = request.SecondId,
                    WorkNumber = t.PersonnelNumber,
                    Name = t.DoctorName,
                    Department = t.Department,
                    WorkPost = t.JobTitle,
                }).ToList();

            SupplementSecondDetail(second, employees, result);

            return result;
        }

        /// <summary>
        /// 补充二次分配 人员明细
        /// </summary>
        /// <param name="second"></param>
        /// <param name="employees"></param>
        /// <param name="result"></param>
        /// <param name="isTitlePerformance">是否补全职称绩效</param>
        private void SupplementSecondDetail(ag_secondallot second, List<per_employee> employees, List<ag_othersource> result, bool isTitlePerformance = true)
        {
            //if (employees == null || !employees.Any(t => t.UnitType == second.UnitType))
            //    return;
            // 补充医院其他绩效  及  预留比例
            var perapramounts = perapramountRepository.GetEntities(t => t.AllotId == second.AllotId && t.Status == 3);
            Func<per_employee, decimal?> getAprAmount = (t) => second.Department == t.AccountingUnit && second.UnitType == t.UnitType
            ? perapramounts?.Where(w => w.PersonnelNumber?.Trim() == t.PersonnelNumber?.Trim())?.Sum(w => w.Amount)
            : 0;

            var distPerformance = rescomputeRepository.GetEntities(t => t.AllotID == second.AllotId && employees.Select(s => s.PersonnelNumber).Contains(t.JobNumber));
            Func<per_employee, decimal?> getDistPerformance = (t) => 0;
            if (UnitTypeUtil.IsOffice(second.UnitType))
                getDistPerformance = (t) => second.Department == t.AccountingUnit ? distPerformance
                ?.Where(w => w.JobNumber?.Trim() == t.PersonnelNumber?.Trim())
                ?.Sum(w => w.GiveFee) : 0;

            foreach (var item in result)
            {
                var empl = employees.FirstOrDefault(w => w.PersonnelNumber?.Trim() == item.WorkNumber?.Trim());
                if (empl != null)
                {
                    item.ReservedRatio = empl.ReservedRatio;
                    item.OtherPerformance = getAprAmount(empl);
                    if (isTitlePerformance)
                        item.TitlePerformance = getDistPerformance(empl);
                }
            }
        }

        public Dictionary<string, string> OtherListHeader(int secondId, decimal? amount)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null) return new Dictionary<string, string>();

            var keyValue = new Dictionary<string, string>
            {
                {"发放月份",  $"{second.Year}年{second.Month.ToString().PadLeft(2, '0')}月"},
                {"绩效合计(考核后)",  second.RealGiveFee.ToString()},
                {"业绩分配绩效总额",  (second.RealGiveFee - (amount ?? 0)).ToString()},
            };

            return keyValue;
        }

        public List<ag_othersource> OtherSave(int secondId, List<ag_othersource> request)
        {
            if (request == null || !request.Any()) return new List<ag_othersource>();

            if (request.Any(t => t.Id != 0))
                agothersourceRepository.UpdateRangeByState(request.Where(t => t.Id != 0));

            var existEntities = agothersourceRepository.GetEntities(t => t.SecondId == secondId);
            if (existEntities != null && existEntities.Any())
            {
                var delIds = existEntities.Select(t => t.Id).Except(request.Select(t => t.Id));
                if (delIds != null)
                    agothersourceRepository.RemoveRange(existEntities.Where(t => delIds.Contains(t.Id)).ToArray());
            }

            var addEntities = request.Where(t => t.Id == 0).ToList();
            if (addEntities != null && addEntities.Any())
            {
                addEntities.ForEach(t => t.SecondId = secondId);
                agothersourceRepository.AddRange(addEntities.ToArray());
            }
            return agothersourceRepository.GetEntities(t => t.SecondId == secondId);
        }

        public void OtherSave(int secondId, SaveCollectData collectData)
        {
            if (collectData.ColHeaders == null || !collectData.ColHeaders.Any()) return;

            var parameters = new List<string>();
            foreach (var item in collectData.ColHeaders)
            {
                if (!SecondAllotDetails.OtherTemp.ContainsValue(item)) throw new PerformanceException($"请确认列'{item}'是否正确");
                parameters.Add(SecondAllotDetails.OtherTemp.FirstOrDefault(t => t.Value == item).Key);
            }
            if (parameters == null || !parameters.Any()) return;

            List<Dictionary<string, object>> result = new List<Dictionary<string, object>>();
            foreach (var item in collectData.Data)
            {
                var list = item.ToList();
                Dictionary<string, object> dict = new Dictionary<string, object>();
                parameters.ForEach(t =>
                {
                    dict.Add(t, list[parameters.IndexOf(t)]);
                });
                result.Add(dict);
            }

            var json = JsonHelper.Serialize(result);
            var data = JsonHelper.Deserialize<List<ag_othersource>>(json);
            data = data.Where(t => !string.IsNullOrEmpty(t.WorkNumber) || !string.IsNullOrEmpty(t.Name))?.ToList();
            if (data == null || !data.Any()) return;

            var existEntities = agothersourceRepository.GetEntities(t => t.SecondId == secondId);
            if (existEntities != null && existEntities.Any())
            {
                agothersourceRepository.RemoveRange(existEntities.ToArray());
            }

            data.ForEach(t => t.SecondId = secondId);
            agothersourceRepository.AddRange(data.ToArray());
        }

        #endregion 二次绩效其他来源

        #region 打印

        public dynamic Print(int secondId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null) return new List<SecPrintResponse>();

            var status = new int[] { (int)SecondAllotStatus.WaitReview, (int)SecondAllotStatus.PassAudit };
            if (!second.Status.HasValue || !status.Contains(second.Status.Value))
                throw new PerformanceException("当前科室分配结果未提交，无法打印！");

            if (!second.UseTempId.HasValue)
                throw new PerformanceException("当前科室分配模板信息错误！");

            var useTempId = second.UseTempId.Value;

            List<SecPrintResponse> result = new List<SecPrintResponse>();
            SecPrintHeaderResponse header = new SecPrintHeaderResponse();
            if (useTempId == 6)
            {
                var data = agothersourceRepository.GetEntities(t => t.SecondId == secondId);
                if (data == null || !data.Any()) return new List<SecPrintResponse>();

                result = _mapper.Map<List<SecPrintResponse>>(data);

                header.TotalDistPerformance = second.RealGiveFee ?? 0;
                header.HosOtherPerformance = result.Sum(t => t.OtherPerformance ?? 0);
                header.NightShiftWorkPerforTotal = result.Sum(t => t.NightWorkPerformance ?? 0);
                header.TotalPerformance = result.Sum(t => t.DistPerformance ?? 0);
            }
            else if ((new int[] { 9, 10 }).Contains(useTempId))
            {
                var data = agbodysourceRepository.GetEntities(t => t.SecondId == secondId);
                if (data == null || !data.Any()) return new List<SecPrintResponse>();

                var bodyDynamic = agworkloadsourceRepository.GetEntities(t => data.Select(w => w.Id).Contains(t.BodyId));
                if (data == null || !data.Any()) return new List<SecPrintResponse>();

                result = data.Select(w => new SecPrintResponse
                {
                    JobNumber = w.WorkNumber,
                    PersonName = w.Name,
                    Department = w.Department,
                    RealAmount = w.RealAmount,
                    WorkPost = w.Post,
                    TitlePerfor = w.TitlePerformance,
                    WorkPerformance = bodyDynamic?.Where(b => b.BodyId == w.Id && b.ItemId.StartsWith("WorkPerformance_")).Sum(b => b.Value) ?? 0,
                    DeptReward = w.DeptReward,
                    PreDeptReward = w.PreDeptReward,
                    DistPerformance = w.DistPerformance,
                    OtherPerformance = w.OtherPerformance,
                    NightWorkPerformance = w.NightWorkPerformance,
                }).ToList();

                var headerdata = agheadsourceRepository.GetEntity(t => t.SecondId == secondId);

                header = _mapper.Map<SecPrintHeaderResponse>(headerdata);
                //header.HosOtherPerformance = result.Sum(t => t.OtherPerformance ?? 0);
            }
            else if ((new int[] { 7, 8 }).Contains(useTempId))
            {
                var itemname = new List<string> { "人员工号", "姓名", "职称", "职称绩效", "工作量绩效工资", "单项奖励小计", "可分配绩效", "医院其他绩效", "夜班工作量绩效" };
                var fixaitems = agfixatitemRepository.GetEntities(t => t.SecondId == secondId && itemname.Contains(t.ItemName));

                if (fixaitems == null || !fixaitems.Any(t => t.RowNumber.HasValue && t.RowNumber != -1)) return new List<SecPrintResponse>();

                var rownumbers = fixaitems.Where(t => t.RowNumber.HasValue && t.RowNumber != -1).Select(t => t.RowNumber.Value).Distinct().OrderBy(t => t).ToList();

                foreach (var rownumber in rownumbers)
                {
                    var distperfor = ConvertHelper.ToDecimalOrNull(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "可分配绩效")?.ItemValue);
                    var nightworkperfor = ConvertHelper.ToDecimalOrNull(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "夜班工作量绩效")?.ItemValue);
                    var sec = new SecPrintResponse
                    {
                        JobNumber = fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "人员工号")?.ItemValue,
                        PersonName = fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "姓名")?.ItemValue,
                        Department = second.Department,
                        RealAmount = (distperfor ?? 0) + (nightworkperfor ?? 0),
                    };
                    sec.WorkPost = fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "职称")?.ItemValue;
                    sec.TitlePerfor = ConvertHelper.ToDecimalOrNull(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "职称绩效")?.ItemValue);
                    sec.WorkPerformance = ConvertHelper.ToDecimalOrNull(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "工作量绩效工资")?.ItemValue);
                    sec.DeptReward = ConvertHelper.ToDecimalOrNull(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "单项奖励小计")?.ItemValue);
                    sec.DistPerformance = distperfor;
                    sec.OtherPerformance = ConvertHelper.ToDecimalOrNull(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "医院其他绩效")?.ItemValue);
                    sec.NightWorkPerformance = nightworkperfor;
                    result.Add(sec);
                }

                fixaitems = agfixatitemRepository.GetEntities(t => t.SecondId == secondId && t.RowNumber == -1);
                if (fixaitems != null && fixaitems.Any())
                {
                    header.TotalDistPerformance = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "科室总绩效")?.ItemValue);
                    header.TotalPerformance = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "可分配绩效")?.ItemValue);
                    header.TheTotalAllocationOfPerformanceResults = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "科室单项奖励")?.ItemValue);
                    header.DirectorBasisPerformance = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "主任基础绩效")?.ItemValue);
                    header.NightShiftWorkPerforTotal = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "夜班绩效总和")?.ItemValue);
                    header.HosOtherPerformance = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "医院其他绩效")?.ItemValue);
                    header.SeniorityTitlesAccountedPerformance = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "年资职称绩效占比")?.ItemValue);
                    header.SeniorityTitlesPerformance = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "年资职称绩效")?.ItemValue);
                    header.Workload_Ratio_Default = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "工作量绩效占比")?.ItemValue);
                    header.Workload_Amount_Default = ConvertHelper.To<decimal>(fixaitems.FirstOrDefault(t => t.ItemName == "工作量分配绩效金额")?.ItemValue);
                }
            }
            else
            {
                var data = agbodysourceRepository.GetEntities(t => t.SecondId == secondId);
                if (data == null || !data.Any()) return new List<SecPrintResponse>();

                var bodyDynamic = agworkloadsourceRepository.GetEntities(t => data.Select(w => w.Id).Contains(t.BodyId));
                if (data == null || !data.Any()) return new List<SecPrintResponse>();

                result = data.Select(w => new SecPrintResponse
                {
                    JobNumber = w.WorkNumber,
                    PersonName = w.Name,
                    Department = w.Department,
                    RealAmount = w.RealAmount,
                    WorkPost = w.JobTitle,
                    TitlePerfor = w.TitlePerformance,
                    WorkPerformance = w.WorkPerformance,
                    DeptReward = w.DeptReward,
                    PreDeptReward = w.PreDeptReward,
                    DistPerformance = w.DistPerformance,
                    OtherPerformance = w.OtherPerformance,
                    NightWorkPerformance = w.NightWorkPerformance,
                }).ToList();

                var headerdata = agheadsourceRepository.GetEntity(t => t.SecondId == secondId);

                header = _mapper.Map<SecPrintHeaderResponse>(headerdata);
            }

            // 补充医院其他绩效  及  预留比例
            var perapramounts = perapramountRepository.GetFullAmount(second.AllotId, 3);
            var employees = personService.GetPerEmployee(second.AllotId.Value);

            // 补充字典中该科室不存在，但有其它绩效的人员信息
            if (perapramounts != null && perapramounts.Any(t => t.AccountingUnit == second.Department))
            {
                var groupData = perapramounts.Where(t => t.AccountingUnit == second.Department).GroupBy(t => t.PersonnelNumber)
                    .Select(t => new SecPrintResponse
                    {
                        JobNumber = t.Key,
                        PersonName = t.FirstOrDefault(w => !string.IsNullOrEmpty(w.DoctorName))?.DoctorName,
                        OtherPerformance = t.Sum(w => w.Amount),
                        RealAmount = t.Sum(w => w.Amount),
                    });

                foreach (var item in groupData)
                {
                    if (!result.Any(w => w.JobNumber == item.JobNumber))
                    {
                        per_employee employee = employees?.FirstOrDefault(t => t.PersonnelNumber == item.JobNumber);
                        if (employee != null && employee.UnitType == second.UnitType)
                        {
                            item.Department = employee.AccountingUnit;
                            item.WorkPost = employee.JobTitle;
                            result.Add(item);
                        }
                    }
                }
            }

            // 重算实发绩效
            foreach (var item in result)
            {
                per_employee employee = employees?.FirstOrDefault(t => t.PersonnelNumber == item.JobNumber);
                if (employee != null)
                    item.ReservedRatio = employee.ReservedRatio ?? 0;
                item.RealAmount = (item.DistPerformance ?? 0) * (1 - (item.ReservedRatio ?? 0)) + (item.OtherPerformance ?? 0) + (item.NightWorkPerformance ?? 0);
            }

            var otherWorktypes = agworktypesourceRepository.GetEntities(t => t.SecondId == secondId);
            if (otherWorktypes != null && otherWorktypes.Any())
            {
                List<TitleValue<decimal>> dict = new List<TitleValue<decimal>>();

                foreach (var worktype in otherWorktypes.OrderBy(t => t.WorkTypeId).ThenBy(t => t.FieldId))
                {
                    dict.Add(new TitleValue<decimal>
                    {
                        Title = worktype.FieldName,
                        Value = worktype.Value ?? 0
                    });
                }

                header.WorkloadTypes = dict;
            }

            return new { header, body = result/*.OrderBy(t => t.JobNumber).ThenBy(t => t.PersonName).ToList()*/ };
        }

        public dynamic NewPrint(int secondId)
        {
            var second = agsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null) return new List<SecPrintResponse>();

            var status = new int[] { (int)SecondAllotStatus.WaitReview, (int)SecondAllotStatus.PassAudit };
            if (!second.Status.HasValue || !status.Contains(second.Status.Value))
                throw new PerformanceException("当前科室分配结果未提交，无法打印！");
            var allotId = second.AllotId ?? 0;
            var allot = perallotRepository.GetEntity(t => t.ID == allotId);

            var header = _service.QuerySecondPrintHead(allotId, second.UnitType, second.Department);
            var body = _service.QuerySecondPrintRow(allotId, second.UnitType, second.Department);
            var column = _service.QueryTableStructure("view_second_print_row");
            var title = $"{allot.Year}年{(string.IsNullOrEmpty(allot.Name) ? $"{allot.Month}月" : allot.Name)}{second.Department}{second.UnitType}绩效分配表";

            return new { title, body, header, column };
        }

        #endregion 打印 

        public List<DeptDataDetails> DeptComputeDetailList(int userId, int allotId, out int isShowManage)
        {
            var userInfo = userRepository.GetUser(userId);
            if (userInfo?.User == null) throw new NotImplementedException("当前用户不存在");
            if (userInfo.URole == null) throw new NotImplementedException("当前用户暂未分配角色");
            if (!userInfo.Hospitals.NotNullOrEmpty()) throw new NotImplementedException("当前用户暂未分配医院");

            var deptDatas = new List<DeptDataDetails>();
            isShowManage = computeService.IsShowManage(allotId);

            var allot = perallotRepository.GetEntity(t => t.ID == allotId);
            // 未下发或未归档 则不可见
            var status = new int[] { (int)AllotStates.绩效下发, (int)AllotStates.归档 };
            if (!status.Contains(allot.States)) return deptDatas;

            // 查询当前角色下科室的绩效
            UnitTypeUtil.Maps.TryGetValue(userInfo?.URole.Type ?? 0, out string[] unitTypes);
            if (unitTypes == null || !unitTypes.Any()) return deptDatas;

            var accountingUnit = userInfo.User.Department;
            var hospitalId = userInfo.HospitalIds.First();
            if (userInfo.IsSecondAdmin)
            {
                var secondList = agsecondallotRepository.Get(allotId, unitTypes, userInfo.User.Department);
                accountingUnit = secondList.FirstOrDefault()?.Department;
                unitTypes = new string[] { secondList.FirstOrDefault()?.UnitType };
            }

            Dictionary<int, List<string>> dict = new Dictionary<int, List<string>>
            {
                { (int)Role.科主任, new List<string>{ AccountUnitType.科主任.ToString()} },
                { (int)Role.护士长, new List<string>{ AccountUnitType.护士长.ToString() } },
                { (int)Role.行政科室, new List<string> { AccountUnitType.行政中层.ToString() } },
                { (int)Role.特殊科室, new List<string> { AccountUnitType.科主任.ToString() , AccountUnitType.护士长.ToString() } },
            };

            int roleType = userInfo?.URole.Type ?? 0;
            var accountTypes = userInfo != null && dict.ContainsKey(roleType) ? dict[roleType] : new List<string>();

            var computes = rescomputeRepository.GetEntities(t => t.AllotID == allotId && t.AccountingUnit == accountingUnit && (unitTypes.Contains(t.UnitType) || accountTypes.Contains(t.AccountType)));
            if (computes == null || !computes.Any()) return new List<DeptDataDetails>();
            foreach (var item in computes)
            {
                if (item.AccountType == AccountUnitType.行政中层.ToString())
                    deptDatas.Add(computeService.GetAdministration(item.ID));
                else
                    deptDatas.Add(computeService.GetDoctorDetail(item.ID));
            }
            return deptDatas;
        }

        /// <summary>
        /// 科主任/护士长管理绩效打印
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="allotId"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public dynamic DeptComputePrint(int userId, int allotId)
        {
            var allot = perallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null) throw new NotImplementedException("当前用户不存在");

            var userInfo = userRepository.GetUser(userId);
            if (userInfo?.User == null) throw new NotImplementedException("当前用户不存在");
            if (userInfo.URole == null) throw new NotImplementedException("当前用户暂未分配角色");
            if (!userInfo.Hospitals.NotNullOrEmpty()) throw new NotImplementedException("当前用户暂未分配医院");

            // 未下发或未归档 则不可见
            var status = new int[] { (int)AllotStates.绩效下发, (int)AllotStates.归档 };
            if (!status.Contains(allot.States)) return new { title = "", body = Array.Empty<dynamic>(), column = Array.Empty<dynamic>() };

            Dictionary<int, string[]> maps = new Dictionary<int, string[]>
            {
                { (int)Role.科主任,   new string[]{ UnitType.医生组.ToString(), UnitType.其他医生组.ToString(), UnitType.医技组.ToString(), UnitType.其他医技组.ToString() } },
                { (int)Role.护士长,   new string[]{ UnitType.护理组.ToString(), UnitType.其他护理组.ToString() } },
                { (int)Role.特殊科室, new string[]{ UnitType.特殊核算组.ToString(), } },
                { (int)Role.行政科室, new string[]{ UnitType.行政中层.ToString(), } },
            };

            // 查询当前角色下科室的绩效
            var accountingUnit = userInfo.User.Department;
            int roleType = userInfo?.URole.Type ?? 0;
            var unitTypes = maps.ContainsKey(roleType) ? maps[roleType] : Array.Empty<string>();
            if (unitTypes?.Any() != true) return new { title = "", body = Array.Empty<dynamic>(), column = Array.Empty<dynamic>() };

            var body = _service.QuerySecondPrintManagement(allotId, unitTypes, accountingUnit);
            var column = _service.QueryTableStructure("view_second_print_management");
            var title = $"{allot.Year}年{(string.IsNullOrEmpty(allot.Name) ? $"{allot.Month}月" : allot.Name)}科主任/护士长管理绩效发放表";

            return new { title, body, column };
        }

        /// <summary>
        /// 获取一次次绩效结果
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private List<SecondPerforResponse> GetAllotPerformance(int allotId, List<res_compute> computes, int isShowManage)
        {
            if (computes == null || !computes.Any()) return new List<SecondPerforResponse>();

            var types1 = new List<string> { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString() };
            var types2 = new List<string> { AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString() };
            // 业务中层人员信息
            var empolyeeList = imemployeeclinicRepository.GetEntities(t => t.AllotID == allotId);

            return computes.Select(t =>
            {
                var comp = new SecondPerforResponse()
                {
                    AccountingUnit = t.AccountingUnit,
                    EmployeeName = t.EmployeeName,
                    JobNumber = t.JobNumber,
                    JobTitle = t.JobTitle,
                    UnitType = t.AccountType,
                    Adjust = t.Adjust,
                    AdjustLaterOtherFee = t.AdjustLaterOtherFee,
                    Scale = t.Scale,
                    Efficiency = t.Efficiency,
                    Grant = t.Grant,
                    ShouldGiveFee = t.ShouldGiveFee,
                };

                // 行政中层  行政高层 补充  夜班费
                if (types2.Contains(t.AccountType))
                    comp.NightWorkPerfor = t.NightWorkPerfor;

                // 科主任/护士长
                if (types1.Contains(t.AccountType))
                {
                    // 等同于考核后管理绩效 AssessLaterManagementFee
                    comp.PerforManagementFee = Math.Round(t.ShouldGiveFee * t.ScoreAverageRate * t.Attendance + t.Punishment ?? 0);
                    // 仅显示管理绩效
                    if (isShowManage == 2)
                        comp.PerforSumFee = 0;
                    else
                        comp.PerforSumFee = t.Avg;
                }

                return comp;
            }).ToList();
        }

        //public List<SecondPerforResponse> AddAprAmount(int allotId, List<SecondPerforResponse> computes)
        //{
        //    if (computes == null || !computes.Any())
        //        return computes;

        //    var list = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Status == 3);
        //    if (list == null || !list.Any())
        //        return computes;

        //    foreach (var item in computes.GroupBy(w => new { w.AccountingUnit, w.JobNumber }))
        //    {
        //        // 补充过一次就不在补充了
        //        var emp = computes.Where(w => w.AccountingUnit == item.Key.AccountingUnit && w.JobNumber == item.Key.JobNumber)
        //            .OrderByDescending(w => w.Source).FirstOrDefault();
        //        var apramount = list.Where(t => t.AccountingUnit == emp.AccountingUnit
        //             && !string.IsNullOrEmpty(t.PersonnelNumber) && emp.JobNumber?.Trim() == t.PersonnelNumber?.Trim());
        //        emp.OthePerfor = apramount?.Sum(w => w.Amount) ?? 0;
        //    }

        //    return computes;
        //}

        public ApiResponse Import(IFormCollection form)
        {
            var secondid = form.ToDictionary().GetValue("secondid", 0);

            var agsecondallot = agsecondallotRepository.GetEntity(t => t.Id == secondid);
            if (agsecondallot == null)
                return new ApiResponse(ResponseType.Fail, "secondid不存在");

            var allot = perallotRepository.GetEntity(t => t.ID == agsecondallot.AllotId);
            if (allot == null)
                return new ApiResponse(ResponseType.Fail, "allotid不存在");

            var file = ((FormFileCollection)form.Files).FirstOrDefault();
            if (file == null)
                return new ApiResponse(ResponseType.Fail, "参数错误", "文件无效");

            if (!ExtractHelper.IsXlsxFile(file.FileName))
                return new ApiResponse(ResponseType.Fail, "文件格式错误", "文件暂只支持xlsx文件");

            var name = FileHelper.GetFileNameNoExtension(file.FileName) + DateTime.Now.ToString("yyyyMMddHHmmssfff");
            var ext = FileHelper.GetExtension(file.FileName);

            var dpath = Path.Combine(_evn.ContentRootPath, "Files", $"{allot.HospitalId}", $"{allot.Year}{allot.Month.ToString().PadLeft(2, '0')}");
            FileHelper.CreateDirectory(dpath);

            var path = Path.Combine(dpath, $"{name}{ext}");

            using (var stream = file.OpenReadStream())
            {
                byte[] bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                if (!FileHelper.CreateFile(path, bytes))
                    return new ApiResponse(ResponseType.Fail, $"{file.FileName}上传失败");
                agsecondallot.AttachFile = path;
                agsecondallot.AttachDate = DateTime.Now;
                agsecondallotRepository.Update(agsecondallot);
                return new ApiResponse(ResponseType.OK, $"{file.FileName}上传成功");
            }
        }

    }
}
