using AutoMapper;
using Microsoft.AspNetCore.Hosting;
using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using Performance.DtoModels;
using Performance.EntityModels;
using Performance.EntityModels.Other;
using Performance.Infrastructure;
using Performance.Infrastructure.Models;
using Performance.Repository;
using Performance.Repository.Repository;
using Performance.Services.ExtractExcelService;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Text.RegularExpressions;

namespace Performance.Services
{
    public class ConfigService : IAutoInjection
    {
        #region
        private readonly IMapper _mapper;
        private readonly UserService _userService;
        private readonly RoleService _roleService;
        private readonly CopyService _copyService;
        private readonly PersonService _personService;
        private readonly LogManageService _logManageService;
        private readonly ExConfigService _exConfigService;
        private readonly PerforReportRepository _perforReport;
        private readonly PerforImdataRepository _imdataRepository;
        private readonly PerforPerallotRepository _perallotRepository;
        private readonly PerforCofdirectorRepository _directorRepository;
        private readonly PerforCofworkitemRepository _workitemRepository;
        private readonly PerforCofagainRepository _againRepository;
        private readonly PerforCofdrugtypeRepository _drugtypeRepository;
        private readonly PerforPerallotRepository _perforPerAllotRepository;
        private readonly PerforPersheetRepository _perforPersheetRepository;
        private readonly PerforImheaderRepository _perforImheaderRepository;
        private readonly PerforCofdepttypeRepository _perforCofdepttypeRepository;
        private readonly PerforCofHrpDeptRepository _perforCofHrpDeptRepository;
        private readonly PerforCofaliasRepository _perforCofaliasRepository;
        private readonly PerforCofaccountingRepository _cofaccountingRepository;
        private readonly PerforCofdrugtypeDisburseRepository _drugtypeDisburseRepository;
        private readonly PerforExmoduleRepository _perforExmoduleRepository;
        private readonly PerforCofdrugtypefactorRepository _cofdrugtypefactorRepository;
        private readonly IWebHostEnvironment _evn;

        public ConfigService(
            IMapper mapper,
            UserService userService,
            RoleService roleService,
            CopyService copyService,
            PersonService personService,
            LogManageService logManageService,
            ExConfigService exConfigService,
            PerforReportRepository perforReport,
            PerforImdataRepository imdataRepository,
            PerforPerallotRepository perallotRepository,
            PerforCofdirectorRepository cofdirectorRepository,
            PerforCofagainRepository againRepository,
            PerforExmoduleRepository perforExmoduleRepository,
            PerforCofdrugtypeRepository drugtypeRepository,
            PerforPerallotRepository perforPerAllotRepository,
            PerforCofworkitemRepository workitemRepository,
            PerforPersheetRepository perforPersheetRepository,
            PerforImheaderRepository perforImheaderRepository,
            PerforCofdepttypeRepository perforCofdepttypeRepository,
            PerforCofHrpDeptRepository perforCofHrpDeptRepository,
            PerforCofaliasRepository perforCofaliasRepository,
            PerforCofaccountingRepository cofaccountingRepository,
            PerforCofdrugtypeDisburseRepository drugtypeDisburseRepository,
            PerforCofdrugtypefactorRepository cofdrugtypefactorRepository,
            IWebHostEnvironment evn)
        {
            _mapper = mapper;
            _userService = userService;
            _roleService = roleService;
            _copyService = copyService;
            _personService = personService;
            _perforReport = perforReport;
            _logManageService = logManageService;
            _exConfigService = exConfigService;
            _imdataRepository = imdataRepository;
            _againRepository = againRepository;
            _drugtypeRepository = drugtypeRepository;
            _perallotRepository = perallotRepository;
            _directorRepository = cofdirectorRepository;
            _workitemRepository = workitemRepository;
            _perforPerAllotRepository = perforPerAllotRepository;
            _perforPersheetRepository = perforPersheetRepository;
            _perforImheaderRepository = perforImheaderRepository;
            _perforCofdepttypeRepository = perforCofdepttypeRepository;
            _perforCofHrpDeptRepository = perforCofHrpDeptRepository;
            _perforCofaliasRepository = perforCofaliasRepository;
            _cofaccountingRepository = cofaccountingRepository;
            _drugtypeDisburseRepository = drugtypeDisburseRepository;
            _perforExmoduleRepository = perforExmoduleRepository;
            _cofdrugtypefactorRepository = cofdrugtypefactorRepository;
            _evn = evn;
        }

