using AutoMapper;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Text.RegularExpressions;
using Performance.DtoModels.Request;
using Performance.DtoModels.Response;
using Performance.Services.ExtractExcelService;

namespace Performance.Services
{
    public class ComputeService : IAutoInjection
    {
        private readonly IMapper _mapper;
        private readonly PerforResaccountRepository perforResaccountRepository;
        private readonly PerforPersheetRepository _perforPerSheetRepository;
        private readonly PerforImdataRepository _perforImDataRepository;
        private readonly PerforImheaderRepository _perforImheaderRepository;
        private readonly PerforRescomputeRepository _perforRescomputeRepository;
        private readonly PerforResspecialunitRepository _perforResspecialunitRepository;
        private readonly PerforResbaiscnormRepository perforResbaiscnormRepository;
        private readonly PerforAgsecondallotRepository _perforAgsecondallotRepository;
        //private readonly PerforAgcomputeRepository _perforAgcomputeRepository;
        private readonly PerforImemployeeclinicRepository _perforImemployeeclinicRepository;
        private readonly PerforImemployeeRepository _perforImemployeeRepository;
        private readonly PerforPerallotRepository perforPerallotRepository;
        private readonly PerforPerbatchRepository perforPerbatchRepository;
        private readonly PerforHospitalRepository hospitalRepository;
        private readonly PerforPerapramountRepository perapramountRepository;
        private readonly PerforPeremployeeRepository perforPeremployeeRepository;
        private readonly PerforPerapramounthideRepository _hideRepository;
        private readonly PerforCofworkitemRepository cofworkitemRepository;
        private readonly PerforCofaliasRepository cofaliasRepository;
        private readonly PerforReportRepository reportRepository;

        public ComputeService(
            IMapper mapper,
            PerforResaccountRepository perforResaccountRepository,
            PerforPersheetRepository perforPerSheetRepository,
            PerforImdataRepository perforImDataRepository,
            PerforImheaderRepository perforImheaderRepository,
            PerforRescomputeRepository perforRescomputeRepository,
            PerforResspecialunitRepository perforResspecialunitRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforAgsecondallotRepository perforAgsecondallotRepository,
            //PerforAgcomputeRepository perforAgcomputeRepository,
            PerforImemployeeclinicRepository perforImemployeeclinicRepository,
            PerforImemployeeRepository perforImemployeeRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforPerbatchRepository perforPerbatchRepository,
            PerforHospitalRepository hospitalRepository,
            PerforPerapramountRepository perapramountRepository,
            PerforPeremployeeRepository perforPeremployeeRepository,
            PerforPerapramounthideRepository hideRepository,
            PerforCofworkitemRepository cofworkitemRepository,
            PerforCofaliasRepository cofaliasRepository,
            PerforReportRepository reportRepository)
        {
            _mapper = mapper;
            this.perforResaccountRepository = perforResaccountRepository;
            this._perforPerSheetRepository = perforPerSheetRepository;
            this._perforImDataRepository = perforImDataRepository;
            this._perforImheaderRepository = perforImheaderRepository;
            this._perforRescomputeRepository = perforRescomputeRepository;
            this._perforResspecialunitRepository = perforResspecialunitRepository;
            this.perforResbaiscnormRepository = perforResbaiscnormRepository;
            this._perforAgsecondallotRepository = perforAgsecondallotRepository;
            //this._perforAgcomputeRepository = perforAgcomputeRepository;
            this._perforImemployeeclinicRepository = perforImemployeeclinicRepository;
            this._perforImemployeeRepository = perforImemployeeRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforPerbatchRepository = perforPerbatchRepository;
            this.hospitalRepository = hospitalRepository;
            this.perapramountRepository = perapramountRepository;
            this.perforPeremployeeRepository = perforPeremployeeRepository;
            _hideRepository = hideRepository;
            this.cofworkitemRepository = cofworkitemRepository;
            this.cofaliasRepository = cofaliasRepository;
            this.reportRepository = reportRepository;
        }

        public int IsShowManage(int allotId)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null)
                throw new PerformanceException("绩效信息无效");

