using AutoMapper;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json.Linq;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.Infrastructure;
using Performance.Repository;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Performance.Repository.Repository;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using Performance.EntityModels.Other;

namespace Performance.Services
{
    public class ConfigService : IAutoInjection
    {
        private readonly IMapper _mapper;
        #region
        private readonly UserService _userService;
        private readonly RoleService _roleService;
        private readonly PerforCofdirectorRepository _directorRepository;
        //private readonly PerforCofdrugpropRepository _drugpropRepository;
        private readonly PerforCofworkitemRepository _workitemRepository;
        private readonly PerforCofagainRepository _againRepository;
        private readonly PerforCofdrugtypeRepository _drugtypeRepository;
        private readonly PerforPerallotRepository perforPerAllotRepository;
        private readonly PerforHospitalRepository perforHospitalRepository;
        private readonly PerforPersheetRepository perforPersheetRepository;
        private readonly PerforImheaderRepository perforImheaderRepository;
        private readonly PerforImdataRepository imdataRepository;
        private readonly PerforCofdepttypeRepository perforCofdepttypeRepository;
        private readonly PerforPerapramountRepository perapramountRepository;
        //private readonly PerforCofcmiRepository perforCofcmiRepository;
        private readonly PerforCofHrpDeptRepository perforCofHrpDeptRepository;
        private readonly PerforCofaliasRepository perforCofaliasRepository;
        private readonly PerforCofaccountingRepository cofaccountingRepository;
        private readonly PerforCofdrugtypeDisburseRepository drugtypeDisburseRepository;
        private readonly PersonService personService;
        private readonly LogManageService logManageService;
        private readonly ExConfigService exConfigService;
        private readonly ILogger<ConfigService> logger;
        private readonly PerforExmoduleRepository perforExmoduleRepository;
        private readonly PerforCofdrugtypefactorRepository cofdrugtypefactorRepository;
        private readonly PerforPerallotRepository perallotRepository;
        private readonly PerforReportRepository perforReport;

        public ConfigService(
            IMapper mapper,
            UserService userService,
            RoleService roleService,
            PerforCofdirectorRepository cofdirectorRepository,
            //PerforCofdrugpropRepository cofdrugpropRepository,
            PerforCofagainRepository againRepository,
            PerforCofdrugtypeRepository drugtypeRepository,
            PerforPerallotRepository perforPerAllotRepository,
            PerforHospitalRepository perforHospitalRepository,
            PerforCofworkitemRepository workitemRepository,
            PerforPersheetRepository perforPersheetRepository,
            PerforImheaderRepository perforImheaderRepository,
            PerforImdataRepository imdataRepository,
            PerforCofdepttypeRepository perforCofdepttypeRepository,
            PerforPerapramountRepository perapramountRepository,
            //PerforCofcmiRepository perforCofcmiRepository,
            PerforCofHrpDeptRepository perforCofHrpDeptRepository,
            PerforCofaliasRepository perforCofaliasRepository,
            PerforCofaccountingRepository cofaccountingRepository,
            PerforCofdrugtypeDisburseRepository drugtypeDisburseRepository,
            PersonService personService,
            LogManageService logManageService,
            ILogger<ConfigService> logger,
            ExConfigService exConfigService,
            PerforExmoduleRepository perforExmoduleRepository,
            PerforCofdrugtypefactorRepository cofdrugtypefactorRepository,
            PerforPerallotRepository perallotRepository,
            PerforReportRepository perforReport)
        {
            _mapper = mapper;
            _userService = userService;
            _roleService = roleService;
            this._directorRepository = cofdirectorRepository;
            //this._drugpropRepository = cofdrugpropRepository;
            this._workitemRepository = workitemRepository;
            this._againRepository = againRepository;
            this._drugtypeRepository = drugtypeRepository;
            this.perforPerAllotRepository = perforPerAllotRepository;
            this.perforHospitalRepository = perforHospitalRepository;
            this.perforPersheetRepository = perforPersheetRepository;
            this.perforImheaderRepository = perforImheaderRepository;
            this.imdataRepository = imdataRepository;
            this.perforCofdepttypeRepository = perforCofdepttypeRepository;
            this.perapramountRepository = perapramountRepository;
            //this.perforCofcmiRepository = perforCofcmiRepository;
            this.perforCofHrpDeptRepository = perforCofHrpDeptRepository;
            this.perforCofaliasRepository = perforCofaliasRepository;
            this.cofaccountingRepository = cofaccountingRepository;
            this.drugtypeDisburseRepository = drugtypeDisburseRepository;
            this.personService = personService;
            this.logManageService = logManageService;
            this.exConfigService = exConfigService;
            this.logger = logger;
            this.perforExmoduleRepository = perforExmoduleRepository;
            this.cofdrugtypefactorRepository = cofdrugtypefactorRepository;
            this.perallotRepository = perallotRepository;
            this.perforReport = perforReport;
        }

        #endregion

        #region 弃用

        //#region cof_director  规模/效率绩效配置
        ///// <summary>
        ///// 获取cof_director列表
        ///// </summary>
        ///// <returns></returns>
        //public List<DirectorResponse> GetDireList(int allotId)
        //{
        //    var list = _directorRepository.GetEntities(t => t.AllotID == allotId);
        //    return _mapper.Map<List<DirectorResponse>>(list);
        //}

        ///// <summary>
        ///// 添加数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public DirectorResponse DireInsert(DirectorRequest request)
        //{
        //    var director = _mapper.Map<cof_director>(request);
        //    if (!_directorRepository.Add(director))
        //        throw new PerformanceException("保存失败");
        //    return _mapper.Map<DirectorResponse>(director);
        //}

        ///// <summary>
        ///// 更新数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public DirectorResponse DireUpdate(DirectorRequest request)
        //{
        //    var director = _directorRepository.GetEntity(t => t.ID == request.ID);
        //    if (null == director)
        //        throw new PerformanceException($"ID不存在 ：{request.ID}");

        //    director.TypeName = request.TypeName;
        //    director.JobTitle = request.JobTitle;
        //    director.Value = request.Value;

        //    if (!_directorRepository.Update(director))
        //        throw new PerformanceException("保存失败");
        //    return _mapper.Map<DirectorResponse>(director);
        //}

        ///// <summary>
        ///// 删除数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public bool DireDelete(DirectorRequest request)
        //{
        //    var director = _directorRepository.GetEntity(t => t.ID == request.ID);
        //    if (null == director)
        //        throw new PerformanceException($"ID不存在 ：{request.ID}");

        //    return _directorRepository.Remove(director);
        //}
        //#endregion

        //#region cof_income  ICU有效收入配置
        ///// <summary>
        ///// 获取cof_income列表
        ///// </summary>
        ///// <returns></returns>
        //public List<IncomeResponse> GetIncomeList(int allotId)
        //{
        //    var list = _incomeRepository.GetEntities(T => T.AllotID == allotId);
        //    return _mapper.Map<List<IncomeResponse>>(list);
        //}

        ///// <summary>
        ///// 添加数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public IncomeResponse IncomeInsert(IncomeRequest request)
        //{
        //    var income = _mapper.Map<cof_income>(request);
        //    if (!_incomeRepository.Add(income))
        //        throw new PerformanceException("保存失败");
        //    return _mapper.Map<IncomeResponse>(income);
        //}

        ///// <summary>
        ///// 更新数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public IncomeResponse IncomeUpdate(IncomeRequest request)
        //{
        //    var income = _incomeRepository.GetEntity(t => t.ID == request.ID);
        //    if (null == income)
        //        throw new PerformanceException($"ID不存在 ：{request.ID}");

        //    income.SheetNameKeyword = request.SheetNameKeyword;
        //    income.UnitName = request.UnitName;
        //    income.Value = request.Value;

        //    if (!_incomeRepository.Update(income))
        //        throw new PerformanceException("保存失败");
        //    return _mapper.Map<IncomeResponse>(income);
        //}

        ///// <summary>
        ///// 删除数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public bool IncomeDelete(IncomeRequest request)
        //{
        //    var income = _incomeRepository.GetEntity(t => t.ID == request.ID);
        //    if (null == income)
        //        throw new PerformanceException($"ID不存在 ：{request.ID}");

        //    return _incomeRepository.Remove(income);
        //}
        //#endregion

        //#region cof_workyear  年资系数配置
        ///// <summary>
        ///// 获取cof_drugprop列表
        ///// </summary>
        ///// <returns></returns>
        //public List<WorkyearResponse> GetWorkList(int allotId)
        //{
        //    var list = _workyearRepository.GetEntities(t => t.AllotID == allotId);
        //    return _mapper.Map<List<WorkyearResponse>>(list);
        //}

        ///// <summary>
        ///// 添加数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public WorkyearResponse WorkInsert(WorkyearRequest request)
        //{
        //    var workyear = _mapper.Map<cof_workyear>(request);
        //    if (!_workyearRepository.Add(workyear))
        //        throw new PerformanceException("保存失败");
        //    return _mapper.Map<WorkyearResponse>(workyear);
        //}

        ///// <summary>
        ///// 更新数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public WorkyearResponse WorkUpdate(WorkyearRequest request)
        //{
        //    var workyear = _workyearRepository.GetEntity(t => t.ID == request.ID);
        //    if (null == workyear)
        //        throw new PerformanceException($"ID不存在 ：{request.ID}");

        //    workyear.MaxRange = request.MaxRange;
        //    workyear.MinRange = request.MinRange;
        //    workyear.Value = request.Value;

        //    if (!_workyearRepository.Update(workyear))
        //        throw new PerformanceException("保存失败");
        //    return _mapper.Map<WorkyearResponse>(workyear);
        //}