        #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("保存失败");

            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,
                IsVerify = 1,
            };
            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 entity = _cofaccountingRepository.GetEntity(t => t.Id == request.Id);
            if (null == entity) throw new PerformanceException($"无法找到您要修改的数据！");

            var existed = _cofaccountingRepository.GetEntity(w => w.Id != request.Id && w.AllotId == request.AllotId && w.Code == request.Code);
            if (existed != null) throw new PerformanceException("核算单元编码重复");

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

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

            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 HandsonTableBase GetBatchAccountingStructrue(int AllotId)
        {
            HandsonTableBase result = new HandsonTableBase()
            {
                Columns = Accounting.Select(t => new HandsonColumn(t.Value)).ToList(),
                ColHeaders = Accounting.Select(c => c.Value).ToList(),
            };

            if (result.Columns != null && result.Columns.Any())
            {
                foreach (var column in result.Columns)
                {
                    if (column.Data == "核算组别")
                    {
                        column.Type = "autocomplete";
                        column.Source = UnitTypeUtil.GetUnitTypeFromEnum().Select(w => w.Description).ToArray();
                        column.Strict = true;
                    }
                    if (column.Data == "核算单元编码")
                    {
                        column.Type = "text";
                        column.NumericFormat = null;
                    }
                }
            }
            return result;
        }

        public ApiResponse 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 = UnitTypeUtil.GetUnitTypeFromEnum().Select(w => w.Description).ToArray();

            var json = JsonHelper.Serialize(dicData);
            var accounts = JsonHelper.Deserialize<List<cof_accounting>>(json)
                .Where(w => !string.IsNullOrEmpty(w.Code) || !string.IsNullOrEmpty(w.UnitType) || !string.IsNullOrEmpty(w.AccountingUnit))
                .ToList();

