using Furion.DependencyInjection; using Furion.DynamicApiController; using Furion.EventBus; using Furion.FriendlyException; using Mapster; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Myshipping.Application.Entity; using Myshipping.Application.Event; using Myshipping.Application.Service.BookingOrder.Dto; using Myshipping.Application.Service.BookingSlot.Dto; using Myshipping.Core; using Myshipping.Core.Service; using SqlSugar; using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; namespace Myshipping.Application { /// /// 订舱舱位 /// [ApiDescriptionSettings("Application", Name = "BookingSlot", Order = 1)] public class BookingSlotService : IDynamicApiController, ITransient, IBookingSlotService { private readonly SqlSugarRepository _repBase; private readonly SqlSugarRepository _repCtn; private readonly SqlSugarRepository _repStock; private readonly SqlSugarRepository _repAllocation; private readonly SqlSugarRepository _repAllocationCtn; private readonly SqlSugarRepository _repBookingLog; private readonly SqlSugarRepository _repBookingLogDetail; private readonly SqlSugarRepository _bookingfile; private readonly ILogger _logger; private readonly ISysCacheService _cache; private readonly IEventPublisher _publisher; public BookingSlotService(SqlSugarRepository repBase, SqlSugarRepository repCtn, SqlSugarRepository repStock, SqlSugarRepository repBookingLog, SqlSugarRepository repBookingLogDetail, SqlSugarRepository bookingfile, ILogger logger, ISysCacheService cache, IEventPublisher publisher, SqlSugarRepository repAllocation) { _repBase = repBase; _repCtn = repCtn; _repStock = repStock; _repBookingLog = repBookingLog; _repBookingLogDetail = repBookingLogDetail; _repAllocation = repAllocation; _logger = logger; _cache = cache; _publisher = publisher; _bookingfile = bookingfile; } #region 舱位 /// /// 保存订舱舱位 /// /// /// [HttpPost("/BookingSlot/save")] public async Task Save(BookingSlotBaseSaveInput input) { BookingSlotBase model = null; if (input.Id > 0) //修改 { var c = _repBase.AsQueryable().Where(x => x.SLOT_BOOKING_NO == input.SLOT_BOOKING_NO && input.Id != input.Id).Count(); if (c > 0) { throw Oops.Bah("订舱编号已存在"); } model = _repBase.FirstOrDefault(x => x.Id == input.Id); var oldObj = model.Adapt(); input.Adapt(model); await _repBase.UpdateAsync(model); await _repCtn.DeleteAsync(x => x.SLOT_ID == model.Id); foreach (var ctn in input.CtnList) { var newCtn = ctn.Adapt(); newCtn.SLOT_ID = model.Id; await _repCtn.InsertAsync(newCtn); } await InsLog("Update", model.Id, typeof(BookingSlotBaseSaveInput), oldObj, input, "CtnList"); } else { var c = _repBase.AsQueryable().Where(x => x.SLOT_BOOKING_NO == input.SLOT_BOOKING_NO).Count(); if (c > 0) { throw Oops.Bah("订舱编号已存在"); } model = input.Adapt(); await _repBase.InsertAsync(model); foreach (var ctn in input.CtnList) { var newCtn = ctn.Adapt(); newCtn.SLOT_ID = model.Id; await _repCtn.InsertAsync(newCtn); } await InsLog("Add", model.Id, "新增舱位"); } //更新库存 await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new BookingSlotStockUpdateModel { BOOKING_SLOT_TYPE = model.BOOKING_SLOT_TYPE, CARRIERID = model.CARRIERID, CONTRACT_NO = model.CONTRACT_NO, VESSEL = model.VESSEL, VOYNO = model.VOYNO })); return await Detail(model.Id); } /// /// 获取订舱舱位 /// /// /// [HttpGet("/BookingSlot/detail")] public async Task Detail(long id) { var slotBase = await _repBase.FirstOrDefaultAsync(u => u.Id == id); var ctns = await _repCtn.Where(x => x.SLOT_ID == id).ToListAsync(); var rtn = slotBase.Adapt(); rtn.CtnList = ctns.Adapt>(); List list = new List(); var main = await _repBookingLog.AsQueryable().Where(u => u.BookingId == slotBase.Id).ToListAsync(); var mailidlist = main.Select(x => x.Id).ToList(); list = main.Adapt>(); if (list != null) { var bookinglogdetail = await _repBookingLogDetail.AsQueryable().Where(x => mailidlist.Contains(x.PId)).ToListAsync(); foreach (var item in list) { var details = bookinglogdetail.Where(x => x.PId == item.Id).ToList(); item.details = details; } } rtn.LogList = list; return rtn; } #region 对外接口 /// /// 舱位接收保存、取消接口 /// /// [HttpPost("/BookingSlot/ApiReceive"), AllowAnonymous, ApiUser] public async Task ApiReceive(BookingSlotBaseApiDto dto) { long id = 0; //接口方法直接调用save、delete等方法会报错,可能因为非token授权登录导致,故重写一遍保存、删除代码 if (dto.OpType == "add" || dto.OpType == "update" || dto.OpType == "del") { BookingSlotBase model = null; if (dto.OpType == "add") { var c = _repBase.AsQueryable().Filter(null, true).Where(x => x.IsDeleted == false && x.TenantId == UserManager.TENANT_ID && x.SLOT_BOOKING_NO == dto.DataObj.SLOT_BOOKING_NO).Count(); if (c > 0) { throw Oops.Bah("订舱编号已存在"); } model = dto.DataObj.Adapt(); await _repBase.InsertAsync(model); id = model.Id; foreach (var ctn in dto.DataObj.CtnList) { var newCtn = ctn.Adapt(); newCtn.SLOT_ID = model.Id; await _repCtn.InsertAsync(newCtn); } await InsLog("Add", model.Id, "新增舱位"); } else if (dto.OpType == "update") { model = await _repBase.AsQueryable().Filter(null, true).FirstAsync(x => x.IsDeleted == false && x.TenantId == UserManager.TENANT_ID && x.SLOT_BOOKING_NO == dto.DataObj.SLOT_BOOKING_NO); if (model == null) { throw Oops.Bah($"未找到订舱编号为 {dto.DataObj.SLOT_BOOKING_NO} 的数据"); } var oldObj = model.Adapt(); dto.DataObj.Adapt(model); await _repBase.UpdateAsync(model); await _repCtn.DeleteAsync(x => x.SLOT_ID == model.Id); foreach (var ctn in dto.DataObj.CtnList) { var newCtn = ctn.Adapt(); newCtn.SLOT_ID = model.Id; await _repCtn.InsertAsync(newCtn); } await InsLog("Update", model.Id, typeof(BookingSlotBaseApiSaveDto), oldObj, dto.DataObj, "CtnList"); } else if (dto.OpType == "del") { var slotNO = dto.DataObj.SLOT_BOOKING_NO; model = await _repBase.AsQueryable().Filter(null, true).FirstAsync(x => x.IsDeleted == false && x.TenantId == UserManager.TENANT_ID && x.SLOT_BOOKING_NO == slotNO); if (model == null) { throw Oops.Bah($"未找到订舱编号为 {slotNO} 的数据"); } model.IsDeleted = true; await _repBase.UpdateAsync(model); var ctns = await _repCtn.AsQueryable().Filter(null, true).Where(x => x.IsDeleted == false && x.TenantId == UserManager.TENANT_ID && x.SLOT_ID == model.Id).ToListAsync(); foreach (var ctn in ctns) { ctn.IsDeleted = true; await _repCtn.UpdateAsync(ctn); } await InsLog("Del", model.Id, "取消舱位"); } //更新库存 await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new BookingSlotStockUpdateModel { BOOKING_SLOT_TYPE = model.BOOKING_SLOT_TYPE, CARRIERID = model.CARRIERID, CONTRACT_NO = model.CONTRACT_NO, VESSEL = model.VESSEL, VOYNO = model.VOYNO })); } else { throw Oops.Bah("操作类型参数有误"); } return id; } #endregion /// /// 插入日志(仅显示一条文本信息) /// /// /// /// /// [NonAction] private async Task InsLog(string type, long slotId, string status) { var bid = await _repBookingLog.InsertReturnSnowflakeIdAsync(new BookingLog { Type = type, BookingId = slotId, TenantId = Convert.ToInt64(UserManager.TENANT_ID), CreatedTime = DateTime.Now, CreatedUserId = UserManager.UserId, CreatedUserName = UserManager.Name, Module = "Slot" }); if (!string.IsNullOrEmpty(status)) { await _repBookingLogDetail.InsertReturnSnowflakeIdAsync(new BookingLogDetail { PId = bid, Field = "", OldValue = "", NewValue = status, }); } } /// /// 插入日志(比对修改内容) /// /// /// /// /// /// /// /// [NonAction] private async Task InsLog(string type, long id, Type objType, object objOld, object objNew, params string[] excepProp) { var bid = await _repBookingLog.InsertReturnSnowflakeIdAsync(new BookingLog { Type = type, BookingId = id, TenantId = Convert.ToInt64(UserManager.TENANT_ID), CreatedTime = DateTime.Now, CreatedUserId = UserManager.UserId, CreatedUserName = UserManager.Name, Module = "Slot" }); foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(objType)) { if (excepProp.Contains(descriptor.Name)) { continue; } var compResult = false; var oldValue = descriptor.GetValue(objOld); var newValue = descriptor.GetValue(objNew); if (oldValue != null && newValue != null) { if (descriptor.PropertyType == typeof(string)) { compResult = oldValue.ToString() == newValue.ToString(); } else if (descriptor.PropertyType == typeof(DateTime) || descriptor.PropertyType == typeof(DateTime?)) { compResult = Convert.ToDateTime(oldValue) == Convert.ToDateTime(newValue); } else if (descriptor.PropertyType == typeof(decimal) || descriptor.PropertyType == typeof(float) || descriptor.PropertyType == typeof(double) || descriptor.PropertyType == typeof(decimal?) || descriptor.PropertyType == typeof(float?) || descriptor.PropertyType == typeof(double?)) { compResult = Convert.ToDecimal(oldValue) == Convert.ToDecimal(newValue); } else if (descriptor.PropertyType == typeof(int) || descriptor.PropertyType == typeof(long) || descriptor.PropertyType == typeof(int?) || descriptor.PropertyType == typeof(long?)) { compResult = Convert.ToInt64(oldValue) == Convert.ToInt64(newValue); } } else { compResult = oldValue == newValue; } if (!compResult) { var fieldName = descriptor.Name; if (!string.IsNullOrWhiteSpace(descriptor.Description)) { fieldName = descriptor.Description; } await _repBookingLogDetail.InsertReturnSnowflakeIdAsync(new BookingLogDetail { PId = bid, Field = fieldName, OldValue = $"{oldValue}", NewValue = $"{newValue}", }); } } } #endregion #region 库存 /// /// 库存查询 /// /// /// [HttpPost("/BookingSlot/pageStock")] public async Task PageStock(BookingSlotStockPageInput input) { var entities = await _repStock.AsQueryable() .WhereIF(!string.IsNullOrEmpty(input.VESSEL), u => u.VESSEL.Contains(input.VESSEL)) .WhereIF(!string.IsNullOrEmpty(input.VOYNO), u => u.VOYNO.Contains(input.VOYNO)) .WhereIF(!string.IsNullOrEmpty(input.CARRIER), u => u.CARRIER.Contains(input.CARRIER)) .WhereIF(!string.IsNullOrEmpty(input.CTN_STAT), u => u.CTN_STAT.Contains(input.CTN_STAT)) .WhereIF(input.ETD_START.HasValue, u => u.ETD >= input.ETD_START.Value) .WhereIF(input.ETD_END.HasValue, u => u.ETD < input.ETD_END.Value.AddDays(1)) .WhereIF(input.ETA_START.HasValue, u => u.ETA >= input.ETA_START.Value) .WhereIF(input.ETA_END.HasValue, u => u.ETA < input.ETA_END.Value.AddDays(1)) .ToPagedListAsync(input.PageNo, input.PageSize); var result = entities.Adapt>(); return result.XnPagedResult(); } /// /// 刷新库存统计 /// /// [HttpPost("/BookingSlot/refreshStock")] public async Task RefreshStock(BookingSlotStockUpdateModel input) { //更新库存 await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", input)); } #endregion #region 舱位引入 /// /// 查询可用的舱位及箱子 /// [HttpGet("/BookingSlot/getAvailableSlots")] public async Task> GetAvailableSlots([FromQuery] BookingSlotBaseDto input) { return await GetAvailableSlots(input, null); } /// /// 查询可用的舱位及箱子列表 /// /// 筛选条件1:舱位信息、箱型 /// 筛选条件2:舱位主键列表 /// 可用的舱位列表(含可用的箱子列表) [NonAction] public async Task> GetAvailableSlots(BookingSlotBaseDto slotInput = null, List slotIdListInput = null) { slotInput ??= new(); slotIdListInput ??= new(); string[] ctnCodeList = null; if (!string.IsNullOrEmpty(slotInput.CTN_STAT)) { ctnCodeList = slotInput.CTN_STAT.Split(','); } // 1. 【舱位基础表】与【箱子表】做关联,并根据【舱位主键】、【箱型】做分组,统计出【总的箱量】,作为queryable1 var queryable1 = _repBase.Context.Queryable((bas, ctn) => bas.Id == ctn.SLOT_ID) .WhereIF(!string.IsNullOrEmpty(slotInput.PORTLOAD), bas => bas.PORTLOAD.Contains(slotInput.PORTLOAD)) .WhereIF(!string.IsNullOrEmpty(slotInput.PORTDISCHARGE), bas => bas.PORTLOAD.Contains(slotInput.PORTLOAD)) .WhereIF(!string.IsNullOrEmpty(slotInput.VESSEL), bas => bas.VESSEL.Contains(slotInput.VESSEL)) .WhereIF(!string.IsNullOrEmpty(slotInput.VOYNO), bas => bas.VOYNO.Contains(slotInput.VOYNO)) .WhereIF(!string.IsNullOrEmpty(slotInput.CARRIAGE_TYPE), bas => bas.CARRIAGE_TYPE == slotInput.CARRIAGE_TYPE) .WhereIF(!string.IsNullOrEmpty(slotInput.BOOKING_SLOT_TYPE), bas => bas.BOOKING_SLOT_TYPE == slotInput.BOOKING_SLOT_TYPE) .WhereIF(ctnCodeList != null, (bas, ctn) => ctnCodeList.Contains(ctn.CTNCODE)) .WhereIF(slotIdListInput.Any(), (bas) => slotIdListInput.Contains(bas.Id)) .GroupBy((bas, ctn) => new { bas.Id, ctn.CTNCODE }) .Select((bas, ctn) => new { id = bas.Id, ctnCode = ctn.CTNCODE, numAll = SqlFunc.AggregateSum(ctn.CTNNUM) }) .MergeTable(); // 2. 【已引入舱位表】与【已使用的箱子表】做关联,并根据【舱位主键】、【箱型】做分组,统计出【已使用的箱量】,作为queryable2 var queryable2 = _repBase.Context.Queryable((alc, ctn) => alc.Id == ctn.SLOT_ALLOC_ID) .GroupBy((alc, ctn) => new { alc.BOOKING_SLOT_ID, ctn.CTNCODE }) .Select((alc, ctn) => new { id = alc.BOOKING_SLOT_ID, ctnCode = ctn.CTNCODE, numUse = SqlFunc.AggregateSum(ctn.CTNNUM) }) .MergeTable(); // 3. 将queryable1 左连接 queryable2,使用【总的箱量】减去【已使用的箱量】,得到【剩余的箱量】,添加【剩余的箱量】> 0 的条件,作为queryable3 var queryable3 = queryable1.LeftJoin(queryable2, (q1, q2) => q1.id == q2.id && q1.ctnCode == q2.ctnCode) .Select((q1, q2) => new { q1.id, q1.ctnCode, numResidue = SqlFunc.IsNull(q1.numAll - q2.numUse, q1.numAll) }) .MergeTable() .Where(r => r.numResidue > 0); // 4. 执行ToList(),得到可用的【舱位主键】、【箱型】、【箱量】列表 var canUselist = await queryable3.ToListAsync(); // 查询舱位列表 var baseIdList = canUselist.Select(c => c.id); List baseList = await _repBase.AsQueryable() .Where(u => baseIdList.Contains(u.Id)) .ToListAsync(); List ctnCodeCache = await _cache.GetAllCodeCtn(); // 构建结果 List result = baseList.Adapt>(); foreach (var item in result) { var ctnList = canUselist.Where(c => c.id == item.Id).ToList(); if (ctnList?.Any() == true) { item.CtnList = ctnList.Select(c => new BookingSlotCtnDto() { CTNCODE = c.ctnCode, CTNNUM = c.numResidue, CTNALL = ctnCodeCache.FirstOrDefault(e => e.Code == c.ctnCode)?.Name ?? throw new Exception($"舱位信息中存在未收录的箱型:{c.ctnCode},需要在箱型字典中补充"), }).ToList(); } } return result; } /// /// 检查指定订舱记录,是否可以引入舱位列表 /// /// 待引入的舱位列表 /// 待关联的订舱记录 /// (指定订舱记录是否已经引入过舱位数据,现有舱位及箱子是否满足需求,提示信息) [NonAction] public async Task<(bool isExists, bool isEnough, string message)> CheckImportSlots(List slots, long bookingOrderId) { slots ??= new List(); // 判断是否已存在引用关系 if (bookingOrderId != 0 && await _repAllocation.IsExistsAsync(a => a.BOOKING_ID == bookingOrderId)) { return (true, false, $"订舱主键{bookingOrderId}已引用舱位"); } var slotIdList = slots.Select(s => s.Id).ToList(); // 查询可用舱位及箱子列表 var latestSlotList = await GetAvailableSlots(null, slotIdList); // 判断余量是否满足需求 foreach (var inSlotItem in slots) { var latestSlot = latestSlotList.FirstOrDefault(b => b.Id == inSlotItem.Id); if (latestSlot == null) { return (false, false, $"订舱编号为{inSlotItem.SLOT_BOOKING_NO}的舱位已被占用或取消,请重新引入"); } if (inSlotItem.CtnList?.Any() == false) { return (false, false, $"每个舱位至少选择一个箱子,订舱编号:{inSlotItem.SLOT_BOOKING_NO}"); } foreach (var inCtnItem in inSlotItem.CtnList) { var latestCtn = latestSlot.CtnList.FirstOrDefault(c => c.CTNCODE == inCtnItem.CTNCODE); if (latestCtn == null) { return (false, false, $"订舱编号为{latestSlot.SLOT_BOOKING_NO}的舱位中,箱型为{inCtnItem.CTNALL}的箱子已被占用或取消,请重新引入"); } if (latestCtn.CTNNUM < inCtnItem.CTNNUM) { return (false, false, $"订舱编号为{latestSlot.SLOT_BOOKING_NO}的舱位中,箱型为{inCtnItem.CTNALL}的箱子当前剩余{latestCtn.CTNNUM}个,少于所需的{inCtnItem.CTNNUM}个,请重新引入"); } } } return (false, true, $"可以引入"); } /// /// 为指定订舱记录引入舱位信息 /// /// 待引入的舱位列表 /// 待关联的订舱记录 /// 是否进行剩余量检查 /// (是否成功,提示消息) [NonAction] public async Task<(bool isSuccess, string message)> ImportSlots(List slots, long bookingOrderId, bool isCheck) { slots ??= new List(); if (isCheck) { (bool isExists, bool isEnough, string message) checkResult = await CheckImportSlots(slots, bookingOrderId); if (checkResult.isExists || !checkResult.isEnough) return (false, checkResult.message); } var slotIdList = slots.Select(s => s.Id).ToList(); List latestSlotList = await _repBase.AsQueryable().Where(b => slotIdList.Contains(b.Id)).ToListAsync(); foreach (var inSlotItem in slots) { var latestSlot = latestSlotList.First(b => b.Id == inSlotItem.Id); var config = new TypeAdapterConfig(); config.ForType() .Ignore(dest => dest.CreatedTime) .Ignore(dest => dest.UpdatedTime) .Ignore(dest => dest.CreatedUserId) .Ignore(dest => dest.UpdatedUserId) .Ignore(dest => dest.CreatedUserName) .Ignore(dest => dest.UpdatedUserName) .Ignore(dest => dest.TenantId) .Ignore(dest => dest.TenantName); var newSlotAllocation = latestSlot.Adapt(config); newSlotAllocation.Id = 0; newSlotAllocation.BOOKING_SLOT_ID = latestSlot.Id; newSlotAllocation.BOOKING_ID = bookingOrderId; newSlotAllocation.ALLO_BILL_NO = latestSlot.SLOT_BOOKING_NO; newSlotAllocation.FINAL_BILL_NO = latestSlot.SLOT_BOOKING_NO; await _repAllocation.InsertAsync(newSlotAllocation); var insertCtnList = inSlotItem.CtnList.Select(c => new BookingSlotAllocationCtn() { SLOT_ALLOC_ID = newSlotAllocation.Id, CTNCODE = c.CTNCODE, CTNALL = c.CTNALL, CTNNUM = c.CTNNUM }); await _repAllocationCtn.InsertAsync(insertCtnList); // 更新库存 await _publisher.PublishAsync(new ChannelEventSource("BookingSlotStock:Update", new Event.BookingSlotStockUpdateModel { BOOKING_SLOT_TYPE = latestSlot.BOOKING_SLOT_TYPE, CARRIERID = latestSlot.CARRIERID, CONTRACT_NO = latestSlot.CONTRACT_NO, VESSEL = latestSlot.VESSEL, VOYNO = latestSlot.VOYNO })); } return (true, "引入成功"); } #endregion #region 获取附件 /// /// 获取附件 /// /// 舱位主键 /// 返回附件列表 [HttpGet("/BookingSlot/GetFile")] public async Task> GetFile(long id) { var list = await _bookingfile.AsQueryable().Filter(null, true) .Where(u => u.BookingId == id && u.Moudle == "BookingSlot").ToListAsync(); return list; } #endregion #region 舱位 /// /// 分页查询订舱舱位 /// /// /// [HttpPost("/BookingSlot/page")] public async Task Page(BookingSlotBasePageInput input) { var entities = await _repBase.AsQueryable() .WhereIF(!string.IsNullOrEmpty(input.SLOT_BOOKING_NO), u => u.SLOT_BOOKING_NO.Contains(input.SLOT_BOOKING_NO)) .WhereIF(!string.IsNullOrEmpty(input.VESSEL), u => u.VESSEL.Contains(input.VESSEL)) .WhereIF(!string.IsNullOrEmpty(input.VOYNO), u => u.VOYNO.Contains(input.VOYNO)) .WhereIF(!string.IsNullOrEmpty(input.PORTLOAD), u => u.PORTLOAD.Contains(input.PORTLOAD)) .WhereIF(!string.IsNullOrEmpty(input.PORTDISCHARGE), u => u.PORTLOAD.Contains(input.PORTLOAD)) .WhereIF(!string.IsNullOrEmpty(input.CARRIER), u => u.CARRIER.Contains(input.CARRIER)) .WhereIF(!string.IsNullOrEmpty(input.LANENAME), u => u.LANENAME.Contains(input.LANENAME)) .WhereIF(!string.IsNullOrEmpty(input.CARRIAGE_TYPE), u => u.CARRIAGE_TYPE == input.CARRIAGE_TYPE) .WhereIF(!string.IsNullOrEmpty(input.BOOKING_SLOT_TYPE), u => u.BOOKING_SLOT_TYPE == input.BOOKING_SLOT_TYPE) .WhereIF(!string.IsNullOrEmpty(input.CTN_STAT), u => u.CTN_STAT.Contains(input.CTN_STAT)) .WhereIF(!string.IsNullOrEmpty(input.VGM_RLT_STAT), u => u.VGM_RLT_STAT == input.VGM_RLT_STAT) .WhereIF(!string.IsNullOrEmpty(input.SI_RLT_STAT), u => u.SI_RLT_STAT == input.SI_RLT_STAT) .WhereIF(input.ETD_START.HasValue, u => u.ETD >= input.ETD_START.Value) .WhereIF(input.ETD_END.HasValue, u => u.ETD < input.ETD_END.Value.AddDays(1)) .WhereIF(input.ETA_START.HasValue, u => u.ETA >= input.ETA_START.Value) .WhereIF(input.ETA_END.HasValue, u => u.ETA < input.ETA_END.Value.AddDays(1)) .ToPagedListAsync(input.PageNo, input.PageSize); var result = entities.Adapt>(); return result.XnPagedResult(); } #endregion } }