            return hospitalRepository.GetEntity(t => t.ID == allot.HospitalId)?.IsShowManage ?? 1;
        }

        /// <summary>
        /// 返回绩效发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <param name="type">绩效基数核算参考对象</param>
        /// <returns></returns>
        public List<ResComputeResponse> GetCompute(int allotId, int type)
        {
            var data = new List<ResComputeResponse>();

            var items = EnumHelper.GetItems<AccountUnitType>();
            if (!items.Any(t => t.Value == type))
                throw new PerformanceException("参数错误，type无效");

            Dictionary<int, List<string>> pairs = new Dictionary<int, List<string>>
            {
                { (int)AccountUnitType.科主任, new List<string>{ UnitType.医生组.ToString(), UnitType.医技组.ToString() } },
                { (int)AccountUnitType.护士长, new List<string>{ UnitType.护理组.ToString() } },
                { (int)AccountUnitType.Null, new List<string>
                    {
                        UnitType.特殊核算组.ToString(),
                        UnitType.其他医生组.ToString(),
                        UnitType.其他护理组.ToString(),
                        UnitType.其他医技组.ToString()
                    }
                },
            };
            var isShowManage = IsShowManage(allotId);

            var apramounts = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Status == 3);
            if (pairs.Keys.Any(t => t == type))
            {
                #region MyRegion

                //var employees = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId && pairs[type].Contains(t.UnitType));
                //if (employees == null || !employees.Any()) return new List<ResComputeResponse>();

                //string[] accountunittype = new string[] { AccountUnitType.行政中层.ToString(), AccountUnitType.行政工勤.ToString(), AccountUnitType.行政高层.ToString() };
                //var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && !accountunittype.Contains(t.AccountType));
                //if (computes == null || !computes.Any()) return new List<ResComputeResponse>();

                //var joinData = employees.Join(computes, outer => new { outer.AccountingUnit, EmployeeName = outer.DoctorName },
                //    inner => new { inner.AccountingUnit, inner.EmployeeName }, (outer, inner) => inner).ToList();
                //if (joinData == null || !joinData.Any()) return new List<ResComputeResponse>();

                //if (type != (int)AccountUnitType.Null)
                //{
                //    var accountUnit = computes.Where(t => t.AccountType == ((AccountUnitType)type).ToString() && joinData.Select(join => join.EmployeeName).Contains(t.EmployeeName));

                //    if (accountUnit != null && accountUnit.Any())
                //    {
                //        accountUnit.ToList().ForEach(t =>
                //        {
                //            var compute = joinData.First(join => join.EmployeeName == t.EmployeeName);
                //            if (compute.AccountingUnit != t.AccountingUnit && !joinData.Any(w => w.EmployeeName == t.EmployeeName && w.AccountingUnit == t.AccountingUnit))
                //                joinData.Add(t);
                //        });
                //    }
                //}
                //else
                //{
                //    var accountUnit = computes.Where(t => joinData.Select(join => join.EmployeeName).Contains(t.EmployeeName));
                //    if (accountUnit != null && accountUnit.Any())
                //    {
                //        var delData = new List<res_compute>();
                //        foreach (var item in joinData)
                //        {
                //            accountUnit.Where(join => join.EmployeeName == item.EmployeeName).ToList().ForEach(t =>
                //            {
                //                if (item.AccountType == t.AccountType && item.AccountingUnit != t.AccountingUnit)
                //                    delData.Add(item);
                //            });
                //        }
                //        if (delData.Count > 0)
                //            joinData.RemoveAll(t => delData.Select(d => d.ID).Contains(t.ID));
                //    }
                //}
                //if (joinData == null || !joinData.Any()) return new List<ResComputeResponse>();

                //data = _mapper.Map<List<ResComputeResponse>>(joinData);

                #endregion MyRegion

                var employees = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId && pairs[type].Contains(t.UnitType));
                if (employees == null || !employees.Any()) return new List<ResComputeResponse>();

                var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && pairs[type].Contains(t.UnitType));
                if (computes == null || !computes.Any()) return new List<ResComputeResponse>();

                data = _mapper.Map<List<ResComputeResponse>>(computes);

                data.ForEach(t =>
                {
                    //t.WorkTime = string.IsNullOrEmpty(t.WorkTime) ? null : Convert.ToDateTime(t.WorkTime).ToString("yyyy-MM-dd");
                    if (isShowManage == 2)
                    {
                        t.PerforSumFee = (t.ShouldGiveFee ?? 0) + (t.AssessBeforeOtherFee ?? 0);
                        var employee = employees.FirstOrDefault(e => e.DoctorName == t.EmployeeName && e.AccountingUnit == t.AccountingUnit && pairs[type].Contains(e.UnitType));
                        var scoreAverageRate = t.ScoreAverageRate ?? employee.ScoreAverageRate ?? 1;
                        var attendance = t.Attendance ?? employee.Attendance ?? 0;
                        t.GiveFee = (t.ShouldGiveFee ?? 0) * scoreAverageRate * attendance + (t.OtherPerfor ?? 0) + (t.Punishment ?? 0) + (t.AssessLaterOtherFee ?? 0);
                        t.RealGiveFee = t.GiveFee * (t.Adjust ?? 1m) + (t.AdjustLaterOtherFee ?? 0);
                        t.BaiscNormValue = (t.RealGiveFee ?? 0);
                    }

                    var aprAmount = apramounts?.Where(w => !(string.IsNullOrEmpty(w.DoctorName) && string.IsNullOrEmpty(w.PersonnelNumber)) && w.DoctorName?.Trim() == t.EmployeeName?.Trim() && w.PersonnelNumber?.Trim() == t.JobNumber?.Trim());
                    t.OtherPerformance = aprAmount?.Sum(w => w.Amount);
                });
                return data.Distinct().OrderByDescending(t => t.AccountingUnit).ToList();
            }
            else
            {
                var name = items.FirstOrDefault(p => p.Value == type)?.Name ?? "";
                var compute = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && t.AccountType == name);
                if (type == (int)AccountUnitType.行政工勤)
                    compute = compute?.Where(w => w.NeedSecondAllot == "否")?.ToList();

                if (compute == null || !compute.Any()) return new List<ResComputeResponse>();

                data = _mapper.Map<List<ResComputeResponse>>(compute);
                data = data.OrderByDescending(t => t.RealGiveFee).ThenBy(t => t.FitPeople).ThenBy(t => t.AccountingUnit).ToList();
                data.ForEach(t =>
                {
                    //t.WorkTime = string.IsNullOrEmpty(t.WorkTime) ? null : Convert.ToDateTime(t.WorkTime).ToString("yyyy-MM-dd");
                    var aprAmount = apramounts?.Where(w => !(string.IsNullOrEmpty(w.DoctorName) && string.IsNullOrEmpty(w.PersonnelNumber)) && w.DoctorName?.Trim() == t.EmployeeName?.Trim() && w.PersonnelNumber?.Trim() == t.JobNumber?.Trim());
                    t.OtherPerformance = aprAmount?.Sum(w => w.Amount);
                });
                return data.Distinct().OrderByDescending(t => t.AccountingUnit).ToList();
            }
        }

        public List<res_baiscnorm> AllComputeAvg(int allotId, List<ComputeResponse> list)
        {
            List<res_baiscnorm> avgs = new List<res_baiscnorm>();
            var emps = perforPeremployeeRepository.GetEntities(w => w.AllotId == allotId);
            var jobCategory = emps?.Select(w => string.IsNullOrEmpty(w.JobCategory) ? "未知" : w.JobCategory).Distinct() ?? new List<string>();
            var basicnorm = perforResbaiscnormRepository.GetEntities(t => t.AllotID == allotId);
            var position = basicnorm?.Select(t => string.IsNullOrEmpty(t.PositionName) ? "" : t.PositionName).Distinct() ?? new List<string>();
            foreach (var item in jobCategory)
            {
                if (position.Contains(item))
                {
                    avgs.Add(basicnorm.First(t => t.PositionName == item));
                    continue;
                }
                var sumfee = (from com in list
                              join emp in emps?.Where(w => w.JobCategory == item)
                              on com.JobNumber equals emp.PersonnelNumber
                              select com.ShouldGiveFee).Sum(w => w);
                var count = emps?.Where(w => w.JobCategory == item).Select(emp => emp.PersonnelNumber).Distinct().Count() ?? 0;
                avgs.Add(new res_baiscnorm
                {
                    PositionName = item,
                    TotelNumber = count,
                    TotelValue = sumfee,
                    AvgValue = count == 0 ? 0 : Math.Round(sumfee / count ?? 0),
                });
            }
            return avgs;
        }

        /// <summary>
        /// 返回特殊科室发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<res_specialunit> GetSpecial(int allotId)
        {
            var list = _perforResspecialunitRepository.GetEntities(t => t.AllotID == allotId);
            if (list != null && list.Any())
            {
                list = list.OrderByDescending(t => t.AccountingUnit).ThenBy(t => t.RealGiveFee).ToList();
                return _mapper.Map<List<res_specialunit>>(list);
            }
            return new List<res_specialunit>();
        }

        /// <summary>
        /// 返回医技组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetMedicalPerformance(int allotId)
        {
            return GetGroupPerformance(allotId, new List<int> { (int)UnitType.医技组 });
        }


        /// <summary>
        /// 返回医生组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetDoctorPerformance(int allotId)
        {
            return GetGroupPerformance(allotId, new List<int> { (int)UnitType.医生组 });
        }

        /// <summary>
        /// 返回护理组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetNursePerformance(int allotId)
        {
            return GetGroupPerformance(allotId, new List<int> { (int)UnitType.护理组 });
        }

        /// <summary>
        /// 返回其他组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetOtherPerformance(int allotId)
        {
            return GetGroupPerformance(allotId, new List<int> { (int)UnitType.其他医技组, (int)UnitType.其他医生组, (int)UnitType.其他护理组, (int)UnitType.专家组 });
        }
        public List<DeptResponse> GetGroupPerformance(int allotId, List<int> group)
        {
            var unitType = group;
            var list = perforResaccountRepository.GetEntities(t => unitType.Contains(t.UnitType.Value) && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> Performance = _mapper.Map<List<DeptResponse>>(list);
            Performance?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return Performance;
        }
        /// <summary>
        /// 返回行政科室绩效列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetOfficePerformance(int allotId)
        {
            var unitType = new List<int> { (int)UnitType.行政后勤 };

            var list = perforResaccountRepository.GetEntities(t => unitType.Contains(t.UnitType.Value) && t.AllotID == allotId && t.NeedSecondAllot == "是")
                ?.OrderBy(t => t.UnitType)
                .ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> other = _mapper.Map<List<DeptResponse>>(list);
            other?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return other;
        }

        ///// <summary>
        ///// 返回院领导、中层、工勤组绩效
        ///// </summary>
        ///// <param name="allotId">绩效ID</param>
        ///// <returns></returns>
        //public List<DeptResponse> GetAdminPerformance(int allotId)
        //{














        //    var result = new List<DeptResponse>();
        //    var resData = perforResaccountRepository.GetEntities(t => t.AllotID == allotId);
        //    if (resData != null && resData.Any())
        //    {
        //        result.AddRange(_mapper.Map<List<DeptResponse>>(resData));
        //        result.ForEach(t =>
        //        {
        //            t.UnitName = ((UnitType)t.UnitType).ToString();
        //            t.AssessLaterPerforTotal = Math.Round((t.PerforTotal * t.ScoringAverage + (t.MedicineExtra ?? 0) + (t.MaterialsExtra ?? 0) + (t.Extra ?? 0) + (t.AssessLaterOtherFee ?? 0)) ?? 0);
        //        });
        //        result = result.OrderBy(t => t.UnitType).ThenBy(t => t.AccountingUnit).ToList();
        //    }

        //    var list = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId);
        //    if (list == null || !list.Any()) return result;

        //    var isShowManage = IsShowManage(allotId);

        //    Dictionary<string, string> dict = new Dictionary<string, string>
        //    {
        //        { "科主任", "医生组" },
        //        { "护士长", "护理组" },
        //        { AccountUnitType.行政高层.ToString(), AccountUnitType.行政高层.ToString() },
        //        { AccountUnitType.行政中层.ToString(), AccountUnitType.行政中层.ToString() },
        //        { AccountUnitType.行政工勤.ToString(), AccountUnitType.行政工勤.ToString() }
        //    };
        //    var doctors = new string[] { "医生组", "护理组", "医技组" };
        //    List<DeptResponse> adminPerfor = list.GroupBy(t => new { t.AccountingUnit, t.AccountType, t.UnitType }).Select(t =>
        //       {
        //           string unitName = !string.IsNullOrEmpty(t.Key.UnitType) ? t.Key.UnitType : result.Where(w => !dict.Values.Contains(w.UnitName)).FirstOrDefault(w => w.AccountingUnit == t.Key.AccountingUnit)?.UnitName ?? "";
        //           var data = new DeptResponse
        //           {
        //               UnitName = !dict.Values.Contains(unitName) && !string.IsNullOrEmpty(unitName) ? unitName : dict.ContainsKey(t.Key.AccountType) ? dict[t.Key.AccountType] : "未知",
        //               AccountingUnit = t.Key.AccountingUnit,
        //               Department = t.Key.AccountingUnit,
        //               Number = t.Count(),
        //           };
        //           if (doctors.Contains(data.UnitName))
        //           {
        //               data.AssessLaterManagementFee = isShowManage == 1
        //                   ? t.Sum(group => group.RealGiveFee ?? 0) + t.Sum(group => group.OtherPerfor ?? 0)  //实发绩效
        //                   : Math.Round((t.Max(m => m.ShouldGiveFee) * t.Max(m => m.ScoreAverageRate) * t.Max(m => m.Attendance) ?? 0.0M) + t.Max(m => m.Punishment ?? 0.0M)); //考核后管理绩效
        //           }
        //           return data;
        //       }).ToList();

        //    result.AddRange(adminPerfor);

        //    var aprAmounts = perapramountRepository.GetEntities(t => t.AllotId == allotId && t.Status == 3) ?? new List<per_apr_amount>();
        //    var employees = perforPeremployeeRepository.GetEntities(t => t.AllotId == allotId) ?? new List<per_employee>();

        //    var otherPerformances = aprAmounts.Join(employees,
        //        outer => new { outer.AccountingUnit, outer.PersonnelNumber },
        //        inner => new { inner.AccountingUnit, inner.PersonnelNumber },
        //        (outer, inner) => new
        //        {
        //            AccountingUnit = outer.AccountingUnit,
        //            UnitType = inner.UnitType,
        //            PersonnelNumber = inner.PersonnelNumber,
        //            PersonnelName = outer.DoctorName,
        //            Amount = outer.Amount
        //        })?.GroupBy(t => new { t.AccountingUnit, t.UnitType }).Select(t => new
        //        {
        //            AccountingUnit = t.Key.AccountingUnit,
        //            UnitType = t.Key.UnitType,
        //            Amount = t.Sum(s => s.Amount)
        //        });

        //    result = result.GroupBy(t => new { t.AccountingUnit, t.UnitName }).Select(t => new DeptResponse
        //    {
        //        UnitName = t.Key.UnitName,
        //        AccountingUnit = t.Key.AccountingUnit,
        //        Department = t.Key.AccountingUnit,
        //        PerforFee = t.Sum(group => group.PerforFee),
        //        WorkloadFee = t.Sum(group => group.WorkloadFee),
        //        AssessBeforeOtherFee = t.Sum(group => group.AssessBeforeOtherFee),
        //        ScoringAverage = t.Sum(group => group.ScoringAverage),
        //        MedicineExtra = t.Sum(group => group.MedicineExtra),
        //        Extra = t.Sum(group => group.Extra),
        //        AssessLaterOtherFee = t.Sum(group => group.AssessLaterOtherFee),
        //        AdjustFactor = t.Max(group => group.AdjustFactor),
        //        AdjustLaterOtherFee = t.Sum(group => group.AdjustLaterOtherFee),
        //        PerforTotal = t.Sum(group => group.PerforTotal),
        //        AssessLaterPerforTotal = t.Sum(group => group.AssessLaterPerforTotal),
        //        AssessLaterManagementFee = t.Sum(group => group.AssessLaterManagementFee),
        //        AprPerforAmount = otherPerformances?.FirstOrDefault(w => w.AccountingUnit == t.Key.AccountingUnit && w.UnitType == t.Key.UnitName)?.Amount ?? 0,
        //        RealGiveFee = t.Sum(group => group.RealGiveFee) + t.Sum(group => group.AssessLaterManagementFee)
        //        + (otherPerformances?.FirstOrDefault(w => w.AccountingUnit == t.Key.AccountingUnit && w.UnitType == t.Key.UnitName)?.Amount ?? 0),
        //    }).ToList();

        //    var specialData = _perforResspecialunitRepository.GetEntities(t => t.AllotID == allotId);
        //    if (specialData != null && specialData.Any())
        //    {
        //        result.AddRange(specialData.GroupBy(t => new { t.AccountingUnit, t.Department }).Select(t =>
        //        {
        //            var data = new DeptResponse
        //            {
        //                UnitName = "特殊核算组",
        //                AccountingUnit = t.Key.AccountingUnit,
        //                Department = t.Key.Department,
        //                PerforFee = t.Max(max => max.GiveFee),
        //                WorkloadFee = 0,
        //                AssessBeforeOtherFee = t.Max(max => max.AssessBeforeOtherFee),
        //                PerforTotal = t.Max(max => max.PerforTotal),
        //                ScoringAverage = t.Max(max => max.ScoringAverage),
        //                MedicineExtra = t.Max(max => max.MedicineExtra),
        //                MaterialsExtra = t.Max(max => max.MaterialsExtra),
        //                Extra = 0,
        //                AssessLaterOtherFee = t.Max(max => max.AssessLaterOtherFee),
        //                AdjustFactor = t.Max(max => max.Adjust),
        //                AdjustLaterOtherFee = t.Max(max => max.AdjustLaterOtherFee),
        //                AssessLaterManagementFee = 0,
        //                AprPerforAmount = 0,
        //                RealGiveFee = t.Max(max => max.RealGiveFee),
        //            };
        //            data.AssessLaterPerforTotal = Math.Round(((data.PerforTotal * data.ScoringAverage) ?? 0) + (data.MedicineExtra ?? 0) + (data.MaterialsExtra ?? 0) + (data.AssessLaterOtherFee ?? 0));
        //            return data;
        //        }));
        //    }

        //    var enumItems = EnumHelper.GetItems<AccountUnitType>();

        //    result = result.OrderBy(t => enumItems.FirstOrDefault(e => e.Name == t.UnitName)?.Value)/*.ThenBy(t => t.AccountingUnit)*/.ToList();
        //    return result;
        //}


        /// <summary>
        /// 返回院领导、中层、工勤组绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetAdminPerformance(int allotId)
        {
            var result = new List<DeptResponse>();
            //var employees = perforPeremployeeRepository.GetEntities(t => t.AllotId == allotId) ?? new List<per_employee>();

            var clinicalTypes = new UnitType[] { UnitType.医生组, UnitType.其他医生组, UnitType.医技组, UnitType.其他医技组, UnitType.护理组, UnitType.其他护理组, UnitType.特殊核算组 };
            var clinicalTypesString = clinicalTypes.Select(w => w.ToString()).ToList();
            var clinicalTypesInt = clinicalTypes.Select(w => (int)w).ToList();
            var clinicalComputes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && clinicalTypesString.Contains(t.UnitType)) ?? new List<res_compute>();
            var clinicalEmployees = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId && clinicalTypesString.Contains(t.UnitType));
            var isShowManage = IsShowManage(allotId);
            // 计算 科主任/护士长 管理绩效
            clinicalComputes?.ForEach(t =>
            {
                if (isShowManage == 2)
                {
                    t.RealGiveFee = Math.Round(t.AssessLaterManagementFee * (t.Adjust ?? 1m) + (t.AdjustLaterOtherFee ?? 0) ?? 0, 2);
                }
            });

            #region 临床科室
            // 临床科室
            var accounts = perforResaccountRepository.GetEntities(t => t.AllotID == allotId && clinicalTypesInt.Contains(t.UnitType.Value)) ?? new List<res_account>();
            var clinicalResult = accounts.Select(t => new DeptResponse
            {
                UnitName = ((UnitType)t.UnitType).ToString(),
                AccountingUnit = t.AccountingUnit,
                Department = t.AccountingUnit,
                PerforFee = t.PerforFee,
                WorkloadFee = t.WorkloadFee,
                AssessBeforeOtherFee = t.AssessBeforeOtherFee,
                PerforTotal = t.PerforTotal,
                ScoringAverage = t.ScoringAverage,
                Extra = t.Extra,
                MedicineExtra = t.MedicineExtra,
                MaterialsExtra = t.MaterialsExtra,
                AssessLaterOtherFee = t.AssessLaterOtherFee,
                AssessLaterPerforTotal = t.AssessLaterPerforTotal,
                AdjustFactor = t.AdjustFactor,
                AdjustLaterOtherFee = t.AdjustLaterOtherFee,
                AssessLaterManagementFee = clinicalComputes?.Where(w => w.AccountingUnit == t.AccountingUnit && w.UnitType == ((UnitType)t.UnitType).ToString())?.Sum(c => c.RealGiveFee),
                RealGiveFee = t.RealGiveFee,
            });

            result.AddRange(clinicalResult);
            #endregion

            #region 特殊核算组科室
            // 特殊核算组科室
            var specialunits = _perforResspecialunitRepository.GetEntities(t => t.AllotID == allotId) ?? new List<res_specialunit>();

            var specialResult = specialunits.GroupBy(t => new { t.AccountingUnit }).Select(t => new DeptResponse
            {
                UnitName = UnitType.特殊核算组.ToString(),
                AccountingUnit = t.Key.AccountingUnit,
                Department = t.Key.AccountingUnit,
                PerforFee = t.Max(w => w.ResultsTotalFee),
                WorkloadFee = 0,
                AssessBeforeOtherFee = t.Max(w => w.AssessBeforeOtherFee),
                PerforTotal = t.Max(w => w.PerforTotal),
                ScoringAverage = t.Max(w => w.ScoringAverage),
                Extra = t.Max(w => w.Punishment),
                MedicineExtra = t.Max(w => w.MedicineExtra),
                MaterialsExtra = t.Max(w => w.MaterialsExtra),
                AssessLaterOtherFee = t.Max(w => w.AssessLaterOtherFee),
                AssessLaterPerforTotal = Math.Round((t.Max(w => w.PerforTotal) * t.Max(w => w.ScoringAverage) + t.Max(w => w.MedicineExtra) + t.Max(w => w.MaterialsExtra) + t.Max(w => w.Punishment) + t.Max(w => w.AssessLaterOtherFee)) ?? 0, MidpointRounding.AwayFromZero),
                AdjustFactor = t.Max(w => w.Adjust),
                AdjustLaterOtherFee = t.Max(w => w.AdjustLaterOtherFee),
                AssessLaterManagementFee = clinicalComputes?.Where(w => w.AccountingUnit == t.Key.AccountingUnit && w.UnitType == UnitType.特殊核算组.ToString())?.Sum(c => c.RealGiveFee),
                RealGiveFee = t.Max(w => w.RealGiveFee),
            }).Distinct();
            result.AddRange(specialResult);
            #endregion

            #region 需要二次分配的行政科室
            // 需要二次分配的行政科室
            var needSecond = perforResaccountRepository.GetEntities(t => t.AllotID == allotId && t.UnitType.Value == (int)UnitType.行政后勤 && t.NeedSecondAllot == "是") ?? new List<res_account>();
            var needSecondResult = needSecond.Select(t => new DeptResponse
            {
                UnitName = ((UnitType)t.UnitType).ToString() == "行政后勤" ? "行政工勤" : ((UnitType)t.UnitType).ToString(),
                AccountingUnit = t.AccountingUnit,
                Department = t.AccountingUnit,
                PerforFee = t.PerforFee,
                WorkloadFee = t.WorkloadFee,
                AssessBeforeOtherFee = t.AssessBeforeOtherFee,
                PerforTotal = t.PerforTotal,
                ScoringAverage = t.ScoringAverage,
                Extra = t.Extra,
                MedicineExtra = t.MedicineExtra,
                MaterialsExtra = t.MaterialsExtra,
                AssessLaterOtherFee = t.AssessLaterOtherFee,
                AssessLaterPerforTotal = t.AssessLaterPerforTotal,
                AdjustFactor = t.AdjustFactor,
                AdjustLaterOtherFee = t.AdjustLaterOtherFee,
                AssessLaterManagementFee = clinicalComputes?.Where(w => w.AccountingUnit == t.AccountingUnit && w.UnitType == ((UnitType)t.UnitType).ToString())?.Sum(c => c.RealGiveFee),
                RealGiveFee = t.RealGiveFee,
            });

            result.AddRange(needSecondResult);
            #endregion

            #region 不需要二次分配的行政科室
            // 不需要二次分配的行政科室
            var officeTypes = new List<string> { "行政工勤", "行政高层", "行政中层" };
            var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && officeTypes.Contains(t.AccountType) && t.NeedSecondAllot == "否") ?? new List<res_compute>();

            var officeResult = computes.GroupBy(t => new { t.AccountingUnit, t.AccountType, t.UnitType }).Select(t => new DeptResponse
            {
                UnitName = t.Key.AccountType == "行政后勤" ? "行政工勤" : t.Key.AccountType,
                AccountingUnit = t.Key.AccountingUnit,
                Department = t.Key.AccountingUnit,
                PerforFee = t.Sum(w => w.PerforTotal),
                WorkloadFee = 0,
                AssessBeforeOtherFee = 0,
                PerforTotal = t.Sum(w => w.PerforTotal),
                ScoringAverage = t.FirstOrDefault(s => s.ScoreAverageRate != null && s.ScoreAverageRate.HasValue)?.ScoreAverageRate ?? 1,
                Extra = t.Sum(w => w.Punishment),
                MedicineExtra = 0,
                MaterialsExtra = 0,
                AssessLaterOtherFee = t.Sum(w => w.AssessLaterOtherFee),
                AssessLaterPerforTotal = t.Sum(w => Math.Round(w.GiveFee ?? 0, MidpointRounding.AwayFromZero)),
                AdjustFactor = t.FirstOrDefault()?.Adjust ?? 1,
                AdjustLaterOtherFee = t.Sum(w => w.AdjustLaterOtherFee),
                RealGiveFee = t.Sum(w => Math.Round((w.GiveFee * w.Adjust + w.AdjustLaterOtherFee) ?? 0, MidpointRounding.AwayFromZero)),
                AssessLaterManagementFee = 0,
            }); ;
            result.AddRange(officeResult);
            #endregion

            #region 医院其他绩效 && 不公示其他绩效

            var otherPerformances = perapramountRepository
                  .GetFullAmount(t => t.AllotId == allotId && t.Status == 3)
                  ?.GroupBy(t => new { t.AccountingUnit, t.UnitType })
                  .Select(t => new view_per_total_amount(t.Key.UnitType.Replace("行政后勤", "行政工勤"), t.Key.AccountingUnit, "", t.Sum(s => s.Amount) ?? 0))
                  .ToList();

            var hideOtherPerformances = _hideRepository
                 .GetFullAmount(t => t.AllotId == allotId && t.Status == 3)
                 ?.GroupBy(t => new { t.AccountingUnit, t.UnitType })
                 .Select(t => new view_per_total_amount(t.Key.UnitType.Replace("行政后勤", "行政工勤"), t.Key.AccountingUnit, "", t.Sum(s => s.Amount) ?? 0))
                 .ToList();

            // 医院其他绩效 / 不公示其他绩效、科主任护士长管理绩效、合并实发
            foreach (var item in result)
            {
                item.AprPerforAmount = 0;
                item.HideAprOtherPerforAmount = 0;
                // 医院其他绩效
                var other = otherPerformances?.FirstOrDefault(w => w.AccountingUnit == item.AccountingUnit && w.UnitType == item.UnitName);
                if (other != null)
                {
                    other.Use = true;
                    item.AprPerforAmount = other?.Amount ?? 0;
                }
                // 不公示其他绩效
                var hideOther = hideOtherPerformances?.FirstOrDefault(w => w.AccountingUnit == item.AccountingUnit && w.UnitType == item.UnitName);
                if (hideOther != null)
                {
                    hideOther.Use = true;
                    item.HideAprOtherPerforAmount = hideOther?.Amount ?? 0;
                }
                item.AssessLaterManagementFee = item.AssessLaterManagementFee ?? 0;
                item.RealGiveFee = (item.RealGiveFee ?? 0) + item.AssessLaterManagementFee + item.AprPerforAmount + item.HideAprOtherPerforAmount;
            }

            // 医院其他绩效匹配不上补充
            var otherResult = otherPerformances
                ?.Where(w => w.Use == false)
                .Select(t => new DeptResponse
                {
                    UnitName = "医院其他绩效",
                    AccountingUnit = t.AccountingUnit,
                    Department = t.AccountingUnit,
                    PerforFee = 0,
                    WorkloadFee = 0,
                    AssessBeforeOtherFee = 0,
                    PerforTotal = 0,
                    ScoringAverage = 1,
                    Extra = 0,
                    MedicineExtra = 0,
                    MaterialsExtra = 0,
                    AssessLaterOtherFee = 0,
                    AssessLaterPerforTotal = 0,
                    AdjustFactor = 1,
                    AdjustLaterOtherFee = 0,
                    AprPerforAmount = t.Amount,
                    HideAprOtherPerforAmount = 0,
                    RealGiveFee = t.Amount,
                }); ;
            result.AddRange(otherResult);

            // 不公示其他绩效匹配不上补充
            var hideOtherResult = hideOtherPerformances
                ?.Where(w => w.Use == false)
                .Select(t => new DeptResponse
                {
                    UnitName = "不公示其他绩效",
                    AccountingUnit = t.AccountingUnit,
                    Department = t.AccountingUnit,
                    PerforFee = 0,
                    WorkloadFee = 0,
                    AssessBeforeOtherFee = 0,
                    PerforTotal = 0,
                    ScoringAverage = 1,
                    Extra = 0,
                    MedicineExtra = 0,
                    MaterialsExtra = 0,
                    AssessLaterOtherFee = 0,
                    AssessLaterPerforTotal = 0,
                    AdjustFactor = 1,
                    AdjustLaterOtherFee = 0,
                    AprPerforAmount = 0,
                    HideAprOtherPerforAmount = t.Amount,
                    RealGiveFee = t.Amount,
                }); ;
            result.AddRange(hideOtherResult);
            #endregion

            var enumItems = EnumHelper.GetItems<UnitType>();
            enumItems.ForEach(t =>
            {
                t.Value = UnitTypeUtil.Is(t.Name, UnitType.护理组) ? t.Value + 2 : t.Value;
                if (t.Name == UnitType.行政后勤.ToString())
                    t.Name = "行政工勤";
            });

            result = result.OrderBy(t => enumItems.FirstOrDefault(e => e.Name == t.UnitName)?.Value).ThenBy(t => t.AccountingUnit).ToList();
            return result;
        }


        /// <summary>
        /// 查看科室绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public DeptDetailResponse GetDepartmentDetail(int allotId, string department, int type)
        {
            if (type == 1)
            {
                var accountList = perforResaccountRepository.GetEntities(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allotId && t.AccountingUnit == department);
                if (accountList != null)
                    return GetDepartmentDetail(allotId, accountList.First().ID, type);
            }
            else if (type == 2)
            {
                var accountList = perforResaccountRepository.GetEntities(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId && t.AccountingUnit == department);
                if (accountList != null)
                    return GetDepartmentDetail(allotId, accountList.First().ID, type);
            }
            return null;
        }

        /// <summary>
        /// 返回科室详情
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="accountId"></param>
        /// <param name="type"> 1 医生组 2 护理组</param>
        /// <returns></returns>
        public DeptDetailResponse GetDepartmentDetail(int allotId, int accountId, int type)
        {
            var sheetList = _perforPerSheetRepository.GetEntities(t => t.AllotID == allotId);
            if (type == 1)
            {
                var account = perforResaccountRepository.GetEntity(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allotId && t.ID == accountId);

                DeptDetailResponse response = new DeptDetailResponse()
                {
                    Pandect = _mapper.Map<PerDataAccountBaisc>(account),
                    Economic = new List<DeptDetail>(),
                    Workload = new List<DeptDetail>()
                };

                var sheetWorkload = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeDoctorWorkload);
                if (sheetWorkload == null)
                    return null;
                var dataWorkloadList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetWorkload.ID && t.IsTotal != 1 && t.AccountingUnit == account.AccountingUnit);
                if (dataWorkloadList != null && dataWorkloadList.Count > 0)
                    dataWorkloadList.ForEach(t => response.Workload.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                var sheetEconomic = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
                if (sheetEconomic == null)
                    return null;
                var dataEconomicList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetEconomic.ID && t.UnitType == 1 && t.IsTotal != 1 && t.AccountingUnit == account.AccountingUnit);
                if (dataEconomicList != null && dataEconomicList.Count > 0)
                    dataEconomicList.ForEach(t => response.Economic.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                return response;
            }
            else if (type == 2)
            {
                var nurse = perforResaccountRepository.GetEntity(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId && t.ID == accountId);
                DeptDetailResponse response = new DeptDetailResponse()
                {
                    Pandect = _mapper.Map<PerDataAccountBaisc>(nurse),
                    Economic = new List<DeptDetail>(),
                    Workload = new List<DeptDetail>()
                };

                var sheetWorkload = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeNurseWorkload);
                if (sheetWorkload == null)
                    return null;
                var dataWorkloadList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetWorkload.ID && t.IsTotal != 1 && t.AccountingUnit == nurse.AccountingUnit);
                if (dataWorkloadList != null && dataWorkloadList.Count > 0)
                    dataWorkloadList.ForEach(t => response.Workload.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));

                var sheetEconomic = sheetList.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
                if (sheetEconomic == null)
                    return null;
                var dataEconomicList = _perforImDataRepository.GetEntities(t => t.SheetID == sheetEconomic.ID && t.UnitType == 2 && t.IsTotal != 1 && t.AccountingUnit == nurse.AccountingUnit);
                if (dataEconomicList != null && dataEconomicList.Count > 0)
                    dataEconomicList.ForEach(t => response.Economic.Add(new DeptDetail { ItemName = t.TypeName, ItemValue = t.CellValue ?? 0 }));
                return response;
            }

            return null;
        }

        #region 绩效发放列表

        /// <summary>
        /// 返回绩效发放列表
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <param name="hospitalId"></param>
        /// <param name="isShowManage"> 仅显示管理绩效 isShowManage == 1 </param>
        /// <returns></returns>
        public List<ComputeResponse> AllCompute(int allotId, int hospitalId, int isShowManage, bool isEmpDic = false)
        {
            // 人员字典
            var employees = perforPeremployeeRepository.GetEntities(w => w.AllotId == allotId);
            //// 获取医院其他绩效汇总结果
            //var fullAmounts = GetTotalAmount(allotId);
            // 获取一次绩效结果
            var one = GetAllotPerformance(allotId, hospitalId, isShowManage);
            // 获取二次绩效结果
            var two = GetSecondPerformance(allotId);

            var response = new List<ComputeResponse>();
            if (one != null)
                response.AddRange(one);
            if (two != null)
                response.AddRange(two);

            // 医院其他绩效汇总
            var totalAmounts = perapramountRepository
                .GetFullAmount(t => t.AllotId == allotId && t.Status == 3)
                ?.GroupBy(w => new { w.AccountingUnit, w.UnitType, w.PersonnelNumber })
                .Select(w => new view_per_total_amount(w.Key.UnitType, w.Key.AccountingUnit, w.Key.PersonnelNumber, w.Sum(t => t.Amount) ?? 0))
                ?.ToList();

            // 医院其他绩效汇总
            var totalAmounts_hide = _hideRepository
                .GetFullAmount(t => t.AllotId == allotId && t.Status == 3)
                ?.GroupBy(w => new { w.AccountingUnit, w.UnitType, w.PersonnelNumber })
                .Select(w => new view_per_total_amount(w.Key.UnitType, w.Key.AccountingUnit, w.Key.PersonnelNumber, w.Sum(t => t.Amount) ?? 0))
                ?.ToList();
            // 补充医院其他绩效 
            AddAprAmount(response, totalAmounts, totalAmounts_hide);

            // 补充一次二次分配不存在，但医院其他绩效的人员信息
            var notMatchs1 = totalAmounts
                ?.Where(w => w.Use == false)
                .Select(other =>
                {
                    per_employee employee = employees?.FirstOrDefault(t => t.UnitType == other.UnitType && t.AccountingUnit == other.AccountingUnit && t.PersonnelNumber == other.PersonnelNumber);
                    var bc = new ComputeResponse("医院其他绩效", other.AccountingUnit, employee?.DoctorName ?? "", other.PersonnelNumber, employee?.JobTitle ?? "");
                    bc.UnitType = other.UnitType;
                    bc.OthePerfor = other.Amount;
                    bc.RealGiveFee = other.Amount;
                    return bc;
                });
            if (notMatchs1 != null)
                response.AddRange(notMatchs1);

            // 补充一次二次分配不存在，但不公示其他绩效的人员信息
            var notMatchs2 = totalAmounts_hide
                ?.Where(w => w.Use == false)
                .Select(other =>
                {
                    per_employee employee = employees?.FirstOrDefault(t => t.UnitType == other.UnitType && t.AccountingUnit == other.AccountingUnit && t.PersonnelNumber == other.PersonnelNumber);
                    var bc = new ComputeResponse("不公示其他绩效", other.AccountingUnit, employee?.DoctorName ?? "", other.PersonnelNumber, employee?.JobTitle ?? "");
                    bc.UnitType = other.UnitType;
                    bc.HideOtherPerfor = other.Amount;
                    bc.RealGiveFee = other.Amount;
                    return bc;
                });
            if (notMatchs2 != null)
                response.AddRange(notMatchs2);

            // 预留比例
            if (response != null)
            {
                var types = new string[] { UnitType.行政高层.ToString(), UnitType.行政中层.ToString(), UnitType.行政后勤.ToString(), "行政工勤" };
                foreach (var item in response)
                {
                    // 二次分配默认 调节系数100%
                    var adjust = item.Source == "二次绩效" ? 1 : (item.Adjust ?? 1);
                    // 计算调节后业绩绩效、管理绩效
                    item.PerforSumFee = Math.Round((item.PerforSumFee * adjust ?? 0), 2, MidpointRounding.AwayFromZero);
                    item.PerforManagementFee = Math.Round((item.PerforManagementFee * adjust ?? 0), 2, MidpointRounding.AwayFromZero);

                    var real = Math.Round((item.PerforSumFee ?? 0) + (item.PerforManagementFee ?? 0) + (item.AdjustLaterOtherFee ?? 0), 2, MidpointRounding.AwayFromZero);
                    // 这里是为了“全院核算绩效发放”金额一致
                    if (item.Source == "一次绩效")
                    {
                        if (isShowManage == 1)
                            real = Math.Round(real, 0, MidpointRounding.AwayFromZero);
                        else if (types.Contains(item.UnitType))
                            real = Math.Round(real, 0, MidpointRounding.AwayFromZero);
                    }

                    item.OthePerfor = Math.Round((item.OthePerfor ?? 0), 2, MidpointRounding.AwayFromZero);
                    item.HideOtherPerfor = Math.Round((item.HideOtherPerfor ?? 0), 2, MidpointRounding.AwayFromZero);
                    item.NightWorkPerfor = Math.Round((item.NightWorkPerfor ?? 0), 2, MidpointRounding.AwayFromZero);

                    item.ShouldGiveFee = Math.Round(real + (item.OthePerfor ?? 0) + (item.HideOtherPerfor ?? 0) + (item.NightWorkPerfor ?? 0), 2, MidpointRounding.AwayFromZero);

                    var emps = employees?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber);

                    item.ReservedRatio = emps?.ReservedRatio ?? 0;
                    item.ReservedRatioFee = Math.Round(real * (item.ReservedRatio ?? 0), 2, MidpointRounding.AwayFromZero);
                    item.RealGiveFee = Math.Round(item.ShouldGiveFee - (item.ReservedRatioFee ?? 0) ?? 0, 2, MidpointRounding.AwayFromZero);
                    // 姓名始终按人员字典显示
                    //item.EmployeeName = employees?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.DoctorName ?? "";

                    item.BankCard = emps?.BankCard ?? "";
                    item.JobCategory = emps?.JobCategory ?? "";
                    item.Duty = emps?.Duty ?? "";
                    item.TitlePosition = emps?.JobTitle ?? "";

                    // 人员信息使用人员字典中数据
                    if (isEmpDic)
                    {
                        item.AccountingUnit = employees?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.AccountingUnit ?? "";
                        item.UnitType = employees?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.UnitType ?? "";
                    }
                }
            }
            response.RemoveAll(w => w.PerforSumFee == 0 && w.PerforManagementFee == 0 && w.ShouldGiveFee == 0 && w.OthePerfor == 0 && w.HideOtherPerfor == 0 && w.RealGiveFee == 0);
            if (response == null || !response.Any())
                return new List<ComputeResponse>();

            var batchs = perforPerbatchRepository.GetEntities(t => t.AllotId == allotId);
            if (batchs != null && batchs.Any())
            {
                response.ForEach(t =>
                {
                    var batch = batchs.FirstOrDefault(b => b.UnitType.NoBlank() == t.UnitType.NoBlank() && b.AccountingUnit.NoBlank() == t.AccountingUnit.NoBlank() && b.PersonnelName.NoBlank() == t.EmployeeName.NoBlank() && b.PersonnelNumber.NoBlank() == t.JobNumber.NoBlank());
                    if (batch != null)
                        t.Batch = batch.Batch;
                });
            }
            response?.ForEach(item =>
            {
                item.UnitType = item.UnitType.Replace("行政后勤", "行政工勤");
            });
            var AccountTypes = EnumHelper.GetItems<AccountUnitType>();

            return response?.OrderBy(t => AccountTypes.FirstOrDefault(a => a.Name == t.UnitType)?.Value).ThenByDescending(t => t.AccountingUnit).ToList();
        }

        public List<ComputeResponse> ComputerGroupBy(List<ComputeResponse> list)
        {
            var result = list?.GroupBy(t => new { t.AccountingUnit, t.UnitType, t.EmployeeName, t.JobNumber }).Select(t => new ComputeResponse
            {
                JobNumber = t.Key.JobNumber,
                EmployeeName = t.Key.EmployeeName,
                AccountingUnit = t.Key.AccountingUnit,
                UnitType = t.Key.UnitType,
                PerforSumFee = t.Sum(s => s.PerforSumFee),
                PerforManagementFee = t.Sum(s => s.PerforManagementFee),
                AdjustLaterOtherFee = t.Sum(s => s.AdjustLaterOtherFee),
                ShouldGiveFee = t.Sum(s => s.ShouldGiveFee),
                OthePerfor = t.Sum(s => s.OthePerfor),
                HideOtherPerfor = t.Sum(s => s.HideOtherPerfor),
                NightWorkPerfor = t.Sum(s => s.NightWorkPerfor),
                RealGiveFee = t.Sum(s => s.RealGiveFee),
                ReservedRatio = t.Sum(s => s.ReservedRatio),
                ReservedRatioFee = t.Sum(s => s.ReservedRatioFee),
                BankCard = t.FirstOrDefault(s => s.JobNumber == t.Key.JobNumber)?.BankCard,
                JobCategory = t.FirstOrDefault(s => s.JobNumber == t.Key.JobNumber)?.JobCategory,
                Duty = t.FirstOrDefault(s => s.JobNumber == t.Key.JobNumber)?.Duty,
                TitlePosition = t.FirstOrDefault(s => s.JobNumber == t.Key.JobNumber)?.TitlePosition
            }).OrderBy(t =>
            {
                string value = t.JobNumber;
                switch (value)
                {
                    case string val when string.IsNullOrEmpty(val):
                        break;

                    case string val when Regex.IsMatch(val, @"^[+-]?\d*$"):
                        value = value.PadLeft(20, '0');
                        break;
                }
                return value;
            });

            return result.ToList();
        }

        ///// <summary>
        ///// 合并医院其他绩效、不公示其他绩效
        ///// </summary>
        ///// <param name="allotId"></param>
        ///// <returns></returns>
        //private List<view_per_apr_amount> GetTotalAmount(int allotId)
        //{
        //    var fullAmounts1 = perapramountRepository.GetFullAmount(t => t.AllotId == allotId && t.Status == 3) ?? new List<view_per_apr_amount>();

        //    var fullAmounts2 = _hideRepository.GetFullAmount(t => t.AllotId == allotId && t.Status == 3) ?? new List<view_per_apr_amount>();

        //    var fullAmounts = new List<view_per_apr_amount>();

        //    if (fullAmounts1 != null && fullAmounts1.Any())
        //        fullAmounts.AddRange(fullAmounts1);
        //    if (fullAmounts2 != null && fullAmounts2.Any())
        //        fullAmounts.AddRange(fullAmounts2);

        //    return fullAmounts;
        //}

        /// <summary>
        /// 获取一次次绩效结果
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private List<ComputeResponse> GetAllotPerformance(int allotId, int hospitalId, int isShowManage)
        {
            var mTypes = new List<string>
            {
                AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString(),
                AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString(),
                AccountUnitType.行政工勤.ToString()
            };
            //// 获取医院是否开启后勤二次分配
            //var hospital = hospitalRepository.GetEntity(w => w.ID == hospitalId);
            //if (hospital?.IsOpenLogisticsSecondAllot != 1)
            //    mTypes.Add(AccountUnitType.行政工勤.ToString());

            var types1 = new List<string> { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString() };
            var types2 = new List<string> { AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString() };
            var types3 = new List<string> { AccountUnitType.行政工勤.ToString() };

            //// 业务中层人员信息
            //var empolyeeList = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId);
            // 一次绩效 获取特定人员绩效结果
            var allot = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && mTypes.Contains(t.AccountType) && (string.IsNullOrEmpty(t.NeedSecondAllot) || t.NeedSecondAllot == "否"))?.OrderByDescending(t => t.AccountingUnit);
            //var apramounts = perapramountRepository.GetEntities(t => t.AllotId == allotId);

            return allot?.Select(t =>
            {
                var comp = new ComputeResponse("一次绩效", t.AccountingUnit, t.EmployeeName, t.JobNumber, t.JobTitle ?? "");
                comp.UnitType = t.AccountType;
                comp.Adjust = t.Adjust;
                comp.AdjustLaterOtherFee = t.AdjustLaterOtherFee;

                // 行政中层  行政高层 补充  夜班费
                if (types2.Contains(t.AccountType))
                {
                    comp.PerforSumFee = t.GiveFee;
                    comp.PerforManagementFee = 0;
                    comp.NightWorkPerfor = t.NightWorkPerfor;
                }

                // 科主任/护士长
                if (types1.Contains(t.AccountType))
                {
                    comp.PerforManagementFee = t.AssessLaterManagementFee ?? 0;
                    // 等同于考核后管理绩效 AssessLaterManagementFee
                    // 兼容历史数据
                    if (comp.PerforManagementFee == 0)
                        comp.PerforManagementFee = Math.Round(t.ShouldGiveFee * t.ScoreAverageRate * t.Attendance + t.Punishment ?? 2);

                    // 仅显示管理绩效
                    if (isShowManage == 2)
                        comp.PerforSumFee = 0;
                    else
                        comp.PerforSumFee = t.Avg;
                }
                // 行政工勤
                if (types3.Contains(t.AccountType) && t.NeedSecondAllot?.Trim() == "否")
                {
                    comp.PerforSumFee = t.GiveFee;
                    comp.AdjustLaterOtherFee = 0;
                    comp.PerforManagementFee = 0;
                }

                return comp;
            }).ToList();
        }

        /// <summary>
        /// 获取二次绩效结果
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private List<ComputeResponse> GetSecondPerformance(int allotId)
        {
            List<ComputeResponse> responses = new List<ComputeResponse>();

            var again = _perforAgsecondallotRepository.GetComputeByAllot(allotId);
            if (again == null || !again.Any())
            {
                return responses;
            }

            var disAgains = again
                .Select(w => new { w.AllotId, w.SecondId, w.UnitType, w.Department, w.WorkPost, w.JobNumber, w.PersonName, w.PerforSumFee, w.NightWorkPerfor })
                .Distinct();

            responses = disAgains
                .GroupBy(t => new { t.UnitType, t.Department, t.WorkPost, t.JobNumber, t.PersonName })
                .Select(t =>
                {
                    var comp = new ComputeResponse("二次绩效", t.Key.Department, t.Key.PersonName, t.Key.JobNumber, t.Key.WorkPost ?? "");
                    comp.UnitType = t.Key.UnitType;
                    comp.PerforSumFee = t.Sum(g => g.PerforSumFee);
                    comp.NightWorkPerfor = t.Sum(g => g.NightWorkPerfor);
                    return comp;
                })?.ToList();

            return responses;
        }

        /// <summary>
        /// 添加额外绩效金额(基础绩效、其他绩效等)
        /// </summary>
        /// <param name="computes"></param>
        /// <param name="totalAmounts">医院其他绩效</param>
        /// <param name="totalAmounts_hide">不公示其他绩效</param>
        public void AddAprAmount(List<ComputeResponse> computes, List<view_per_total_amount> totalAmounts, List<view_per_total_amount> totalAmounts_hide)
        {
            foreach (var item in computes?.Where(w => !string.IsNullOrEmpty(w.JobNumber)).GroupBy(w => new { w.UnitType, w.AccountingUnit, w.JobNumber }))
            {
                var apramount1 = totalAmounts?.FirstOrDefault(t => t.UnitType == item.Key.UnitType && t.AccountingUnit == item.Key.AccountingUnit && item.Key.JobNumber?.Trim() == t.PersonnelNumber?.Trim());
                // 如果医院其他绩效 已经被使用，则不再多次带出，防止单个人多次出现造成金额叠加
                if (apramount1 != null)
                {
                    item.First().OthePerfor = apramount1.Amount;
                    apramount1.Use = true;
                }
                var apramount2 = totalAmounts_hide?.FirstOrDefault(t => t.UnitType == item.Key.UnitType && t.AccountingUnit == item.Key.AccountingUnit && item.Key.JobNumber?.Trim() == t.PersonnelNumber?.Trim());
                // 如果医院其他绩效 已经被使用，则不再多次带出，防止单个人多次出现造成金额叠加
                if (apramount2 != null)
                {
                    item.First().HideOtherPerfor = apramount2.Amount;
                    apramount2.Use = true;
                }
            }
        }

        #endregion 绩效发放列表

        public res_compute GetComputeSingle(int computeid)
        {
            return _perforRescomputeRepository.GetEntity(t => t.ID == computeid);
        }

        /// <summary>
        /// 修改实发绩效
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public res_compute UpdateRealfee(ComputerRequest request, int userId, string realName)
        {
            var compute = _perforRescomputeRepository.GetEntity(t => t.ID == request.ComputeId);
            var log = JsonHelper.Deserialize<List<ChangeLog>>(compute.ChangeLog);
            log = log ?? new List<ChangeLog>();
            log.Add(new ChangeLog
            {
                uid = userId,
                user = realName,
                date = DateTime.Now,
                value = compute.RealGiveFee
            });
            compute.RealGiveFee = request.RealGiveFee;
            compute.ChangeLog = JsonHelper.Serialize(log);
            if (!_perforRescomputeRepository.Update(compute))
                throw new PerformanceException("修改失败");

            return compute;
        }

        /// <summary>
        /// 返回绩效平均值
        /// </summary>
        /// <param name="type"></param>
        /// <param name="id"></param>
        /// <param name="score"></param>
        /// <returns></returns>
        public List<res_baiscnorm> GetBaiscnorm(int allotId)
        {
            return perforResbaiscnormRepository.GetEntities(t => t.AllotID == allotId)?.OrderBy(t => t.PositionName).ToList();
        }

        /// <summary>
        /// 返回科室详情
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="accountId"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        public DeptDataDetails DeptDetail(int accountId)
        {
            var account = perforResaccountRepository.GetEntity(t => t.ID == accountId);
            var allot = perforPerallotRepository.GetEntity(t => t.ID == account.AllotID);
            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == account.AllotID);
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == account.AllotID);
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == account.AllotID && t.AccountingUnit == account.AccountingUnit);

            //Func<string, string> getShowKey = (name) =>
            //{
            //    string _key = "开单";
            //    if (string.IsNullOrEmpty(name)) return _key;

            //    if (name.IndexOf("就诊") > -1)
            //        _key = "就诊";

            //    return _key;
            //};

            //string key = getShowKey.Invoke(persheet.FirstOrDefault(t => t.SheetName.NoBlank().StartsWith("1.1.1"))?.SheetName);


            DeptDataDetails deptDetails = new DeptDataDetails
            {
                ShowFormula = allot.ShowFormula,
                Pandect = _mapper.Map<PerDataAccountBaisc>(account),
                Detail = new List<DetailDtos>()
            };

            if (basicData == null || !basicData.Any()) return deptDetails;

            var sheetType = new List<int>
            {
                (int)SheetType.Income, (int)SheetType.OtherIncome, (int)SheetType.Expend, (int)SheetType.Workload,
                (int)SheetType.AccountExtra,(int)SheetType.AccountDrugAssess, (int)SheetType.AccountMaterialsAssess, (int)SheetType.AccountScoreAverage,
                (int)SheetType.AccountAdjustLaterOtherFee, (int)SheetType.BudgetRatio, (int)SheetType.AssessBeforeOtherFee,
            };

            int groupbasis = 1; string single = "";
            foreach (var stype in sheetType)
            {
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    var type = TypeConversion(account.UnitType);
                    if (single != "" && sheet.SheetName.Substring(0, 3) != single)
                        groupbasis += 1;
                    single = sheet.SheetName.Substring(0, 3);

                    var sheetName = new Regex("[0-9]*").Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    // 只是显示好看而已
                    if (sheetName != "科室考核")
                        sheetName = sheetName.Replace("科室绩效", "").Replace("科室", "");
                    var (sheettype, amount) = ClinicDepartmentDetail(persheet, account, basicData, sheet, type, sheetName);
                    (sheettype, amount) = CommonDepartmentDetail(basicData, sheet, type, sheettype, amount);
                    var items = CommonDetailItems(basicData, headers, sheet, type);

                    if (sheet.SheetType == (int)SheetType.Workload)
                    {
                        items = items.Where(w => w.Factor.HasValue && w.Factor != 0).ToList();
                        if ((sheetName.Contains("医生") && account.UnitType == (int)UnitType.护理组) || (sheetName.Contains("护理") && account.UnitType != (int)UnitType.护理组))
                            continue;

                        var workitems = cofworkitemRepository.GetEntities(t => t.AllotID == account.AllotID);
                        //var allotCmi = cofcmiRepository.GetEntity(t => t.AllotId == account.AllotID && t.UnitType == account.UnitType && t.AccountingUnit == account.AccountingUnit);
                        var medicineFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadMedicineProp);
                        var cmiFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadCMI);
                        var inclineFactor = GetFactors(persheet, basicData, type, SheetType.WorkloadIncline);

                        foreach (var dto in items)
                        {
                            if (workitems != null && workitems.Any(a => a.Type == 1 && a.Item == dto.ItemName) && medicineFactor != null)
                                dto.MediFactor = medicineFactor;
                            if (workitems != null && workitems.Any(a => a.Type == 2 && a.Item == dto.ItemName) && cmiFactor != null)
                                dto.CMIFactor = cmiFactor;
                            if (workitems != null && workitems.Any(a => a.Type == 3 && a.Item == dto.ItemName) && inclineFactor != null)
                                dto.InclineFactor = inclineFactor;
                            dto.ItemValue = dto.ItemValue * (dto.MediFactor ?? 1) * (dto.CMIFactor ?? 1) * (dto.InclineFactor ?? 1);
                        }
                    }

                    if (sheet.SheetType == (int)SheetType.OtherIncome)
                        items = items.Where(t => (t.ItemValue ?? 0) != 0).ToList();

                    if (items != null && items.Count > 0)
                    {
                        var item = new DetailDtos { ItemName = sheetName, IncomeType = sheettype, OriginalType = sheet.SheetType ?? 0, Amount = amount, GroupBasis = groupbasis, Items = items };
                        deptDetails.Detail.Add(item);
                    }
                }
            }

            // 展示额外处理，根据禅道057
            deptDetails.Pandect.ScoringAverage = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountScoreAverage)?.Amount ?? deptDetails.Pandect.ScoringAverage;
            deptDetails.Pandect.Extra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountExtra)?.Amount ?? deptDetails.Pandect.Extra;
            deptDetails.Pandect.MaterialsExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountMaterialsAssess)?.Amount ?? deptDetails.Pandect.MaterialsExtra;
            deptDetails.Pandect.MedicineExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountDrugAssess)?.Amount ?? deptDetails.Pandect.MedicineExtra;

            //return MergeDetails(deptDetails, key);
            return deptDetails;
        }

        private decimal? GetFactors(List<per_sheet> persheet, List<im_data> basicData, UnitType type, SheetType sheetType)
        {
            var sheet = persheet.FirstOrDefault(w => w.SheetType == (int)sheetType);
            return basicData.FirstOrDefault(t => t.SheetID == sheet?.ID && t.UnitType == (int)type && t.IsTotal == 1)?.CellValue;
        }

        private (int sheettype, decimal amount) ClinicDepartmentDetail(List<per_sheet> persheet, res_account account, List<im_data> basicData, per_sheet sheet, UnitType type, string sheetName)
        {
            var sheettype = 1;
            var amount = 0m;

            if (sheet.SheetType == (int)SheetType.Income)
            {
                sheettype = 1;
                amount = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal != 1)?.Sum(t => t.IsFactor == 1 ? t.CellValue * (t.FactorValue ?? 0) : t.CellValue) ?? 0;
            }
            else if (sheet.SheetType == (int)SheetType.Workload)
            {
                sheettype = 3;
                amount = account.WorkloadFee ?? 0m;
            }
            else if (sheet.SheetType == (int)SheetType.OtherIncome)
            {
                sheettype = 1;
                amount = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal != 1)?.Sum(t => t.IsFactor == 1 ? t.CellValue * (t.FactorValue ?? 0) : t.CellValue) ?? 0;
            }
            else if (sheet.SheetType == (int)SheetType.Expend)
            {
                //科室经济
                var sheetEconomic = persheet.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
                var dataEconomicList = basicData.Where(t => t.SheetID == sheetEconomic?.ID && t.IsTotal != 1 && t.AccountingUnit == account.AccountingUnit).ToList();
                string typeValue = EnumHelper.GetDescription((UnitType)account.UnitType);
                var economic = dataEconomicList?.Select(t => new
                {
                    ItemName = t.TypeName.Replace($"({typeValue})", ""),
                    ItemValue = t.CellValue ?? 0,
                    t.UnitType
                });
                sheettype = 2;
                amount = economic.FirstOrDefault(t => t.ItemName.Contains(sheetName) && t.UnitType == (int)type)?.ItemValue ?? 0m;
            }
            return (sheettype, amount);
        }

        private (int sheettype, decimal amount) CommonDepartmentDetail(List<im_data> basicData, per_sheet sheet, UnitType type, int sheettype = -1, decimal amount = 0)
        {
            //var sheettype = 1; var amount = 0m;

            //if (pairs.ContainsKey((SheetType)sheet.SheetType))
            //{
            //    sheettype = 5;
            //    amount = pairs[(SheetType)sheet.SheetType] ?? 0;
            //}
            //else if (sheet.SheetType == (int)SheetType.AccountScoreAverage)
            //{
            //    sheettype = 8;
            //    amount = Math.Round(basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0, 4);
            //}
            //else if (sheet.SheetType == (int)SheetType.AccountAdjustLaterOtherFee)
            //{
            //    sheettype = 9;
            //    amount = Math.Round(basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0, 0);
            //}

            SheetType[] pairs = new SheetType[]
            {
                SheetType.AccountExtra, SheetType.AccountDrugAssess, SheetType.AccountMaterialsAssess, SheetType.AccountScoreAverage, SheetType.AccountAdjustLaterOtherFee,
                SheetType.AssessBeforeOtherFee, SheetType.BudgetRatio,
            };
            if (pairs.Contains((SheetType)sheet.SheetType))
            {
                sheettype = 5;
                amount = basicData?.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)type && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0;
                //if (sheet.SheetType != (int)SheetType.BudgetRatio)
                //    amount = GetDecimal(amount, 0);
                if (amount > 5)
                    amount = GetDecimal(amount, 0);
            }
            return (sheettype, amount);
        }

        private List<DetailModule> CommonDetailItems(List<im_data> basicData, List<im_header> headers, per_sheet sheet, UnitType type)
        {
            Expression<Func<im_data, bool>> exp = (t) => t.SheetID == sheet.ID && (t.IsTotal ?? 0) != 1;

            if (sheet.SheetType == (int)SheetType.Workload && new int[] { (int)UnitType.医技组, (int)UnitType.其他医技组 }.Contains((int)type))
                exp = exp.And(t => new int[] { (int)UnitType.医生组, (int)UnitType.医技组, (int)UnitType.其他医技组 }.Contains(t.UnitType.Value));
            else
                exp = exp.And(t => t.UnitType == (int)type);

            var items = basicData.Where(exp.Compile())?.Select(t => new DetailModule
            {
                ItemName = t.TypeName,
                CellValue = t.CellValue,
                Factor = sheet.SheetType == (int)SheetType.Workload ? t.FactorValue : t.FactorValue * 100,
                ItemValue = t.IsFactor == 1 ? (t.CellValue * (t.FactorValue ?? 0)) : t.CellValue,
            }).ToList();

            if (items != null && items.Any())
            {
                items = items.GroupBy(t => t.ItemName).Select(t =>
                {
                    var dto = new DetailModule
                    {
                        ItemName = t.Key,
                        CellValue = t.Sum(group => group.CellValue),
                        Factor = t.FirstOrDefault().Factor,
                        ItemValue = t.Sum(group => group.ItemValue),
                    };

                    return dto;
                }).ToList();
            }
            var headerData = headers?.Where(t => t.SheetID == sheet.ID);
            if (headerData != null && headerData.Any())
            {
                items = items
                    ?.OrderBy(t => (headerData.FirstOrDefault(h => h.CellValue == t.ItemName)?.PointCell) ?? 100)
                    ?.ThenBy(t => t.ItemName).ToList();
            }
            return items;
        }

        private DeptDataDetails<DetailModuleExtend> MergeDetails(DeptDataDetails details, string key)
        {
            if (details == null) return new DeptDataDetails<DetailModuleExtend>();

            var result = new DeptDataDetails<DetailModuleExtend>()
            {
                ShowFormula = details.ShowFormula,
                Pandect = details.Pandect,
                Detail = new List<DetailDtos<DetailModuleExtend>>(),
            };

            if (details.Detail == null) return result;

            foreach (var groupbasis in details.Detail.Select(t => t.GroupBasis).Distinct())
            {
                var items = new List<DetailModuleExtend>();
                var data = details.Detail.Where(t => t.GroupBasis == groupbasis).ToList();
                if (data.Count() > 1)
                {
                    var depts = new List<string>();
                    data.ForEach(t =>
                    {
                        depts.AddRange(t.Items.Select(o => o.ItemName));
                    });
                    var billing = data.FirstOrDefault(t => t.ItemName.IndexOf(key) > -1);
                    var execute = data.FirstOrDefault(t => t.ItemName.IndexOf("执行") > -1);
                    foreach (var dept in depts.Distinct().OrderBy(t => t))
                    {
                        var item1 = billing?.Items.FirstOrDefault(t => t.ItemName == dept);
                        var item2 = execute?.Items.FirstOrDefault(t => t.ItemName == dept);

                        items.Add(new DetailModuleExtend
                        {
                            ItemName = dept,
                            ItemValue = item1?.ItemValue,
                            ItemValue2 = item2?.ItemValue,
                            CellValue = item1?.CellValue,
                            CellValue2 = item2?.CellValue,
                            Factor = item1?.Factor,
                            Factor2 = item2?.Factor,
                        });
                    }
                }
                else
                {
                    if (data.FirstOrDefault().ItemName.IndexOf("执行") > -1)
                    {
                        items = data.First().Items.Select(t => new DetailModuleExtend
                        {
                            ItemName = t.ItemName,
                            ItemValue2 = t.ItemValue,
                            CellValue2 = t.CellValue,
                            Factor2 = t.Factor,
                        }).ToList();
                    }
                    else
                    {
                        items = data.First().Items.Select(t => new DetailModuleExtend
                        {
                            ItemName = t.ItemName,
                            ItemValue = t.ItemValue,
                            CellValue = t.CellValue,
                            Factor = t.Factor,
                            MediFactor = t.MediFactor,
                            CMIFactor = t.CMIFactor,
                            InclineFactor = t.InclineFactor,
                        }).ToList();
                    }
                }

                result.Detail.Add(new DetailDtos<DetailModuleExtend>
                {
                    ItemName = data.FirstOrDefault(t => t.ItemName.IndexOf("执行") > -1) is null ? data.First().ItemName :
                    data.FirstOrDefault(t => t.ItemName.IndexOf("执行") > -1).ItemName?.Replace("执行", $"{key}/执行"),
                    IncomeType = data.First()?.IncomeType ?? 0,
                    OriginalType = data.First()?.OriginalType ?? 0,
                    Amount = data.Sum(w => w.Amount),
                    GroupBasis = groupbasis,
                    Items = items
                });
            }

            return result;
        }

        private UnitType TypeConversion(int? unitType)
        {
            UnitType type = (UnitType)unitType.Value;

            var docUnitTypes = new List<UnitType> { UnitType.专家组, UnitType.其他医生组, UnitType.其他医技组 };
            if (docUnitTypes.Contains(type))
                type = UnitType.医生组;
            else if (type == UnitType.其他护理组)
                type = UnitType.护理组;
            return type;
        }

        public DeptDataDetails DeptOfficeDetail(int accountId)
        {
            var account = perforResaccountRepository.GetEntity(t => t.ID == accountId);
            var allot = perforPerallotRepository.GetEntity(t => t.ID == account.AllotID);
            var computes = _perforRescomputeRepository.GetEntities(t => t.AllotID == account.AllotID && t.AccountType == AccountUnitType.行政工勤.ToString() && t.AccountingUnit == account.AccountingUnit);
            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == account.AllotID);
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == account.AllotID);
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == account.AllotID && t.AccountingUnit == account.AccountingUnit);

            DeptDataDetails deptDetails = new DeptDataDetails
            {
                ShowFormula = allot.ShowFormula,
                Pandect = _mapper.Map<PerDataAccountBaisc>(account),
                Detail = new List<DetailDtos>()
            };

            var detail = new DetailDtos
            {
                ItemName = "后勤人员",
                IncomeType = 9,
                OriginalType = 4,
                Amount = account.PerforTotal ?? 0,
                Items = new List<DetailModule>(),
                GroupBasis = 1,
            };
            if (computes != null)
            {
                foreach (var item in computes)
                {
                    detail.Items.Add(new DetailModule
                    {
                        JobNumber = item.JobNumber,
                        ItemName = item.EmployeeName,
                        ItemValue = Math.Round(item.PerforTotal ?? 0, 2),
                        OtherPerfor = item.OtherPerfor,
                        Attendance = item.Attendance,
                        PostCoefficient = item.PostCoefficient,
                    });
                }
            }

            deptDetails.Detail.Add(detail);

            if (basicData == null || !basicData.Any()) return deptDetails;

            var sheetType = new List<int>
            {
                (int)SheetType.AccountExtra, (int)SheetType.AccountDrugAssess, (int)SheetType.AccountMaterialsAssess,
                (int)SheetType.AccountScoreAverage, (int)SheetType.AccountAdjustLaterOtherFee
            };
            int groupBasis = 0;
            foreach (var stype in sheetType)
            {
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    groupBasis++;
                    var (sheettype, amount) = CommonDepartmentDetail(basicData, sheet, UnitType.行政后勤);
                    var items = CommonDetailItems(basicData, headers, sheet, UnitType.行政后勤);

                    var sheetName = new Regex("[0-9]*").Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    // 只是显示好看而已
                    if (sheetName != "科室考核")
                        sheetName = sheetName.Replace("科室绩效", "").Replace("科室", "");

                    if (items != null && items.Count > 0)
                    {
                        var item = new DetailDtos { ItemName = sheetName, IncomeType = sheettype, OriginalType = sheet.SheetType ?? 0, Amount = amount, GroupBasis = groupBasis, Items = items };
                        deptDetails.Detail.Add(item);
                    }
                }
            }
            // 特殊 6.11个人岗位系数
            var postSheet = persheet.FirstOrDefault(t => t.SheetType == (int)SheetType.PersonPostCoefficient);
            if (postSheet != null)
            {
                groupBasis++;
                var postDatas = basicData?.Where(w => w.SheetID == postSheet.ID && w.AccountingUnit == account?.AccountingUnit);
                foreach (var post in postDatas?.GroupBy(w => new { w.JobNumber }))
                {
                    var amount = post.FirstOrDefault(w => w.IsTotal == 1)?.CellValue ?? 0;
                    var items = post.Where(w => w.SheetID == postSheet.ID && w.IsTotal != 1)?.Select(t => new DetailModule
                    {
                        ItemName = t.TypeName,
                        CellValue = t.CellValue,
                        Factor = t.FactorValue,
                        ItemValue = t.IsFactor == 1 ? (t.CellValue * (t.FactorValue ?? 0)) : t.CellValue,
                    }).ToList();

                    if (items != null && items.Count > 0)
                    {
                        var itemName = $"个人系数（{post.Key.JobNumber} {post.FirstOrDefault()?.EmployeeName}）";
                        var item = new DetailDtos { ItemName = itemName, IncomeType = 5, OriginalType = postSheet.SheetType ?? 0, Amount = amount, GroupBasis = groupBasis, Items = items };
                        deptDetails.Detail.Add(item);
                    }
                }
            }
            // 展示额外处理，根据禅道057
            deptDetails.Pandect.ScoringAverage = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountScoreAverage)?.Amount ?? deptDetails.Pandect.ScoringAverage;
            deptDetails.Pandect.Extra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountExtra)?.Amount ?? deptDetails.Pandect.Extra;
            deptDetails.Pandect.MaterialsExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountMaterialsAssess)?.Amount ?? deptDetails.Pandect.MaterialsExtra;
            deptDetails.Pandect.MedicineExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountDrugAssess)?.Amount ?? deptDetails.Pandect.MedicineExtra;

            return deptDetails;
        }

        public DeptDataDetails SpecialDeptDetail(ag_secondallot second)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == second.AllotId);
            var special = _perforResspecialunitRepository.GetEntities(t => t.AllotID == second.AllotId && t.Department == second.Department);
            if (special == null || !special.Any())
                return new DeptDataDetails();

            DeptDataDetails deptDetails = new DeptDataDetails
            {
                ShowFormula = allot.ShowFormula,
                Pandect = new PerDataAccountBaisc
                {
                    UnitType = second.UnitType,
                    AccountingUnit = second.Department,
                    //Department = second.Department,
                    ScoringAverage = special.FirstOrDefault()?.ScoringAverage ?? 1,
                    //OtherPerfor1 = special.FirstOrDefault()?.OtherPerfor ?? 0,
                    AdjustFactor = special.FirstOrDefault()?.Adjust ?? 1,
                    Avg = special.FirstOrDefault()?.Avg,
                    RealGiveFee = special.FirstOrDefault()?.RealGiveFee,
                    Number = special.FirstOrDefault()?.Number ?? 0,
                    PerforFee = special.FirstOrDefault()?.GiveFee,
                    PerforTotal = special.FirstOrDefault()?.ResultsTotalFee,
                    Income = special.FirstOrDefault()?.ResultsTotalFee,
                    Extra = special.FirstOrDefault()?.Punishment ?? 0,
                    MedicineExtra = special.FirstOrDefault()?.MedicineExtra ?? 0,
                    MaterialsExtra = special.FirstOrDefault()?.MaterialsExtra ?? 0,
                    AssessBeforeOtherFee = special.FirstOrDefault()?.AssessBeforeOtherFee ?? 0,
                    AssessLaterOtherFee = special.FirstOrDefault()?.AssessLaterOtherFee ?? 0,
                    AdjustLaterOtherFee = special.FirstOrDefault()?.AdjustLaterOtherFee ?? 0,
                    AssessLaterPerforTotal = special.FirstOrDefault()?.GiveFee ?? 0, // 考核后绩效 特殊情况，为了前端统一
                },
                Detail = new List<DetailDtos>(),
            };
            var detail = new DetailDtos
            {
                ItemName = "特殊核算单元绩效测算表",
                IncomeType = 4,
                OriginalType = 4,
                Amount = special.First().ResultsTotalFee ?? 0,
                Items = new List<DetailModule>(),
                GroupBasis = 1,
            };
            foreach (var item in special)
            {
                detail.Items.Add(new DetailModule
                {
                    ItemName = item.QuantitativeIndicators,
                    CellValue = item.Quantity,
                    Factor = item.QuantitativeIndicatorsValue,
                    ItemValue = Math.Round(item.QuantitativeFee ?? 0, 2)
                });
            }
            deptDetails.Detail.Add(detail);

            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == second.AllotId);
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == second.AllotId);
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == second.AllotId && t.AccountingUnit == second.Department);

            var sheetType = new List<int>
            {
                (int)SheetType.AccountExtra,(int)SheetType.AccountDrugAssess, (int)SheetType.AccountMaterialsAssess,
                (int)SheetType.AccountScoreAverage, (int)SheetType.AccountAdjustLaterOtherFee,
                (int)SheetType.BudgetRatio, (int)SheetType.AssessBeforeOtherFee,
            };

            int groupBasis = 0;
            foreach (var stype in sheetType)
            {
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    groupBasis++;
                    var (sheettype, amount) = CommonDepartmentDetail(basicData, sheet, UnitType.特殊核算组);
                    var items = CommonDetailItems(basicData, headers, sheet, UnitType.特殊核算组);

                    var sheetName = new Regex("[0-9]*").Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    // 只是显示好看而已
                    if (sheetName != "科室考核")
                        sheetName = sheetName.Replace("科室绩效", "").Replace("科室", "");

                    if (items != null && items.Count > 0)
                    {
                        var item = new DetailDtos { ItemName = sheetName, IncomeType = sheettype, OriginalType = sheet.SheetType ?? 0, Amount = amount, GroupBasis = groupBasis, Items = items };
                        deptDetails.Detail.Add(item);
                    }
                }
            }

            // 展示额外处理，根据禅道057
            deptDetails.Pandect.ScoringAverage = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountScoreAverage)?.Amount ?? deptDetails.Pandect.ScoringAverage;
            deptDetails.Pandect.Extra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountExtra)?.Amount ?? deptDetails.Pandect.Extra;
            deptDetails.Pandect.MaterialsExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountMaterialsAssess)?.Amount ?? deptDetails.Pandect.MaterialsExtra;
            deptDetails.Pandect.MedicineExtra = deptDetails.Detail?.FirstOrDefault(w => w.OriginalType == (int)SheetType.AccountDrugAssess)?.Amount ?? deptDetails.Pandect.MedicineExtra;

            return deptDetails;
        }

        //private List<DetailModule> GetExtraDetail(int allotId, int unitType, string accountingUnit)
        //{
        //    var result = new List<DetailModule>();
        //    var sheetId = _perforPerSheetRepository.GetEntity(t => t.AllotID == allotId && t.SheetType == (int)SheetType.AccountExtra)?.ID;
        //    if (!sheetId.HasValue) return result;

        //    var data = _perforImDataRepository.GetEntities(t => t.AllotID == allotId && t.SheetID == sheetId && t.UnitType == unitType
        //    && t.AccountingUnit == accountingUnit && t.IsTotal != 1);
        //    if (data == null || !data.Any()) return result;

        //    result = data.Select(t => new DetailModule
        //    {
        //        ItemName = t.TypeName,
        //        CellValue = t.CellValue,
        //        ItemValue = t.CellValue,
        //    }).ToList();

        //    return result;
        //}

        public ag_secondallot GetAccountId(int secondId, out int accountId)
        {
            accountId = 0;
            var second = _perforAgsecondallotRepository.GetEntity(t => t.Id == secondId);
            if (second != null)
            {
                var unitType = EnumHelper.GetItems<UnitType>().FirstOrDefault(t => t.Name == second.UnitType);
                var account = perforResaccountRepository.GetEntity(t => t.AllotID == second.AllotId && t.UnitType == unitType.Value && t.AccountingUnit == second.Department);
                if (account == null && second.UnitType != UnitType.特殊核算组.ToString())
                    throw new PerformanceException("科室信息错误");
                accountId = account?.ID ?? 0;
            }
            return second;
        }

        public ag_secondallot GetSecondByAccountId(int accountId)
        {
            var special = _perforResspecialunitRepository.GetEntity(t => t.ID == accountId);
            if (special == null)
                throw new PerformanceException("科室信息错误");
            return new ag_secondallot
            {
                AllotId = special.AllotID,
                Department = special.AccountingUnit,
                UnitType = UnitType.特殊核算组.ToString()
            };
        }

        public DeptDataDetails GetDoctorDetail(int computeId)
        {
            var resCompute = _perforRescomputeRepository.GetEntity(t => t.ID == computeId);
            if (resCompute == null) return new DeptDataDetails();

            //var allot = perforPerallotRepository.GetEntity(t => t.ID == resCompute.AllotID);
            //if (allot == null) return new DeptDataDetails();

            var employee = _perforImemployeeclinicRepository.GetEntity(t => t.AllotID == resCompute.AllotID && t.AccountingUnit == resCompute.AccountingUnit && t.UnitType == resCompute.UnitType && t.PersonnelNumber == resCompute.JobNumber);
            DeptDataDetails doctorDetails = new DeptDataDetails
            {
                ShowFormula = 0,
                Pandect = new PerDataAccountBaisc
                {
                    BasicFactor = employee?.Basics ?? 0,    //基础绩效系数
                    Effic = employee?.Efficiency ?? 0,   //效率绩效系数
                    Scale = employee?.Scale ?? 0,    //规模绩效系数
                    Management = employee?.Management ?? 0,//管理绩效发放系数
                    AdjustFactor = employee?.Adjust ?? 1,   //调节系数
                    AdjustLaterOtherFee = employee?.AdjustLaterOtherFee ?? 0, //调节后其他绩效

                    AccountingUnit = resCompute.AccountingUnit,
                    EmployeeName = resCompute.EmployeeName,
                    PerforTotal = resCompute.PerforTotal,   //科室考核前绩效
                    Number = resCompute.Number ?? 0,    //核算人数
                    AvgPerfor = (resCompute.Number ?? 0) == 0 ? 0 : resCompute.PerforTotal / resCompute.Number, //人均绩效
                    Attendance = resCompute.Attendance ?? 1, //出勤率
                    Avg = resCompute.Avg,   //实际人均
                    PermanentStaff = resCompute.PermanentStaff ?? 0,    //效率绩效人数
                    EfficPerfor = resCompute.Efficiency ?? 0,   //效率绩效
                    ScalePerfor = resCompute.Scale ?? 0,    //规模绩效
                    Extra = resCompute.Punishment ?? 0,     //医院奖罚
                    OtherManagePerfor = resCompute.OtherManagePerfor ?? 0, //其他管理绩效
                    ShouldGiveFee = resCompute.ShouldGiveFee ?? 0,  //考核前管理绩效
                    ScoringAverage = resCompute.ScoreAverageRate ?? 1,  //考核得分率
                    AssessLaterManagementFee = GetDecimal(resCompute.ShouldGiveFee * resCompute.ScoreAverageRate * resCompute.Attendance + resCompute.Punishment ?? 0), //考核后管理绩效
                    RealGiveFee = resCompute.RealGiveFee    //绩效合计
                },
                Detail = new List<DetailDtos>()
            };
            var isShowManage = IsShowManage(resCompute.AllotID.Value);

            // 开启 显示管理绩效
            if (isShowManage != 1)
                doctorDetails.Pandect.RealGiveFee = doctorDetails.Pandect.AssessLaterManagementFee * (resCompute.Adjust ?? 1) + (resCompute.AdjustLaterOtherFee ?? 0);

            var types = new int[]
            {
                (int)SheetType.PersonExtra, (int)SheetType.PersonAdjustLaterOtherFee, (int)SheetType.PersonAdjustLaterOtherManagePerforFee,
                (int)SheetType.PersonPostCoefficient, (int)SheetType.PersonOtherManagePerforFee,
            };
            var sheets = _perforPerSheetRepository.GetEntities(t => t.AllotID == resCompute.AllotID && types.Contains(t.SheetType.Value));
            if (sheets == null || !sheets.Any()) return doctorDetails;

            var data = _perforImDataRepository.GetEntities(t => t.AllotID == resCompute.AllotID && sheets.Select(s => s.ID).Contains(t.SheetID.Value)
                && t.JobNumber == resCompute.JobNumber) ?? new List<im_data>();
            data = data.Where(t => ((UnitType)t.UnitType).ToString() == resCompute.UnitType && t.AccountingUnit == resCompute.AccountingUnit).ToList();

            foreach (var sheet in sheets)
            {
                var sheetData = data.Where(t => t.SheetID == sheet.ID);
                if (sheetData == null || !sheetData.Any()) continue;

                var itemName = Regex.Replace(sheet.SheetName, @"\d", "");
                var detail = new DetailDtos
                {

                    ItemName = itemName.Replace(".", "").Replace(" ", ""),
                    IncomeType = sheet.SheetType == (int)SheetType.PersonExtra ? 5 : 8,
                    OriginalType = sheet.SheetType ?? 0,
                    Amount = sheetData.Where(t => t.IsTotal == 1)?.Sum(t => t.CellValue) ?? 0,
                    Items = sheetData.Where(t => t.IsTotal != 1)?.Select(t => new DetailModule
                    {
                        ItemName = t.TypeName,
                        ItemValue = t.CellValue
                    }).ToList()
                };
                doctorDetails.Detail.Add(detail);
            }
            return doctorDetails;
        }

        public DeptDataDetails GetAdministration(int computeId)
        {
            var resCompute = _perforRescomputeRepository.GetEntity(t => t.ID == computeId);
            if (resCompute == null) return new DeptDataDetails();

            //var employee = _perforImemployeeRepository.GetEntity(t => t.AllotID == resCompute.AllotID && t.AccountingUnit == resCompute.AccountingUnit && t.PersonnelNumber == resCompute.JobNumber);

            DeptDataDetails doctorDetails = new DeptDataDetails
            {
                ShowFormula = 0,
                Pandect = new PerDataAccountBaisc
                {
                    EmployeeName = resCompute.EmployeeName,//医生姓名
                    JobNumber = resCompute.JobNumber,//工号
                    AccountingUnit = resCompute.AccountingUnit,//核算单元
                    AccountType = resCompute.AccountType,//核算单元类型
                    JobTitle = resCompute.JobTitle,//职称
                    FitPeople = resCompute.FitPeople,//绩效基数核算参考对象
                    FitPeopleValue = resCompute.FitPeopleValue ?? 0,//绩效基础核算参考值
                    FitPeopleRatio = resCompute.FitPeopleRatio,//绩效基础核算系数
                    PostCoefficient = resCompute.PostCoefficient,//岗位系数
                    Attendance = resCompute.Attendance,//出勤率
                    ScoringAverage = resCompute?.ScoreAverageRate,//考核得分率
                    AssessBeforeOtherFee = resCompute.AssessBeforeOtherFee ?? 0,
                    Extra = resCompute.Punishment,//医院奖罚
                    NightShiftWorkPerforFee = resCompute.NightWorkPerfor,//夜班费
                    AdjustFactor = resCompute.Adjust,//调节系数
                    AdjustLaterOtherFee = resCompute?.AdjustLaterOtherFee ?? 0,//调解后其他绩效
                    PerforTotal = resCompute.PerforTotal,//考核前绩效
                    GiveFee = resCompute.GiveFee,//考核后绩效
                    RealGiveFee = resCompute.RealGiveFee //实发绩效

                },

                Detail = new List<DetailDtos>()
            };

            var isShowManage = IsShowManage(resCompute.AllotID.Value);

            var types = new int[]
            {
                (int)SheetType.PersonExtra, (int)SheetType.PersonAdjustLaterOtherFee, (int)SheetType.PersonAdjustLaterOtherManagePerforFee,
                (int)SheetType.PersonPostCoefficient, (int)SheetType.PersonOtherManagePerforFee,
            };
            var sheets = _perforPerSheetRepository.GetEntities(t => t.AllotID == resCompute.AllotID && types.Contains(t.SheetType.Value));
            if (sheets == null || !sheets.Any()) return doctorDetails;

            var data = _perforImDataRepository.GetEntities(t => t.AllotID == resCompute.AllotID && sheets.Select(s => s.ID).Contains(t.SheetID.Value));
            if (data == null || !data.Any(t => t.JobNumber == (resCompute.JobNumber ?? "") && t.EmployeeName == resCompute.EmployeeName)) return doctorDetails;

            data = data.Where(t => t.JobNumber == (resCompute.JobNumber ?? "") && t.EmployeeName == resCompute.EmployeeName).ToList();
            foreach (var sheet in sheets)
            {
                var sheetData = data.Where(t => t.SheetID == sheet.ID);
                if (sheetData == null || !sheetData.Any()) continue;

                var itemName = Regex.Replace(sheet.SheetName, @"\d", "");
                var detail = new DetailDtos
                {
                    ItemName = itemName.Replace(".", "").Replace(" ", ""),
                    IncomeType = sheet.SheetType == (int)SheetType.PersonExtra ? 5 : 8,
                    OriginalType = sheet.SheetType ?? 0,
                    Amount = sheetData.Where(t => t.IsTotal == 1)?.Sum(t => t.CellValue) ?? 0,
                    Items = sheetData.Where(t => t.IsTotal != 1)?.Select(t => new DetailModule
                    {
                        ItemName = t.TypeName,
                        ItemValue = t.CellValue
                    }).ToList()
                };
                doctorDetails.Detail.Add(detail);
            }

            return doctorDetails;
        }

        public res_baiscnorm EditHospitalAvg(ComputerAvgRequest request)
        {
            if (request.Id == 0)
            {
                var baiscnorm = _mapper.Map<res_baiscnorm>(request);
                if (!perforResbaiscnormRepository.Add(baiscnorm))
                    throw new PerformanceException("保存失败");
                return _mapper.Map<res_baiscnorm>(baiscnorm);
            }
            else
            {
                var baiscnorm = perforResbaiscnormRepository.GetEntity(t => t.ID == request.Id);
                if (baiscnorm == null)
                    throw new PerformanceException($"ID不存在 ：{request.Id}");

                baiscnorm.TotelNumber = request.TotelNumber;
                baiscnorm.TotelValue = request.TotelValue;
                baiscnorm.AvgValue = request.AvgValue;

                //var baiscnorm = _mapper.Map<res_baiscnorm>(request);
                if (!perforResbaiscnormRepository.Update(baiscnorm))
                    throw new PerformanceException("保存失败");
                return _mapper.Map<res_baiscnorm>(baiscnorm);
            }
        }


        //public List<Dictionary<string, string>> GetOtherPerStats(List<per_apr_amount> employees)
        //{
        //    var others = new List<Dictionary<string, string>>();
        //    if (employees == null)
        //        return others;

        //    var perForType = employees.Where(c => c.Status == 3).Select(t => t.PerforType).Distinct();
        //    var doctorNum = employees.Where(c => c.Status == 3).Select(t => t.PersonnelNumber).Distinct().ToList();

        //    if (!doctorNum.Any())
        //        return others;

        //    foreach (var num in doctorNum)
        //    {
        //        var dicData = new Dictionary<string, string>();
        //        var amount = employees.Find(t => t.PersonnelNumber == num);
        //        if (amount == null)
        //            continue;
        //        dicData.Add("核算单元", amount?.AccountingUnit ?? "");
        //        dicData.Add("工号", amount?.PersonnelNumber ?? "");
        //        dicData.Add("人员姓名", amount?.DoctorName ?? "");

        //        foreach (var type in perForType)
        //        {
        //            var emp = employees.Where(t => t.PerforType == type && t.PersonnelNumber == num)?.ToList();
        //            if (!emp.Any())
        //                dicData.Add(type, "0");
        //            else
        //                dicData.Add(type, Math.Round(Convert.ToDecimal(emp?.Sum(c => c.Amount))).ToString());
        //        }

        //        var sum = employees.Where(c => c.PersonnelNumber == num)?.Sum(t => t.Amount);
        //        dicData.Add("合计", Math.Round(Convert.ToDecimal(sum), 0).ToString());
        //        others.Add(dicData);
        //    }

        //    return others;
        //}

        private decimal GetDecimal(decimal? value, decimal _ = 0)
        {
            if (!value.HasValue)
                return _;

            int decimals = Math.Abs(value.Value) > 100 ? 0 : 2;
            return Math.Round(value.Value, decimals, MidpointRounding.AwayFromZero);
        }



        /// <summary>
        /// 自定义列头显示状态
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool UpdateHeadersStatus(ComputerAliasUpdate request)
        {
            var heads = CustomColumnHeaders(request.HospitalId, request.Route);
            var list = cofaliasRepository.GetEntities(w => w.HospitalId == request.HospitalId && w.Route == request.Route);

            var hasreq = request.computerAliasHead != null && request.computerAliasHead.Any();
            var hasdata = list != null && list.Any();

            // 数据库中无数据
            if (hasreq && !hasdata)
            {
                var items = request.computerAliasHead.Select(t => t.Head.ToLower());
                var data = heads.Select(t => new cof_alias
                {
                    Route = request.Route,
                    Alias = request.computerAliasHead.FirstOrDefault(w => w.Name == t.Name)?.Head ?? t.Alias,
                    OriginalName = t.Alias,
                    HospitalId = request.HospitalId,
                    Name = t.Name,
                    States = items.Contains(t.Alias ?? "") ? 1 : 0,
                    SumStatus = t.SumStatus,
                    Sort = request.computerAliasHead.Any(w => w.Name == t.Name)
                        ? request.computerAliasHead.FirstOrDefault(w => w.Name == t.Name).Sort
                        : t.Sort
                });
                cofaliasRepository.AddRange(data.ToArray());
            }

            // 未提交数据
            else if (!hasreq && hasdata)
            {
                list.ForEach(t => t.States = 0);
                cofaliasRepository.UpdateRange(list.ToArray());
            }

            // 修改 && 新增
            else if (hasreq && hasdata)
            {
                var headIds = request.computerAliasHead.Select(t => t.HeadId);
                if (list.Any(w => headIds.Contains(w.Id)))
                {
                    list.ForEach(t =>
                    {
                        if (headIds.Contains(t.Id))
                        {
                            var item = request.computerAliasHead.FirstOrDefault(w => w.HeadId == t.Id);
                            t.States = 1;
                            t.Alias = item.Head;
                            t.Sort = item.Sort;
                        }
                        else
                            t.States = 0;
                    });
                    cofaliasRepository.UpdateRange(list.ToArray());
                }

                if (headIds.Any(w => w == 0))
                {
                    var table = cofaliasRepository.GetEntities(w => w.Route == request.Route);
                    var items = heads.Where(w => request.computerAliasHead.Where(w => w.HeadId == 0).Select(t => t.Head).Contains(w.Alias));

                    var data = items.Select(t => new cof_alias
                    {
                        Route = request.Route,
                        Alias = t.Alias,
                        OriginalName = t.Alias,
                        HospitalId = request.HospitalId,
                        Name = t.Name,
                        States = 1,
                        SumStatus = t.SumStatus,
                        Sort = request.computerAliasHead.FirstOrDefault(w => w.Head == t.Alias).Sort
                    });
                    cofaliasRepository.AddRange(data.ToArray());
                }
            }

            return true;

        }

        /// <summary>
        /// 发放表自定义列头
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<cof_alias> CustomColumnHeaders(int hospitalId, string route, params string[] heads)
        {
            var hos = hospitalRepository.GetEntity(w => w.ID == hospitalId);
            return CustomColumnHeaders(hos, route, heads);
        }
        public List<cof_alias> CustomColumnHeaders(sys_hospital hos, string route, params string[] heads)
        {
            var pairs = new Dictionary<string, List<cof_alias>>
                {
                    { "/result/compute" , ComputeConfig.AllComputeView },
                    { "/result/wholehospital" , ComputeConfig.AllComputePersonView },
                    { "/result/print/compute" , ComputeConfig.AllComputeDepartmentView },

                    { "/report/wholehospital_grant" , ComputeConfig.AllComputeViewByDate },
                    { "/report/wholehospital_accounting_grant" , ComputeConfig.AllComputeDepartmentViewByDate },
                    { "/report/wholehospital_finance_grant" , ComputeConfig.AllComputePersonViewByDate },

                    { "/report/wholehospital_grant_summary" , ComputeConfig.PerformanceTotal(route,heads) },
                    { "/report/wholehospital_accounting_grant_summary" , ComputeConfig.PerformanceTotal(route,heads) },
                    { "/report/wholehospital_finance_grant_summary" , ComputeConfig.PerformanceTotal(route,heads) },

                    { "/result/all_employee" , ComputeConfig.GetAllPersonnelTags(hos?.IsOwnerQuery == 1) },
                };
            var init = pairs.ContainsKey(route.ToLower()) ? pairs[route.ToLower()] : new List<cof_alias>();

            if (hos == null)
                return init;

            var alias = cofaliasRepository.GetEntities(t => t.HospitalId == hos.ID && t.Route.Equals(route, StringComparison.OrdinalIgnoreCase))?.OrderBy(w => w.Sort).ToList()
                ?? new List<cof_alias>();

            if (alias == null || !alias.Any()) return init;

            foreach (var item in alias)
            {
                var x = init.FirstOrDefault(w => w.Name.Equals(item.Name, StringComparison.OrdinalIgnoreCase));
                if (x == null)
                {
                    init.Add(item);
                }
                else
                {
                    x.Id = item.Id;
                    x.HospitalId = hos.ID;
                    x.Route = route;
                    x.OriginalName = item.OriginalName;
                    x.Alias = item.Alias;
                    x.States = item.States;
                    x.SumStatus = item.SumStatus;
                    x.Sort = item.Sort;
                }
            };

            return init?.OrderBy(t => t.Sort).ToList();
        }

        #region 标记批次号
        /// <summary>
        /// 标记批次号
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="PerformanceException"></exception>
        public ApiResponse Batch(BatchRequest request)
        {
            if (request == null || request.Details == null || !request.Details.Any())
                throw new PerformanceException("提交了空白的人员信息，当前操作已拒绝");

            if (string.IsNullOrEmpty(request.Batch))
                throw new PerformanceException("“批次信息”空白，当前操作已拒绝");

            var batchs = perforPerbatchRepository.GetEntities(w => w.AllotId == request.AllotId) ?? new List<per_batch>();
            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();

            foreach (var item in request.Details)
            {
                var bt = batchs.FirstOrDefault(w => !string.IsNullOrEmpty(w.Batch) && w.UnitType == item.UnitType && w.AccountingUnit == item.AccountingUnit && w.PersonnelNumber == item.JobNumber);
                if (bt != null)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "核算组别", item.UnitType??"" },
                        { "核算单元", item.AccountingUnit??"" },
                        { "人员工号", item.JobNumber??"" },
                        { "姓名", item.EmployeeName??"" },
                        { "错误原因",$"已经标记;请取消标记后重试；批次“{bt.Batch}”" },
                    });
                }
                if (string.IsNullOrEmpty(item.UnitType) || string.IsNullOrEmpty(item.AccountingUnit) || string.IsNullOrEmpty(item.JobNumber))
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "核算组别", item.UnitType??"" },
                        { "核算单元", item.AccountingUnit??"" },
                        { "人员工号", item.JobNumber??"" },
                        { "姓名", item.EmployeeName??"" },
                        { "错误原因",$"关键信息缺失" },
                    });
                }
            }

            if (error.Count > 0)
                return new ApiResponse(ResponseType.WarningTable, "验证不通过,当前操作已拒绝", error);

            var data = request.Details.Select(t => new per_batch
            {
                HospitalId = request.HospitalId,
                AllotId = request.AllotId,
                Batch = request.Batch,
                BatchDate = request.BatchDate ?? DateTime.Now,
                BankName = request.BankName,
                UnitType = t.UnitType,
                AccountingUnit = t.AccountingUnit,
                PersonnelNumber = t.JobNumber,
                PersonnelName = t.EmployeeName
            });
            perforPerbatchRepository.AddRange(data.ToArray());

            return new ApiResponse(ResponseType.OK, "标记成功");
        }

        /// <summary>
        /// 取消标记
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        /// <exception cref="PerformanceException"></exception>
        public ApiResponse BatchCancel(BatchCancelRequest request)
        {
            if (request == null || request.Details == null || !request.Details.Any())
                throw new PerformanceException("提交了空白的人员信息，当前操作已拒绝");

            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();
            var batchs = perforPerbatchRepository.GetEntities(w => w.AllotId == request.AllotId) ?? new List<per_batch>();
            var deletes = new List<per_batch>();

            foreach (var item in request.Details)
            {
                if (string.IsNullOrEmpty(item.UnitType) || string.IsNullOrEmpty(item.AccountingUnit) || string.IsNullOrEmpty(item.JobNumber))
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "核算组别", item.UnitType??"" },
                        { "核算单元", item.AccountingUnit??"" },
                        { "人员工号", item.JobNumber??"" },
                        { "姓名", item.EmployeeName??"" },
                        { "错误原因",$"关键信息缺失" },
                    });
                }
                var bt = batchs.FirstOrDefault(w => w.UnitType == item.UnitType && w.AccountingUnit == item.AccountingUnit && w.PersonnelNumber == item.JobNumber);
                if (bt != null)
                {
                    deletes.Add(bt);
                }
            }

            if (error.Count > 0)
                return new ApiResponse(ResponseType.WarningTable, "验证不通过,当前操作已拒绝", error);

            if (deletes.Count > 0)
                perforPerbatchRepository.RemoveRange(deletes.ToArray());

            return new ApiResponse(ResponseType.OK, "取消标记操作成功");
        }
        #endregion

        public List<dynamic> GetAllComputeView(int hospitalId, int AllotId, string viewName)
        {
            return reportRepository.QueryCompute(AllotId, viewName);
        }

        public List<dynamic> GetAllComputeViewByDate(string viewName, BeginEndTime request)
        {
            request.EndTime = Convert.ToDateTime(request.EndTime).AddMonths(1).ToString();
            return reportRepository.QueryComputeByDate(viewName, request);
        }


        public List<dynamic> GetAllComputeViewByDateAndTotal(string viewName, HospitalGrantSummary request)
        {
            request.EndTime = Convert.ToDateTime(request.EndTime).AddMonths(1).ToString();
            return reportRepository.QueryComputeByDateAndTotal(viewName, request);
        }

        public QueryComputeByDateGetPage GetPerformanceSummary(HospitalGrantSummary request, string ViewName)
        {
            DateTime bdate = DateTime.Now;
            DateTime edate = DateTime.Now;
            if (string.IsNullOrEmpty(request.BeginTime) || !DateTime.TryParse(request.BeginTime, out bdate) ||
                string.IsNullOrEmpty(request.EndTime) || !DateTime.TryParse(request.EndTime, out edate))
                throw new PerformanceException("请输入正确的时间");

            request.EndTime = Convert.ToDateTime(request.EndTime).AddMonths(1).ToString();
            var datas = reportRepository.QueryComputeByDateAndTotal(ViewName, request);
            if (null == datas)
                throw new PerformanceException("当前绩效记录不存在");

            var list = new QueryComputeByDateGetPage
            {
                Data = datas.Skip(request.PageSize * (request.CurrentPage - 1)).Take(request.PageSize).ToList(),
                TotalData = SumDatas(datas),
                TotalCount = datas.Count(),
                TotalPages = (int)Math.Ceiling((double)datas.Count() / request.PageSize),
                CurrentPage = request.CurrentPage,
                PageSize = request.PageSize
            };
            return list;
        }

        /// <summary>
        /// 合计数据
        /// </summary>
        /// <param name="datas"></param>
        /// <returns></returns>
        public Dictionary<string, decimal> SumDatas(List<dynamic> datas)
        {
            string[] notSum = new string[] { "hospitalid", "allotid", "year", "month", "jobnumber", "bankcard", "jobtitle", "secondid", "states", "isshowmanage", "batch" };
            Dictionary<string, decimal> pairs = new Dictionary<string, decimal>();

            foreach (var dt in datas)
            {
                var row = (IDictionary<string, object>)dt;
                foreach (var item in row)
                {
                    if (notSum.Contains(item.Key.ToLower())) continue;

                    if (decimal.TryParse(item.Value?.ToString(), out decimal v))
                    {
                        if (pairs.TryGetValue(item.Key, out decimal sum))
                        {
                            sum += v;
                            pairs[item.Key] = sum;
                        }
                        else
                        {
                            pairs[item.Key] = v;
                        }
                    }
                }
            }
            foreach (var item in pairs)
            {
                pairs[item.Key] = Math.Round(item.Value, 2, MidpointRounding.AwayFromZero);
            }
            return pairs;
        }
    }
}
