using AutoMapper;
using NPOI.SS.Formula.Functions;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace Performance.Services
{
    public class ComputeService : IAutoInjection
    {
        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 PerforHospitalRepository hospitalRepository;
        private readonly PerforPerapramountRepository perapramountRepository;
        private readonly PerforCofcmiRepository cofcmiRepository;
        private readonly PerforPeremployeeRepository perforPeremployeeRepository;
        private readonly PerforCofworkitemRepository cofworkitemRepository;

        public ComputeService(PerforResaccountRepository perforResaccountRepository,
            PerforPersheetRepository perforPerSheetRepository,
            PerforImdataRepository perforImDataRepository,
            PerforImheaderRepository perforImheaderRepository,
            PerforRescomputeRepository perforRescomputeRepository,
            PerforResspecialunitRepository perforResspecialunitRepository,
            PerforResbaiscnormRepository perforResbaiscnormRepository,
            PerforAgsecondallotRepository perforAgsecondallotRepository,
            PerforAgcomputeRepository perforAgcomputeRepository,
            PerforImemployeeclinicRepository perforImemployeeclinicRepository,
            PerforImemployeeRepository perforImemployeeRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforHospitalRepository hospitalRepository,
            PerforPerapramountRepository perapramountRepository,
            PerforCofcmiRepository cofcmiRepository,
            PerforPeremployeeRepository perforPeremployeeRepository,
            PerforCofworkitemRepository cofworkitemRepository)
        {
            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.hospitalRepository = hospitalRepository;
            this.perapramountRepository = perapramountRepository;
            this.cofcmiRepository = cofcmiRepository;
            this.perforPeremployeeRepository = perforPeremployeeRepository;
            this.cofworkitemRepository = cofworkitemRepository;
        }

        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);
            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

                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;
                        var employee = employees.FirstOrDefault(e => e.DoctorName == t.EmployeeName && e.AccountingUnit == t.AccountingUnit && pairs[type].Contains(e.UnitType));
                        var scoreAverageRate = t.ScoreAverageRate ?? employee.ScoreAverageRate ?? 0;
                        var attendance = t.Attendance ?? employee.Attendance ?? 0;
                        t.GiveFee = t.ShouldGiveFee * scoreAverageRate * attendance + (t.OtherPerfor ?? 0);
                        t.RealGiveFee = t.GiveFee * (t.Adjust ?? 1m);
                        t.BaiscNormValue = t.RealGiveFee;
                    }

                    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 compute = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && t.AccountType == items.FirstOrDefault(p => p.Value == type).Name);

                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();
            }
        }

        /// <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> GetDoctorPerformance(int allotId)
        {
            List<int> types = new List<int> { (int)UnitType.医生组, (int)UnitType.医技组 };
            var list = perforResaccountRepository.GetEntities(t => types.Contains(t.UnitType.Value) && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> doctor = Mapper.Map<List<DeptResponse>>(list);
            doctor?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return doctor;
        }

        /// <summary>
        /// 返回护理组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetNursePerformance(int allotId)
        {
            var list = perforResaccountRepository.GetEntities(t => t.UnitType == (int)UnitType.护理组 && t.AllotID == allotId)?.OrderBy(t => t.UnitType).ThenByDescending(t => t.AccountingUnit);
            List<DeptResponse> nurse = Mapper.Map<List<DeptResponse>>(list);
            nurse?.ForEach(t => t.UnitName = ((UnitType)t.UnitType).ToString());
            return nurse;
        }

        /// <summary>
        /// 返回其他组科室绩效
        /// </summary>
        /// <param name="allotId">绩效ID</param>
        /// <returns></returns>
        public List<DeptResponse> GetOtherPerformance(int allotId)
        {
            var unitType = new List<int> { (int)UnitType.其他医技组, (int)UnitType.其他医生组, (int)UnitType.其他护理组, (int)UnitType.专家组 };
            var list = perforResaccountRepository.GetEntities(t => unitType.Contains(t.UnitType.Value) && t.AllotID == allotId)?.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> GetOfficePerformance(int allotId)
        {
            var unitType = new List<int> { (int)UnitType.行政后勤 };

            var list = perforResaccountRepository.GetEntities(t => unitType.Contains(t.UnitType.Value) && t.AllotID == allotId)
                ?.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.ScoringPerfor = t.PerforFee * (t.ScoringAverage ?? 0);
                });
                result = result.OrderBy(t => t.UnitType).ThenBy(t => t.AccountingUnit).ToList();
            }

            var accountType = new List<AccountUnitType> { AccountUnitType.行政高层, AccountUnitType.行政中层, AccountUnitType.行政工勤 };
            var list = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && accountType.Select(a => a.ToString()).Contains(t.AccountType));
            if (list == null || !list.Any()) return result;

            List<DeptResponse> adminPerfor = list.GroupBy(t => new { t.AccountingUnit, t.AccountType })
                .Select(t => new DeptResponse
                {
                    UnitName = t.Key.AccountType,
                    AccountingUnit = t.Key.AccountingUnit,
                    Department = t.Key.AccountingUnit,
                    Number = t.Count(),
                    //Extra = t.FirstOrDefault(group => group.Punishment > 0)?.Punishment, // 医院奖罚
                    //ScoringAverage = t.FirstOrDefault(group => group.ScoreAverageRate > 0)?.ScoreAverageRate, //考核得分率
                    //AdjustFactor = t.FirstOrDefault(group => group.Adjust > 0)?.Adjust, //调节系数
                    //WorkloadFee = t.Sum(group => group.Workload),  //工作量绩效
                    //PerforTotal = t.Sum(group => group.RealGiveFee),  //绩效合计
                    //ScoringPerfor = t.Sum(group => group.RealGiveFee) * (t.FirstOrDefault(group => group.ScoreAverageRate > 0)?.ScoreAverageRate ?? 0),
                    Avg = t.Sum(group => group.RealGiveFee) / t.Count(), //人均绩效
                    OtherPerfor1 = t.Sum(group => group.OtherPerfor),
                    RealGiveFee = t.Sum(group => group.RealGiveFee) + t.Sum(group => group.OtherPerfor),  //实发绩效
                }).ToList();
            var enumItems = EnumHelper.GetItems<AccountUnitType>();
            adminPerfor = adminPerfor.OrderBy(t => enumItems.FirstOrDefault(e => e.Name == t.UnitName).Value).ThenBy(t => t.AccountingUnit).ToList();
            result.AddRange(adminPerfor);

            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 doctor = perforResaccountRepository.GetEntity(t => t.UnitType != (int)UnitType.护理组 && t.AllotID == allotId && t.ID == accountId);

                DeptDetailResponse response = new DeptDetailResponse()
                {
                    Pandect = Mapper.Map<PerDataAccountBaisc>(doctor),
                    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 == doctor.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 == doctor.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="isShowManage"> 仅显示管理绩效 isShowManage == 1 </param>
        /// <returns></returns>
        public List<ComputeResponse> AllCompute(int allotId, int isShowManage)
        {
            // 获取一次次绩效结果
            var list = GetAllotPerformance(allotId, isShowManage);
            // 获取二次绩效结果
            var seconds = GetSecondPerformance(allotId);
            if (seconds != null)
                list?.AddRange(seconds);

            // 补充医院其他绩效
            var result = AddAprAmount(allotId, list);

            // 预留比例
            if (result != null)
            {
                var empDic = perforPeremployeeRepository.GetEntities(w => w.AllotId == allotId);
                foreach (var item in result)
                {
                    item.PerforSumFee = Math.Round(item.PerforSumFee ?? 0, 0, MidpointRounding.AwayFromZero);
                    item.PerforManagementFee = Math.Round(item.PerforManagementFee ?? 0, 0, MidpointRounding.AwayFromZero);
                    item.OthePerfor = Math.Round(item.OthePerfor ?? 0, 0, MidpointRounding.AwayFromZero);
                    item.NightWorkPerfor = Math.Round(item.NightWorkPerfor ?? 0, 0, MidpointRounding.AwayFromZero);
                    item.ShouldGiveFee = Math.Round((item.PerforSumFee ?? 0) + (item.PerforManagementFee ?? 0) + (item.OthePerfor ?? 0) + (item.NightWorkPerfor ?? 0), 0, MidpointRounding.AwayFromZero);
                    item.ReservedRatio = empDic?.FirstOrDefault(w => w.PersonnelNumber == item.JobNumber)?.ReservedRatio ?? 0;
                    item.ReservedRatioFee = Math.Round(((item.PerforSumFee ?? 0) + (item.PerforManagementFee ?? 0)) * item.ReservedRatio ?? 0, 0, MidpointRounding.AwayFromZero);
                    item.RealGiveFee = Math.Round(item.ShouldGiveFee - (item.ReservedRatioFee ?? 0) ?? 0, 0, MidpointRounding.AwayFromZero);
                }
            }

            return result?.OrderByDescending(t => t.AccountingUnit).ToList();
        }

        /// <summary>
        /// 获取一次次绩效结果
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private List<ComputeResponse> GetAllotPerformance(int allotId, int isShowManage)
        {
            var mTypes = new[] { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString(), AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString() };
            var types1 = new List<string> { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString() };
            var types2 = new List<string> { AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString() };
            // 业务中层人员信息
            var empolyeeList = _perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId);
            // 一次绩效 获取特定人员绩效结果
            var allot = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && mTypes.Contains(t.AccountType))?.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;

                if (types1.Contains(t.AccountType))
                    comp.PerforManagementFee = (t.ShouldGiveFee ?? 0) + (t.OtherPerfor ?? 0) + (t.Punishment ?? 0);
                else
                    comp.PerforManagementFee = t.RealGiveFee;
                // 行政中层  行政高层 补充  夜班费
                if (types2.Contains(t.AccountType))
                    comp.NightWorkPerfor = t.NightWorkPerfor;
                // 获取科主任系数，解决共用科主任重复计算人均问题
                var basics = empolyeeList?.FirstOrDefault(w => w.AccountingUnit == t.AccountingUnit && w.DoctorName == t.EmployeeName && w.PersonnelNumber == t.JobNumber)?.Basics;
                // 仅显示管理绩效
                if (isShowManage == 2)
                    comp.PerforSumFee = 0;
                else
                    comp.PerforSumFee = basics.HasValue ? t.Avg * basics : t.Avg;

                return comp;
            }).ToList();
        }

        /// <summary>
        /// 获取二次绩效结果
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        private List<ComputeResponse> GetSecondPerformance(int allotId)
        {
            var again = _perforAgcomputeRepository.GetEntities(t => t.AllotId == allotId);
            if (again != null && again.Any())
            {
                var group = again
                    .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;
                    });
                return group?.ToList();
            }

            return null;
        }

        /// <summary>
        /// 添加额外绩效金额(基础绩效、其他绩效等)
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="computes"></param>
        private List<ComputeResponse> AddAprAmount(int allotId, List<ComputeResponse> computes)
        {
            if (computes == null || !computes.Any())
                return computes;

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

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

                //foreach (var emp in computes)
                //{
                //    if (!emp.OthePerfor.HasValue || emp.OthePerfor == 0)
                //    {
                //        var apramount = list.Where(t => t.AccountingUnit == emp.AccountingUnit
                //            && !string.IsNullOrEmpty(t.PersonnelNumber) && emp.JobNumber?.Trim() == t.PersonnelNumber?.Trim());
                //        emp.OthePerfor = apramount?.Sum(w => w.Amount) ?? 0;
                //    }
                //}
            }


            return computes;
        }

        ///// <summary>
        ///// 返回绩效发放列表
        ///// 科主任护士长返回管理绩效
        ///// </summary>
        ///// <param name="allotId">绩效ID</param>
        ///// <returns></returns>
        //public List<ComputeResponse> AllManageCompute(int allotId)
        //{
        //    var list = new List<ComputeResponse>();
        //    var mTypes = new[] { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString(), AccountUnitType.行政中层.ToString(), AccountUnitType.行政高层.ToString() };

        //    var allot = _perforRescomputeRepository.GetEntities(t => t.AllotID == allotId && mTypes.Contains(t.AccountType))?.OrderByDescending(t => t.AccountingUnit);
        //    if (allot != null && allot.Any(t => t.AllotID == allotId))
        //    {
        //        var types = new List<string> { AccountUnitType.护士长.ToString(), AccountUnitType.科主任.ToString() };
        //        list = allot.Select(t => new ComputeResponse
        //        {
        //            Source = "一次绩效",
        //            AccountingUnit = t.AccountingUnit,
        //            EmployeeName = t.EmployeeName,
        //            JobNumber = t.JobNumber,
        //            JobTitle = t.JobTitle,
        //            RealGiveFee = types.Contains(t.AccountType) ? t.ShouldGiveFee : t.RealGiveFee
        //        }).ToList();
        //    }
        //    var again = _perforAgcomputeRepository.GetEntities(t => t.AllotId == allotId);
        //    if (again != null && again.Any())
        //    {
        //        var group = again.GroupBy(t => new { t.Department, t.WorkPost, t.JobNumber, t.PersonName })
        //            .Select(t => new
        //            {
        //                department = t.Key.Department,
        //                jobtitle = t.Key.WorkPost,
        //                jobnumber = t.Key.JobNumber,
        //                name = t.Key.PersonName,
        //                fee = t.Sum(g => g.RealGiveFee)
        //            });
        //        list.AddRange(group.Select(t => new ComputeResponse
        //        {
        //            Source = "二次绩效",
        //            AccountingUnit = t.department,
        //            JobNumber = t.jobnumber,
        //            JobTitle = t.jobtitle,
        //            EmployeeName = t.name,
        //            RealGiveFee = t.fee
        //        }).OrderByDescending(t => t.AccountingUnit));
        //    }
        //    var result = AddAprAmount(allotId, list);
        //    if (result != null)
        //    {
        //        var empDic = perforPeremployeeRepository.GetEntities(w => w.AllotId == allotId);
        //        foreach (var item in result)
        //        {
        //            var temp = item.RealGiveFee ?? 0;
        //            item.ReservedRatio = empDic?.FirstOrDefault(w => w.DoctorName == item.EmployeeName && w.PersonnelNumber == item.JobNumber)?.ReservedRatio ?? 0;
        //            item.ReservedRatioFee = temp * item.ReservedRatio;
        //            item.RealGiveFee = temp - item.ReservedRatioFee;
        //        }
        //    }
        //    return result;
        //} 
        #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<DetailModuleExtend> DeptDetail(int accountId)
        {
            var doctor = perforResaccountRepository.GetEntity(t => t.ID == accountId);

            var workitems = cofworkitemRepository.GetEntities(t => t.AllotID == doctor.AllotID);
            var allotCmi = cofcmiRepository.GetEntity(t => t.AllotId == doctor.AllotID && t.UnitType == doctor.UnitType && t.AccountingUnit == doctor.AccountingUnit);

            var allot = perforPerallotRepository.GetEntity(t => t.ID == doctor.AllotID);
            DeptDataDetails deptDetails = new DeptDataDetails
            {
                ShowFormula = allot.ShowFormula,
                Pandect = Mapper.Map<PerDataAccountBaisc>(doctor),
                Detail = new List<DetailDtos>()
            };

            var persheet = _perforPerSheetRepository.GetEntities(t => t.AllotID == doctor.AllotID);
            var headers = _perforImheaderRepository.GetEntities(t => t.AllotID == doctor.AllotID);

            //科室经济
            var sheetEconomic = persheet.FirstOrDefault(t => t.SheetType == (int)SheetType.ComputeEconomic);
            var basicData = _perforImDataRepository.GetEntities(t => t.AllotID == doctor.AllotID && t.AccountingUnit == doctor.AccountingUnit);
            var dataEconomicList = basicData.Where(t => t.SheetID == sheetEconomic?.ID && t.IsTotal != 1 && t.AccountingUnit == doctor.AccountingUnit).ToList();
            string typeValue = EnumHelper.GetDescription((UnitType)doctor.UnitType);
            var economic = dataEconomicList?.Select(t => new
            {
                ItemName = t.TypeName.Replace($"({typeValue})", ""),
                ItemValue = t.CellValue ?? 0,
                t.UnitType
            });

            Regex reg = new Regex("[0-9]*");

            int type = doctor.UnitType.Value;

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

            int groupbasis = 1;
            string single = "";
            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
            };
            foreach (var stype in sheetType)
            {
                //if (type == 3 && stype == (int)SheetType.Workload) type = 1;
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    if (single != "" && sheet.SheetName.Substring(0, 3) != single)
                        groupbasis += 1;
                    single = sheet.SheetName.Substring(0, 3);

                    var sheetName = reg.Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    //var nType = (stype == (int)SheetType.Workload) ? 1 : type; 
                    var sheetData = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == type && t.IsTotal != 1).ToList();
                    if (sheetData == null || !sheetData.Any()) continue;

                    var headerData = headers?.Where(t => t.SheetID == sheet.ID);

                    var sheettype = 1; //特殊核算科室 4
                    var amount = 0m;
                    if (sheet.SheetType == (int)SheetType.Income || sheet.SheetType == (int)SheetType.OtherIncome)
                    {
                        amount = sheetData?.Sum(t => t.IsFactor == 1 ? t.CellValue * (t.FactorValue ?? 0) : t.CellValue) ?? 0;
                    }
                    else if (sheet.SheetType == (int)SheetType.Expend)
                    {
                        sheettype = 2;
                        amount = economic.FirstOrDefault(t => t.ItemName.Contains(sheetName) && t.UnitType == type)?.ItemValue ?? 0m;
                    }
                    else if (sheet.SheetType == (int)SheetType.Workload)
                    {
                        sheettype = 3;
                        amount = doctor.WorkloadFee ?? 0m;
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountExtra)
                    {
                        sheettype = 5;
                        amount = doctor?.Extra ?? 0;
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountDrugAssess)
                    {
                        sheettype = 6;
                        amount = doctor?.MedicineExtra ?? 0;
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountMaterialsAssess)
                    {
                        sheettype = 7;
                        amount = doctor?.MaterialsExtra ?? 0;
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountScoreAverage)
                    {
                        sheettype = 8;
                        //amount = Math.Round(doctor?.ScoringAverage ?? 0, 4);
                        amount = Math.Round(basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == 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 == type && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0, 0);
                    }

                    var item = new DetailDtos
                    {
                        ItemName = sheetName,
                        IncomeType = sheettype,
                        Amount = amount,
                        GroupBasis = groupbasis,
                    };

                    var items = sheetData?.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),
                            };

                            if (sheet.SheetType == (int)SheetType.Workload)
                            {
                                if (workitems != null && workitems.Any(a => a.Type == 1 && a.Item == t.Key))
                                    dto.MediFactor = doctor.MedicineFactor;
                                if (workitems != null && workitems.Any(a => a.Type == 2 && a.Item == t.Key) && allotCmi != null)
                                    dto.CMIFactor = allotCmi.Value;
                                dto.ItemValue = dto.ItemValue * (dto.MediFactor ?? 1) * (dto.CMIFactor ?? 1);
                            }

                            return dto;
                        }).ToList();

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

                    }

                    if (headerData != null && headerData.Any())
                    {
                        items = items
                            ?.OrderBy(t => (headerData.FirstOrDefault(h => h.CellValue == t.ItemName)?.PointCell) ?? 100)
                            ?.ThenBy(t => t.ItemName).ToList();
                    }

                    item.Items = items;
                    deptDetails.Detail.Add(item);
                }
            }

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

        private DeptDataDetails<DetailModuleExtend> MergeDetails(DeptDataDetails details)
        {
            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 || !details.Detail.Any(t => t.IncomeType == 1)) 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.Replace("就诊", "开单").IndexOf("开单") > -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,
                        }).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("执行", "开单/执行"),
                    IncomeType = data.First().IncomeType,
                    Amount = data.Sum(w => w.Amount),
                    GroupBasis = groupbasis,
                    Items = items
                });
            }

            return result;
        }

        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 ?? 0,
                    OtherPerfor1 = special.FirstOrDefault()?.OtherPerfor ?? 0,
                    AdjustFactor = special.FirstOrDefault()?.Adjust ?? 0,
                    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,
                },
                Detail = new List<DetailDtos>(),
            };
            var detail = new DetailDtos
            {
                ItemName = "特殊核算单元绩效测算表",
                IncomeType = 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
            };
            Regex reg = new Regex("[0-9]*");
            int groupBasis = 0;
            foreach (var stype in sheetType)
            {
                foreach (var sheet in persheet.Where(t => t.SheetType == stype))
                {
                    groupBasis++;
                    var sheetName = reg.Replace(sheet.SheetName, "", 5).Replace(".", "").Replace(" ", "");
                    var sheetData = basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)UnitType.特殊核算组 && t.IsTotal != 1).ToList();
                    if (sheetData == null || !sheetData.Any()) continue;

                    var headerData = headers?.Where(t => t.SheetID == sheet.ID);

                    var sheettype = 1; //特殊核算科室 4
                    var amount = 0m;
                    if (sheet.SheetType == (int)SheetType.AccountExtra)
                    {
                        sheettype = 5;
                        amount = special.FirstOrDefault()?.Punishment ?? 0;
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountDrugAssess)
                    {
                        sheettype = 6;
                        amount = special.FirstOrDefault()?.MedicineExtra ?? 0;
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountMaterialsAssess)
                    {
                        sheettype = 7;
                        amount = special.FirstOrDefault()?.MaterialsExtra ?? 0;
                    }
                    else if (sheet.SheetType == (int)SheetType.AccountScoreAverage)
                    {
                        sheettype = 8;
                        //amount = Math.Round(special.FirstOrDefault()?.ScoringAverage ?? 0, 4);
                        amount = Math.Round(basicData.Where(t => t.SheetID == sheet.ID && t.UnitType == (int)UnitType.特殊核算组 && 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)UnitType.特殊核算组 && t.IsTotal == 1)?.FirstOrDefault()?.CellValue ?? 0, 0);
                    }

                    var item = new DetailDtos
                    {
                        ItemName = sheetName,
                        IncomeType = sheettype,
                        Amount = amount,
                        GroupBasis = groupBasis,
                    };

                    var items = sheetData?.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 =>
                        new DetailModule
                        {
                            ItemName = t.Key,
                            CellValue = t.Sum(group => group.CellValue),
                            Factor = t.FirstOrDefault().Factor,
                            ItemValue = t.Sum(group => group.ItemValue),
                        }
                        ).ToList();
                    }

                    if (headerData != null && headerData.Any())
                    {
                        items = items
                            ?.OrderBy(t => (headerData.FirstOrDefault(h => h.CellValue == t.ItemName)?.PointCell) ?? 100)
                            ?.ThenBy(t => t.ItemName).ToList();
                    }

                    item.Items = items;
                    deptDetails.Detail.Add(item);
                }
            }

            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()
            };
        }
    }
}