        ///// <summary>
        ///// 删除数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public bool WorkDelete(WorkyearRequest request)
        //{
        //    var workyear = _workyearRepository.GetEntity(t => t.ID == request.ID);
        //    if (null == workyear)
        //        throw new PerformanceException($"ID不存在 ：{request.ID}");

        //    return _workyearRepository.Remove(workyear);
        //}
        //#endregion

        #endregion

        #region cof_drugprop  药占比系数配置

        ///// <summary>
        ///// 获取cof_drugprop列表
        ///// </summary>
        ///// <returns></returns>
        //public List<DrugpropResponse> GetDrugList(int allotId)
        //{
        //    var list = _drugpropRepository.GetEntities(t => t.AllotID == allotId);
        //    return _mapper.Map<List<DrugpropResponse>>(list);
        //}

        ///// <summary>
        ///// 添加数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public DrugpropResponse DrugInsert(DrugpropRequest request)
        //{
        //    var drugprop = _mapper.Map<cof_drugprop>(request);
        //    if (!_drugpropRepository.Add(drugprop))
        //        throw new PerformanceException("保存失败");
        //    return _mapper.Map<DrugpropResponse>(drugprop);
        //}

        ///// <summary>
        ///// 更新数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public DrugpropResponse DrugUpdate(DrugpropRequest request)
        //{
        //    var drugprop = _drugpropRepository.GetEntity(t => t.ID == request.ID);
        //    if (null == drugprop)
        //        throw new PerformanceException($"ID不存在 ：{request.ID}");

        //    drugprop.MaxRange = request.MaxRange;
        //    drugprop.MinRange = request.MinRange;
        //    drugprop.Value = request.Value;

        //    if (!_drugpropRepository.Update(drugprop))
        //        throw new PerformanceException("保存失败");
        //    return _mapper.Map<DrugpropResponse>(drugprop);
        //}

        ///// <summary>
        ///// 删除数据
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public bool DrugDelete(DrugpropRequest request)
        //{
        //    var drugprop = _drugpropRepository.GetEntity(t => t.ID == request.ID);
        //    if (null == drugprop)
        //        throw new PerformanceException($"ID不存在 ：{request.ID}");

        //    return _drugpropRepository.Remove(drugprop);
        //}

        #endregion

        #region cof_drugtype  药占比类别配置

