using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using AutoMapper;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using Performance.DtoModels;
using Performance.DtoModels.Request;
using Performance.DtoModels.Response;
using Performance.EntityModels;
using Performance.EntityModels.Entity;
using Performance.Infrastructure;
using Performance.Repository;
using Performance.Repository.Repository;

namespace Performance.Services
{
    public class EmployeeService : IAutoInjection
    {
        private readonly IMapper _mapper;
        private readonly DapperService _service;
        private readonly PerforImemployeeRepository perforImemployeeRepository;
        private readonly PerforPersheetRepository perforPersheetRepository;
        private readonly PerforImdataRepository perforImdataRepository;
        private readonly PerforPerallotRepository perforPerallotRepository;
        private readonly PerforImemployeeclinicRepository perforImemployeeclinicRepository;
        private readonly PerforUserhospitalRepository perforUserhospitalRepository;
        private readonly PerforPerallotRepository perallotRepository;
        private readonly PerforPerapramountRepository perapramountRepository;
        private readonly PerforImemployeelogisticsRepository perforImemployeelogisticsRepository;
        private readonly PerforUserroleRepository userroleRepository;
        private readonly PerforPeremployeeRepository peremployeeRepository;
        private readonly PerforUserRepository userRepository;
        private readonly PerforPerapramounthideRepository _hideRepository;
        private readonly PerforExresultgatherRepository exresultgatherRepository;
        private readonly PerforPerdeptdicRepository perdeptdicRepository;
        private readonly PerforExmoduleRepository exmoduleRepository;
        private readonly PerforExitemRepository exitemRepository;
        private readonly PerforExspecialRepository exspecialRepository;
        private readonly PerforCollectpermissionRepository perforcollectpermissionRepository;
        private readonly ILogger<EmployeeService> logger;
        private readonly RoleService roleService;
        private readonly UserService userService;
        private readonly DownloadService downloadService;
        private readonly PerAprAmountTypeRepository perAprAmountTypeRepository;
        private readonly PerAprAmountTypeHideRepository perAprAmountTypeHIdeRepository;





        public EmployeeService(
            IMapper mapper,
            DapperService service,
            PerforImemployeeRepository perforImemployeeRepository,
            PerforPersheetRepository perforPersheetRepository,
            PerforImdataRepository perforImdataRepository,
            PerforPerallotRepository perforPerallotRepository,
            PerforImemployeeclinicRepository perforImemployeeclinicRepository,
            PerforUserhospitalRepository perforUserhospitalRepository,
            PerforPerallotRepository perallotRepository,
            PerforPerapramountRepository perapramountRepository,
            PerforImemployeelogisticsRepository perforImemployeelogisticsRepository,
            PerforUserroleRepository userroleRepository,
            PerforPeremployeeRepository peremployeeRepository,
            PerforUserRepository userRepository,
            PerforPerapramounthideRepository hideRepository,
            PerforExresultgatherRepository exresultgatherRepository,
            PerforPerdeptdicRepository perdeptdicRepository,
            PerforExmoduleRepository exmoduleRepository,
            PerforExitemRepository exitemRepository,
            PerforExspecialRepository exspecialRepository,
            PerforExresultRepository exresultRepository,
            PerforCollectpermissionRepository perforcollectpermissionRepository,
            ILogger<EmployeeService> logger,
            RoleService roleService,
            UserService userService,
            DownloadService downloadService,
            PerAprAmountTypeRepository perAprAmountTypeRepository,
            PerAprAmountTypeHideRepository perAprAmountTypeHideRepository
            )
        {
            _mapper = mapper;
            _service = service;
            this.perforImemployeeRepository = perforImemployeeRepository;
            this.perforPersheetRepository = perforPersheetRepository;
            this.perforImdataRepository = perforImdataRepository;
            this.perforPerallotRepository = perforPerallotRepository;
            this.perforImemployeeclinicRepository = perforImemployeeclinicRepository;
            this.perforUserhospitalRepository = perforUserhospitalRepository;
            this.perallotRepository = perallotRepository;
            this.perapramountRepository = perapramountRepository;
            this.perforImemployeelogisticsRepository = perforImemployeelogisticsRepository;
            this.userroleRepository = userroleRepository;
            this.peremployeeRepository = peremployeeRepository;
            this.userRepository = userRepository;
            _hideRepository = hideRepository;
            this.exresultgatherRepository = exresultgatherRepository;
            this.perdeptdicRepository = perdeptdicRepository;
            this.exmoduleRepository = exmoduleRepository;
            this.exitemRepository = exitemRepository;
            this.exspecialRepository = exspecialRepository;
            this.perforcollectpermissionRepository = perforcollectpermissionRepository;
            this.logger = logger;
            this.roleService = roleService;
            this.userService = userService;
            this.downloadService = downloadService;
            this.perAprAmountTypeRepository = perAprAmountTypeRepository;
            this.perAprAmountTypeHIdeRepository = perAprAmountTypeHideRepository;
        }

        #region 行政人员

        /// <summary>
        ///获取人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee GetEmployee(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            return employee;
        }

