using AutoMapper;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Performance.DtoModels;
using Performance.DtoModels.AppSettings;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Performance.Services
{
    public class SecondAllotService : IAutoInjection
    {
        private readonly Application application;
        private readonly ILogger<SecondAllotService> _logger;
        private readonly PerforHospitalRepository hospitalRepository;
        private readonly PerforUserRepository perforUserRepository;
        private readonly PerforUserhospitalRepository perforUserhospitalRepository;
        private readonly PerforPerallotRepository perforPerallotRepository;
        private readonly PerforAgsecondallotRepository perforAgsecondallotRepository;
        private readonly PerforResaccountRepository perforResaccountRepository;
        private readonly PerforUserroleRepository userroleRepository;
        private readonly PerforAgworkloadRepository perforAgworkloadRepository;
        private readonly PerforAgtempRepository perforAgtempRepository;
        private readonly PerforAgtempitemRepository perforAgtempitemRepository;
        private readonly PerforAgfixatitemRepository perforAgfixatitemRepository;
        private readonly PerforAgusetempRepository perforAgusetempRepository;
        private readonly PerforAgcomputeRepository perforAgcomputeRepository;
        private readonly PerforCofagainRepository perforCofagainRepository;
        private readonly PerforAgothersourceRepository perforAgothersourceRepository;
        private readonly PerforAgworkloadtypeRepository perforAgworkloadtypeRepository;
        private readonly PerforRoleRepository roleRepository;
        private readonly PerforPerapramountRepository perapramountRepository;
        private readonly PerforResspecialunitRepository resspecialunitRepository;
        private readonly PersonService personService;
        private readonly ComputeService computeService;
        private readonly PerforRescomputeRepository rescomputeRepository;
        private readonly PerforPeremployeeRepository peremployeeRepository;
        private readonly PerforImemployeeclinicRepository imemployeeclinicRepository;
        private readonly List<ag_tempitem> tempitems = new List<ag_tempitem>();

        public SecondAllotService(IOptions<Application> application,
            ILogger<SecondAllotService> logger,
            PerforHospitalRepository hospitalRepository,
            PerforUserRepository perforUserRepository,
            PerforUserhospitalRepository perforUserhospitalRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforAgsecondallotRepository perforAgsecondallotRepository,
            PerforResaccountRepository perforResaccountRepository,
            PerforUserroleRepository userroleRepository,
            PerforAgworkloadRepository perforAgworkloadRepository,
            PerforAgtempRepository perforAgtempRepository,
            PerforAgtempitemRepository perforAgtempitemRepository,
            PerforAgfixatitemRepository perforAgfixatitemRepository,
            PerforAgusetempRepository perforAgusetempRepository,
            PerforAgcomputeRepository perforAgcomputeRepository,
            PerforCofagainRepository perforCofagainRepository,
            PerforAgothersourceRepository perforAgothersourceRepository,
            PerforAgworkloadtypeRepository perforAgworkloadtypeRepository,
            PerforRoleRepository roleRepository,
            PerforPerapramountRepository perapramountRepository,
            PerforResspecialunitRepository resspecialunitRepository,
            PersonService personService,
            ComputeService computeService,
            PerforRescomputeRepository rescomputeRepository,
            PerforPeremployeeRepository peremployeeRepository,
            PerforImemployeeclinicRepository imemployeeclinicRepository)
        {
            this.application = application.Value;
            _logger = logger;
            this.hospitalRepository = hospitalRepository;
            this.perforUserRepository = perforUserRepository;
            this.perforUserhospitalRepository = perforUserhospitalRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforAgsecondallotRepository = perforAgsecondallotRepository;
            this.perforResaccountRepository = perforResaccountRepository;
            this.userroleRepository = userroleRepository;
            this.perforAgworkloadRepository = perforAgworkloadRepository;
            this.perforAgtempRepository = perforAgtempRepository;
            this.perforAgtempitemRepository = perforAgtempitemRepository;
            this.perforAgfixatitemRepository = perforAgfixatitemRepository;
            this.perforAgusetempRepository = perforAgusetempRepository;
            this.perforAgcomputeRepository = perforAgcomputeRepository;
            this.perforCofagainRepository = perforCofagainRepository;
            this.perforAgothersourceRepository = perforAgothersourceRepository;
            this.perforAgworkloadtypeRepository = perforAgworkloadtypeRepository;
            this.roleRepository = roleRepository;
            this.perapramountRepository = perapramountRepository;
            this.resspecialunitRepository = resspecialunitRepository;
            this.personService = personService;
            this.computeService = computeService;
            this.rescomputeRepository = rescomputeRepository;
            this.peremployeeRepository = peremployeeRepository;
            this.imemployeeclinicRepository = imemployeeclinicRepository;
            this.tempitems = perforAgtempitemRepository.GetEntities();
        }

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

        /// <summary>
        /// 获取二次绩效列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<SecondListResponse> GetSecondList(int userId)
        {
            var user = perforUserRepository.GetEntity(t => t.ID == userId);
            if (user == null)
                throw new NotImplementedException("人员ID无效");
            var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
            var role = roleRepository.GetEntity(t => t.ID == userrole.RoleID);
            var hospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
            if (hospital == null)
                throw new NotImplementedException("人员未选择医院");
            var allotList = perforPerallotRepository.GetEntities(t => t.HospitalId == hospital.HospitalID && new List<int> { 6, 8, 10 }.Contains(t.States));
            if (allotList == null || allotList.Count == 0)
                return new List<SecondListResponse>();

            var allotListId = allotList.Select(t => t.ID).ToList();
            Expression<Func<ag_secondallot, bool>> exp = t => allotListId.Contains(t.AllotId.Value) && t.Department == user.Department;
            if (role.Type == application.DirectorRole)
                exp = exp.And(t => new List<string> { UnitType.医生组.ToString(), UnitType.其他医生组.ToString(), UnitType.其他医技组.ToString(), UnitType.医技组.ToString() }.Contains(t.UnitType));
            else if (role.Type == application.NurseRole)
                exp = exp.And(t => t.UnitType == UnitType.护理组.ToString() || t.UnitType == UnitType.其他护理组.ToString());
            else if (role.Type == application.SpecialRole)
                exp = exp.And(t => t.UnitType == UnitType.特殊核算组.ToString());
            else if (role.Type == application.OfficeRole)
                exp = exp.And(t => t.UnitType == UnitType.行政后勤.ToString());

            var secondList = perforAgsecondallotRepository.GetEntities(exp);
            var list = Mapper.Map<List<SecondListResponse>>(secondList);
            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;
                }
            });
            return list;
        }

        #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 = perforAgfixatitemRepository.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 = perforAgfixatitemRepository.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 = perforAgsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
            if (second == null)
                throw new PerformanceException("当前科室二次分配绩效信息无效");

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

            var usetemp = perforAgusetempRepository.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(employees, 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 = perforAgusetempRepository.GetEntity(t => t.HospitalId == request.HospitalId
            && t.Department == request.Department && t.UnitType == request.UnitType);   //获取科室二次绩效费用分配使用的模板
            if (usetemp == null)
                throw new PerformanceException("当前科室暂未配置绩效模板");

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

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

            var result = new SecondResponse();

            var fixatList = perforAgfixatitemRepository.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(employees, second, userId, headItems, second.UnitType));
                    }
                }
                else
                {
                    //无数据 根据IsBring带出历史二次绩效中需要带出的数据
                    //result.BodyItems = GetBringItems(request, headItems);
                    var employees = personService.GetPersons(second.AllotId.Value, userId);
                    result.BodyItems = GetEmployees(employees, 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.WorkType).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 = perforAgsecondallotRepository.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(List<per_employee> employees, ag_secondallot second, int userId, List<HeadItem> heads, string unittype, string empName = "", string jobNumber = "")
        {
            var list = new List<BodyItem>();

            //var employees = personService.GetPersons(allotId, userId);
            if (employees == null || !employees.Any()) return list;

            var hospital = hospitalRepository.GetEntity(t => t.ID == employees.First().HospitalId);
            if (hospital == null) return list;

            if (string.IsNullOrEmpty(empName) && string.IsNullOrEmpty(jobNumber))
                employees = employees.Where(t => t.UnitType == unittype).ToList();

            if (!string.IsNullOrEmpty(empName))
                employees = employees?.Where(w => w.DoctorName?.Trim() == empName?.Trim()).ToList();
            if (!string.IsNullOrEmpty(jobNumber))
                employees = employees?.Where(w => !string.IsNullOrEmpty(w.PersonnelNumber) && w.PersonnelNumber.Trim() == jobNumber.Trim()).ToList();

            var perapramounts = perapramountRepository.GetEntities(t => t.AllotId == second.AllotId && t.Status == 3);
            Func<per_employee, decimal?> getAprAmount = (t) => second.Department == t.AccountingUnit ? 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)},
            };

            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++;
            }

            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 = 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);
                var fixatList = new List<ag_fixatitem>();
                if (index != 0)
                    fixatList = perforAgfixatitemRepository.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 account = perforResaccountRepository.GetEntity(t => t.AllotID == second.AllotId && t.AccountingUnit == second.Department && ((UnitType)t.UnitType).ToString() == second.UnitType);

            var keyValue = new Dictionary<string, string>
            {
                {"发放月份",  $"{second.Year}年{second.Month.ToString().PadLeft(2, '0')}月"},
                {"可分配绩效",  second.RealGiveFee.ToString()},
                //{"主任基础绩效", account?.Avg?.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 = perforCofagainRepository.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 = perforAgworkloadtypeRepository.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;
                        headItem.WorkType = item.Id;
                        headerItems.Add(headItem);
                        sortindex++;
                    }
                }
            }
            var defauleHeader = new List<ag_workload_type>
            {
                new ag_workload_type { Id = 2, TypeName = "工作量绩效占比", },
                new ag_workload_type { Id = 2, TypeName = "工作量分配绩效金额" },
            };
            foreach (var item in defauleHeader)
            {
                result.HeadItems.Where(t => t.FiledName == item.TypeName).ToList()?.ForEach(t =>
                {
                    t.WorkType = item.Id;
                    t.SpecialAttr = item.TypeName.IndexOf("占比") > -1 ? 1 : 2;
                });
                result.BodyItems.Where(t => t.FiledName == item.TypeName).ToList()?.ForEach(t =>
                {
                    t.WorkType = item.Id;
                    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 = perforAgsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null)
                throw new PerformanceException("二次绩效ID不存在");

            var fixatitems = perforAgfixatitemRepository.GetEntities(t => t.SecondId == secondId);
            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 = perforAgfixatitemRepository.UpdateRange(update.ToArray());
            result = perforAgfixatitemRepository.AddRange(insert.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 = perforAgfixatitemRepository.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 = perforAgfixatitemRepository.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 = perforAgfixatitemRepository.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 = perforAgsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second == null)
                throw new PerformanceException("二次绩效ID不存在");
            if (second.Status == 2)
                throw new PerformanceException("二次绩效已提交，无法重复提交");

            var compute = perforAgcomputeRepository.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;
                    perforAgcomputeRepository.Update(cellItem);
                }
                else
                {
                    perforAgcomputeRepository.Add(item);
                }
            }
            return true;
        }

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

        #region 模板

        /// <summary>
        /// 获取模板列表
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<SecondTempResponse> GetTemp(int hospitalid, string department, int userId)
        {
            var temps = perforAgtempRepository.GetEntities(t => t.IsEnable == 1);
            if (temps != null && temps.Any())
            {
                var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
                var role = roleRepository.GetEntity(t => t.ID == userrole.RoleID);

                Dictionary<int, string[]> dic = new Dictionary<int, string[]>
                {
                    { application.DirectorRole, new[]{ UnitType.医生组.ToString(), UnitType.其他医生组.ToString(), UnitType.医技组.ToString(), UnitType.其他医技组.ToString() } },
                    { application.NurseRole, new[]{ UnitType.护理组.ToString(), UnitType.其他护理组.ToString()} },
                    { application.SpecialRole, new[]{ UnitType.特殊核算组.ToString() }},
                    { application.OfficeRole, new[]{ UnitType.行政后勤.ToString() } },
                };

                Expression<Func<ag_usetemp, bool>> exp = t => t.HospitalId == hospitalid && t.Department == department;
                if (role.Type.HasValue && dic.ContainsKey(role.Type.Value))
                    exp = exp.And(t => dic[role.Type.Value].Contains(t.UnitType));

                var useTemp = perforAgusetempRepository.GetEntity(exp);
                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 entity = perforAgusetempRepository.GetEntity(t => t.HospitalId == request.HospitalId
            && t.Department == request.Department && t.UnitType == request.UnitType);
            if (entity == null)
            {
                entity = Mapper.Map<ag_usetemp>(request);
                result = perforAgusetempRepository.Add(entity);
            }
            else
            {
                entity.UseTempId = request.TempId;
                result = perforAgusetempRepository.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 = perforPerallotRepository.GetEntities(t => t.HospitalId == request.HospitalId);
                    var seconds = perforAgsecondallotRepository.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 = perforAgfixatitemRepository.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 = perforCofagainRepository.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);
                    //    perforAgfixatitemRepository.RemoveRange(delList.Where(w => w.SecondId == request.SecondId).ToArray());

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

        /// <summary>
        /// 应用模板
        /// </summary>
        /// <returns></returns>
        public void RefreshTemp(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("参数usetempId 无效");
            //获取工作量列头
            var workItem = perforAgworkloadRepository.GetEntities(t => t.HospitalId == usetemp.HospitalId && t.Department == usetemp.Department && t.UnitType == usetemp.UnitType);
            //获取固定模板列头
            var tempItem = perforAgtempitemRepository.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 = perforAgfixatitemRepository.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;
            });
            perforAgfixatitemRepository.UpdateRange(fixatList.ToArray());
            //删除  列 不存在的数据
            var header = fixatList.Select(t => t.ItemName).Distinct();
            var delItems = header.Except(tempHeader);
            if (delItems != null && delItems.Count() > 0)
                perforAgfixatitemRepository.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)
                perforAgfixatitemRepository.AddRange(addItems.ToArray());
        }

        #endregion 模板

        #region 工作量绩效配置

        /// <summary>
        /// 获取工作量列表
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public List<ag_workload> GetWorkloadList(WorkloadRequest request)
        {
            return perforAgworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department
            && t.UnitType == request.UnitType && t.WorkTypeId != (int)AgWorkloadType.SingleAwards);
        }

        /// <summary>
        /// 新增工作量绩效配置
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool WorkloadAdd(WorkloadRequest request)
        {
            var workloadList = perforAgworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
            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,
                WorkTypeId = request.WorkTypeId,
            };
            var result = perforAgworkloadRepository.Add(workload);
            if (result)
            {
                workload.ItemId = $"Feild{workload.Id}";
                perforAgworkloadRepository.Update(workload);
            }

            return result;
        }

        /// <summary>
        /// 修改工作量绩效配置
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool WorkloadUpdate(WorkloadRequest request)
        {
            var workloadList = perforAgworkloadRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.Department == request.Department && t.UnitType == request.UnitType);
            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.Sort = request.Sort;
            workload.ItemId = $"Feild{workload.Id}";
            workload.WorkTypeId = request.WorkTypeId;

            return perforAgworkloadRepository.Update(workload);
        }

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

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

        /// <summary>
        /// 获取工作量类型列表
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public List<TitleValue<int>> WorkTypeList(WorkloadRequest request, int userId)
        {
            var (unit, dept) = GetDeptAndUnit(userId);
            var worktypes = perforAgworkloadtypeRepository.GetEntities(t => request.HospitalId.Value == t.HospitalId && t.Department == dept && t.UnitType == unit);
            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 ag_workload_type SaveWorkType(ag_workload_type request, int userId)
        {
            var (unit, dept) = GetDeptAndUnit(userId);
            var entity = perforAgworkloadtypeRepository.GetEntity(t => request.HospitalId == t.HospitalId && t.Department == dept && t.UnitType == unit && t.TypeName == request.TypeName);
            if (entity == null)
            {
                if (request.Id > 0)
                {
                    entity = perforAgworkloadtypeRepository.GetEntity(t => t.Id == request.Id);
                    entity.HospitalId = request.HospitalId;
                    entity.TypeName = request.TypeName;

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

        /// <summary>
        /// 获取工作量类型列表
        /// </summary>
        /// <param name="secondId"></param>
        /// <returns></returns>
        public bool DeleteWorkType(WorkloadRequest request)
        {
            var entity = perforAgworkloadtypeRepository.GetEntity(t => t.Id == request.Id);
            if (entity != null)
            {
                return perforAgworkloadtypeRepository.Remove(entity);
            }
            else
                return false;
        }

        public (string, string) GetDeptAndUnit(int userId)
        {
            var user = perforUserRepository.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 = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null)
                throw new PerformanceException("所选绩效不存在！");

            var accountUnit = perforResaccountRepository.GetEntities(t => t.AllotID == allotId && !new int[] { (int)UnitType.行政高层, (int)UnitType.行政中层 }.Contains(t.UnitType.Value));
            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 = perforAgsecondallotRepository.GetEntities(t => t.AllotId == allot.ID && t.Year == allot.Year && t.Month == allot.Month);
            var result = temps.Select(t =>
            {
                var second = secondList?.FirstOrDefault(f => f.UnitType == ((UnitType)t.UnitType).ToString() && 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 = EnumHelper.GetItems<UnitType>();
            return result.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 = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null)
                throw new PerformanceException("所选绩效不存在！");
            var types = new int[] { (int)UnitType.其他护理组, (int)UnitType.护理组 };
            var accountUnit = perforResaccountRepository.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 = perforPerallotRepository.GetEntity(t => t.ID == second.AllotId);
            if (allot == null)
                throw new PerformanceException("二次绩效无效！");

            var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
            var role = roleRepository.GetEntity(t => t.ID == userrole.RoleID);

            Dictionary<int, string[]> dic = new Dictionary<int, string[]>
            {
                { application.DirectorRole, new[]{ UnitType.医生组.ToString(), UnitType.其他医生组.ToString(), UnitType.医技组.ToString(), UnitType.其他医技组.ToString() } },
                { application.NurseRole, new[]{ UnitType.护理组.ToString(), UnitType.其他护理组.ToString()} },
                { application.SpecialRole, new[]{ UnitType.特殊核算组.ToString() }},
                { application.OfficeRole, new[]{ UnitType.行政后勤.ToString() } },
            };

            Expression<Func<ag_usetemp, bool>> exp = t => t.HospitalId == allot.HospitalId && t.Department == second.Department;
            if (role.Type.HasValue && dic.ContainsKey(role.Type.Value))
                exp = exp.And(t => dic[role.Type.Value].Contains(t.UnitType));

            var temp = perforAgusetempRepository.GetEntity(exp);
            if (temp == null)
                throw new PerformanceException("选择模板不可用，请确定模板及数据是否存在！");
            if (temp.UseTempId == 6)
            {
                var data = perforAgothersourceRepository.GetEntities(t => t.SecondId == second.Id);
                if (data == null || !data.Any())
                    throw new PerformanceException("提交时未检测到数据!");
            }
            else
            {
                var data = perforAgfixatitemRepository.GetEntities(t => t.SecondId == second.Id);
                if (data == null || !data.Any())
                    throw new PerformanceException("提交时未检测到数据!");
            }
            second.UseTempId = temp.UseTempId;
            second.Status = 2;
            second.NursingDeptStatus = 2;
            second.SubmitType = temp.UseTempId == 6 ? 2 : 1;
            second.SubmitTime = DateTime.Now;
            //second.Remark = "已提交审核，等待审核中";
            return perforAgsecondallotRepository.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 = perforAgsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
            //if (second.Status != 2)
            //    throw new PerformanceException("该绩效未提交至审核，请确认");

            if (request.IsPass == 1)
            {
                second.Status = 3;
            }
            else
            {
                second.UseTempId = null;
                second.Status = 4;
            }
            //second.Status = request.IsPass == 1 ? 3 : 4;
            second.AuditUser = userId;
            second.AuditTime = DateTime.Now;
            second.Remark = request.Remark;
            //if (string.IsNullOrEmpty(second.Remark))
            //{
            //    second.Remark = request.IsPass == 1 ? "审核通过" : "驳回";
            //}
            var result = perforAgsecondallotRepository.Update(second);

            // 无论驳回还是通过，都需要清空该科室历史数据
            var histories = perforAgcomputeRepository.GetEntities(w => w.SecondId == request.SecondId);
            if (histories != null && histories.Any())
                perforAgcomputeRepository.RemoveRange(histories.ToArray());

            #region 添加至二次绩效汇总

            if (result && request.IsPass == 1)
            {
                // 护理部审核
                var allot = perforPerallotRepository.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;

                var computes = new List<ag_compute>();
                if (second.SubmitType == 1)
                {
                    var items = perforAgfixatitemRepository.GetEntities(t => t.SecondId == request.SecondId);
                    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 (second.SubmitType == 2)
                {
                    var others = perforAgothersourceRepository.GetEntities(t => t.SecondId == request.SecondId);
                    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,
                            });
                        }
                    }
                }
                perforAgcomputeRepository.AddRange(computes.ToArray());
            }

            #endregion 添加至二次绩效汇总

            return result;
        }

        /// <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 = perforAgsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
            if (second == null)
                throw new PerformanceException("二次分配绩效无效");
            if (request.IsPass == 1)
            {
                second.NursingDeptStatus = 3;
                second.NursingDeptRemark = $"{request.Remark}";
            }
            else
            {
                second.UseTempId = null;
                second.NursingDeptStatus = 4;
                second.NursingDeptRemark = $"{request.Remark}";
            }
            second.NursingDeptAuditUser = userId;
            second.NursingDeptAuditTime = DateTime.Now;

            return perforAgsecondallotRepository.Update(second);
        }

        #endregion 二次绩效考核

        #region common

        /// <summary>
        /// 获取二次绩效
        /// </summary>
        /// <param name="secondId">二次绩效Id</param>
        /// <returns></returns>
        public ag_secondallot GetSecondallot(int secondId)
        {
            return perforAgsecondallotRepository.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 = perforAgtempitemRepository.GetEntities(t => t.TempId == tempId);

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

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

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

            //获取工作量列头
            var workItem = perforAgworkloadRepository.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 = perforAgsecondallotRepository.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 = perforAgothersourceRepository.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 = perforAgsecondallotRepository.GetEntity(t => t.Id == request.SecondId);
            if (second == null)
                throw new PerformanceException("当前科室二次分配绩效信息无效");

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

            var usetemp = perforAgusetempRepository.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);

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

            if (!string.IsNullOrEmpty(request.EmployeeName))
                employees = employees?.Where(w => w.DoctorName?.Trim() == request.EmployeeName?.Trim()).ToList();
            if (!string.IsNullOrEmpty(request.JobNumber))
                employees = employees?.Where(w => !string.IsNullOrEmpty(w.PersonnelNumber) && w.PersonnelNumber.Trim() == request.JobNumber.Trim()).ToList();

            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
            ? 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 (second.UnitType == UnitType.行政后勤.ToString())
                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 = perforAgsecondallotRepository.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)
        {
            var existEntities = perforAgothersourceRepository.GetEntities(t => t.SecondId == secondId);
            if (existEntities != null && existEntities.Any())
            {
                foreach (var item in request.Where(t => t.Id != 0))
                {
                    existEntities.First(t => t.Id == item.Id).WorkNumber = item.WorkNumber;
                    existEntities.First(t => t.Id == item.Id).Name = item.Name;
                    existEntities.First(t => t.Id == item.Id).Department = item.Department;
                    existEntities.First(t => t.Id == item.Id).WorkPost = item.WorkPost;
                    existEntities.First(t => t.Id == item.Id).TitlePerformance = item.TitlePerformance;
                    existEntities.First(t => t.Id == item.Id).WorkPerformance = item.WorkPerformance;
                    existEntities.First(t => t.Id == item.Id).DeptReward = item.DeptReward;
                    existEntities.First(t => t.Id == item.Id).DistPerformance = item.DistPerformance;
                    existEntities.First(t => t.Id == item.Id).OtherPerformance = item.OtherPerformance;
                    existEntities.First(t => t.Id == item.Id).NightWorkPerformance = item.NightWorkPerformance;
                    existEntities.First(t => t.Id == item.Id).RealAmount = item.RealAmount;
                    existEntities.First(t => t.Id == item.Id).ManagementAllowance = item.ManagementAllowance;
                    existEntities.First(t => t.Id == item.Id).IndividualReward = item.IndividualReward;
                    existEntities.First(t => t.Id == item.Id).AllocationOfKeySpecialty = item.AllocationOfKeySpecialty;
                }
                perforAgothersourceRepository.UpdateRange(existEntities.ToArray());

                var delIds = existEntities.Select(t => t.Id).Except(request.Select(t => t.Id));
                if (delIds != null)
                    perforAgothersourceRepository.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);
                perforAgothersourceRepository.AddRange(addEntities.ToArray());
            }
            return perforAgothersourceRepository.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 = perforAgothersourceRepository.GetEntities(t => t.SecondId == secondId);
            if (existEntities != null && existEntities.Any())
            {
                perforAgothersourceRepository.RemoveRange(existEntities.ToArray());
            }

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

        #endregion 二次绩效其他来源

        #region 打印

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

            //var computes = perforAgcomputeRepository.GetEntities(t => t.SecondId == secondId);
            //if (computes == null || !computes.Any())
            //    return new List<SecPrintResponse>();

            bool isOtherTemp = second.UseTempId.HasValue && second.UseTempId == 6;

            if (isOtherTemp)
            {
                var data = perforAgothersourceRepository.GetEntities(t => t.SecondId == secondId);
                if (data == null || !data.Any()) return new List<SecPrintResponse>();

                var result = Mapper.Map<List<SecPrintResponse>>(data);
                return result.OrderBy(t => t.JobNumber).ThenBy(t => t.PersonName).ToList();
            }
            else
            {
                var itemname = new List<string> { "人员工号", "姓名", "职称", "职称绩效", "工作量绩效工资", "单项奖励小计", "可分配绩效", "医院其他绩效", "夜班工作量绩效" };
                var fixaitems = perforAgfixatitemRepository.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();
                var result = new List<SecPrintResponse>();
                foreach (var rownumber in rownumbers)
                {
                    var distperfor = ConvertHelper.To<decimal?>(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "可分配绩效")?.ItemValue);
                    var nightworkperfor = ConvertHelper.To<decimal?>(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.To<decimal?>(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "职称绩效")?.ItemValue);
                    sec.WorkPerformance = ConvertHelper.To<decimal?>(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "工作量绩效工资")?.ItemValue);
                    sec.DeptReward = ConvertHelper.To<decimal?>(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "单项奖励小计")?.ItemValue);
                    sec.DistPerformance = distperfor;
                    sec.OtherPerformance = ConvertHelper.To<decimal?>(fixaitems.FirstOrDefault(t => t.RowNumber == rownumber && t.ItemName == "医院其他绩效")?.ItemValue);
                    sec.NightWorkPerformance = nightworkperfor;
                    result.Add(sec);
                }
                return result.OrderBy(t => t.RowNumber).ToList();
            }
        }

        #endregion 打印

        public List<SecondPerforResponse> DeptComputeDetail(int userId, int allotId, out int isShowManage)
        {
            var user = perforUserRepository.GetEntity(t => t.ID == userId);
            if (user == null)
                throw new NotImplementedException("人员ID无效");

            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            isShowManage = computeService.IsShowManage(allotId);

            var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
            var role = roleRepository.GetEntity(t => t.ID == userrole.RoleID);
            Dictionary<int, string> dict = new Dictionary<int, string>
            {
                { application.DirectorRole, AccountUnitType.科主任.ToString() },
                { application.NurseRole, AccountUnitType.护士长.ToString() },
                { application.OfficeRole, AccountUnitType.行政中层.ToString() },
                { application.SpecialRole, AccountUnitType.科主任.ToString() },
            };

            if (!dict.Keys.Contains(role.Type.Value)) return new List<SecondPerforResponse>();

            var computes = rescomputeRepository.GetEntities(t => t.AllotID == allotId && t.AccountingUnit == user.Department && t.AccountType == dict[role.Type.Value]);
            if (computes == null || !computes.Any()) return new List<SecondPerforResponse>();

            var data = GetAllotPerformance(allotId, computes, isShowManage);
            // 补充医院其他绩效
            var result = AddAprAmount(allotId, data);

            // 预留比例
            if (result != null)
            {
                var empDic = peremployeeRepository.GetEntities(w => w.AllotId == allotId);
                foreach (var item in result)
                {
                    item.PerforSumFee = Math.Round(item.PerforSumFee ?? 0, 0, MidpointRounding.AwayFromZero);
                    item.PerforManagementFee = Math.Round(item.PerforManagementFee ?? 0, 0, MidpointRounding.AwayFromZero);
                    var real = Math.Round((item.PerforSumFee ?? 0) + (item.PerforManagementFee ?? 0), 0) * item.Adjust + (item.AdjustLaterOtherFee ?? 0);

                    item.OthePerfor = Math.Round(item.OthePerfor ?? 0, 0, MidpointRounding.AwayFromZero);
                    item.NightWorkPerfor = Math.Round(item.NightWorkPerfor ?? 0, 0, MidpointRounding.AwayFromZero);
                    item.ShouldGiveFee = Math.Round((real ?? 0) + (item.OthePerfor ?? 0) + (item.NightWorkPerfor ?? 0), 0, MidpointRounding.AwayFromZero);
                    item.ReservedRatio = empDic?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.ReservedRatio ?? 0;
                    item.ReservedRatioFee = Math.Round((real ?? 0) * (item.ReservedRatio ?? 0), 0, MidpointRounding.AwayFromZero);
                    item.RealGiveFee = Math.Round(item.ShouldGiveFee - (item.ReservedRatioFee ?? 0) ?? 0, 0, MidpointRounding.AwayFromZero);
                }
            }

            return result;
        }

        public List<DeptDataDetails> DeptComputeDetailList(int userId, int allotId, out int isShowManage)
        {
            var user = perforUserRepository.GetEntity(t => t.ID == userId);
            if (user == null)
                throw new NotImplementedException("人员ID无效");

            var deptDatas = new List<DeptDataDetails>();
            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            isShowManage = computeService.IsShowManage(allotId);

            var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
            var role = roleRepository.GetEntity(t => t.ID == userrole.RoleID);
            Dictionary<int, string> dict = new Dictionary<int, string>
            {
                { application.DirectorRole, AccountUnitType.科主任.ToString() },
                { application.NurseRole, AccountUnitType.护士长.ToString() },
                { application.OfficeRole, AccountUnitType.行政中层.ToString() },
                { application.SpecialRole, AccountUnitType.科主任.ToString() },
            };

            if (!dict.Keys.Contains(role.Type.Value)) return new List<DeptDataDetails>();

            var computes = rescomputeRepository.GetEntities(t => t.AllotID == allotId && t.AccountingUnit == user.Department && t.AccountType == dict[role.Type.Value]);
            if (computes == null || !computes.Any()) return new List<DeptDataDetails>();
            foreach (var item in computes)
            {
                deptDatas.Add(computeService.GetDoctorDetail(item.ID));
            }
            return deptDatas;
        }

        /// <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;
        }
    }
}