            List<Dictionary<string, string>> error = new List<Dictionary<string, string>>();
            for (int i = 0; i < accounts.Count(); i++)
            {
                if (string.IsNullOrEmpty(accounts[i].Code) || string.IsNullOrEmpty(accounts[i].UnitType) || string.IsNullOrEmpty(accounts[i].AccountingUnit))
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "核算单元编码", accounts[i].Code ?? "" },
                        { "核算组别", accounts[i].UnitType ?? "" },
                        { "核算单元", accounts[i].AccountingUnit ?? "" },
                        { "错误原因", "“关键信息缺失”请补全或删除" },
                    });
                }
                else if (accounts.Count(w => w.Code == accounts[i].Code) > 1)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "核算单元编码", accounts[i].Code ?? "" },
                        { "核算组别", accounts[i].UnitType ?? "" },
                        { "核算单元", accounts[i].AccountingUnit ?? "" },
                        { "错误原因", "“核算单元编码”重复值，请修改或删除" },
                    });
                }
                else if (accounts.Count(w => w.AccountingUnit == accounts[i].AccountingUnit && w.UnitType == accounts[i].UnitType) > 1)
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "核算单元编码", accounts[i].Code ?? "" },
                        { "核算组别", accounts[i].UnitType ?? "" },
                        { "核算单元", accounts[i].AccountingUnit ?? "" },
                        { "错误原因", "“核算组别/核算单元”重复，请修改或删除" },
                    });
                }
                else if (getAccounts.Any(w => w.Code != accounts[i].Code && w.AccountingUnit == accounts[i].AccountingUnit && w.UnitType == accounts[i].UnitType))
                {
                    error.Add(new Dictionary<string, string>
                    {
                        { "行号", $"第{i+1}行" },
                        { "核算单元编码", accounts[i].Code ?? "" },
                        { "核算组别", accounts[i].UnitType ?? "" },
                        { "核算单元", accounts[i].AccountingUnit ?? "" },
                        { "错误原因", "“核算组别/核算单元”重复但“核算单元编码”不同，请修改或删除" },
                    });
                }
            }
            if (error.Count > 0)
                return new ApiResponse(ResponseType.WarningTable, "验证不通过,当前操作已拒绝", error);

            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());
            }
            _perforPerAllotRepository.AccoungtingVerify(allotId);
            return new ApiResponse(ResponseType.OK);
        }


        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)
        {
            NewCopy(new CopyRequest()
            {
                AllotId = allot.ID,
                Type = new[] { "personnels", "workItems", "drugTypeDisburses", "drugTypeFactors", "deptTypes", "agains", "accountings", "department", "attendanceType", "assessType" }
            });
        }

        //todo:新copy
        /// <summary>
        /// 
        /// </summary>
        /// <param name="allotId"></param>
        /// <param name="type"></param>
        public void NewCopy(CopyRequest request)
        {
            if (request.Type.Length < 1) return;

            var allot = _perallotRepository.GetEntity(t => t.ID == request.AllotId);
            var prevAllotId = _perallotRepository.GetPrevAllot(allot);

            var pairs = new Dictionary<string, Action<per_allot, int>>
            {
                { "personnels", (allot, prevAllotId) => _personService.CreateAllotPersons(allot.HospitalId, allot.ID, prevAllotId) },
                { "workItems", (allot, prevAllotId) => _copyService.Copy_WorkItems(allot, prevAllotId, delHistotyData:true) },
                //{ "drugTypes", (allot, prevAllotId) =>_copyService.Copy_DrugTypes(allot, prevAllotId, delHistotyData:true) },
                { "drugTypeDisburses",  (allot, prevAllotId) =>_copyService.Copy_DrugTypeDisburses(allot, prevAllotId, delHistotyData:true) },
                { "drugTypeFactors", (allot, prevAllotId) =>_copyService.Copy_DrugTypeFactors(allot, prevAllotId, delHistotyData:true) },
                { "deptTypes", (allot, prevAllotId) =>_copyService.Copy_DeptTypes(allot, prevAllotId, delHistotyData:true) },
                { "agains", (allot, prevAllotId) =>_copyService.Copy_Agains(allot, prevAllotId, delHistotyData:true) },
                { "accountings", (allot, prevAllotId) =>_copyService.Copy_Accountings(allot, prevAllotId, delHistotyData:true) },
                { "attendanceType", (allot, prevAllotId) =>_copyService.Copy_AttendanceType(allot, prevAllotId, delHistotyData:true) },
                { "assessType", (allot, prevAllotId) =>_copyService.Copy_AssessType(allot, prevAllotId, delHistotyData:true) },
                { "department", (allot, prevAllotId) =>_copyService.Copy_DeptDic(allot, prevAllotId, delHistotyData:true) },
            };

            foreach (var item in request.Type)
            {
                pairs[item].Invoke(allot, prevAllotId);
            }
        }

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


        #region HRP人员科室

        public HandsonTableBase GetHrpDeptHands(int HospitalId, int AllotId)
        {
            HandsonTableBase result = new HandsonTableBase()
            {
                Columns = HrpDept.Select(t => new HandsonColumn(t.Value)).ToList(),
                ColHeaders = HrpDept.Select(c => c.Value).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);
            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 HandsonTableBase GetSecondaryAlias()
        {
            HandsonTableBase result = new HandsonTableBase()
            {
                Columns = Alias.Select(t => new HandsonColumn(t.Value)).ToList(),
                ColHeaders = Alias.Select(c => c.Value).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);
            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;
        }



        #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<DtoModels.Row>
            {
                new DtoModels.Row(0){ Data = mergeCells },
                new DtoModels.Row(1){ Data = cells }
            };

            #endregion

            #region data

            List<DtoModels.Row> rows = new List<DtoModels.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 DtoModels.Row(index) { Data = rowcells });
                    index++;
                }
            }

            sheet.Row = rows;

            #endregion

            return sheet;
        }

        public HandsonTableBase GetDrugtypeFactorConfig(int hospitalId, int allotId)
        {
            HandsonTableBase table = new HandsonTableBase()
            {
                Columns = new List<HandsonColumn>(),
                ColHeaders = new List<string>(),
            };

            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 HandsonTableBase QueryHandsCustom(CustomPagingRequest request)
        {
            var custom = _perforReport.QueryCustomColumn(request.TableName);
            if (custom == null || !custom.Any()) return null;

            var isView = custom.FirstOrDefault(w => !string.IsNullOrEmpty(w.TableType))?.TableType == "VIEW";
            if (isView) return new HandsonTableBase();  //如果是视图，不加载HandsonTable，则直接跳过

            var isExist = _perforReport.QueryIsAllotId(request.TableName, "allotid", "accountingunit", "unittype");
            if (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("表列头名称重复, 请补全注释或修改重复注释！");

            HandsonTableBase result = new HandsonTableBase()
            {
                Columns = new List<HandsonColumn>(),
                ColHeaders = new List<string>(),
            };

            var jsonData = JsonHelper.Serialize(_perforReport.QueryCustom(request, true, false).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 = UnitTypeUtil.GetUnitTypeFromEnum().Select(w => w.Description).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);
            if (heads == null || !heads.Any()) return null;

            var isView = heads.FirstOrDefault(w => !string.IsNullOrEmpty(w.TableType))?.TableType == "VIEW";
            var isExist = _perforReport.QueryIsAllotId(request.TableName, "allotid", "accountingunit", "unittype");
            if (!isView && isExist == false)
                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, "表不符合规范,请补全注释或修改重复注释");

            var user = _userService.GetUser(userId);
            var roleType = _roleService.GetUserRole(userId)?.FirstOrDefault()?.Type ?? 0;

            var result = new CustomResponse
            {
                Heads = headList.ToList()
            };
            var unitTypes = UnitTypeUtil.GetMaps(roleType);
            if (unitTypes.Any())
                result.Datas = _perforReport.QueryCustom(request.TableName, request.AllotId, user?.Department ?? "", unitTypes, request.PageIndex, request.PageSize, isView);
            else
                result.Datas = _perforReport.QueryCustom(request, false, isView);

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

        public string CustomDownloadFile(int userId, CustomPagingRequest request, per_allot allot)
        {
            var dpath = Path.Combine(_evn.ContentRootPath, "Files", "Dictionary", $"{allot.HospitalId}");
            FileHelper.CreateDirectory(dpath);

            string filename = $"{allot.Year}{allot.Month.ToString().PadLeft(2, '0')}导入数据-{DateTime.Now.ToString("yyyyMMddhhmmss")}.xlsx";
            string filepath = Path.Combine(dpath, filename);
            FileStream stream = new FileStream(filepath, FileMode.Create);

            var user = _userService.GetUser(userId);
            var roleType = _roleService.GetUserRole(userId)?.FirstOrDefault()?.Type ?? 0;

            var heads = _perforReport.QueryCustomColumn(request.TableName) ?? new List<ColumnEntity>();
            if (heads != null && heads.Any(w => string.IsNullOrEmpty(w.Comment)))
                heads.RemoveAll(w => string.IsNullOrEmpty(w.Comment));

            var unitTypes = UnitTypeUtil.GetMaps(roleType);
            var data = _perforReport.QueryCustom(request.TableName, request.AllotId, user?.Department ?? "", unitTypes) ?? new List<dynamic>();

            try
            {
                XSSFWorkbook workbook = new XSSFWorkbook();
                ExcelStyle excelStyle = new ExcelStyle(workbook);
                var style = excelStyle.SetBgkColorAndFormat(excelStyle.GetCellStyle());

                ISheet sheet = workbook.CreateSheet("人员字典");

                var header = sheet.CreateRow(0);
                int cellIndex = 0;
                foreach (var item in heads)
                {
                    var cell = header.CreateCell(cellIndex);
                    cell.SetCellValue(item.Comment);
                    cell.CellStyle = style;
                    cellIndex++;
                }

                if (data != null && data.Any())
                {
                    var retult = JsonHelper.Deserialize<List<Dictionary<string, object>>>(JsonHelper.Serialize(data));
                    int startIndex = 1;
                    foreach (var item in retult)
                    {
                        var row = sheet.CreateRow(startIndex);
                        cellIndex = 0;
                        foreach (var field in heads.Select(w => w.Name.ToLower()))
                        {
                            var cell = row.CreateCell(cellIndex);
                            cell.CellStyle = style;
                            cellIndex++;

                            if (!item.Keys.Contains(field)) continue;

                            cell.SetCellOValue(item[field]);
                        }
                        startIndex++;
                    }
                }

                workbook.Write(stream);
            }
            catch (Exception ex)
            {
                Console.WriteLine("写入异常" + ex);
            }
            finally
            {
                stream.Close();
            }
            return filepath;
        }
        #endregion
    }
}