        /// <summary>
        ///获取人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee> GetEmployeeList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.归档, (int)AllotStates.绩效下发 }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeeRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee Insert(EmployeeRequest request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.Employee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "行政人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            var employee = _mapper.Map<im_employee>(request);
            employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.SheetID = sheet.ID;
            perforImemployeeRepository.Add(employee);
            return employee;
        }

        /// <summary>
        /// 修改人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee Update(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.AccountType = request.AccountType;
            employee.Department = request.Department;
            employee.FitPeople = request.FitPeople;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Attendance = request.Attendance;
            employee.PeopleNumber = request.PeopleNumber;
            employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            employee.Punishment = request.Punishment;
            employee.Adjust = request.Adjust;
            employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeeRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool Delete(EmployeeRequest request)
        {
            var employee = perforImemployeeRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeeRepository.Remove(employee);
        }

        #endregion 行政人员

        #region 临床人员

        /// <summary>
        ///获取临床人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee_clinic> GetEmployeeClinicList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.归档, (int)AllotStates.绩效下发 }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeeclinicRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_clinic InsertClinic(im_employee_clinic request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.ClinicEmployee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "临床人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            request.SheetID = sheet.ID;
            perforImemployeeclinicRepository.Add(request);
            return request;
        }

        /// <summary>
        /// 修改临床人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_clinic UpdateClinic(im_employee_clinic request)
        {
            var employee = perforImemployeeclinicRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.UnitType = request.UnitType;
            employee.Department = request.Department;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Efficiency = request.Efficiency;
            employee.Scale = request.Scale;
            employee.Management = request.Management;
            employee.Attendance = request.Attendance;
            employee.PeopleNumber = request.PeopleNumber;
            employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            employee.Punishment = request.Punishment;
            employee.Adjust = request.Adjust;
            employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeeclinicRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DeleteClinic(im_employee_clinic request)
        {
            var employee = perforImemployeeclinicRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeeclinicRepository.Remove(employee);
        }

        #endregion 临床人员

        #region 行政后勤

        /// <summary>
        ///获取临床人员列表
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public List<im_employee_logistics> GetEmployeeLogisticsList(int? allotId, int userId)
        {
            if (allotId == null || allotId == 0)
            {
                var userHospital = perforUserhospitalRepository.GetEntity(t => t.UserID == userId);
                if (userHospital == null)
                    throw new PerformanceException("用户未绑定医院！");
                var allotList = perallotRepository.GetEntities(t => t.HospitalId == userHospital.HospitalID
                && new List<int> { (int)AllotStates.归档, (int)AllotStates.绩效下发 }.Contains(t.States));
                if (allotList != null && allotList.Any())
                {
                    allotId = allotList.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).First().ID;
                }
            }

            var employee = perforImemployeelogisticsRepository.GetEntities(t => t.AllotID == allotId);
            return employee?.OrderBy(t => t.RowNumber).ToList();
        }

        /// <summary>
        /// 新增临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_logistics InsertLogistics(im_employee_logistics request)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == request.AllotID);
            if (allot == null)
                throw new PerformanceException("绩效方案不存在");

            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == request.AllotID && t.SheetType == (int)SheetType.LogisticsEmployee);
            if (sheet == null)
            {
                sheet = new per_sheet { AllotID = allot.ID, SheetName = "临床人员名单", SheetType = (int)SheetType.Employee, Source = 1 };
                perforPersheetRepository.Add(sheet);
            }

            request.SheetID = sheet.ID;
            perforImemployeelogisticsRepository.Add(request);
            return request;
        }

        /// <summary>
        /// 修改临床人员信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public im_employee_logistics UpdateLogistics(im_employee_logistics request)
        {
            var employee = perforImemployeelogisticsRepository.GetEntity(t => t.ID == request.ID);
            if (employee == null)
                throw new PerformanceException("该人员不存在");
            employee.AccountingUnit = request.AccountingUnit;
            employee.DoctorName = request.DoctorName;

            employee.AccountType = request.AccountType;
            employee.Department = request.Department;
            employee.FitPeople = request.FitPeople;
            employee.JobTitle = request.JobTitle;
            employee.PostCoefficient = request.PostCoefficient;
            //employee.WorkTime = ConvertHelper.To<DateTime?>(request.WorkTime);
            employee.ScoreAverageRate = request.ScoreAverageRate;
            employee.Attendance = request.Attendance;
            //employee.PeopleNumber = request.PeopleNumber;
            //employee.Workload = request.Workload;
            employee.OtherPerfor = request.OtherPerfor;
            //employee.Punishment = request.Punishment;
            //employee.Adjust = request.Adjust;
            //employee.Grant = request.Grant;
            //修改人员信息
            perforImemployeelogisticsRepository.Update(employee);
            return employee;
        }

        /// <summary>
        /// 删除临床人员
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DeleteLogistics(im_employee_clinic request)
        {
            var employee = perforImemployeelogisticsRepository.GetEntity(t => t.ID == request.ID);
            if (null == employee)
                throw new PerformanceException("该人员不存在");

            return perforImemployeelogisticsRepository.Remove(employee);
        }

        #endregion 行政后勤

        /// <summary>
        /// 人事科修改后提交状态
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public bool Audit(int allotId)
        {
            var allot = perforPerallotRepository.GetEntity(t => t.ID == allotId);
            if (allot == null || !new List<int> { (int)AllotStates.绩效下发, (int)AllotStates.绩效结果解析成功 }.Contains(allot.States))
                throw new PerformanceException("绩效信息错误");
            if ((int)AllotStates.归档 == allot.States)
                throw new PerformanceException("绩效已归档，暂不支持修改");

            allot.Generate = (int)AllotGenerate.PersonnelOffice;
            return perforPerallotRepository.Update(allot);
        }

        #region 医院其他绩效
        /// <summary>
        /// 获取所有医院其他绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<OhterAmountAuditResponse> GetAprList(int allotId, int userId, int isAudit)
        {
            var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
            if (userrole == null) throw new PerformanceException("用户未绑定角色");

            Expression<Func<per_apr_amount, bool>> expression = t => t.AllotId == allotId && (t.Amount ?? 0) != 0;
            var roles = new int[] { (int)Role.绩效管理员, (int)Role.医院管理员, (int)Role.绩效核算办, (int)Role.院领导, (int)Role.审计 };
            if (!roles.Contains(userrole.RoleID))   //  绩效管理员、医院管理员、绩效核算办、院领导查看所有科室的数据
                expression = expression.And(t => t.CreateUser == userId);

            if (isAudit == 1)
                expression = expression.And(t => new int[] { 2, 3 }.Contains(t.Status ?? 1));

            var list = perapramountRepository.GetEntities(expression) ?? new List<per_apr_amount>();
            if (list != null && list.Any())
                list = list.OrderBy(w => w.IsVerify).ThenBy(t => t.DoctorName).ToList();

            var result = list.GroupBy(t => new { TypeInDepartment = t.TypeInDepartment ?? "", t.CreateDate })
                .Select(t =>
                {
                    string createDate = "";
                    if (t.Key.CreateDate != null)
                        createDate = t.Key.CreateDate.Value.ToString("yyyy-MM-dd HH:mm:ss");

                    var status = t.OrderByDescending(w => w.Id).FirstOrDefault()?.Status ?? 0;
                    var perforTypes = string.Join("/", t.Select(w => w.PerforType).Distinct());
                    if (perforTypes.Length > 10) perforTypes = perforTypes.Substring(0, 10) + "……";
                    return new OhterAmountAuditResponse
                    {
                        TypeInDepartment = t.Key.TypeInDepartment,
                        CreateDate = createDate,
                        Amount = t.Sum(s => s.Amount ?? 0),
                        Status = status,
                        PerforType = perforTypes,
                        AuditTime = t.Any(s => s.Status == 2) ? "" : t.Max(w => w.AuditTime)?.ToString("yyyy-MM-dd HH:mm:ss"),
                        Remark = t.Any(s => !s.MarkStatus.HasValue) ? "" : $"已审计{t.Max(w => w.MarkTime)?.ToString("(yyyy-MM-dd HH:mm:ss)")}",
                        ShowCommit = (new int[] { 1, 4 }).Contains(status) && t.FirstOrDefault(t => t.CreateUser.HasValue).CreateUser == userId,
                    };
                });

            if (result != null && result.Any())
                result = result.OrderByDescending(o => o.CreateDate).ToList();

            return result.ToList();
        }

        /// <summary>
        /// 医院其他绩效提交
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool SubmitDeptList(SubmitAmountRequest request)
        {
            var createDate = DateTime.Parse(request.CreateDate);
            var result = perapramountRepository.GetEntities(w => w.AllotId == request.AllotId && w.TypeInDepartment == request.TypeInDepartment && w.CreateDate == createDate);
            result.ForEach(w =>
            {
                w.Status = 2;
            });
            return perapramountRepository.UpdateRange(result.ToArray());

        }
        /// <summary>
        /// 医院其他绩效审核详情
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department"></param>
        /// <param name="status"></param>
        /// <param name="date"></param>
        /// <returns></returns>
        public List<view_per_apr_amount> GetAprList(int allotId, string department, int? status = null, DateTime? date = null)
        {
            var list = perapramountRepository.GetFullAmount(allotId, status, department, date);
            if (list != null && list.Any())
                list = list.OrderBy(t => t.DoctorName).ToList();

            return list;
        }
        /// <summary>
        /// 新增医院其他绩效
        /// </summary>
        /// <param name="request"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public bool InsertApr(per_apr_amount request, int userId)
        {
            if (request == null)
                throw new PerformanceException("无效数据");

            if (string.IsNullOrEmpty(request.PersonnelNumber))
                throw new PerformanceException("文件中存在“工号”为空的数据");
            if (string.IsNullOrEmpty(request.PerforType) && request.Amount != 0)
                throw new PerformanceException("文件中存在“绩效类型”为空的数据");

            var employee = peremployeeRepository.GetEntity(t => t.AllotId == request.AllotId && t.PersonnelNumber == request.PersonnelNumber && t.DoctorName == request.DoctorName);
            if (employee == null)
                throw new PerformanceException("工号或姓名信息错误");

            var types = perAprAmountTypeRepository.GetEntities(t => t.AllotId == request.AllotId);
            if (types?.Any() == true && !types.Any(w => w.PerforType == request.PerforType))
                throw new PerformanceException("“绩效类型”错误，请按规定类型填入");

            request.TypeInDepartment = GetTypeInDepartment(userId);
            request.Status = 1;
            request.CreateUser = userId;
            return perapramountRepository.Add(request);
        }
        /// <summary>
        /// 修改医院其他绩效
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool UpdateApr(per_apr_amount request)
        {
            if (request == null)
                throw new PerformanceException("无效数据");

            if (string.IsNullOrEmpty(request.PersonnelNumber))
                throw new PerformanceException("“工号”不能为空");
            if (string.IsNullOrEmpty(request.PerforType) && request.Amount != 0)
                throw new PerformanceException("“绩效类型”不能为空");

            var data = perapramountRepository.GetEntity(t => t.Id == request.Id);
            if (data == null)
                throw new PerformanceException("修改数据无效");

            var employee = peremployeeRepository.GetEntity(t => t.AllotId == request.AllotId && t.PersonnelNumber == request.PersonnelNumber && t.DoctorName == request.DoctorName);
            if (employee == null)
                throw new PerformanceException("工号或姓名信息错误");

            var types = perAprAmountTypeRepository.GetEntities(t => t.AllotId == request.AllotId);
            if (types?.Any() == true && !types.Any(w => w.PerforType == request.PerforType))
                throw new PerformanceException("“绩效类型”错误，请按规定类型填入");

            data.Status = 1;
            data.PersonnelNumber = request.PersonnelNumber;
            data.DoctorName = request.DoctorName;
            data.PerforType = request.PerforType;
            //data.AccountingUnit = request.AccountingUnit;
            data.Amount = request.Amount;
            data.Remark = request.Remark;

            return perapramountRepository.Update(data);
        }

        /// <summary>
        /// 删除医院其他绩效
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool DeleteApr(int id)
        {
            var data = perapramountRepository.GetEntity(t => t.Id == id);
            if (data != null)
                return perapramountRepository.Remove(data);

            return true;
        }

        /// <summary>
        /// 提交、撤销医院其他绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department">录入科室</param>
        /// <param name="status">1.撤销 2.提交</param>
        /// <returns></returns>
        public bool CommitApr(int allotId, string department, int status, DateTime date)
        {
            var list = status == 1
                ? GetAprByTypeInDepartment(allotId, department, date, 2) // 撤销操作，获取已提交等待审核的数据
                : GetAprByTypeInDepartment(allotId, department, date, 1, 4);  // 提交操作，获取未提交、驳回的数据
            if (list == null) return true;

            list.ForEach(t => t.Status = status);
            perapramountRepository.UpdateRange(list.ToArray());
            return true;
        }

        /// <summary>
        /// 审核医院其他绩效
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public ApiResponse ConfirmAudit(int userid, AprAmountAuditRequest request)
        {
            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();

            if (request?.Members == null || !request.Members.Any())
                throw new PerformanceException("审核信息无效，请确认");

            var err = request.Members
                .Select((w, i) =>
                {
                    if (string.IsNullOrEmpty(w.PersonnelNumber))
                    {
                        return new Dictionary<string, string>
                        {
                            { "行号", $"第{i+1}行" }, { "人员工号", w.PersonnelNumber??"" }, { "姓名", w.DoctorName??"" }, { "错误原因", "“人员工号”为空" },
                        };
                    }
                    return null;
                })
                .Where(w => w != null);

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

            var allApramounts = request.IsPass == 1
                ? GetAprByTypeInDepartment(request.AllotId, request.TypeInDepartment, request.CreateDate, 2)  // 获取等待审核的数据
                : GetAprByTypeInDepartment(request.AllotId, request.TypeInDepartment, request.CreateDate, 2, 3); // 获取等待审核、审核通过的数据
            foreach (var member in request.Members)
            {
                var apramounts = allApramounts?.Where(t => (t.PersonnelNumber ?? "") == member.PersonnelNumber);
                if (apramounts != null && apramounts.Any())
                {
                    foreach (var item in apramounts)
                    {
                        item.Status = (request.IsPass == 1) ? 3 : 4;
                        item.AuditUser = userid;
                        item.AuditTime = DateTime.Now;
                        perapramountRepository.UpdateRange(apramounts.ToArray());
                    }
                }
            }
            _service.FreezeAllotSync(request.AllotId);
            return new ApiResponse(ResponseType.OK, "");
        }

        /// <summary>
        /// 医院其他绩效审计
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public ApiResponse AprMark(int userid, AprAmountMarkRequest request)
        {

            if (request?.TypeInDepartments == null || !request.TypeInDepartments.Any())
                throw new PerformanceException("审计信息无效，请确认");

            foreach (var department in request.TypeInDepartments)
            {
                string update = "update per_apr_amount set MarkStatus=@MarkStatus,MarkUser=@MarkUser,MarkTime=@MarkTime where TypeInDepartment=@TypeInDepartment and AllotId=@AllotId; ";
                perapramountRepository.Execute(update, new { MarkStatus = 1, MarkUser = userid, MarkTime = DateTime.Now, TypeInDepartment = department, request.AllotId });
            }
            return new ApiResponse(ResponseType.OK, "");
        }
        /// <summary>
        /// 上传导入医院其他绩效
        /// </summary>
        /// <param name="allotid"></param>
        /// <param name="path"></param>
        /// <param name="userid"></param>
        public ApiResponse ImportAprEmployees(int allotid, string path, int userid)
        {
            var userrole = userroleRepository.GetEntity(t => t.UserID == userid);
            if (userrole == null) throw new PerformanceException("用户未绑定角色");

            List<per_apr_amount> entities = new List<per_apr_amount>();
            var typeIn = GetTypeInDepartment(userid);
            var createtime = DateTime.Now;

            var types = perAprAmountTypeRepository.GetEntities(t => t.AllotId == allotid) ?? new List<per_apr_amount_type>();

            var res = OpenAndReadAprAmountExcel(allotid, path, types.Select(w => w.PerforType).ToList(), entities);
            if (res.State == ResponseType.OK)
            {
                if (!entities.Any()) throw new PerformanceException("未能找到有效数据，请检查后重试！");

                foreach (var entity in entities)
                {
                    entity.Status = 1;
                    entity.TypeInDepartment = typeIn;
                    entity.AllotId = allotid;
                    entity.CreateDate = createtime;
                    entity.CreateUser = userid;
                }
                perapramountRepository.AddRange(entities.ToArray());
            }
            return res;
        }

        /// <summary>
        /// 上传导入医院其他绩效
        /// </summary>
        /// <param name="allotid"></param>
        /// <param name="path"></param>
        /// <param name="userid"></param>
        private ApiResponse OpenAndReadAprAmountExcel(int allotid, string path, List<string> types, List<per_apr_amount> entities)
        {
            entities ??= new List<per_apr_amount>();
            try
            {
                IWorkbook workbook = null;

                var version = FileHelper.GetExtension(path) == ".xlsx" ? ExcelVersion.xlsx : ExcelVersion.xls;
                using (FileStream fs = new FileStream(path, FileMode.OpenOrCreate))
                {
                    workbook = version == ExcelVersion.xlsx ? new XSSFWorkbook(fs) : new HSSFWorkbook(fs);
                }
                if (workbook == null) throw new PerformanceException("Excel读取失败，请稍后重试");
                var sheet = workbook.GetSheetAt(0);

                var firstRow = sheet.GetRow(0);
                Dictionary<int, string> excelheader = new Dictionary<int, string>();
                for (int cellindex = 0; cellindex < firstRow.LastCellNum + 1; cellindex++)
                {
                    var value = firstRow.GetCell(cellindex).GetValue();
                    if (!string.IsNullOrEmpty(value) && !excelheader.ContainsKey(cellindex))
                        excelheader.Add(cellindex, value);
                }

                if (excelheader == null || excelheader.Count == 0)
                    throw new PerformanceException("上传excel内容错误");

                Dictionary<string, int> dict = new Dictionary<string, int>
                {
                    { "人员工号", -1 }, { "姓名", -1 }, { "绩效类型", -1 }, { "金额", -1 }, { "备注", -1 },
                };

                foreach (var key in dict.Keys.Where(key => excelheader.Any(w => w.Value == key)))
                {
                    dict[key] = excelheader.First(w => w.Value == key).Key;
                }

                List<Dictionary<string, string>> errors = new List<Dictionary<string, string>>();
                foreach (var key in dict.Where(w => w.Value < 0).Select(w => w.Key))
                {
                    errors.Add(new Dictionary<string, string> { { "列名", key }, { "来源", "上传文件" }, { "错误原因", $"“{key}”列不存在" } });
                }
                if (errors.Count > 0) return new ApiResponse(ResponseType.WarningTable, "验证不通过,当前操作已拒绝", errors);

                var employees = peremployeeRepository.GetEntities(t => t.AllotId == allotid) ?? new List<per_employee>();
                for (int rowindex = 1; rowindex < sheet.LastRowNum + 1; rowindex++)
                {
                    var row = sheet.GetRow(rowindex);
                    if (row == null) continue;

                    var entity = new per_apr_amount
                    {
                        PersonnelNumber = dict["人员工号"] < 0 ? "" : row.GetCell(dict["人员工号"]).GetValue(),
                        DoctorName = dict["姓名"] < 0 ? "" : row.GetCell(dict["姓名"]).GetValue(),
                        PerforType = dict["绩效类型"] < 0 ? "" : row.GetCell(dict["绩效类型"]).GetValue(),
                        Amount = dict["金额"] < 0 ? 0 : ConvertHelper.To<decimal>(row.GetCell(dict["金额"]).GetValue(), 0),
                        Remark = dict["备注"] < 0 ? "" : row.GetCell(dict["备注"]).GetValue(),
                    };
                    if (string.IsNullOrEmpty(entity.DoctorName) && string.IsNullOrEmpty(entity.PersonnelNumber) && string.IsNullOrEmpty(entity.PerforType) && entity.Amount == 0)
                        continue;

                    if (string.IsNullOrEmpty(entity.DoctorName) || string.IsNullOrEmpty(entity.PersonnelNumber))
                    {
                        errors.Add(new Dictionary<string, string>
                        {
                            { "行号", $"第{rowindex}行" },
                            { "人员工号", entity.PersonnelNumber },
                            { "姓名", entity.DoctorName },
                            { "来源", "上传文件" },
                            { "错误原因", "“人员工号/姓名”信息缺失，请补全或删除" },
                        });
                    }

                    if (entity.Amount == 0)
                    {
                        errors.Add(new Dictionary<string, string>
                        {
                            { "行号", $"第{rowindex}行" },
                            { "人员工号", entity.PersonnelNumber },
                            { "姓名", entity.DoctorName },
                            { "来源", "上传文件" },
                            { "错误原因", "“金额”不能为“0”，请补全或删除" },
                        });
                    }

                    var employee = employees.FirstOrDefault(w => w.PersonnelNumber == entity.PersonnelNumber);
                    if (employee == null)
                    {
                        errors.Add(new Dictionary<string, string>
                        {
                            { "行号", $"第{rowindex}行" },
                            { "人员工号", entity.PersonnelNumber },
                            { "姓名", entity.DoctorName },
                            { "来源", "上传文件" },
                            { "错误原因","“人员工号”在人员字典中不存在，请修改或删除" },
                        });
                    }
                    else if (employee.DoctorName != entity.DoctorName)
                    {
                        errors.Add(new Dictionary<string, string>
                        {
                            { "行号", $"第{rowindex}行" },
                            { "人员工号", entity.PersonnelNumber },
                            { "姓名", entity.DoctorName },
                            { "来源", "上传文件" },
                            { "错误原因", "“姓名”与人员字典不一致，请修改或删除" },
                        });
                    }
                    else if (types.Any() && !types.Any(type => type == entity.PerforType))
                    {
                        errors.Add(new Dictionary<string, string>
                        {
                            { "行号", $"第{rowindex}行" },
                            { "人员工号", entity.PersonnelNumber },
                            { "姓名", entity.DoctorName },
                            { "来源", "上传文件" },
                            { "错误原因", "“绩效类型”错误，请按规定类型填入" },
                        });
                    }

                    entities.Add(entity);
                }

                if (errors.Count > 0) return new ApiResponse(ResponseType.WarningTable, "验证不通过,当前操作已拒绝", errors);
            }
            catch (Exception ex)
            {
                logger.LogError(ex.ToString());
            }
            return new ApiResponse(ResponseType.OK);
        }

        /// <summary>
        /// 获取绩效类型字典
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public List<TitleValue> GetPerforTypeDict(int allotId)
        {
            var defaultTypes = new List<string> { "基础绩效", "管理绩效" };

            var aprAmountList = perapramountRepository.GetEntities(w => w.AllotId == allotId);
            if (aprAmountList != null && aprAmountList.Any(w => !defaultTypes.Contains(w.PerforType)))
            {
                var savedTypes = aprAmountList.Where(w => !defaultTypes.Contains(w.PerforType)).Select(t => t.PerforType).Distinct().OrderBy(t => t).ToList();
                defaultTypes.AddRange(savedTypes);
            }
            return defaultTypes.Select(t => new TitleValue
            {
                Title = t,
                Value = t
            }).ToList();
        }

        /// <summary>
        /// 医院其他绩效统计
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public List<Dictionary<string, string>> GetOtherPerStats(int allotId, string department = null)
        {
            var others = new List<Dictionary<string, string>>();
            var aprAmountList = perapramountRepository.GetFullAmount(allotId, 3);
            if (department != null)
                aprAmountList = aprAmountList.Where(t => t.AccountingUnit == department).ToList();
            var perForType = aprAmountList.Select(t => t.PerforType).Distinct();

            foreach (var num in aprAmountList.Select(t => t.PersonnelNumber).Distinct())
            {
                var dicData = new Dictionary<string, string>();
                var amount = aprAmountList.FirstOrDefault(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 = aprAmountList.Where(t => t.PerforType == type && t.PersonnelNumber == num);
                    dicData.Add(type, Math.Round(emp?.Sum(c => c.Amount) ?? 0, 2).ToString());
                }

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

            return others;
        }
        #endregion

        #region 医院其他绩效类型
        public ApiResponse<List<per_apr_amount_type>> GetAprTypeList(int allotId)
        {
            var result = perAprAmountTypeRepository.GetEntities(t => t.AllotId == allotId).ToList();
            if (result != null)
                return new ApiResponse<List<per_apr_amount_type>>(ResponseType.OK, result);
            else return new ApiResponse<List<per_apr_amount_type>>(ResponseType.NotFound);
        }

        public ApiResponse<AprTypeRequest> InsertAprType(int createUser, AprTypeRequest request)
        {
            if (string.IsNullOrEmpty(request.PerforType.Trim()) || request.AllotId <= 0)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "输入参数不能为空！");
            var tepm = perAprAmountTypeRepository.GetEntity(t => t.AllotId == request.AllotId && t.PerforType == request.PerforType);
            if (tepm != null)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "已存在该类型");
            per_apr_amount_type per_Apr_Amount_Type = new per_apr_amount_type()
            {
                AllotId = request.AllotId,
                PerforType = request.PerforType.Trim(),
                CreateDate = DateTime.Now,
                CreateUser = createUser,
            };
            if (perAprAmountTypeRepository.Add(per_Apr_Amount_Type)) return new ApiResponse<AprTypeRequest>(ResponseType.OK, "添加成功");
            else return new ApiResponse<AprTypeRequest>(ResponseType.Fail, "添加失败");
        }

        public ApiResponse<AprTypeRequest> UpdateAprType(int typeId, AprTypeRequest request)
        {
            if (string.IsNullOrEmpty(request.PerforType.Trim()) || request.AllotId <= 0)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "输入参数不能为空！");
            var tepm = perAprAmountTypeRepository.GetEntity(t => t.Id != t.Id && t.AllotId == request.AllotId && t.PerforType == request.PerforType);
            if (tepm != null)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "已存在该类型");
            var res = perAprAmountTypeRepository.GetEntity(t => t.Id == typeId);
            if (res == null)
                return new ApiResponse<AprTypeRequest>(ResponseType.NotFound, "未查询到内容");
            var use = perapramountRepository.GetEntity(t => t.AllotId == res.AllotId && t.PerforType == res.PerforType);
            if (use != null)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "该类型正在使用！");
            res.UpdateTime = DateTime.Now;
            res.AllotId = request.AllotId;
            res.PerforType = request.PerforType.Trim();
            if (perAprAmountTypeRepository.Update(res)) return new ApiResponse<AprTypeRequest>(ResponseType.OK, "修改成功");
            else return new ApiResponse<AprTypeRequest>(ResponseType.Fail, "修改失败");
        }
        public ApiResponse DeleteAprType(int typeId)
        {
            var any = perAprAmountTypeRepository.GetEntity(t => t.Id == typeId);
            if (any == null)
                return new ApiResponse(ResponseType.NotFound, "没有该数据");
            var use = perapramountRepository.GetEntity(t => t.AllotId == any.AllotId && t.PerforType == any.PerforType);
            if (use != null)
                return new ApiResponse(ResponseType.ParameterError, "该类型正在使用！");
            if (perAprAmountTypeRepository.DeleteFromQuery(t => t.Id == typeId) > 0)
                return new ApiResponse(ResponseType.OK, "删除成功");
            else return new ApiResponse(ResponseType.Fail, "删除失败");
        }
        #endregion

        /// <summary>
        /// 根据人员工号获取人员信息
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="personnelNumber"></param>
        /// <param name="doctorName"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<per_employee> GetEmployeeMessage(int allotId, string personnelNumber, string doctorName, int userId)
        {
            if (string.IsNullOrEmpty(personnelNumber) && string.IsNullOrEmpty(doctorName)) return new List<per_employee>();

            var user = userRepository.GetEntity(w => w.ID == userId && w.IsDelete == 1);
            if (user == null) throw new PerformanceException("操作用户不存在或用户信息错误!");

            var employees = new List<per_employee>();
            var employeeId = 0;
            if (!string.IsNullOrEmpty(personnelNumber))
            {
                var employee = peremployeeRepository.GetEntity(w => w.AllotId == allotId && w.PersonnelNumber != null && w.PersonnelNumber.Trim() == personnelNumber.Trim());
                if (employee != null)
                {
                    employees.Add(employee);
                    employeeId = employee.Id;
                }
            }

            if (!string.IsNullOrEmpty(doctorName))
            {
                var filterEmployees = peremployeeRepository.GetEntities(w => w.AllotId == allotId && w.DoctorName != null
                && w.DoctorName.Trim().Contains(doctorName.Trim()) && w.Id != employeeId);
                if (filterEmployees != null && filterEmployees.Any()) employees.AddRange(filterEmployees);
            }
             
            return employees ?? new List<per_employee>();
        }

        /// <summary>
        /// 更加用户ID获取录入科室
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public string GetTypeInDepartment(int userId)
        {
            var user = userRepository.GetEntity(t => t.ID == userId);
            return user?.Login ?? "";
        }

        #region 科室考核

        public List<Dictionary<string, string>> GetDeptAssessment(int allotId)
        {
            var sheet = perforPersheetRepository.GetEntity(t => t.AllotID == allotId && t.SheetName == "5.4 科室材料考核2");
            if (sheet == null)
                return new List<Dictionary<string, string>>();

            var imData = perforImdataRepository.GetEntities(t => t.AllotID == allotId && t.SheetID == sheet.ID);
            var headers = imData.OrderByDescending(c => c.IsTotal).Select(t => t.TypeName).Distinct();
            var dataNum = imData.Select(t => t.RowNumber)?.OrderBy(c => c.Value).Distinct().ToList();
            if (!dataNum.Any())
                return new List<Dictionary<string, string>>();

            var rowData = new List<Dictionary<string, string>>();
            foreach (var num in dataNum)
            {
                var dicData = new Dictionary<string, string>();
                var fisHeader = false;
                foreach (var header in headers)
                {
                    var headData = imData.Find(t => t.RowNumber == num && t.TypeName == header)?.CellValue;
                    dicData.Add(header, Math.Round((decimal)headData * 100) + "%");
                    if (!fisHeader)
                    {
                        var data = imData?.First(t => t.RowNumber == num);
                        switch (data.UnitType)
                        {
                            case (int)UnitType.医技组:
                                dicData.Add("核算单元类型", "医技组");
                                break;
                            case (int)UnitType.医生组:
                                dicData.Add("核算单元类型", "医生组");
                                break;
                            case (int)UnitType.护理组:
                                dicData.Add("核算单元类型", "护理组");
                                break;
                        }
                        dicData.Add("核算单元", data.AccountingUnit);
                        fisHeader = true;
                    }
                }
                rowData.Add(dicData);
            }

            return rowData;
        }

        #endregion

        #region 不公示其他绩效
        /// <summary>
        /// 获取所有医院其他绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public List<OhterAmountAuditResponse> GetAprHideList(int allotId, int userId, int isAudit)
        {
            var userrole = userroleRepository.GetEntity(t => t.UserID == userId);
            if (userrole == null) throw new PerformanceException("用户未绑定角色");
            Expression<Func<per_apr_amount_hide, bool>> expression = t => t.AllotId == allotId && (t.Amount ?? 0) != 0;

            var roles = new int[] { (int)Role.绩效管理员, (int)Role.医院管理员, (int)Role.绩效核算办, (int)Role.院领导, (int)Role.审计 };
            if (!roles.Contains(userrole.RoleID))   //  绩效管理员、医院管理员、绩效核算办查看所有科室的数据
                expression = expression.And(t => t.CreateUser == userId);

            if (isAudit == 1)
                expression = expression.And(t => new int[] { 2, 3 }.Contains(t.Status ?? 1));

            var list = _hideRepository.GetEntities(expression) ?? new List<per_apr_amount_hide>();
            if (list != null && list.Any())
                list = list.OrderBy(w => w.IsVerify).ThenBy(t => t.DoctorName).ToList();

            var result = list.GroupBy(t => new { TypeInDepartment = t.TypeInDepartment ?? "", t.CreateDate })
                .Select(t =>
                {
                    string createDate = "";
                    if (t.Key.CreateDate != null)
                        createDate = t.Key.CreateDate.Value.ToString("yyyy-MM-dd HH:mm:ss");
                    var status = t.OrderByDescending(w => w.Id).FirstOrDefault()?.Status ?? 0;
                    var perforTypes = string.Join("/", t.Select(w => w.PerforType).Distinct());
                    if (perforTypes.Length > 10) perforTypes = perforTypes.Substring(0, 10) + "……";

                    return new OhterAmountAuditResponse()
                    {
                        TypeInDepartment = t.Key.TypeInDepartment,
                        CreateDate = createDate,
                        Amount = t.Sum(s => s.Amount ?? 0),
                        Status = status,
                        PerforType = perforTypes,
                        AuditTime = t.Any(s => s.Status == 2) ? "" : t.Max(w => w.AuditTime)?.ToString("yyyy-MM-dd HH:mm:ss"),
                        Remark = t.Any(s => !s.MarkStatus.HasValue) ? "" : $"已审计{t.Max(w => w.MarkTime)?.ToString("(yyyy-MM-dd HH:mm:ss)")}",
                        ShowCommit = (new int[] { 1, 4 }).Contains(status) && t.FirstOrDefault(t => t.CreateUser.HasValue).CreateUser == userId,
                    };
                });
            if (result != null && result.Any())
                result = result.OrderByDescending(o => o.CreateDate).ToList();

            return result.ToList();
        }




        /// <summary>
        /// 不公示其他绩效提交
        /// </summary>
        /// <returns></returns>
        public bool SubmitHideDeptList(SubmitAmountRequest request)
        {
            var createDate = DateTime.Parse(request.CreateDate);
            var result = _hideRepository.GetEntities(w => w.AllotId == request.AllotId && w.TypeInDepartment == request.TypeInDepartment && w.CreateDate == createDate);
            result.ForEach(w =>
            {
                w.Status = 2;
            });
            return _hideRepository.UpdateRange(result.ToArray());

        }
        /// <summary>
        /// 医院其他绩效审核详情
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department"></param>
        /// <returns></returns>
        public List<view_per_apr_amount> GetAprHideList(int allotId, string department, int? status = null, DateTime? date = null)
        {
            Expression<Func<per_apr_amount_hide, bool>> predicate = w => w.AllotId == allotId && w.Amount.HasValue && w.Amount != 0;
            if (!string.IsNullOrEmpty(department))
                predicate = predicate.And(w => !string.IsNullOrEmpty(w.TypeInDepartment) && w.TypeInDepartment == department);

            if (status.HasValue)
                predicate = predicate.And(w => w.Status == status);

            if (date.HasValue)
                predicate = predicate.And(w => w.CreateDate == date);

            var list = _hideRepository.GetFullAmount(predicate);
            if (list != null && list.Any())
                list = list.OrderBy(t => t.DoctorName).ToList();

            return list;
        }
        /// <summary>
        /// 新增医院其他绩效
        /// </summary>
        /// <param name="request"></param>
        /// <param name="userId"></param>
        /// <returns></returns>
        public bool InsertAprHide(per_apr_amount_hide request, int userId)
        {
            if (request == null)
                throw new PerformanceException("无效数据");

            if (string.IsNullOrEmpty(request.PersonnelNumber))
                throw new PerformanceException("文件中存在“工号”为空的数据");
            if (string.IsNullOrEmpty(request.PerforType) && request.Amount != 0)
                throw new PerformanceException("文件中存在“绩效类型”为空的数据");

            var employee = peremployeeRepository.GetEntity(t => t.AllotId == request.AllotId && t.PersonnelNumber == request.PersonnelNumber);
            if (employee == null)
                throw new PerformanceException("工号在字典中不存在");

            var types = perAprAmountTypeHIdeRepository.GetEntities(t => t.AllotId == request.AllotId);
            if (types?.Any() == true && !types.Any(w => w.PerforType == request.PerforType))
                throw new PerformanceException("“绩效类型”错误，请按规定类型填入");

            request.TypeInDepartment = GetTypeInDepartment(userId);
            request.Status = 1;
            request.CreateUser = userId;
            return _hideRepository.Add(request);
        }
        /// <summary>
        /// 修改医院其他绩效
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool UpdateAprHide(per_apr_amount_hide request)
        {
            if (request == null)
                throw new PerformanceException("无效数据");

            if (string.IsNullOrEmpty(request.PersonnelNumber))
                throw new PerformanceException("文件中存在“工号”为空的数据");
            if (string.IsNullOrEmpty(request.PerforType) && request.Amount != 0)
                throw new PerformanceException("文件中存在“绩效类型”为空的数据");

            var data = _hideRepository.GetEntity(t => t.Id == request.Id);
            if (data == null)
                throw new PerformanceException("修改数据无效");

            var types = perAprAmountTypeHIdeRepository.GetEntities(t => t.AllotId == request.AllotId);
            if (types?.Any() == true && !types.Any(w => w.PerforType == request.PerforType))
                throw new PerformanceException("“绩效类型”错误，请按规定类型填入");

            data.Status = 1;
            data.PersonnelNumber = request.PersonnelNumber;
            data.DoctorName = request.DoctorName;
            data.PerforType = request.PerforType;
            //data.AccountingUnit = request.AccountingUnit;
            data.Amount = request.Amount;
            data.Remark = request.Remark;

            return _hideRepository.Update(data);
        }
        /// <summary>
        /// 删除医院其他绩效
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool DeleteAprHide(int id)
        {
            var data = _hideRepository.GetEntity(t => t.Id == id);
            if (data != null)
                return _hideRepository.Remove(data);

            return true;
        }


        /// <summary>
        /// 提交、撤销医院不公示其他绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department">录入科室</param>
        /// <param name="status">1.撤销 2.提交</param>
        /// <returns></returns>
        public bool CommitAprHide(int allotId, string department, int status, DateTime date)
        {
            var list = status == 1
                ? GetAprHideByTypeInDepartment(allotId, department, date, 2) // 撤销操作，获取已提交等待审核的数据
                : GetAprHideByTypeInDepartment(allotId, department, date, 1, 4);  // 提交操作，获取未提交、驳回的数据
            if (list == null) return true;

            list.ForEach(t => t.Status = status);
            _hideRepository.UpdateRange(list.ToArray());
            return true;
        }

        /// <summary>
        /// 审核医院其他绩效
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public ApiResponse ConfirmAuditHide(int userid, AprAmountAuditRequest request)
        {
            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();

            if (request?.Members == null || !request.Members.Any())
                throw new PerformanceException("审核信息无效，请确认");


            var err = request.Members
                .Select((w, i) =>
                {
                    if (string.IsNullOrEmpty(w.PersonnelNumber))
                    {
                        return new Dictionary<string, string>
                        {
                            { "行号", $"第{i+1}行" }, { "人员工号", w.PersonnelNumber??"" }, { "姓名", w.DoctorName??"" }, { "错误原因", "“人员工号”为空" },
                        };
                    }
                    return null;
                })
                .Where(w => w != null);

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

            var allApramounts = request.IsPass == 1
                ? GetAprHideByTypeInDepartment(request.AllotId, request.TypeInDepartment, request.CreateDate, 2)  // 获取等待审核的数据
                : GetAprHideByTypeInDepartment(request.AllotId, request.TypeInDepartment, request.CreateDate, 2, 3); // 获取等待审核、审核通过的数据
            foreach (var member in request.Members)
            {
                var apramounts = allApramounts?.Where(t => (t.PersonnelNumber ?? "") == member.PersonnelNumber);
                if (apramounts != null && apramounts.Any())
                {
                    foreach (var item in apramounts)
                    {
                        item.Status = (request.IsPass == 1) ? 3 : 4;
                        item.AuditUser = userid;
                        item.AuditTime = DateTime.Now;
                        _hideRepository.UpdateRange(apramounts.ToArray());
                    }
                }
            }
            _service.FreezeAllotSync(request.AllotId);
            return new ApiResponse(ResponseType.OK, "");
        }
        /// <summary>
        /// 不公示其他绩效审计
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public ApiResponse AprMarkHide(int userid, AprAmountMarkRequest request)
        {
            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();

            if (request?.TypeInDepartments == null || !request.TypeInDepartments.Any())
                throw new PerformanceException("审计信息无效，请确认");

            foreach (var department in request.TypeInDepartments)
            {
                string update = "update per_apr_amount_hide set MarkStatus=@MarkStatus,MarkUser=@MarkUser,MarkTime=@MarkTime where TypeInDepartment=@TypeInDepartment and AllotId=@AllotId; ";
                _hideRepository.Execute(update, new { MarkStatus = 1, MarkUser = userid, MarkTime = DateTime.Now, TypeInDepartment = department, request.AllotId });
            }
            return new ApiResponse(ResponseType.OK, "");
        }

        /// <summary>
        /// 上传导入医院其他绩效
        /// </summary>
        /// <param name="allotid"></param>
        /// <param name="path"></param>
        /// <param name="userid"></param>
        public ApiResponse ImportAprHideEmployees(int allotid, string path, int userid)
        {
            var userrole = userroleRepository.GetEntity(t => t.UserID == userid);
            if (userrole == null) throw new PerformanceException("用户未绑定角色");

            List<per_apr_amount> entities = new List<per_apr_amount>();
            var typeIn = GetTypeInDepartment(userid);
            var createtime = DateTime.Now;

            var types = perAprAmountTypeHIdeRepository.GetEntities(t => t.AllotId == allotid) ?? new List<per_apr_amount_hide_type>();

            var res = OpenAndReadAprAmountExcel(allotid, path, types.Select(w => w.PerforType).ToList(), entities);
            if (res.State == ResponseType.OK)
            {
                if (!entities.Any()) throw new PerformanceException("未能找到有效数据，请检查后重试！");

                List<per_apr_amount_hide> newEntities = new List<per_apr_amount_hide>();

                foreach (var entity in entities)
                {
                    newEntities.Add(new per_apr_amount_hide
                    {
                        PersonnelNumber = entity.PersonnelNumber,
                        DoctorName = entity.DoctorName,
                        PerforType = entity.PerforType,
                        Amount = entity.Amount,
                        Remark = entity.Remark,

                        Status = 1,
                        TypeInDepartment = typeIn,
                        AllotId = allotid,
                        CreateDate = createtime,
                        CreateUser = userid,
                    });
                }
                _hideRepository.AddRange(newEntities.ToArray());
            }
            return res;
        }

        /// <summary>
        /// 获取绩效类型字典
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public List<TitleValue> GetPerforTypeDictHide(int allotId)
        {
            var defaultTypes = new List<string> { "基础绩效", "管理绩效" };

            var aprAmountList = _hideRepository.GetEntities(w => w.AllotId == allotId);
            if (aprAmountList != null && aprAmountList.Any(w => !defaultTypes.Contains(w.PerforType)))
            {
                var savedTypes = aprAmountList.Where(w => !defaultTypes.Contains(w.PerforType)).Select(t => t.PerforType).Distinct().OrderBy(t => t).ToList();
                defaultTypes.AddRange(savedTypes);
            }
            return defaultTypes.Select(t => new TitleValue
            {
                Title = t,
                Value = t
            }).ToList();
        }

        /// <summary>
        /// 医院其他绩效统计
        /// </summary>
        /// <param name="allotId"></param>
        /// <returns></returns>
        public List<Dictionary<string, string>> GetOtherPerStatsHide(int allotId)
        {
            var others = new List<Dictionary<string, string>>();
            var aprAmountList = _hideRepository.GetFullAmount(w => w.AllotId == allotId && w.Status == 3);
            var perForType = aprAmountList.Select(t => t.PerforType).Distinct();

            foreach (var num in aprAmountList.Select(t => t.PersonnelNumber).Distinct())
            {
                var dicData = new Dictionary<string, string>();
                var amount = aprAmountList.FirstOrDefault(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 = aprAmountList.Where(t => t.PerforType == type && t.PersonnelNumber == num);
                    dicData.Add(type, Math.Round(emp?.Sum(c => c.Amount) ?? 0, 2).ToString());
                }

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

            return others;
        }
        #endregion

        #region 不公示医院其他绩效类型
        public ApiResponse<List<per_apr_amount_hide_type>> GetAprTypeListHide(int allotId)
        {
            var result = perAprAmountTypeHIdeRepository.GetEntities(t => t.AllotId == allotId).ToList();
            if (result != null)
                return new ApiResponse<List<per_apr_amount_hide_type>>(ResponseType.OK, result);
            else return new ApiResponse<List<per_apr_amount_hide_type>>(ResponseType.NotFound);
        }

        public ApiResponse<AprTypeRequest> InsertAprTypeHide(int createUser, AprTypeRequest request)
        {
            if (string.IsNullOrEmpty(request.PerforType.Trim()) || request.AllotId <= 0)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "输入参数不能为空！");
            var tepm = perAprAmountTypeHIdeRepository.GetEntity(t => t.AllotId == request.AllotId && t.PerforType == request.PerforType);
            if (tepm != null)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "已存在该类型");
            per_apr_amount_hide_type per_apr_amount_hide_type = new per_apr_amount_hide_type()
            {
                AllotId = request.AllotId,
                PerforType = request.PerforType.Trim(),
                CreateDate = DateTime.Now,
                CreateUser = createUser,
            };
            if (perAprAmountTypeHIdeRepository.Add(per_apr_amount_hide_type)) return new ApiResponse<AprTypeRequest>(ResponseType.OK, "添加成功");
            else return new ApiResponse<AprTypeRequest>(ResponseType.Fail, "添加失败");
        }

        public ApiResponse<AprTypeRequest> UpdateAprTypeHide(int typeId, AprTypeRequest request)
        {
            if (string.IsNullOrEmpty(request.PerforType.Trim()) || request.AllotId <= 0)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "输入参数不能为空！");
            var tepm = perAprAmountTypeHIdeRepository.GetEntity(t => t.Id != t.Id && t.AllotId == request.AllotId && t.PerforType == request.PerforType);
            if (tepm != null)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "已存在该类型");
            var res = perAprAmountTypeHIdeRepository.GetEntity(t => t.Id == typeId);
            if (res == null)
                return new ApiResponse<AprTypeRequest>(ResponseType.NotFound, "未查询到内容");
            var use = _hideRepository.GetEntity(t => t.AllotId == res.AllotId && t.PerforType == res.PerforType);
            if (use != null)
                return new ApiResponse<AprTypeRequest>(ResponseType.ParameterError, "该类型正在使用！");
            res.UpdateTime = DateTime.Now;
            res.AllotId = request.AllotId;
            res.PerforType = request.PerforType.Trim();
            if (perAprAmountTypeHIdeRepository.Update(res)) return new ApiResponse<AprTypeRequest>(ResponseType.OK, "修改成功");
            else return new ApiResponse<AprTypeRequest>(ResponseType.Fail, "修改失败");
        }
        public ApiResponse DeleteAprTypeHide(int typeId)
        {
            var any = perAprAmountTypeHIdeRepository.GetEntity(t => t.Id == typeId);
            if (any == null)
                return new ApiResponse(ResponseType.NotFound, "没有该数据");
            var use = _hideRepository.GetEntity(t => t.AllotId == any.AllotId && t.PerforType == any.PerforType);
            if (use != null)
                return new ApiResponse(ResponseType.ParameterError, "该类型正在使用！");
            if (perAprAmountTypeHIdeRepository.DeleteFromQuery(t => t.Id == typeId) > 0)
                return new ApiResponse(ResponseType.OK, "删除成功");
            else return new ApiResponse(ResponseType.Fail, "删除失败");
        }
        #endregion

        public ComparisonResponse<DtoModels.Comparison<view_check_emp>> GetComparison(ComparisonPagingRequest request)
        {
            var result = new ComparisonResponse<DtoModels.Comparison<view_check_emp>>();

            if (request.ViewName == "view_check_dept")
            {
                result.Heads = ComparisonConfig.DeptHeads;
                result.Datas = peremployeeRepository.CheckAccountingUnitRealGiveFeeDiff(request);
                result.Datas.Datas.ForEach(t =>
                {
                    t.UnitTypeId = UnitTypeUtil.GetUnitTypeFromEnum(t.UnitType).Value;
                });
            }
            else if (request.ViewName == "view_check_emp")
            {
                result.Heads = ComparisonConfig.EmpHeads;
                result.Datas = peremployeeRepository.CheckEmployeeRealGiveFeeDiff(request);
            }
            else
            {
                result.Datas = new DtoModels.Comparison<view_check_emp> { Datas = new List<view_check_emp>(), TotalCount = 0 };
            }
            //result.Datas = peremployeeRepository.GetComparison(request);
            return result;
        }

        public ComparisonResponse<DtoModels.Comparison<DeptComparisonTotal>> GetDeptComparisonTotal(int AllotId)
        {
            var result = new ComparisonResponse<DtoModels.Comparison<DeptComparisonTotal>>();
            result.Heads = ComparisonConfig.DeptTotalHeads;
            result.Datas = peremployeeRepository.CheckView_check_deptUnitRealGiveFeeDiffTotal(AllotId);

            return result;
        }

        #region 手工数据录入

        public List<GatherDropResponse> GetGatherDrop(Gather gather)
        {
            List<GatherDropResponse> result = new List<GatherDropResponse>();

            var username = userRepository.GetEntity(t => t.ID == gather.UserId);

            var takeOut = new[] { "核算单元(医技组)", "核算单元(医生组)", "核算单元(护理组)", " ", "" };

            var userrole = userroleRepository.GetEntity(t => t.UserID == gather.UserId);
            if (userrole == null) throw new PerformanceException("用户未绑定角色");

            var roles = new int[] { (int)Role.医院管理员, (int)Role.绩效管理员, (int)Role.绩效核算办 };
            if (roles.Contains(userrole.RoleID))
            {
                var types = new[] { (int)SheetType.OtherIncome, (int)SheetType.Expend, (int)SheetType.Workload, (int)SheetType.SpecialUnit };

                var sheets = exmoduleRepository.GetEntities(w => types.Contains(w.SheetType ?? 0));

                var specials = exspecialRepository.GetEntities();


                var headers = exitemRepository.GetEntities(w => sheets.Select(m => m.Id).Contains(w.ModuleId ?? 0)) ?? new List<ex_item>();

                if (specials != null && specials.Any())
                {
                    sheets.Add(new ex_module
                    {
                        SheetType = (int)SheetType.SpecialUnit,
                        ModuleName = "4.2 特殊核算单元绩效测算表",
                        Id = 0,
                    });

                    headers.AddRange(specials.Select(t => new ex_item { ItemName = t.Target, ModuleId = 0 }));
                }

                // 查询sheet和列头对应
                var sheetHeads = from sheet in sheets
                                 join head in headers on sheet.Id equals head.ModuleId
                                 select new { sheet.ModuleName, sheet.SheetType, HeadName = head.ItemName };
                sheetHeads = sheetHeads.Where(w => !takeOut.Contains(w.HeadName));
                result = sheetHeads.GroupBy(t => t.ModuleName).Select(s => new GatherDropResponse
                {
                    Value = Regex.Replace(s.Key.Replace(" ", "").Replace(".", ""), "[0-9]", ""),
                    Children = sheetHeads.Where(t => t.ModuleName == s.Key).Select(t => new GatherDropResponse()
                    {
                        Value = Regex.Replace(t.HeadName.Replace(" ", "").Replace(".", ""), "[0-9]", "")
                    }).ToList()
                }).ToList();
            }
            else
            {

                var permissions = perforcollectpermissionRepository.GetEntities(w => w.UserId == gather.UserId && !takeOut.Contains(w.HeadName));

                result = permissions.GroupBy(t => t.SheetName).Select(s => new GatherDropResponse
                {
                    Value = Regex.Replace(s.Key.Replace(" ", "").Replace(".", ""), "[0-9]", ""),
                    Children = permissions.Where(t => t.SheetName == s.Key).Select(t => new GatherDropResponse()
                    {
                        Value = Regex.Replace(t.HeadName.Replace(" ", "").Replace(".", ""), "[0-9]", "")
                    }).ToList()
                }).ToList();
            }
            return result;

        }

        public HandsonTableBase GetGatherHands(int AllotId, GatherRequest request)
        {
            HandsonTableBase result = new HandsonTableBase()
            {
                Columns = Gather.Select(t => new HandsonColumn(t.Value)).ToList(),
                ColHeaders = Gather.Select(t => t.Value).ToList(),
            };

            if (result.Columns != null && result.Columns.Any())
            {
                foreach (var column in result.Columns)
                {
                    if (column.Data == "数值")
                    {
                        column.Type = "numeric";
                        column.NumericFormat = new NumericFormat { Pattern = "0,00.00" };
                    }
                    else
                        column.Type = "text";
                }
            }
            List<ex_result_gather> data = new List<ex_result_gather>();
            if (!string.IsNullOrEmpty(request.Source) && !string.IsNullOrEmpty(request.Category))
            {
                data = exresultgatherRepository.GetEntities(t => t.AllotId == AllotId && t.Source.Contains(request.Source) && t.Category.Contains(request.Category));
            }

            if (data == null)
                return result;

            List<HandsonRowData> rowDatas = new List<HandsonRowData>();
            int i = 1;
            foreach (var item in data)
            {
                var json = JsonHelper.Serialize(item);
                var firstDic = JsonHelper.Deserialize<Dictionary<string, string>>(json);

                var cells = (from conf in Gather join fst in firstDic on conf.Key.ToUpper() equals fst.Key.ToUpper() select new HandsonCellData(conf.Value, fst.Value)).ToList();

                rowDatas.Add(new HandsonRowData(i, cells));
                i++;
            }
            result.SetRowData(rowDatas);
            return result;
        }

        public bool DeleteGather(Gather gather)
        {
            var delete = exresultgatherRepository.GetEntities(t => t.AllotId == gather.AllotId && t.Department == gather.Department && t.Source == gather.Source && t.Category == gather.Category);
            //exresultgatherRepository.Execute($@"delete from ex_result_gather where allotid = @allotid and department like '%{request.Department}%'and source like '%{request.Source}%' and category like '%{request.Category}%' ", new { allotId });
            return exresultgatherRepository.RemoveRange(delete.ToArray());
        }

        public GatherInfo GetGather(Gather gather)
        {
            Expression<Func<ex_result_gather, bool>> exp = t => t.AllotId == gather.AllotId && t.Department == gather.Department && t.Source.Contains(gather.Source) && t.Category.Contains(gather.Category);

            if (gather != null && !string.IsNullOrEmpty(gather.SearchQuery))
                exp = exp.And(t => t.DoctorName.Contains(gather.SearchQuery) || t.PersonnelNumber.Contains(gather.SearchQuery));
            var datas = exresultgatherRepository.GetEntities(exp).OrderByDescending(t => t.CreateTime);

            var result = datas.Select(t => new GatherInfoRequest
            {
                Source = Regex.Replace(t.Source.Replace(" ", "").Replace(".", ""), "[0-9]", ""),
                CreateTime = t.CreateTime.ToString("d"),
                Department = t.Department,
                UserId = t.Submitter,
                PersonnelNumber = t.PersonnelNumber,
                DoctorName = t.DoctorName,
                Detail = new GatherInfoFee[] { new GatherInfoFee { Category = gather.Category, Fee = t.Fee } }
            });

            var head = ColumnHeadsConfig.GatherHeads;
            head.ForEach(t =>
            {
                t.Name = t.Name.ToLower();
            });

            GatherInfo gatherInfo = new GatherInfo()
            {
                Heads = head,
                Datas = result.Skip((gather.PageNumber - 1) * gather.PageSize).Take(gather.PageSize).ToList(),
                CurrentPage = gather.PageNumber,
                TotalCount = result.Count(),
                PageSize = gather.PageSize,
                TotalPages = (int)Math.Ceiling((double)result.Count() / gather.PageSize)
            };
            return gatherInfo;
        }

        public GatherResponse GetGatherTotal(Gather gather)
        {
            Expression<Func<ex_result_gather, bool>> exp = t => t.AllotId == gather.AllotId;

            if (gather != null && !string.IsNullOrEmpty(gather.SearchQuery))
            {
                exp = exp.And(t => t.Category.Contains(gather.SearchQuery) || t.Source.Contains(gather.SearchQuery) || t.Department.Contains(gather.SearchQuery));
            }
            var user = userRepository.GetEntities();
            var userLogin = user.FirstOrDefault(t => t.ID == gather.UserId);

            var userSource = perforcollectpermissionRepository.GetEntities(t => t.UserId == gather.UserId)
                .Select(s => Regex.Replace(s.SheetName.Replace(" ", "").Replace(".", ""), "[0-9]", ""))
                .Distinct().ToList();

            var userrole = userroleRepository.GetEntity(t => t.UserID == gather.UserId);
            if (userrole == null) throw new PerformanceException("用户未绑定角色");

            var roles = new int[] { (int)Role.医院管理员, (int)Role.绩效管理员, (int)Role.绩效核算办 };

            List<ex_result_gather> exresultgather = new List<ex_result_gather>();

            if (!roles.Contains(userrole.RoleID))
            {
                if (userSource.Count() != 0)
                {
                    exp = exp.And(t => userSource.Contains(t.Source));
                    var hasDepartment = perdeptdicRepository.GetEntities(p => p.AccountingUnit.Contains(userLogin.Department)).Select(s => s.HISDeptName).Distinct().ToList();
                    exp = exp.And(t => hasDepartment.Contains(t.Department));

                    exresultgather = exresultgatherRepository.GetEntities(exp);
                }
            }
            else
            {
                exresultgather = exresultgatherRepository.GetEntities(exp);
            }


            var datas = exresultgather
                .GroupBy(t => new { t.Department, t.Source, t.Category, t.Submitter })
                .Select(s => new
                {
                    Department = s.Key.Department,
                    Source = s.Key.Source,
                    Category = s.Key.Category,
                    UserId = s.Key.Submitter,
                    Login = user.FirstOrDefault(t => t.ID == s.Key.Submitter).Login,
                    CreateTime = s.Max(t => t.CreateTime).ToString("d"),
                    AuditTime = s.Max(t => t.AuditTime)?.ToString("d"),
                    States = s.Any(w => w.States == (int)EnumResult.AuditGather.未通过) ? "未通过"
                    : s.Count() == s.Where(w => w.States == (int)EnumResult.AuditGather.已通过).Count() ? "已通过"
                    : s.Count() == s.Where(w => w.States == (int)EnumResult.AuditGather.未审核).Count() ? "未审核" : "未知",
                    Remark = s.FirstOrDefault()?.Remark,
                    Path = s.FirstOrDefault()?.Path,
                });

            if (gather.Status == "失败") datas = datas.Where(w => w.States == "未通过");
            if (gather.Status == "通过") datas = datas.Where(w => w.States == "已通过");

            var ser = JsonConvert.SerializeObject(datas.OrderByDescending(t => t.CreateTime));
            var rows = JsonConvert.DeserializeObject<List<Dictionary<string, object>>>(ser);

            var data = new List<Dictionary<string, object>>();
            foreach (var obj in rows)
            {
                Dictionary<string, object> nobj = new Dictionary<string, object>();

                foreach (var item in obj)
                {
                    nobj[item.Key.ToLower()] = item.Value;
                }
                data.Add(nobj);
            }

            var head = ColumnHeadsConfig.GatherTotal;
            head.ForEach(t =>
            {
                t.Name = t.Name.ToLower();
            });
            GatherResponse gatherResponse = new GatherResponse()
            {
                Heads = head,
                Datas = data.Skip((gather.PageNumber - 1) * gather.PageSize).Take(gather.PageSize).ToList(),
                CurrentPage = gather.PageNumber,
                TotalCount = data.Count(),
                PageSize = gather.PageSize,
                TotalPages = (int)Math.Ceiling((double)data.Count() / gather.PageSize)
            };
            return gatherResponse;

        }
        public string UploadGatherFile(string path, Gather gather)
        {
            var datas = exresultgatherRepository.GetEntities(w => w.AllotId == gather.AllotId && w.Department == gather.Department && w.Source == gather.Source && w.Category == gather.Category);

            if (datas?.Any() != true)
                return "未找到核算项目信息";
            datas.ForEach(w =>
                {
                    w.Path = path;
                });
            exresultgatherRepository.UpdateRange(datas.ToArray());
            return "";
        }
        public static Dictionary<string, string> Gather { get; } = new Dictionary<string, string>
        {
            {nameof(ex_result_gather.Department), "科室"},
            {nameof(ex_result_gather.DoctorName), "医生姓名"},
            {nameof(ex_result_gather.PersonnelNumber), "人员工号"},
            //{nameof(ex_result_gather.Category), "费用类型"},
            {nameof(ex_result_gather.Fee), "数值"},
            //{nameof(ex_result_gather.Source), "来源"}
        };

        private List<Dictionary<string, string>> CreateDataRow(int hospitalId, int allotId, SaveGatherData request, Dictionary<string, string> config)
        {
            List<Dictionary<string, string>> allData = new List<Dictionary<string, string>>();

            for (int r = 0; r < request.Data.Length; r++)
            {
                // 创建固定数据列
                Dictionary<string, string> baseData = CreateBaseData(request, config, r);
                baseData.Add(nameof(cof_hrp_department.AllotId), hospitalId.ToString());
                allData.Add(baseData);

            }
            return allData;
        }

        private Dictionary<string, string> CreateBaseData(SaveGatherData request, Dictionary<string, string> config, int rownumber)
        {
            Dictionary<string, string> result = new Dictionary<string, string>();
            for (int c = 0; c < request.ColHeaders.Length; c++)
            {
                var header = request.ColHeaders[c];
                var first = config.FirstOrDefault(w => w.Value == header);
                if (!default(KeyValuePair<string, string>).Equals(first)
                    && !result.ContainsKey(header)
                    && request.Data[rownumber].Length > c)
                {
                    result.Add(first.Key, request.Data[rownumber][c]);
                }
            }

            return result;
        }



        #endregion

        public ApiResponse SaveGatherHands(int allotId, SaveGatherData saveGather)
        {
            var allot = perallotRepository.GetEntity(w => w.ID == allotId);
            if (allot == null) throw new PerformanceException("绩效记录不存在");

            var employees = peremployeeRepository.GetEntities(w => w.AllotId == allotId);
            if (employees == null || !employees.Any()) throw new PerformanceException("未配置人员字典");

            var departments = perdeptdicRepository.GetEntities(w => w.HospitalId == allot.HospitalId);
            if (departments == null || !departments.Any()) throw new PerformanceException("未配置科室字典");

            var sheets = perforPersheetRepository.GetEntities(w => w.AllotID == allotId);
            if (sheets != null && sheets.Any())
            {
                if (!sheets.Select(t => t.SheetName).Any(t => t.Contains(saveGather.Source)))
                    throw new PerformanceException($"来源错误[{saveGather.Source}]");
            }

            var accountingUnit = userRepository.GetEntity(t => t.ID == saveGather.UserId);
            if (accountingUnit == null) throw new PerformanceException($"核算单元不存在");

            var depts = new List<string>();
            for (int i = 0; i < saveGather.Data.Length; i++)
            {
                depts.Add(saveGather.Data[i][0]);
            }

            var dict = new Dictionary<string, string>();
            Gather.ToList().ForEach(t => dict.Add(t.Key, t.Value));

            var dicData = CreateDataRow(0, allotId, saveGather, dict);
            if (dicData == null || dicData.Count == 0)
                return new ApiResponse(ResponseType.Error, "空数据，无效操作");

            var jsons = JsonHelper.Serialize(dicData);
            var newGather = JsonHelper.Deserialize<List<ex_result_gather>>(jsons);

            var oldGather = exresultgatherRepository.GetEntities(t => t.AllotId == allotId && t.Source == saveGather.Source && t.Category == saveGather.Category && depts.Distinct().Contains(t.Department));

            var perdeptdic = perdeptdicRepository.GetEntities(d => d.AccountingUnit == accountingUnit.Department);

            var hasDepartment = perdeptdic.Select(s => s.Department).Union(perdeptdic.Select(s => s.HISDeptName));


            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();

            for (int i = 0; i < newGather.Count; i++)
            {

                if (string.IsNullOrEmpty(newGather[i].Department))
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "科室", newGather[i].Department??"" },
                        { "医生姓名", newGather[i].DoctorName??"" },
                        { "人员工号", newGather[i].PersonnelNumber??"" },
                        { "数值", newGather[i].Fee.ToString() },
                        { "来源", "粘贴数据" },
                        { "错误原因", "科室不能为空" },
                    });

                if (newGather[i].Fee == 0)
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "科室", newGather[i].Department??"" },
                        { "医生姓名", newGather[i].DoctorName??"" },
                        { "人员工号", newGather[i].PersonnelNumber??"" },
                        { "数值", newGather[i].Fee.ToString() },
                        { "来源", "粘贴数据" },
                        { "错误原因", "数值不能为空和0" },
                    });

                var ExistsDeptData = departments.FirstOrDefault(w => w.AllotId == allotId
                && (w.Department != null && w.Department.Contains(newGather[i].Department))
                || (w.HISDeptName != null && w.HISDeptName.Contains(newGather[i].Department))
                );
                if (ExistsDeptData == null)
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "科室", newGather[i].Department??"" },
                        { "医生姓名", newGather[i].DoctorName??"" },
                        { "人员工号", newGather[i].PersonnelNumber??"" },
                        { "数值", newGather[i].Fee.ToString() },
                        { "来源", "粘贴数据" },
                        { "错误原因", $"科室字典中不存在科室[{newGather[i].Department}]" },
                    });

                if (!string.IsNullOrEmpty(newGather[i].DoctorName))
                {
                    var ExistNameData = employees.FirstOrDefault(w => w.AllotId == allotId && (w.DoctorName != null && w.DoctorName == newGather[i].DoctorName));
                    if (ExistNameData == null)
                        error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "科室", newGather[i].Department??"" },
                        { "医生姓名", newGather[i].DoctorName??"" },
                        { "人员工号", newGather[i].PersonnelNumber??"" },
                        { "数值", newGather[i].Fee.ToString() },
                        { "来源", "粘贴数据" },
                        { "错误原因", $"人员字典中不存在医生姓名[{newGather[i].DoctorName}]" },
                    });
                }

                if (!string.IsNullOrEmpty(newGather[i].DoctorName))
                {
                    var ExistNumberData = employees.FirstOrDefault(w => w.AllotId == allotId && (w.PersonnelNumber != null && w.PersonnelNumber == newGather[i].PersonnelNumber));
                    if (ExistNumberData == null)
                        error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "科室", newGather[i].Department??"" },
                        { "医生姓名", newGather[i].DoctorName??"" },
                        { "人员工号", newGather[i].PersonnelNumber??"" },
                        { "数值", newGather[i].Fee.ToString() },
                        { "来源", "粘贴数据" },
                        { "错误原因", $"人员字典中不存在工号[{newGather[i].PersonnelNumber}]" },
                    });

                    var ExistNameData = employees.FirstOrDefault(w => w.AllotId == allotId && (w.DoctorName != null && w.DoctorName == newGather[i].DoctorName));
                    if ((ExistNumberData == null || ExistNumberData.DoctorName != newGather[i].DoctorName)
                    || (ExistNameData == null || ExistNameData.PersonnelNumber != newGather[i].PersonnelNumber))
                        error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "科室", newGather[i].Department??"" },
                        { "医生姓名", newGather[i].DoctorName??"" },
                        { "人员工号", newGather[i].PersonnelNumber??"" },
                        { "数值", newGather[i].Fee.ToString() },
                        { "来源", "粘贴数据" },
                        { "错误原因", $"该人员姓名和工号与人员字典中不匹配" },
                    });
                }

                //if (accountingUnit.Login != "admin")
                //{
                //    if (!hasDepartment.Contains(newGather[i].Department))
                //        error.Add(new Dictionary<string, string>
                //    {
                //        { "行号", $"第{i+1}行" },
                //        { "科室", newGather[i].Department??"" },
                //        { "医生姓名", newGather[i].DoctorName??"" },
                //        { "人员工号", newGather[i].PersonnelNumber??"" },
                //        { "数值", newGather[i].Fee.ToString() },
                //        { "来源", "粘贴数据" },
                //        { "错误原因", $"[{newGather[i].Department}]科室不属于[{accountingUnit.Department}]核算单元，[{accountingUnit.Department}]核算单元有【{string.Join("】【", hasDepartment)}】科室" },
                //    });
                //}
            }
            if (error.Count > 0)
                return new ApiResponse(ResponseType.WarningTable, "验证不通过,当前操作已拒绝", error);

            newGather.ForEach(t =>
            {
                t.AllotId = allotId;
                t.States = 0;
                t.Source = saveGather.Source;
                t.Category = saveGather.Category;
                t.Submitter = saveGather.UserId;
                t.CreateTime = DateTime.Now;
            });

            exresultgatherRepository.RemoveRange(oldGather.ToArray());
            if (newGather != null && newGather.Any())
                exresultgatherRepository.AddRange(newGather.ToArray());

            AddCategoryToConfig(allotId);

            return new ApiResponse(ResponseType.OK, "");

        }

        public void AddCategoryToConfig(int allotId)
        {
            var allot = perallotRepository.GetEntity(w => w.ID == allotId);

            var data = exresultgatherRepository.GetEntities(w => w.AllotId == allotId);
            if (data == null || !data.Any()) return;

            var modules = exmoduleRepository.GetEntities(w => w.HospitalId == allot.HospitalId && w.SheetType != (int)SheetType.Income);
            if (modules == null || !modules.Any()) return;

            var items = exitemRepository.GetEntities(w => modules.Select(t => t.Id).Distinct().Contains(w.ModuleId ?? 0));
            if (items == null || !items.Any()) return;

            try
            {
                var insertList = new List<ex_item>();
                foreach (var module in modules)
                {
                    var categories = data.Where(t => module.ModuleName.Contains(t.Source))?.Select(t => t.Category).Distinct();
                    if (categories == null || !categories.Any()) continue;

                    var moduleItems = items.Where(w => w.ModuleId == module.Id)?.Select(t => t.ItemName).Distinct();
                    if (moduleItems != null && moduleItems.Any())
                        categories = categories.Except(moduleItems);

                    if (categories == null || !categories.Any()) continue;

                    insertList.AddRange(categories.Select(t => new ex_item
                    {
                        ModuleId = module.Id,
                        ItemName = t,
                        ReadOnly = 0
                    }));
                }

                if (insertList != null && insertList.Any())
                {
                    exitemRepository.AddRange(insertList.ToArray());
                }

                var speacialCategories = data.Where(t => t.Source.Contains("特殊核算单元"))?.Select(t => new { t.Category, t.Department }).Distinct();
                if (speacialCategories == null || !speacialCategories.Any()) return;

                var specials = exspecialRepository.GetEntities(w => w.HospitalId == allot.HospitalId);
                if (specials == null || !specials.Any()) return;

                var list = (specials == null || !specials.Any())
                    ? speacialCategories
                    : speacialCategories.Where(w => !specials.Select(t => t.Target + t.Department).Contains(w.Category + w.Department));

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

                exspecialRepository.AddRange(list.Select(t => new ex_special
                {
                    HospitalId = allot.HospitalId,
                    Department = t.Department,
                    Target = t.Category
                }).ToArray());
            }
            catch (Exception ex)
            {
                logger.LogError(ex.Message);
            }
        }

        public void AuditGather(List<Gather> gather)
        {
            List<ex_result_gather> ex_Result_Gathers = new List<ex_result_gather>();

            var submitter = userRepository.GetEntities(u => gather.Select(g => g.UserId).Contains(u.ID));

            var audit = gather.GroupBy(g => new
            {
                g.AllotId,
                g.UserId,
                g.Department,
                g.Source,
                g.Category
            }).Select(s => new
            {
                s.Key.AllotId,
                s.Key.UserId,
                s.Key.Department,
                s.Key.Source,
                s.Key.Category
            }).ToList();

            var datas = exresultgatherRepository.GetEntities(t =>
            t.AllotId == audit.FirstOrDefault().AllotId
            && audit.Select(a => a.UserId).Contains(t.Submitter)
            && audit.Select(a => a.Department).Contains(t.Department)
            && audit.Select(a => a.Source).Contains(t.Source)
            && audit.Select(a => a.Category).Contains(t.Category)
            );

            var gatherFirst = gather.FirstOrDefault();
            if (gatherFirst.Status == "通过")
                datas.ForEach(d =>
                {
                    d.AuditTime = DateTime.Now;
                    d.States = (int)EnumResult.AuditGather.已通过;
                    d.Remark = null;
                });
            else if (gatherFirst.Status == "失败")
                datas.ForEach(d =>
                {
                    d.AuditTime = DateTime.Now;
                    d.States = (int)EnumResult.AuditGather.未通过;
                    d.Remark = gatherFirst.Remark;
                });
            exresultgatherRepository.UpdateRange(datas.ToArray());

            if (gatherFirst.Status == "通过")
            {
                _service.SyncDataToResult(gatherFirst.AllotId);
            }
        }

        /// <summary>
        /// 清理该科室录入数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool ClearAprData(AprAmountAuditRequest request)
        {
            var data = perapramountRepository.GetEntities(t => t.AllotId == request.AllotId
                && t.TypeInDepartment == request.TypeInDepartment && t.CreateDate == request.CreateDate);
            if (data == null || !data.Any()) return true;

            return perapramountRepository.RemoveRange(data.ToArray());
        }

        /// <summary>
        /// 清理该科室录入不公示数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool ClearAprHideData(AprAmountAuditRequest request)
        {
            var data = _hideRepository.GetEntities(t => t.AllotId == request.AllotId
                && t.TypeInDepartment == request.TypeInDepartment && t.CreateDate == request.CreateDate);
            if (data == null || !data.Any()) return true;

            return _hideRepository.RemoveRange(data.ToArray());
        }

        /// <summary>
        /// 根据录入科室获取其他绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department">录入科室</param>
        /// <param name="date"></param>
        /// <param name="status">1.未提交 2.等待审核 3.审核通过 4.驳回</param>
        /// <returns></returns>
        public List<per_apr_amount> GetAprByTypeInDepartment(int allotId, string department, DateTime date, params int[] status)
        {
            Expression<Func<per_apr_amount, bool>> exp = (w) => w.AllotId == allotId && w.TypeInDepartment == department && w.CreateDate == date;

            //if (!string.IsNullOrEmpty(date))
            //    exp = exp.And((w) => w.CreateDate.ToString("yyyy-MM-dd HH:mm:ss") == date);

            if (status != null && status.Any())
                exp = exp.And((w) => status.Contains(w.Status ?? 1));

            var data = perapramountRepository.GetEntities(exp);
            return data;
        }

        /// <summary>
        /// 根据录入科室获取不公示其他绩效
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="department">录入科室</param>
        /// <param name="date"></param>
        /// <param name="status">1.未提交 2.等待审核 3.审核通过 4.驳回</param>
        /// <returns></returns>
        public List<per_apr_amount_hide> GetAprHideByTypeInDepartment(int allotId, string department, DateTime date, params int[] status)
        {
            Expression<Func<per_apr_amount_hide, bool>> exp = (w) => w.AllotId == allotId && w.TypeInDepartment == department && w.CreateDate == date;

            //if (!string.IsNullOrEmpty(date))
            //    exp = exp.And((w) => w.CreateDate.ToString("yyyy-MM-dd HH:mm:ss") == date);

            if (status != null && status.Any())
                exp = exp.And((w) => status.Contains(w.Status ?? 1));

            var data = _hideRepository.GetEntities(exp);
            return data;
        }
        /// <summary>
        /// 医院其他绩效/不公示其他绩效统计下载
        /// </summary>
        /// <param name="filepath"></param>
        /// <param name="userId"></param>
        /// <param name="amounts"></param>
        /// <returns></returns>
        public string AprListDownload(string name, int userId, List<view_per_apr_amount> amounts)
        {
            var roleType = new[] { (int)Role.护士长, (int)Role.科主任, (int)Role.特殊科室, (int)Role.行政科室, };
            var user = userService.GetUser(userId);
            var role = roleService.GetUserRole(user.UserID);

            if (role.Any(t => roleType.Contains(t.Type.Value)))
                amounts = amounts.Where(w => w.AccountingUnit == user.Department).ToList();

            var allTypes = amounts.Select(w => w.PerforType).Distinct().ToList();


            List<Dictionary<string, object>> dics = new List<Dictionary<string, object>>();
            foreach (var item in amounts.GroupBy(t => new { t.AccountingUnit, t.PersonnelNumber, t.DoctorName }))
            {
                var x = new Dictionary<string, object>()
                {
                    { "核算单元", item.Key.AccountingUnit },
                    { "人员工号", item.Key.PersonnelNumber },
                    { "姓名", item.Key.DoctorName },
                };
                allTypes.ForEach(w => x.Add(string.IsNullOrEmpty(w) ? "未知" : w, ""));

                foreach (var type in item.GroupBy(group => group.PerforType))
                {
                    x.AddOrUpdate(string.IsNullOrEmpty(type.Key) ? "未知" : type.Key, type.Sum(sum => sum.Amount ?? 0));
                }
                x.Add("状态", "审核通过");
                x.Add("合计", item.Sum(t => t.Amount));
                dics.Add(x);
            }
            var headers = ((IDictionary<string, object>)dics.ElementAt(0)).Keys;
            var excelDownloadHeads = headers.Select((value, index) => new ExcelDownloadHeads { Name = value, Alias = value, Sort = index }).ToList();
            var noSum = new[] { "核算单元", "人员工号", "姓名", "状态" };

            return downloadService.ExcelDownload(dics, name, excelDownloadHeads, noSum, null);
        }
    }

    public class ComparisonConfig
    {
        public static List<Heads> DeptHeads { get; } = new List<Heads>
        {
            new Heads{Column="核算单元组别",Name=nameof(view_check_dept.UnitType)},
            new Heads{Column="核算单元",Name=nameof(view_check_dept.AccountingUnit)},
            new Heads{Column="测算表实发",Name=nameof(view_check_dept.RealGiveFeeExecl)},
            new Heads{Column="软件实发",Name=nameof(view_check_dept.RealGiveFeeCompute)},
            new Heads{Column="差额",Name=nameof(view_check_dept.Diff)},
        };

        public static List<Heads> EmpHeads { get; } = new List<Heads>
        {
            new Heads{Column="核算单元组别",Name=nameof(view_check_emp.UnitType)},
            new Heads{Column="核算单元",Name=nameof(view_check_emp.AccountingUnit)},
            new Heads{Column="人员工号",Name=nameof(view_check_emp.JobNumber)},
            new Heads{Column="姓名",Name=nameof(view_check_emp.EmployeeName)},
            new Heads{Column="测算表实发",Name=nameof(view_check_emp.RealGiveFeeExecl)},
            new Heads{Column="软件实发",Name=nameof(view_check_emp.RealGiveFeeCompute)},
            new Heads{Column="差额",Name=nameof(view_check_emp.Diff)},
        };

        public static List<Heads> DeptTotalHeads { get; } = new List<Heads>
        {
            new Heads{Column="分类",Name=nameof(view_check_dept.UnitType)},
            new Heads{Column="实发不一致",Name="Count"},
            new Heads{Column="总额",Name="SumFee"},
        };

    }
}