        /// <summary>
        /// 获取cof_drugprop列表
        /// </summary>
        /// <returns></returns>
        public List<cof_drugtype> GetDrugtypeList(int HospitalId, int allotId)
        {
            var list = _drugtypeRepository.GetEntities(t => t.AllotID == allotId && t.HospitalId == HospitalId);
            return list;
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_drugtype DrugtypeInsert(DrugpropRequest request)
        {
            var entity = new cof_drugtype
            {
                HospitalId = request.HospitalId,
                AllotID = request.AllotID,
                Charge = request.Charge,
                ChargeType = request.ChargeType
            };
            if (!_drugtypeRepository.Add(entity))
                throw new PerformanceException("保存失败");
            return entity;
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_drugtype DrugtypeUpdate(DrugpropRequest request)
        {
            var entity = _drugtypeRepository.GetEntity(t => t.ID == request.ID);
            if (null == entity)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            entity.Charge = request.Charge;
            entity.ChargeType = request.ChargeType;

            if (!_drugtypeRepository.Update(entity))
                throw new PerformanceException("保存失败");

            //var factors = cofdrugtypefactorRepository.GetEntities(t => t.HospitalId == entity.HospitalId && t.AllotID == entity.AllotID && t.Charge == entity.Charge);
            //if (factors != null && factors.Any())
            //{
            //    factors.ForEach(t => t.Charge = request.Charge);
            //    cofdrugtypefactorRepository.UpdateRange(factors.ToArray());
            //}
            return entity;
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DrugtypeDelete(DrugpropRequest request)
        {
            var entity = _drugtypeRepository.GetEntity(t => t.ID == request.ID);
            if (null == entity)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            return _drugtypeRepository.Remove(entity);
        }

        #endregion

        #region cof_drugtype_disburse  药占比支出类别配置

        /// <summary>
        /// 获取cof_drugprop列表
        /// </summary>
        /// <returns></returns>
        public List<cof_drugtype_disburse> GetDrugtypeDisburseList(int HospitalId, int allotId)
        {
            var list = drugtypeDisburseRepository.GetEntities(t => t.AllotID == allotId && t.HospitalId == HospitalId);
            return list;
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_drugtype_disburse DrugtypeDisburseInsert(DrugpropRequest request)
        {
            var entity = new cof_drugtype_disburse
            {
                HospitalId = request.HospitalId,
                AllotID = request.AllotID,
                Charge = request.Charge,
                ChargeType = request.ChargeType
            };
            if (!drugtypeDisburseRepository.Add(entity))
                throw new PerformanceException("保存失败");
            return entity;
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_drugtype_disburse DrugtypeDisburseUpdate(DrugpropRequest request)
        {
            var entity = drugtypeDisburseRepository.GetEntity(t => t.ID == request.ID);
            if (null == entity)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            entity.Charge = request.Charge;
            entity.ChargeType = request.ChargeType;

            if (!drugtypeDisburseRepository.Update(entity))
                throw new PerformanceException("保存失败");
            return entity;
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DrugtypeDisburseDelete(DrugpropRequest request)
        {
            var entity = drugtypeDisburseRepository.GetEntity(t => t.ID == request.ID);
            if (null == entity)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            return drugtypeDisburseRepository.Remove(entity);
        }

        public void SaveDrugtypeDisburse(int allotId)
        {
            var Disburse = drugtypeDisburseRepository.GetEntities(t => t.AllotID == allotId);
            if (Disburse == null || !Disburse.Any()) return;

            var perSheet = perforPersheetRepository.GetEntities(t => t.AllotID == allotId && t.SheetType == (int)SheetType.Expend);
            if (perSheet == null || !perSheet.Any()) return;

            var TypeNames = imdataRepository.GetEntities(t => perSheet.Select(c => c.ID).Contains(t.SheetID.Value)).Select(t => t.TypeName).Distinct().ToList();
            if (TypeNames == null || !TypeNames.Any()) return;

            var except = Disburse.Select(t => t.Charge).Distinct().Intersect(TypeNames);

            if (except != null || except.Any())
            {
                foreach (var item in except)
                {
                    TypeNames.Remove(item);
                }
            }
            var drugDis = TypeNames?.Select(t => new cof_drugtype_disburse { HospitalId = Disburse.FirstOrDefault().HospitalId, AllotID = allotId, Charge = t, ChargeType = "" });

            drugtypeDisburseRepository.AddRange(drugDis.ToArray());
        }

        #endregion

        #region cof_workitem  工作量绩效

        /// <summary>
        /// 获取cof_workitem列表
        /// </summary>
        /// <returns></returns>
        public List<cof_workitem> GetWorkItems(int allotId, int type)
        {
            var list = (type > 0)
                ? _workitemRepository.GetEntities(t => t.AllotID == allotId && t.Type == type)
                : _workitemRepository.GetEntities(t => t.AllotID == allotId);

            return _mapper.Map<List<cof_workitem>>(list);
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_workitem WorkItemInsert(WorkItemRequest request)
        {
            var workyear = _mapper.Map<cof_workitem>(request);
            if (!_workitemRepository.Add(workyear))
                throw new PerformanceException("保存失败");
            return _mapper.Map<cof_workitem>(workyear);
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_workitem WorkItemUpdate(WorkItemRequest request)
        {
            var workyear = _workitemRepository.GetEntity(t => t.ID == request.ID);
            if (null == workyear)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            workyear.Item = request.Item;
            workyear.Type = request.Type;

            if (!_workitemRepository.Update(workyear))
                throw new PerformanceException("保存失败");
            return _mapper.Map<cof_workitem>(workyear);
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool WorkItemkDelete(WorkItemRequest request)
        {
            var workyear = _workitemRepository.GetEntity(t => t.ID == request.ID);
            if (null == workyear)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            return _workitemRepository.Remove(workyear);
        }

        #endregion

        #region cof_depttype  科室别配置

        /// <summary>
        /// 获取cof_drugprop列表
        /// </summary>
        /// <returns></returns>
        public List<cof_depttype> GetDepttypeList(int allotId)
        {
            var list = perforCofdepttypeRepository.GetEntities(t => t.AllotID == allotId);
            return list;
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_depttype DepttypeInsert(DrugpropRequest request)
        {
            var entity = new cof_depttype
            {
                AllotID = request.AllotID,
                Charge = request.Charge,
                ChargeType = request.ChargeType
            };
            if (!perforCofdepttypeRepository.Add(entity))
                throw new PerformanceException("保存失败");
            return entity;
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_depttype DepttypeUpdate(DrugpropRequest request)
        {
            var entity = perforCofdepttypeRepository.GetEntity(t => t.ID == request.ID);
            if (null == entity)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            entity.Charge = request.Charge;
            entity.ChargeType = request.ChargeType;

            if (!perforCofdepttypeRepository.Update(entity))
                throw new PerformanceException("保存失败");
            return entity;
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool DepttypeDelete(DrugpropRequest request)
        {
            var entity = perforCofdepttypeRepository.GetEntity(t => t.ID == request.ID);
            if (null == entity)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            return perforCofdepttypeRepository.Remove(entity);
        }

        #endregion

        #region cof_cmi  cmi

        ///// <summary>
        ///// 获取 CMI配置
        ///// </summary>
        ///// <returns></returns>
        //public List<cof_cmi> GetCMIList(int allotId)
        //{
        //    var list = perforCofcmiRepository.GetEntities(t => t.AllotId == allotId);
        //    return list;
        //}

        ///// <summary>
        ///// 添加 CMI配置
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public cof_cmi HosCMIInsert(cof_cmi request)
        //{
        //    if (!perforCofcmiRepository.Add(request))
        //        throw new PerformanceException("保存失败");
        //    return request;
        //}

        ///// <summary>
        ///// 更新 CMI配置
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public cof_cmi HosCMIUpdate(cof_cmi request)
        //{
        //    var entity = perforCofcmiRepository.GetEntity(t => t.Id == request.Id);
        //    if (null == entity)
        //        throw new PerformanceException($"ID不存在 ：{request.Id}");

        //    entity.UnitType = request.UnitType;
        //    entity.AccountingUnit = request.AccountingUnit;
        //    entity.Value = request.Value;

        //    if (!perforCofcmiRepository.Update(entity))
        //        throw new PerformanceException("保存失败");
        //    return entity;
        //}

        ///// <summary>
        ///// 删除 CMI配置
        ///// </summary>
        ///// <param name="request"></param>
        ///// <returns></returns>
        //public bool HosCMIDelete(cof_cmi request)
        //{
        //    var entity = perforCofcmiRepository.GetEntity(t => t.Id == request.Id);
        //    if (null == entity)
        //        throw new PerformanceException($"ID不存在 ：{request.Id}");

        //    return perforCofcmiRepository.Remove(entity);
        //}

        #endregion

        #region cof_again

        /// <summary>
        /// 获取cof_drugprop列表
        /// </summary>
        /// <returns></returns>
        public List<cof_again> GetAgainList(int allotId)
        {
            var list = _againRepository.GetEntities(t => t.AllotID == allotId);
            return list;
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_again AgainInsert(CofAgainRequest request)
        {
            var again = _mapper.Map<cof_again>(request);
            if (!_againRepository.Add(again))
                throw new PerformanceException("保存失败");
            return again;
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_again AgainUpdate(CofAgainRequest request)
        {
            var again = _againRepository.GetEntity(t => t.ID == request.ID);
            if (null == again)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            again.Type = request.Type;
            again.Department = request.Department;
            again.TypeName = request.TypeName;
            again.Value = request.Value;

            if (!_againRepository.Update(again))
                throw new PerformanceException("保存失败");
            return again;
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public bool AgainDelete(CofAgainRequest request)
        {
            var again = _againRepository.GetEntity(t => t.ID == request.ID);
            if (null == again)
                throw new PerformanceException($"ID不存在 ：{request.ID}");

            return _againRepository.Remove(again);
        }

        #endregion

        #region cof_accounting  核算单元及类别（4.1）配置

        /// <summary>
        /// 获取cof_accounting列表
        /// </summary>
        /// <returns></returns>
        public List<cof_accounting> GetAccountingList(AccoungingRequest request)
        {
            Expression<Func<cof_accounting, bool>> exp = t => t.AllotId == request.AllotId;
            if (request.AllotId == 0)
            {
                var allots = perforPerAllotRepository.GetEntities(t => t.HospitalId == request.HospitalId);
                if (allots == null || !allots.Any())
                    throw new PerformanceException("请先配置科室信息");
                exp = t => allots.Select(a => a.ID).Contains(t.AllotId);
            }

            if (request.Type == (int)AccountTypeEnum.AccountingUnit && !string.IsNullOrEmpty(request.UnitType))
                exp = exp.And(t => t.UnitType.Replace("行政后勤", "行政工勤") == request.UnitType.Replace("行政后勤", "行政工勤"));

            return cofaccountingRepository.GetEntities(exp)?.OrderBy(t => t.IsVerify).ThenBy(t => ConvertHelper.To<int>(t.Code)).ToList() ?? new List<cof_accounting>();
        }

        /// <summary>
        /// 添加数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_accounting AccountingInsert(cof_accounting request)
        {
            var existed = cofaccountingRepository.GetEntity(w => w.AllotId == request.AllotId && w.Code == request.Code);
            if (existed != null) throw new PerformanceException("核算单元编码重复");

            existed = cofaccountingRepository.GetEntity(w => w.AllotId == request.AllotId && w.UnitType == request.UnitType && w.AccountingUnit == request.AccountingUnit);
            if (existed != null) throw new PerformanceException("核算单元、核算组别已存在");

            var entity = new cof_accounting
            {
                AllotId = request.AllotId,
                Code = request.Code,
                UnitType = request.UnitType,
                AccountingUnit = request.AccountingUnit
            };
            if (!cofaccountingRepository.Add(entity))
                throw new PerformanceException("保存失败");
            return entity;
        }

        /// <summary>
        /// 更新数据
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public cof_accounting AccountingUpdate(cof_accounting request)
        {
            var existed = cofaccountingRepository.GetEntity(w => w.AllotId == request.AllotId && w.Code == request.Code);
            if (existed != null) throw new PerformanceException("核算单元编码重复");

            existed = cofaccountingRepository.GetEntity(w => w.AllotId == request.AllotId && w.UnitType == request.UnitType && w.AccountingUnit == request.AccountingUnit);
            if (existed != null) throw new PerformanceException("核算单元、核算组别已存在");

            var entity = cofaccountingRepository.GetEntity(t => t.Id == request.Id);
            if (null == entity)
                throw new PerformanceException($"ID不存在 ：{request.Id}");

            entity.AllotId = request.AllotId;
            entity.Code = request.Code;
            entity.UnitType = request.UnitType;
            entity.AccountingUnit = request.AccountingUnit;

            if (!cofaccountingRepository.Update(entity))
                throw new PerformanceException("保存失败");
            return entity;
        }

        /// <summary>
        /// 删除数据
        /// </summary>
        /// <param name="accountingId"></param>
        /// <returns></returns>
        public bool AccountingDelete(int accountingId)
        {
            var entity = cofaccountingRepository.GetEntity(t => t.Id == accountingId);
            if (null == entity)
                throw new PerformanceException($"ID不存在 ：{accountingId}");

            return cofaccountingRepository.Remove(entity);
        }

        public HandsonTable GetBatchAccountingStructrue(int AllotId)
        {
            var result = new HandsonTable((int)SheetType.Unidentifiable, Accounting.Select(t => t.Value).ToArray(), Accounting.Select(t => new collect_permission
            {
                HeadName = t.Value,
                Visible = 1
            }).ToList());

            if (result.Columns != null && result.Columns.Any())
            {
                foreach (var column in result.Columns)
                {
                    if (column.Data == "核算组别")
                    {
                        column.Type = "autocomplete";
                        column.Source = EnumHelper.GetItems<UnitType>().Select(w => w.Description.Replace("行政后勤", "行政工勤")).ToArray();
                        column.Strict = true;
                    }
                    if (column.Data == "核算单元编码")
                    {
                        column.Type = "text";
                        column.NumericFormat = null;
                    }
                }
            }
            return result;
        }

        public bool BatchSaveAccounting(int allotId, SaveCollectData request)
        {
            var dicData = CreateDataRow(0, allotId, request, Accounting);
            if (dicData == null || !dicData.Any()) throw new PerformanceException("未提交数据");

            var getAccounts = cofaccountingRepository.GetEntities(t => t.AllotId == allotId) ?? new List<cof_accounting>();
            var unitType = EnumHelper.GetItems<UnitType>().Select(w => w.Description.Replace("行政后勤", "行政工勤")).ToArray();

            var json = JsonHelper.Serialize(dicData);
            var accounts = JsonHelper.Deserialize<List<cof_accounting>>(json);

            if (accounts.Any(w => string.IsNullOrEmpty(w.Code))) throw new PerformanceException("核算单元编码有空值");

            if (accounts.GroupBy(t => t.Code).Any(w => w.Count() > 1)) throw new PerformanceException("核算单元编码有重复值");

            if (accounts.Any(w => string.IsNullOrEmpty(w.AccountingUnit))) throw new PerformanceException("核算单元有空值");

            if (accounts.Any(w => string.IsNullOrEmpty(w.UnitType))) throw new PerformanceException("核算单元类型有空值");

            var grouped = accounts.GroupBy(t => new { t.AccountingUnit, t.UnitType });

            if (grouped.Any(w => w.Count() > 1)) throw new PerformanceException("核算单元、核算单元类型有重复值");

            var delAccounts = new List<cof_accounting>();

            foreach (var item in accounts)
            {
                var account = getAccounts.FirstOrDefault(w => w.Code == item.Code);
                if (account != null)
                    delAccounts.Add(account);
            }
            if (delAccounts != null && delAccounts.Any())
                cofaccountingRepository.RemoveRange(delAccounts.ToArray());

            if (accounts != null && accounts.Any())
            {
                accounts.ForEach(account =>
                {
                    account.AllotId = allotId;
                    account.IsVerify = 1;
                });
                cofaccountingRepository.AddRange(accounts.ToArray());
            }

            return true;
        }

        public bool BatchCheckAccounting(int allotId)
        {
            var accounts = cofaccountingRepository.GetEntities(t => t.AllotId == allotId);

            if (accounts == null || !accounts.Any()) return true;

            accounts.ForEach(t =>
            {
                t.IsVerify = 1;
                t.VerifyMessage = string.Empty;
            });

            if (accounts.GroupBy(t => t.Code).Any(w => w.Count() > 1))
            {
                var items = accounts.GroupBy(t => t.Code).Where(w => w.Count() > 1).SelectMany(w => w.Select(t => t.Id));

                foreach (var item in accounts.Where(w => items.Contains(w.Id)))
                {
                    item.IsVerify = 0;
                    item.VerifyMessage = "核算单元编码重复";
                }
            }

            var grouped = accounts.GroupBy(t => new { t.AccountingUnit, t.UnitType });

            if (grouped.Any(w => w.Count() > 1))
            {
                var items = grouped.Where(w => w.Count() > 1).SelectMany(w => w.Select(t => t.Id));

                foreach (var item in accounts.Where(w => items.Contains(w.Id)))
                {
                    var extend = string.IsNullOrEmpty(item.VerifyMessage) ? "" : "；";
                    item.IsVerify = 0;
                    item.VerifyMessage += $"{extend}核算单元、核算单元类型重复";
                }
            }

            return cofaccountingRepository.UpdateRange(accounts.ToArray());
        }

        public static Dictionary<string, string> Accounting { get; } = new Dictionary<string, string>
        {
            {nameof(cof_accounting.Code), "核算单元编码"},
            {nameof(cof_accounting.AccountingUnit), "核算单元"},
            {nameof(cof_accounting.UnitType), "核算组别"},
        };


        #endregion

        #region Copy

        /// <summary>
        /// 复制报表基础配置
        /// </summary>
        /// <param name="iD"></param>
        public void Copy(per_allot allot)
        {
            var list = perforPerAllotRepository.GetEntities(t => t.HospitalId == allot.HospitalId);
            if (list == null || !list.Any(t => t.ID == allot.ID)) return;

            list = list.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).ToList();

            var index = list.IndexOf(list.First(t => t.ID == allot.ID));

            // 先取上一个月的绩效Id，若没有取最后一个月的绩效Id，若都不存在则获取allotId为-1的数据
            int allotId = index + 1 < list.Count ? list[index + 1].ID : list.First().ID;
            if (allotId == allot.ID) allotId = -1;

            CopyCommand(allot, allotId);
        }

        public void CopyCommand(per_allot allot, int prevAllotId, bool delHistotyData = false)
        {
            #region 弃用

            //var hospital = perforHospitalRepository.GetEntity(t => t.ID == allot.HospitalId);

            //logger.LogInformation($"apramount{allotId} {allot.ID}");
            //CopyAprData(allotId, allot.ID);
            //CopyCMIData(allotId, allot.ID);

            //var orgDirector = _directorRepository.GetEntities(t => t.AllotID == allot.ID);
            //if (orgDirector == null || orgDirector.Count == 0)
            //{
            //    var director = _directorRepository.GetEntities(t => t.AllotID == allotId) ?? _directorRepository.GetEntities(t => t.AllotID == -1);
            //    var newDirectors = director.Select(t => new cof_director { AllotID = allot.ID, JobTitle = t.JobTitle, TypeName = t.TypeName, Value = t.Value });
            //    if (hospital != null && hospital?.IsOpenDirector == 2)
            //        newDirectors = director.Select(t => new cof_director { AllotID = allot.ID, JobTitle = t.JobTitle, TypeName = t.TypeName, Value = 1 });
            //    _directorRepository.AddRange(newDirectors.ToArray());
            //}

            //var orgIncome = _incomeRepository.GetEntities(t => t.AllotID == allot.ID);
            //if (orgIncome == null || orgIncome.Count == 0)
            //{
            //    var income = _incomeRepository.GetEntities(t => t.AllotID == allotId) ?? _incomeRepository.GetEntities(t => t.AllotID == -1);
            //    var newIncomes = income.Select(t => new cof_income { AllotID = allot.ID, SheetNameKeyword = t.SheetNameKeyword, UnitName = t.UnitName, Value = t.Value });
            //    if (hospital != null && hospital?.IsOpenIncome == 2)
            //        newIncomes = income.Select(t => new cof_income { AllotID = allot.ID, SheetNameKeyword = t.SheetNameKeyword, UnitName = t.UnitName, Value = 1 });
            //    _incomeRepository.AddRange(newIncomes.ToArray());
            //}

            //var orgWorkyear = _workyearRepository.GetEntities(t => t.AllotID == allot.ID);
            //if (orgWorkyear == null || orgWorkyear.Count == 0)
            //{
            //    var workyear = _workyearRepository.GetEntities(t => t.AllotID == allotId) ?? _workyearRepository.GetEntities(t => t.AllotID == -1);
            //    var newWorkyears = workyear.Select(t => new cof_workyear { AllotID = allot.ID, MaxRange = t.MaxRange, MinRange = t.MinRange, Value = t.Value });
            //    if (hospital != null && hospital?.IsOpenWorkYear == 2)
            //        newWorkyears = new List<cof_workyear> { new cof_workyear { AllotID = allot.ID, MaxRange = 1000, MinRange = 0, Value = 1 } };
            //    _workyearRepository.AddRange(newWorkyears.ToArray());
            //}

            //logger.LogInformation($"orgDurgprop");
            //var orgDurgprop = _drugpropRepository.GetEntities(t => t.AllotID == allot.ID);
            //if (orgDurgprop == null || orgDurgprop.Count == 0)
            //{
            //    var durgprop = _drugpropRepository.GetEntities(t => t.AllotID == allotId) ?? _drugpropRepository.GetEntities(t => t.AllotID == -1);
            //    var newDurgprops = durgprop?.Select(t => new cof_drugprop { AllotID = allot.ID, MaxRange = t.MaxRange, MinRange = t.MinRange, Value = t.Value });
            //    //if (hospital != null && hospital?.IsOpenDrugprop == 2)
            //    //    newDurgprops = new List<cof_drugprop> { new cof_drugprop { AllotID = allot.ID, MaxRange = 1000, MinRange = 0, Value = 1 } };
            //    if (durgprop != null && durgprop.Any())
            //        _drugpropRepository.AddRange(newDurgprops.ToArray());
            //}

            #endregion

            var flag = delHistotyData;

            personService.CreateAllotPersons(allot.HospitalId, allot.ID, prevAllotId);

            logger.LogInformation($"copy workItems");
            var workItems = _workitemRepository.GetEntities(t => t.AllotID == allot.ID);
            if (delHistotyData && workItems != null && workItems.Any())
                flag = _workitemRepository.RemoveRange(workItems.ToArray());
            if (flag || workItems == null || !workItems.Any())
            {
                workItems = _workitemRepository.GetEntities(t => t.AllotID == prevAllotId) ?? _workitemRepository.GetEntities(t => t.AllotID == -1);
                if (workItems != null && workItems.Any())
                {
                    var newWorkItems = workItems.Select(t => new cof_workitem { AllotID = allot.ID, Type = t.Type, Item = t.Item });
                    _workitemRepository.AddRange(newWorkItems.ToArray());
                }
            }

            logger.LogInformation($"copy drugTypes");
            var drugTypes = _drugtypeRepository.GetEntities(t => t.AllotID == allot.ID && t.HospitalId == allot.HospitalId);
            if (delHistotyData && drugTypes != null && drugTypes.Any())
                flag = _drugtypeRepository.RemoveRange(drugTypes.ToArray());
            if (flag || drugTypes == null || !drugTypes.Any())
            {
                drugTypes = _drugtypeRepository.GetEntities(t => t.AllotID == prevAllotId && t.HospitalId == allot.HospitalId) ?? _drugtypeRepository.GetEntities(t => t.AllotID == -1);
                if (drugTypes != null && drugTypes.Any())
                {
                    var newDrugTypes = drugTypes.Select(t => new cof_drugtype { HospitalId = allot.HospitalId, AllotID = allot.ID, Charge = t.Charge, ChargeType = t.ChargeType });
                    _drugtypeRepository.AddRange(newDrugTypes.ToArray());
                }
            }

            logger.LogInformation($"copy drugTypeDisburses");
            var drugTypeDisburses = drugtypeDisburseRepository.GetEntities(t => t.AllotID == allot.ID && t.HospitalId == allot.HospitalId);
            if (delHistotyData && drugTypeDisburses != null && drugTypeDisburses.Any())
                flag = drugtypeDisburseRepository.RemoveRange(drugTypeDisburses.ToArray());
            if (flag || drugTypeDisburses == null || !drugTypeDisburses.Any())
            {
                drugTypeDisburses = drugtypeDisburseRepository.GetEntities(t => t.AllotID == prevAllotId && t.HospitalId == allot.HospitalId)
                    ?? drugtypeDisburseRepository.GetEntities(t => t.AllotID == -1);
                if (drugTypeDisburses != null && drugTypeDisburses.Any())
                {
                    var newDrugTypeDisburses = drugTypeDisburses.Select(t => new cof_drugtype_disburse { HospitalId = allot.HospitalId, AllotID = allot.ID, Charge = t.Charge, ChargeType = t.ChargeType });
                    drugtypeDisburseRepository.AddRange(newDrugTypeDisburses.ToArray());
                }
            }

            logger.LogInformation($"copy drugTypeFactors");
            var drugTypeFactors = cofdrugtypefactorRepository.GetEntities(t => t.AllotID == allot.ID && t.HospitalId == allot.HospitalId);
            if (delHistotyData && drugTypeFactors != null && drugTypeFactors.Any())
                flag = cofdrugtypefactorRepository.RemoveRange(drugTypeFactors.ToArray());
            if (flag || drugTypeFactors == null || !drugTypeFactors.Any())
            {
                drugTypeFactors = cofdrugtypefactorRepository.GetEntities(t => t.AllotID == prevAllotId && t.HospitalId == allot.HospitalId)
                    ?? cofdrugtypefactorRepository.GetEntities(t => t.AllotID == -1);
                if (drugTypeFactors != null && drugTypeFactors.Any())
                {
                    var newDrugtypeFactors = drugTypeFactors.Select(t => new cof_drugtype_factor
                    {
                        HospitalId = allot.HospitalId,
                        AllotID = allot.ID,
                        ExModuleId = t.ExModuleId,
                        Charge = t.Charge,
                        YSZ = t.YSZ,
                        HLZ = t.HLZ,
                        YJZ = t.YJZ
                    });
                    cofdrugtypefactorRepository.AddRange(newDrugtypeFactors.ToArray());
                }
            }

            logger.LogInformation($"copy deptTypes");
            var deptTypes = perforCofdepttypeRepository.GetEntities(t => t.AllotID == allot.ID);
            if (delHistotyData && deptTypes != null && deptTypes.Any())
                flag = perforCofdepttypeRepository.RemoveRange(deptTypes.ToArray());
            if (flag || deptTypes == null || !deptTypes.Any())
            {
                deptTypes = perforCofdepttypeRepository.GetEntities(t => t.AllotID == prevAllotId) ?? perforCofdepttypeRepository.GetEntities(t => t.AllotID == -1);
                if (deptTypes != null && deptTypes.Any())
                {
                    var newDeptTypes = deptTypes.Select(t => new cof_depttype { AllotID = allot.ID, Charge = t.Charge, ChargeType = t.ChargeType });
                    perforCofdepttypeRepository.AddRange(newDeptTypes.ToArray());
                }
            }

            logger.LogInformation($"copy agains");
            var agains = _againRepository.GetEntities(t => t.AllotID == allot.ID);
            if (delHistotyData && agains != null && agains.Any())
                flag = _againRepository.RemoveRange(agains.ToArray());
            if (flag || agains == null || !agains.Any())
            {
                agains = _againRepository.GetEntities(t => t.AllotID == prevAllotId) ?? _againRepository.GetEntities(t => t.AllotID == -1);
                if (agains != null && agains.Any())
                {
                    var days = DateTime.DaysInMonth(allot.Year, allot.Month);
                    var newAgains = agains.Select(t => new cof_again
                    {
                        AllotID = allot.ID,
                        Type = t.Type,
                        Department = t.Department,
                        TypeName = t.TypeName,
                        Value = t.TypeName == "满勤天数" ? days : t.Value
                    });
                    _againRepository.AddRange(newAgains.ToArray());
                }
            }

            logger.LogInformation($"copy accountings");
            var accountings = cofaccountingRepository.GetEntities(t => t.AllotId == allot.ID);
            if (delHistotyData && accountings != null && accountings.Any())
                flag = cofaccountingRepository.RemoveRange(accountings.ToArray());
            if (flag || accountings == null || !accountings.Any())
            {
                accountings = cofaccountingRepository.GetEntities(t => t.AllotId == prevAllotId) ?? cofaccountingRepository.GetEntities(t => t.AllotId == -1);
                if (accountings != null && accountings.Any())
                {
                    var newAccountings = accountings.Select(t => new cof_accounting
                    {
                        AllotId = allot.ID,
                        UnitType = t.UnitType,
                        AccountingUnit = t.AccountingUnit,
                        Code = t.Code,
                        IsVerify = t.IsVerify,
                        VerifyMessage = t.VerifyMessage
                    });
                    cofaccountingRepository.AddRange(newAccountings.ToArray());
                }
            }
        }

        //todo:新copy
        /// <summary>
        /// 
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="type"></param>
        public void NewCopy(CopyRequest request)
        {
            var allot = perallotRepository.GetEntity(t => t.ID == request.AllotId);

            var list = perforPerAllotRepository.GetEntities(t => t.HospitalId == allot.HospitalId);
            if (list == null || !list.Any(t => t.ID == allot.ID)) return;

            list = list.OrderByDescending(t => t.Year).ThenByDescending(t => t.Month).ToList();

            var index = list.IndexOf(list.First(t => t.ID == allot.ID));

            // 先取上一个月的绩效Id，若没有取最后一个月的绩效Id，若都不存在则获取allotId为-1的数据
            int allotId = index + 1 < list.Count ? list[index + 1].ID : list.First().ID;
            if (allotId == allot.ID) request.AllotId = -1;

            if (request.Type.Length < 1)
                return;

            foreach (var item in request.Type)
            {
                switch (item)
                {
                    case "personnels":
                        personService.CreateAllotPersons(allot.HospitalId, allot.ID, allotId);
                        break;
                    case "workItems":
                        logger.LogInformation($"copy workItems");
                        var workItems = _workitemRepository.GetEntities(t => t.AllotID == allot.ID);
                        //先判断是否为空，不为空删除再执行下面的代码
                        if (workItems != null)
                        {
                            _workitemRepository.RemoveRange(workItems.ToArray());
                        }
                        workItems = _workitemRepository.GetEntities(t => t.AllotID == allotId) ?? _workitemRepository.GetEntities(t => t.AllotID == -1);
                        if (workItems != null && workItems.Any())
                        {
                            var newWorkItems = workItems.Select(t => new cof_workitem { AllotID = allot.ID, Type = t.Type, Item = t.Item });
                            _workitemRepository.AddRange(newWorkItems.ToArray());
                        }
                        break;
                    case "drugTypes":
                        logger.LogInformation($"copy drugTypes");
                        var drugTypes = _drugtypeRepository.GetEntities(t => t.AllotID == allot.ID && t.HospitalId == allot.HospitalId);
                        if (drugTypes != null)
                        {
                            _drugtypeRepository.RemoveRange(drugTypes.ToArray());
                        }

                        var Types = _drugtypeRepository.GetEntities(t => t.AllotID == allot.ID && t.HospitalId == allot.HospitalId);
                        drugTypes = _drugtypeRepository.GetEntities(t => t.AllotID == allotId) ?? _drugtypeRepository.GetEntities(t => t.AllotID == -1);
                        if (drugTypes != null && drugTypes.Any())
                        {
                            var newDrugTypes = drugTypes.Select(t => new cof_drugtype { HospitalId = allot.HospitalId, AllotID = allot.ID, Charge = t.Charge, ChargeType = t.ChargeType });
                            _drugtypeRepository.AddRange(newDrugTypes.ToArray());
                        }
                        break;
                    case "drugTypeDisburses":
                        logger.LogInformation($"copy drugTypeDisburses");
                        var drugTypeDisburses = drugtypeDisburseRepository.GetEntities(t => t.AllotID == allot.ID && t.HospitalId == allot.HospitalId);
                        if (drugTypeDisburses != null)
                        {
                            drugtypeDisburseRepository.RemoveRange(drugTypeDisburses.ToArray());
                        }
                        drugTypeDisburses = drugtypeDisburseRepository.GetEntities(t => t.AllotID == allotId) ?? drugtypeDisburseRepository.GetEntities(t => t.AllotID == -1);
                        if (drugTypeDisburses != null && drugTypeDisburses.Any())
                        {
                            var newDrugTypeDisburses = drugTypeDisburses.Select(t => new cof_drugtype_disburse { HospitalId = allot.HospitalId, AllotID = allot.ID, Charge = t.Charge, ChargeType = t.ChargeType });
                            drugtypeDisburseRepository.AddRange(newDrugTypeDisburses.ToArray());
                        }
                        break;
                    case "drugTypeFactors":
                        logger.LogInformation($"copy drugTypeFactors");
                        var drugTypeFactors = cofdrugtypefactorRepository.GetEntities(t => t.AllotID == allot.ID);
                        if (drugTypeFactors != null)
                        {
                            cofdrugtypefactorRepository.RemoveRange(drugTypeFactors.ToArray());
                        }
                        drugTypeFactors = cofdrugtypefactorRepository.GetEntities(t => t.AllotID == allotId) ?? cofdrugtypefactorRepository.GetEntities(t => t.AllotID == -1);
                        if (drugTypeFactors != null && drugTypeFactors.Any())
                        {
                            var newDrugtypeFactors = drugTypeFactors.Select(t => new cof_drugtype_factor
                            {
                                HospitalId = allot.HospitalId,
                                AllotID = allot.ID,
                                ExModuleId = t.ExModuleId,
                                Charge = t.Charge,
                                YSZ = t.YSZ,
                                HLZ = t.HLZ,
                                YJZ = t.YJZ
                            });
                            cofdrugtypefactorRepository.AddRange(newDrugtypeFactors.ToArray());
                        }
                        break;
                    case "deptTypes":
                        logger.LogInformation($"copy deptTypes");
                        var deptTypes = perforCofdepttypeRepository.GetEntities(t => t.AllotID == allot.ID);
                        if (deptTypes != null)
                        {
                            perforCofdepttypeRepository.RemoveRange(deptTypes.ToArray());
                        }
                        deptTypes = perforCofdepttypeRepository.GetEntities(t => t.AllotID == allotId) ?? perforCofdepttypeRepository.GetEntities(t => t.AllotID == -1);
                        if (deptTypes != null && deptTypes.Any())
                        {
                            var newDeptTypes = deptTypes.Select(t => new cof_depttype { AllotID = allot.ID, Charge = t.Charge, ChargeType = t.ChargeType });
                            perforCofdepttypeRepository.AddRange(newDeptTypes.ToArray());
                        }
                        break;
                    case "agains":
                        logger.LogInformation($"copy agains");
                        var agains = _againRepository.GetEntities(t => t.AllotID == allot.ID);
                        if (agains != null)
                        {
                            _againRepository.RemoveRange(agains.ToArray());
                        }
                        agains = _againRepository.GetEntities(t => t.AllotID == allotId) ?? _againRepository.GetEntities(t => t.AllotID == -1);
                        if (agains != null && agains.Any())
                        {
                            var days = DateTime.DaysInMonth(allot.Year, allot.Month);
                            var newAgains = agains.Select(t => new cof_again { AllotID = allot.ID, Type = t.Type, Department = t.Department, TypeName = t.TypeName, Value = t.TypeName == "满勤天数" ? days : t.Value });
                            _againRepository.AddRange(newAgains.ToArray());
                        }
                        break;
                    case "accountings":
                        logger.LogInformation($"copy accountings");
                        var accountings = cofaccountingRepository.GetEntities(t => t.AllotId == allot.ID);
                        if (accountings != null)
                        {
                            cofaccountingRepository.RemoveRange(accountings.ToArray());
                        }
                        accountings = cofaccountingRepository.GetEntities(t => t.AllotId == allotId) ?? cofaccountingRepository.GetEntities(t => t.AllotId == -1);
                        if (accountings != null && accountings.Any())
                        {
                            var newAccountings = accountings.Select(t => new cof_accounting
                            {
                                AllotId = allot.ID,
                                UnitType = t.UnitType,
                                AccountingUnit = t.AccountingUnit,
                                Code = t.Code,
                                IsVerify = t.IsVerify,
                                VerifyMessage = t.VerifyMessage
                            });
                            cofaccountingRepository.AddRange(newAccountings.ToArray());
                        }
                        break;
                    default:
                        break;
                }
            }
            //personService.CreateAllotPersons(allot.HospitalId, allot.ID, allotId);

        }

        #endregion

        #region 清楚无效数据 Clear

        /// <summary>
        /// 清楚无效数据
        /// </summary>
        /// <param name="allotId"></param>
        public void Clear(int allotId)
        {
            _directorRepository.DeleteData(allotId);
            logManageService.WriteMsg("清理无效数据", $"清理无效数据！", 1, allotId, "ReceiveMessage", true);
        }

        /// <summary>
        /// 删除绩效相关数据
        /// </summary>
        /// <param name="allotId"></param>
        public void ClearAllotData(int allotId)
        {
            _directorRepository.DeleteAllotData(allotId);
        }

        /// <summary>
        /// 清除核算数据
        /// </summary>
        /// <param name="allotId"></param>
        public void ClearResData(int allotId)
        {
            var count = _directorRepository.DeleteResData(allotId);
            logManageService.WriteMsg("清理无效数据", $"清理无效数据，受影响行数：{count}", 1, allotId, "ReceiveMessage", true);
        }

        /// <summary>
        /// 清除二次绩效中无效数据
        /// </summary>
        /// <param name="againId"></param>
        public void ClearAgain(int againId)
        {
            var count = _directorRepository.DelAgain(againId);
            logManageService.WriteMsg("清理无效数据", $"清除二次绩效中无效数据，受影响行数：{count}", 1, againId, "ReceiveMessage", true);
        }

        #endregion

        /// <summary>
        /// 获取工作量绩效列头
        /// </summary>
        /// <returns></returns>
        public List<TitleValue> WorkHeader(int allotId)
        {
            var sheets = perforPersheetRepository.GetEntities(t => t.AllotID == allotId && t.SheetName.Contains("工作量"));
            if (sheets == null)
                return new List<TitleValue>();
            var header = perforImheaderRepository.GetEntities(t => sheets.Select(s => s.ID).Contains(t.SheetID.Value) && !t.CellValue.Contains("核算单元") && t.CellValue != "科室名称")?.ToList();
            if (header != null && header.Count > 0)
            {
                var list = header.Select(t => t.CellValue).Where(t => !string.IsNullOrEmpty(t)).Distinct();
                return list?.Select(t => new TitleValue { Title = t, Value = t }).ToList();
            }
            return null;
        }

        ///// <summary>
        ///// 人员绩效额外金额
        ///// </summary>
        //private void CopyAprData(int prevAllotId, int allotId)
        //{
        //    if (prevAllotId == 0) return;
        //    var list = perapramountRepository.GetEntities(t => new List<int> { prevAllotId, allotId }.Contains(t.AllotId));
        //    if (list == null || !list.Any(t => t.AllotId == prevAllotId)) return;

        //    if (list.Any(t => t.AllotId == allotId))
        //    {
        //        var prevData = list.Where(t => t.AllotId == prevAllotId);
        //        var existData = list.Where(t => t.AllotId == allotId);
        //        if (existData != null && existData.Any())
        //            list = prevData.Where(t => !existData.Select(w => w.PersonnelNumber).Contains(t.PersonnelNumber)).ToList();
        //    }
        //    if (list.Any())
        //    {
        //        var data = list.Select(t => new per_apr_amount
        //        {
        //            Status = 2,
        //            AllotId = allotId,
        //            PersonnelNumber = t.PersonnelNumber,
        //            DoctorName = t.DoctorName,
        //            PerforType = t.PerforType,
        //            Amount = t.Amount,
        //            CreateDate = DateTime.Now
        //        });
        //        perapramountRepository.AddRange(data.ToArray());
        //    }
        //}


        #region HRP人员科室

        public HandsonTable GetHrpDeptHands(int HospitalId, int AllotId)
        {
            var result = new HandsonTable((int)SheetType.Unidentifiable, HrpDept.Select(t => t.Value).ToArray(), HrpDept.Select(t => new collect_permission
            {
                HeadName = t.Value,
                Visible = 1
            }).ToList());

            var data = perforCofHrpDeptRepository.GetEntities(t => t.HospitalId == HospitalId && t.AllotId == AllotId);
            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 HrpDept 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, rowDatas != null);
            return result;
        }

        public void SaveDepttypeHands(int hospitalId, int allotId, SaveCollectData request)
        {
            var dicData = CreateDataRow(hospitalId, allotId, request, HrpDept);

            List<cof_hrp_department> depts = new List<cof_hrp_department>();
            foreach (var item in dicData)
            {
                var json = JsonHelper.Serialize(item);
                var data = JsonHelper.Deserialize<cof_hrp_department>(json);
                if (!string.IsNullOrEmpty(data.HRPDepartment) && !string.IsNullOrEmpty(data.AccountingUnit))
                {
                    data.HospitalId = hospitalId;
                    data.AllotId = allotId;
                    depts.Add(data);
                }
            }

            perforCofHrpDeptRepository.Execute("delete from cof_hrp_department where HospitalId=@hospitalId and allotid = @allotid"
                , new { hospitalId, allotId });
            perforCofHrpDeptRepository.AddRange(depts.ToArray());
        }

        public static Dictionary<string, string> HrpDept { get; } = new Dictionary<string, string>
        {
            {nameof(cof_hrp_department.HRPDepartment), "hrp人员科室"},
            {nameof(cof_hrp_department.AccountingUnit), "核算单元"},
        };

        #endregion

        #region 二次分配别名配置

        public HandsonTable GetSecondaryAlias()
        {
            var result = new HandsonTable((int)SheetType.Unidentifiable, Alias.Select(t => t.Value).ToArray(), Alias.Select(t => new collect_permission
            {
                HeadName = t.Value,
                Visible = 1
            }).ToList());

            if (result.Columns != null && result.Columns.Any())
            {
                foreach (var column in result.Columns)
                {
                    if (column.Data == "状态")
                    {
                        column.Type = "autocomplete";
                        column.Source = new[] { "可用", "禁用" };
                        column.Strict = true;
                    }
                }
            }
            var data = perforCofaliasRepository.GetEntities()?.OrderBy(t => t.Route);
            if (data == null) return result;

            List<HandsonRowData> rowDatas = new List<HandsonRowData>();
            int i = 0;
            foreach (var item in data)
            {
                var json = JsonHelper.Serialize(item);
                var firstDic = JsonHelper.Deserialize<Dictionary<string, string>>(json);
                firstDic["states"] = firstDic["states"] == "1" ? "可用" : "禁用";
                var cells = (from conf in Alias 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, rowDatas != null);
            return result;
        }

        public void SaveSecondaryAlias(SaveCollectData request)
        {
            var dicData = CreateDataRow(0, 0, request, Alias);

            List<cof_alias> aliases = new List<cof_alias>();
            foreach (var item in dicData)
            {
                var states = new[] { "可用", "禁用" };
                if (item["States"] != null && states.Contains(item["States"]))
                {
                    item["States"] = item["States"] == "可用" ? "1" : "0";
                }
                else continue;

                var json = JsonHelper.Serialize(item);
                var data = JsonHelper.Deserialize<cof_alias>(json);
                if (!string.IsNullOrEmpty(data.Name) && !string.IsNullOrEmpty(data.OriginalName) && !string.IsNullOrEmpty(data.Route) && !string.IsNullOrEmpty(data.Alias))
                {
                    aliases.Add(data);
                }
            }

            perforCofaliasRepository.Execute("delete from cof_alias", null);
            perforCofaliasRepository.AddRange(aliases.ToArray());
        }

        public static Dictionary<string, string> Alias { get; } = new Dictionary<string, string>
        {
            {nameof(cof_alias.Route), "前端路由地址"},
            {nameof(cof_alias.Name), "描述名称"},
            {nameof(cof_alias.OriginalName), "原始名"},
            {nameof(cof_alias.Alias), "别名"},
            {nameof(cof_alias.States), "状态"},
        };
        #endregion

        private List<Dictionary<string, string>> CreateDataRow(int hospitalId, int allotId, SaveCollectData 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.HospitalId), hospitalId.ToString());
                allData.Add(baseData);

            }
            return allData;
        }

        private Dictionary<string, string> CreateBaseData(SaveCollectData 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;
        }


        ///// <summary>
        ///// CMI值
        ///// </summary>
        ///// <param name="prevAllotId"></param>
        ///// <param name="allotId"></param>
        //private void CopyCMIData(int prevAllotId, int allotId)
        //{
        //    if (prevAllotId == 0) return;
        //    var list = perforCofcmiRepository.GetEntities(t => new List<int> { prevAllotId, allotId }.Contains(t.AllotId));
        //    if (list == null || !list.Any(t => t.AllotId == prevAllotId)) return;

        //    if (list.Any(t => t.AllotId == allotId))
        //    {
        //        var prevData = list.Where(t => t.AllotId == prevAllotId);
        //        var existData = list.Where(t => t.AllotId == allotId);
        //        if (existData != null && existData.Any())
        //            list = prevData.Where(t => !existData.Select(w => w.UnitType + w.AccountingUnit).Contains(t.UnitType + t.AccountingUnit)).ToList();
        //    }
        //    if (list.Any())
        //    {
        //        var data = list.Select(t => new cof_cmi
        //        {
        //            AllotId = allotId,
        //            UnitType = t.UnitType,
        //            AccountingUnit = t.AccountingUnit,
        //            Value = t.Value,
        //        });
        //        perforCofcmiRepository.AddRange(data.ToArray());
        //    }
        //}

        #region 费用类型系数

        public SheetExportResponse GetDrugtypeFactor(AllotDeptRequest request)
        {
            SheetExportResponse sheet = new SheetExportResponse();

            #region header

            var models = perforExmoduleRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.SheetType == (int)SheetType.Income);
            if (models == null || !models.Any())
            {
                exConfigService.DefaultModules(request.HospitalId);

                models = perforExmoduleRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.SheetType == (int)SheetType.Income);
                if (models == null || !models.Any()) return sheet;
            }

            var mergeCells = new List<Cell>
            {
                new Cell{ CellType = "header", CellValue = "", PointCell = 0, MergeRow = 1, MergeCell = 1 },
                new Cell{ CellType = "header", CellValue = "", PointCell = 1, MergeRow = 1, MergeCell = 1 },
                new Cell{ CellType = "header", CellValue = "", PointCell = 2, MergeRow = 1, MergeCell = 1 },
            };
            var cells = new List<Cell>
            {
                new Cell{ CellType = "header", CellValue = "序号", PointCell = 0, MergeRow = 1, MergeCell = 1 },
                new Cell{ CellType = "header", CellValue = "项目小类(测算表)", PointCell = 1, MergeRow = 1, MergeCell = 1 },
                new Cell{ CellType = "header", CellValue = "费用大类(大屏展示)", PointCell = 2, MergeRow = 1, MergeCell = 1 }
            };

            var defaultColumns = new Dictionary<string, string>
            {
                { UnitType.医生组.ToString(), "ysz" },
                { UnitType.护理组.ToString(), "hlz" },
                { UnitType.医技组.ToString(), "yjz" }
            };

            int index = 0;
            foreach (var model in models)
            {
                mergeCells.Add(new Cell { CellType = "header", CellValue = model.ModuleName, PointCell = 3 + index * 3, MergeRow = 1, MergeCell = defaultColumns.Count });

                int i = 1;
                cells.AddRange(defaultColumns.Select(t =>
                {
                    i++;
                    return new Cell
                    {
                        CellType = "header",
                        CellValue = t.Key,
                        PointCell = 1 + index * 3 + i,
                        MergeRow = 1,
                        MergeCell = 1
                    };
                }));
                index++;
            }

            sheet.Header = new List<Row>
            {
                new Row(0){ Data = mergeCells },
                new Row(1){ Data = cells }
            };

            #endregion

            #region data

            List<Row> rows = new List<Row>();
            var querydata = _directorRepository.QueryCategoryFactor(request.HospitalId, request.AllotId)?.ToList();
            if (querydata != null && querydata.Any())
            {
                var fields = new Dictionary<string, Func<view_dic_category_factor, object>>
                {
                    { "ysz", t => t.YSZ },
                    { "hlz", t => t.HLZ },
                    { "yjz", t => t.YJZ }
                };
                var charges = querydata.Select(t => new { t.Charge, t.ChargeType }).Distinct().OrderBy(t => t.Charge).ThenBy(t => t.ChargeType);

                index = 0;
                foreach (var charge in charges)
                {
                    var rowcells = new List<Cell>
                    {
                        new Cell { CellType = "body", CellValue = index+1, PointCell = 0, MergeRow = 1, MergeCell = 1 },
                        new Cell { CellType = "body", CellValue = charge.Charge, PointCell = 1, MergeRow = 1, MergeCell = 1 },
                        new Cell { CellType = "body", CellValue = charge.ChargeType, PointCell = 2, MergeRow = 1, MergeCell = 1 },
                    };

                    int i = 1;
                    foreach (var model in models)
                    {
                        var modeldata = querydata.FirstOrDefault(t => t.Charge == charge.Charge && t.ChargeType == charge.ChargeType && t.ExModuleId == model.Id);

                        int j = 0;
                        foreach (var column in defaultColumns)
                        {
                            rowcells.Add(new Cell
                            {
                                CellType = "body",
                                CellValue = modeldata == null ? null : fields[column.Value].Invoke(modeldata),
                                PointCell = i * 3 + j,
                                MergeRow = 1,
                                MergeCell = 1
                            });
                            j++;
                        }
                        i++;
                    }
                    rows.Add(new Row(index) { Data = rowcells });
                    index++;
                }
            }

            sheet.Row = rows;

            #endregion

            return sheet;
        }

        public HandsonTable GetDrugtypeFactorConfig(int hospitalId, int allotId)
        {
            HandsonTable table = new HandsonTable((int)SheetType.Unidentifiable, new string[] { }, new List<collect_permission>());

            var models = perforExmoduleRepository.GetEntities(t => t.HospitalId == hospitalId && t.SheetType == (int)SheetType.Income);
            if (models == null || !models.Any())
            {
                //exConfigService.DefaultModules(hospitalId);

                models = perforExmoduleRepository.GetEntities(t => t.HospitalId == hospitalId && t.SheetType == (int)SheetType.Income);
                if (models == null || !models.Any()) return table;
            }

            var defaultColumns = new Dictionary<string, string>
            {
                { UnitType.医生组.ToString(), "ysz" },
                { UnitType.护理组.ToString(), "hlz" },
                { UnitType.医技组.ToString(), "yjz" }
            };

            var mergeCells = new List<NestedHeader>
            {
                new NestedHeader("", 1),
                new NestedHeader("", 1),
            };
            var cells = new List<string>
            {
                "项目小类(测算表)", "费用大类(大屏展示)",
            };

            var columns = new List<HandsonColumn>
            {
                new HandsonColumn("charge", false),
                new HandsonColumn("chargetype", false),
            };

            foreach (var model in models)
            {
                mergeCells.Add(new NestedHeader(model.ModuleName, defaultColumns.Count));
                cells.AddRange(defaultColumns.Select(t => t.Key));
                columns.AddRange(defaultColumns.Select(t => new HandsonColumn(t.Value + $"_{model.Id}", false, DataFormat.百分比)));
            }

            #region data

            List<Dictionary<string, object>> data = new List<Dictionary<string, object>>();
            var querydata = _directorRepository.QueryCategoryFactor(hospitalId, allotId)?.ToList();
            if (querydata != null && querydata.Any())
            {
                var fields = new Dictionary<string, Func<view_dic_category_factor, object>>
                {
                    { "ysz", t => t.YSZ },
                    { "hlz", t => t.HLZ },
                    { "yjz", t => t.YJZ }
                };
                var charges = querydata.Select(t => new { t.Charge, t.ChargeType }).Distinct().OrderBy(t => t.Charge).ThenBy(t => t.ChargeType);
                foreach (var charge in charges)
                {
                    Dictionary<string, object> dict = new Dictionary<string, object>
                    {
                        { "Charge", charge.Charge },
                        { "ChargeType", charge.ChargeType }
                    };
                    foreach (var model in models)
                    {
                        var modeldata = querydata.FirstOrDefault(t => t.Charge == charge.Charge && t.ChargeType == charge.ChargeType && t.ExModuleId == model.Id);


                        foreach (var column in defaultColumns)
                        {
                            if (modeldata == null)
                            {
                                dict.Add(column.Value + $"_{model.Id}", null);
                            }
                            else
                            {
                                dict.Add(column.Value + $"_{model.Id}", fields[column.Value].Invoke(modeldata));
                            }
                        }
                    }
                    data.Add(dict);
                }
            }

            #endregion

            table.Columns = columns;
            table.NestedHeadersArray = new object[] { mergeCells, cells };
            table.ColHeaders = cells;
            table.Data = data;
            return table;
        }

        public void SaveDrugtypeFactor(DrugtypeFactorRequest request)
        {
            if (request.Data == null || !request.Data.Any()) return;

            var moduleIds = request.Data.FirstOrDefault().Keys.Where(t => t.Contains("_")).Select(t => t.Split('_')[1]).Distinct();

            var factors = new List<cof_drugtype_factor>();
            var charges = new List<cof_drugtype>();
            bool isHasChargeData = false;

            foreach (var item in request.Data)
            {
                string charge = string.Empty; string chargeType = string.Empty;
                if (item.ContainsKey("charge")) charge = item["charge"]?.ToString();
                if (item.ContainsKey("chargetype")) chargeType = item["chargetype"]?.ToString();

                if (string.IsNullOrEmpty(charge) && string.IsNullOrEmpty(chargeType)) continue;

                isHasChargeData = true;
                charges.Add(new cof_drugtype
                {
                    HospitalId = request.HospitalId,
                    AllotID = request.AllotId,
                    Charge = charge,
                    ChargeType = chargeType,
                });

                foreach (var moduleId in moduleIds)
                {
                    var data = item.Where(t => t.Key.EndsWith(moduleId));
                    factors.Add(new cof_drugtype_factor
                    {
                        HospitalId = request.HospitalId,
                        AllotID = request.AllotId,
                        Charge = charge,
                        ExModuleId = ConvertHelper.To<int>(moduleId),
                        YSZ = item.ContainsKey("ysz_" + moduleId) ? ConvertHelper.To<decimal?>(item["ysz_" + moduleId]) : null,
                        HLZ = item.ContainsKey("hlz_" + moduleId) ? ConvertHelper.To<decimal?>(item["hlz_" + moduleId]) : null,
                        YJZ = item.ContainsKey("yjz_" + moduleId) ? ConvertHelper.To<decimal?>(item["yjz_" + moduleId]) : null,
                    });
                }
            }

            var savedData = cofdrugtypefactorRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.AllotID == request.AllotId);
            if (savedData != null && savedData.Any())
            {
                cofdrugtypefactorRepository.RemoveRange(savedData.ToArray());
            }
            if (factors != null && factors.Any())
                cofdrugtypefactorRepository.AddRange(factors.ToArray());

            if (isHasChargeData)
            {
                var drugtypes = _drugtypeRepository.GetEntities(t => t.HospitalId == request.HospitalId && t.AllotID == request.AllotId);
                if (drugtypes != null && drugtypes.Any())
                {
                    _drugtypeRepository.RemoveRange(drugtypes.ToArray());
                }
                if (charges != null && charges.Any())
                    _drugtypeRepository.AddRange(charges.ToArray());
            }
        }

        #endregion

        #region 自定义表


        public HandsonTable QueryHandsCustom(CustomPagingRequest request)
        {
            var custom = perforReport.QueryCustomColumn(request.TableName);

            var isExist = perforReport.QueryIsAllotId(request.TableName, "AllotId", "AccountingUnit", "UnitType");
            if (custom == null || isExist == false)
                return null;

            var skip = new string[] { "allotid" };

            var dicCustom = custom
                .Where(w => !skip.Any(s => s.Equals(w.Name, StringComparison.OrdinalIgnoreCase)))
                .Select(w => new { w.Name, w.Comment });

            if (dicCustom.GroupBy(x => x.Comment).Where(x => x.Count() > 1).Any())
                throw new PerformanceException("表列头名称重复, 请补全注释或修改重复注释！");

            var result = new HandsonTable((int)SheetType.Unidentifiable, new string[] { }, new List<collect_permission>());

            var jsonData = JsonHelper.Serialize(perforReport.QueryCustom(request, true).DataList);
            var data = JsonHelper.Deserialize<List<Dictionary<string, string>>>(jsonData);

            var headDic = new List<Dictionary<string, object>>();

            foreach (var item in data)
            {
                var head = new Dictionary<string, object>();
                foreach (var dic in dicCustom)
                {
                    if (item.ContainsKey(dic.Name.ToLower()))
                        head.Add(dic.Comment, item.FirstOrDefault(t => t.Key == dic.Name.ToLower()).Value);
                }
                headDic.Add(head);
            }

            var Columns = dicCustom.Select(t => new HandsonColumn(t.Comment, false, DataFormat.普通格式)).ToList();
            //表类型
            var columnType = perforReport.QueryType(request.TableName);

            if (Columns != null && Columns.Any())
            {
                foreach (var column in Columns)
                {
                    if (dicCustom.FirstOrDefault(t => t.Comment.Equals(column.Data)).Name.ToLower() == "unittype")
                    {
                        column.Type = "autocomplete";
                        column.Source = EnumHelper.GetItems<UnitType>().Select(w => w.Description.Replace("行政后勤", "行政工勤")).ToArray();
                        column.Strict = true;
                    }

                    for (int i = 0; i < columnType.Count(); i++)
                    {
                        var type = ((IDictionary<string, object>)columnType.ElementAt(i)).Values;
                        var itemDic = column.Data.ToUpper() == type.ElementAt(0).ToString().ToUpper();
                        var dic = dicCustom.FirstOrDefault(t => t.Comment == column.Data);

                        if (dic.Name.ToUpper() == type.ElementAt(0).ToString().ToUpper() && type.ElementAt(1).ToString() == "int")
                        {
                            column.Type = "numeric";
                            column.NumericFormat = new NumericFormat { Pattern = "0,00" };
                        }

                        if (dic.Name.ToUpper() == type.ElementAt(0).ToString().ToUpper() && type.ElementAt(1).ToString() == "decimal")
                        {
                            column.Type = "numeric";
                            column.NumericFormat = new NumericFormat { Pattern = "0,00.00" };
                        }
                    }
                }
            }

            result.Data = headDic;
            result.ColHeaders = dicCustom.Select(w => w.Comment).ToList();
            result.Columns = Columns;
            return result;
        }


        public ApiResponse SaveCustomTable(SaveCustomData request)
        {
            if (!request.Data.Any())
                perforReport.CreatCustom(request.AllotId, request.TableName, null);

            var custom = perforReport.QueryCustomColumn(request.TableName);

            if (custom.Count > 50)
                return new ApiResponse(ResponseType.ParameterError, "最多支持50列数据！");

            var skip = new string[] { "allotid" };

            var dicCustom = custom
                .Where(w => !skip.Any(s => s.Equals(w.Name, StringComparison.OrdinalIgnoreCase)));

            if (dicCustom.GroupBy(x => x.Comment).Where(x => x.Count() > 1).Any())
                return new ApiResponse(ResponseType.ParameterError, "表列头名称重复,请补全注释或修改重复注释！");

            var dicData = CreateCustomRow(request.AllotId, request, dicCustom);
            //字段类型
            var typeColumn = perforReport.QueryType(request.TableName);

            var datas = new List<dynamic>();
            foreach (var item in dicData)
            {
                for (int i = 0; i < typeColumn.Count(); i++)
                {
                    var type = ((IDictionary<string, object>)typeColumn.ElementAt(i)).Values.ElementAt(0).ToString();
                    var itemDic = item.FirstOrDefault(t => t.Key.ToUpper() == type.ToUpper());
                    var value = ((IDictionary<string, object>)typeColumn.ElementAt(i)).Values.ElementAt(1).ToString();

                    if (string.IsNullOrEmpty(itemDic.Value.ToString()) && value.Contains("date"))
                        item.AddOrUpdate(itemDic.Key, null);
                    else if (!string.IsNullOrEmpty(itemDic.Value.ToString()) && value.Contains("date"))
                    {
                        try
                        {
                            var s = DateTime.Parse(itemDic.Value.ToString());
                        }
                        catch (FormatException)
                        {
                            return new ApiResponse(ResponseType.ParameterError, "请输入正确的日期格式");
                        }
                    }


                    if (string.IsNullOrEmpty(itemDic.Value.ToString()) && !value.Contains("date"))
                        item.AddOrUpdate(itemDic.Key, 0);

                    if (!string.IsNullOrEmpty(itemDic.Value.ToString()) && !Regex.IsMatch(itemDic.Value.ToString(), @"^(\-|\+)?\d+(\.\d+)?$") && !value.Contains("date"))
                        return new ApiResponse(ResponseType.ParameterError, "保存失败,请修改红色输入内容！");
                }
                datas.Add(item);
            }
            if (datas.Any())
                perforReport.CreatCustom(request.AllotId, request.TableName, datas);

            return new ApiResponse(ResponseType.OK);

        }

        public ApiResponse QueryCustom(int userId, CustomPagingRequest request)
        {
            var heads = perforReport.QueryCustomColumn(request.TableName);
            var isExist = perforReport.QueryIsAllotId(request.TableName, "AllotId", "AccountingUnit", "UnitType");
            if (isExist == false || heads == null)
                return new ApiResponse(ResponseType.ParameterError, "表不符合规范,请补全注释或修改重复注释");
            if (heads.Count > 50)
                return new ApiResponse(ResponseType.ParameterError, "最多支持50列数据");

            var skip = new string[] { "allotid" };
            var headList = heads
                .Where(w => !skip.Any(s => s.Equals(w.Name, StringComparison.OrdinalIgnoreCase)))
                .Select(w => new Heads { Name = w.Comment, Column = w.Name.ToLower() });

            var customGroup = headList.GroupBy(x => x.Name).Where(x => x.Count() > 1);
            if (customGroup.Any())
                return new ApiResponse(ResponseType.ParameterError, "表不符合规范,请补全注释或修改重复注释");

            Dictionary<int, string[]> dic = new Dictionary<int, string[]>
            {
                { (int)Role.科主任, new[]{ UnitType.医生组.ToString(), UnitType.其他医生组.ToString(), UnitType.医技组.ToString(), UnitType.其他医技组.ToString() } },
                { (int)Role.护士长, new[]{ UnitType.护理组.ToString(), UnitType.其他护理组.ToString()} },
                { (int)Role.特殊科室, new[]{ UnitType.特殊核算组.ToString() }},
                { (int)Role.行政科室, new[]{ UnitType.行政后勤.ToString() } },
            };
            var user = _userService.GetUser(userId);
            var roleType = _roleService.GetUserRole(userId)?.FirstOrDefault()?.Type ?? 0;

            var result = new CustomResponse
            {
                Heads = headList.ToList()
            };

            if (dic.Keys.Contains(roleType))
                result.Datas = perforReport.QueryCustom(request.TableName, request.AllotId, user?.Department ?? "", dic[roleType], request.PageIndex, request.PageSize);
            else
                result.Datas = perforReport.QueryCustom(request, false);

            return new ApiResponse(ResponseType.OK, result);
        }

        private List<Dictionary<string, object>> CreateCustomRow(int allotId, SaveCustomData request, IEnumerable<ColumnEntity> config)
        {
            List<Dictionary<string, object>> allData = new List<Dictionary<string, object>>();

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

            }
            return allData;
        }

        private Dictionary<string, object> CreateCustomData(SaveCustomData request, IEnumerable<ColumnEntity> config, int rownumber)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            for (int c = 0; c < request.ColHeaders.Length; c++)
            {
                var header = request.ColHeaders[c];
                var first = config.FirstOrDefault(w => w.Comment.ToString().ToUpper() == header);
                if (!default(KeyValuePair<string, object>).Equals(first)
                    && !result.ContainsKey(header)
                    && request.Data[rownumber].Length > c)
                {
                    result.Add(first.Name, request.Data[rownumber][c]);
                }
            }

            return result;
        }
        #endregion
    }
}
