.net Core增删改查(API)

项目背景WMS  智能仓储管理系统:


1.实现简单的增删改查:


1.1. Entities: 
 

using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace Qhbx.Tibet.Wms.Entities.Basic
{
    /// <summary>
    /// 货物信息
    /// </summary>
    [Table("bx_wms_goods")]
    public class GoodsEntity : Entity
    {
        /// <summary>
        /// 货物类别
        /// </summary>
        [Required]
        [StringLength(32)]
        [Description("货物类别")]
        public string GcId { get; set; }
        /// <summary>
        /// 货物编号
        /// </summary>
        [Required]
        [StringLength(32)]
        [Description("货物编号"), UniqueIndexKey]
        public string GoodsCode { get; set; }
        /// <summary>
        /// 货物名称
        /// </summary>
        [Required]
        [StringLength(100)]
        [Description("货物名称")]
        public string GoodsName { get; set; }
        /// <summary>
        /// 内包装数量
        /// </summary>
        [Description("内包装数量")]
        public double InnerPackingQuantity { get; set; }
        /// <summary>
        /// 内包装货物体积
        /// </summary>
        [Description("内包装货物体积")]
        public double InnerPackingVolume { get; set; }
        /// <summary>
        /// 内包装货物重量
        /// </summary>
        [Description("内包装货物重量")]
        public double InnerPackingWeight { get; set; }
        /// <summary>
        /// 材质
        /// </summary>
        [StringLength(32)]
        [Description("材质")]
        public string Material { get; set; }
        /// <summary>
        /// 最大库存量
        /// </summary>
        [Description("最大库存量")]
        public double MaxStock { get; set; }
        /// <summary>
        /// 最小库存量
        /// </summary>
        [Description("最小库存量")]
        public double MinStock { get; set; }
        /// <summary>
        /// 外包装数量
        /// </summary>
        [Description("外包装数量")]
        public double OuterPackingQuantity { get; set; }
        /// <summary>
        /// 外包装货物重量
        /// </summary>
        [Description("外包装货物重量")]
        public double OuterPackingWeight { get; set; }
        /// <summary>
        /// 价格
        /// </summary>
        [Description("价格")]
        public double Price { get; set; }
        /// <summary>
        /// 重量
        /// </summary>
        [Description("重量")]
        public double Weight { get; set; }
        /// <summary>
        /// 保质期
        /// </summary>
        [Description("保质期")]
        public double ShelfLife { get; set; }
        /// <summary>
        /// 规格
        /// </summary>
        [Required]
        [StringLength(50)]
        [Description("规格")]
        public string Specs { get; set; }
        /// <summary>
        /// 供应商编号
        /// </summary>
        [Required]
        [StringLength(32)]
        [Description("供应商编号")]
        public string SupplierId { get; set; }

        /// <summary>
        /// 状态
        /// </summary>
        [Description("状态(0启用1禁用)")]
        public override Status Status { get; set; }

        /// <summary>
        /// 是否删除(0未删除1已删除)
        /// </summary>
        [Description("是否删除(0未删除1已删除)")]
        public override DeleteStatus IsDelete { get; set; }
        /// <summary>
        /// 创建人
        /// </summary>
        [StringLength(32)]
        [Description("创建人")]
        public override string Creator { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        [Description("创建时间")]
        public override DateTime CreateDate { get; set; }
        /// <summary>
        /// 编辑人
        /// </summary>
        [StringLength(32)]
        [Description("编辑人")]
        public override string Updator { get; set; }
        /// <summary>
        /// 编辑时间
        /// </summary>
        [Description("编辑时间")]
        public override DateTime UpdateDate { get; set; }
    }
}
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace Qhbx.Tibet.Wms.Entities
{
    /// <summary>
    /// 实体类基类
    /// </summary>
    public abstract class Entity : IMapper
    {
        /// <summary>
        /// 编号
        /// </summary>
        [Key]
        [Required]
        [StringLength(32)]
        [Description("编号")]
        public virtual string Id { get; set; }
        /// <summary>
        /// 状态
        /// </summary>
        public virtual Status Status { get; set; }

        /// <summary>
        /// 是否删除(0未删除1已删除)
        /// </summary>
        public virtual DeleteStatus IsDelete { get; set; }
        /// <summary>
        /// 创建人id
        /// </summary>
        [StringLength(32)]
        public virtual string Creator { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        public virtual DateTime CreateDate { get; set; }
        /// <summary>
        /// 编辑人id
        /// </summary>
        [StringLength(32)]
        public virtual string Updator { get; set; }
        /// <summary>
        /// 编辑时间
        /// </summary>
        public virtual DateTime UpdateDate { get; set; }
    }
}


1.2 Model:
 

using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;

namespace Qhbx.Tibet.Wms.Models.Basic
{
    /// <summary>
    /// 货物信息的模型
    /// </summary>
    public class GoodsModel: IMapper
    {
        /// <summary>
        /// 编号
        /// </summary>
        [Key]
        [MaxLength(32, ErrorMessage = "编号的最大长度是32")]
        public virtual string Id { get; set; }
        /// <summary>
        /// 货物类别
        /// </summary>
        [Required]
        [MaxLength(32, ErrorMessage = "货物类别的最大长度是32")]
        public string GcId { get; set; }
        /// <summary>
        /// 货物类别名称
        /// </summary>
        public string GcName { get; set; }
        /// <summary>
        /// 货物编号
        /// </summary>
        [Required]
        [MaxLength(32, ErrorMessage = "货物编号的最大长度是32")]
        public string GoodsCode { get; set; }
        /// <summary>
        /// 货物名称
        /// </summary>
        [Required]
        [MaxLength(100, ErrorMessage = "货物名称的最大长度是100")]
        public string GoodsName { get; set; }
        /// <summary>
        /// 内包装数量
        /// </summary>
        public double InnerPackingQuantity { get; set; }
        /// <summary>
        /// 内包装货物体积
        /// </summary>
        public double InnerPackingVolume { get; set; }
        /// <summary>
        /// 内包装货物重量
        /// </summary>
        public double InnerPackingWeight { get; set; }
        /// <summary>
        /// 材质
        /// </summary>
        [MaxLength(32, ErrorMessage = "材质的最大长度是32")]
        public string Material { get; set; }
        /// <summary>
        /// 最大库存量
        /// </summary>
        public double MaxStock { get; set; }
        /// <summary>
        /// 最小库存量
        /// </summary>
        public double MinStock { get; set; }
        /// <summary>
        /// 外包装数量
        /// </summary>
        public double OuterPackingQuantity { get; set; }
        /// <summary>
        /// 外包装货物重量
        /// </summary>
        public double OuterPackingWeight { get; set; }
        /// <summary>
        /// 价格
        /// </summary>
        public double Price { get; set; }
        /// <summary>
        /// 重量
        /// </summary>
        public double Weight { get; set; }
        /// <summary>
        /// 保质期
        /// </summary>
        public double ShelfLife { get; set; }
        /// <summary>
        /// 规格
        /// </summary>
        [Required]
        [MaxLength(50, ErrorMessage = "规格的最大长度是50")]
        public string Specs { get; set; }
        /// <summary>
        /// 供应商编号
        /// </summary>
        [Required]
        [MaxLength(32)]
        public string SupplierId { get; set; }
        /// <summary>
        /// 供应商名称
        /// </summary>
        public string SupplierName { get; set; }

        /// <summary>
        /// 状态(0启用,1禁用)
        /// </summary>
        [Range(0, 1, ErrorMessage = "{0}只能是0或者1【0启用,1禁用】")]
        public Status Status { get; set; }
        /// <summary>
        /// 状态名称
        /// </summary>
        public string StatusText => this.Status.GetDescription();
        /// <summary>
        /// 是否删除(0未删除1已删除)
        /// </summary>
        [Range(0, 1, ErrorMessage = "{0}值只能是0或者1【0未删除,1已删除】")]
        public DeleteStatus IsDelete { get; set; }
        /// <summary>
        /// 状态名称
        /// </summary>
        public string IsDeleteText => this.IsDelete.GetDescription();
       
        /// <summary>
        /// 创建人
        /// </summary>
        [MaxLength(32, ErrorMessage = "创建人的最大长度是32")]
        public string Creator { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateDate { get; set; }
        /// <summary>
        /// 编辑人
        /// </summary>
        [MaxLength(32, ErrorMessage = "编辑人的最大长度是32")]
        public string Updator { get; set; }
        /// <summary>
        /// 编辑时间
        /// </summary>
        public DateTime UpdateDate { get; set; }
    }
}

1.3 API-Controllers
 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Api.Filters;
using Qhbx.Tibet.Wms.Api.Models;
using Qhbx.Tibet.Wms.Core;
using Qhbx.Tibet.Wms.Entities.Basic;
using Qhbx.Tibet.Wms.IServices.Basic;
using Qhbx.Tibet.Wms.Models;
using Qhbx.Tibet.Wms.Models.Basic;

namespace Qhbx.Tibet.Wms.Api.Controllers
{
    /// <summary>
    /// 货物
    /// </summary>
    [Route("api/[controller]/[action]")]
    [ApiController]
    [Authorize]
    [FunctionAuthorize(FunctionConst.GoodsFuncCode)]
    public class GoodsController : ControllerBase
    {
        private IGoodsService _service { get; }
        private ILogger _log { get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="service"></param>
        /// <param name="logger"></param>
        public GoodsController(IGoodsService service, ILogger<GoodsController> logger)
        {
            _service = service;
            _log = logger;
        }

        /// <summary>
        /// 获取货物列表分页数据
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页显示条数</param>
        /// <param name="key">查询条件(货物编号、货物名称、货物类别、供应商编号)</param>
        /// <returns></returns>
        [HttpGet]
        [Log("获取货物列表分页数据")]
        public Page<GoodsModel> GetPageList(int pageIndex = 1, int pageSize = 10, string key = "")
        {
            return  _service.GetPageList(pageIndex, pageSize, key);
        }
        /// <summary>
        /// 获取货物列表数据
        /// </summary>
        /// <param name="key">查询条件(Name或Code或Id)</param>
        /// <returns></returns>
        [HttpGet]
        [Log("获取货物列表数据")]
        public async Task<List<GoodsModel>> GetList(string key = "")
        {
            return await _service.GetList(key);
        }
        /// <summary>
        /// 添加货物信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Log("添加货物信息")]
        public async Task<IActionResult> Add(GoodsModel model)
        {
            model.Id = GuidUtil.FormatN();
            model.Creator = User.GetUserId();
            model.CreateDate = System.DateTime.Now;
            model.UpdateDate = System.DateTime.Now;
            model.Updator = User.GetUserId();
            await _service.AddAsync(model);
            return Ok();
        }
        /// <summary>
        /// 更新货物信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        [Log("更新货物信息")]
        public async Task<IActionResult> Edit(GoodsModel model)
        {
            model.UpdateDate = System.DateTime.Now;
            model.Updator = User.GetUserId();
            await _service.EditAsync(model);
            return Ok();
        }
        /// <summary>
        /// 批量删除货物信息
        /// </summary>
        /// <param name="ids">主键ID</param>
        /// <returns></returns>
        [HttpDelete]
        [Log("删除货物信息")]
        public async Task<IActionResult> Delete(string[] ids)
        {
            var updator = User.GetUserId();
            await _service.DeleteAsync(ids, updator);
            return Ok();
        }
    }
}

1.4  IService
 

using Qhbx.Tibet.Wms.Entities.Basic;
using Qhbx.Tibet.Wms.Models;
using Qhbx.Tibet.Wms.Models.Basic;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Qhbx.Tibet.Wms.IServices.Basic
{
    /// <summary>
    /// 货物的服务接口
    /// </summary>
    public interface IGoodsService : IService<GoodsEntity>
    {
        /// <summary>
        /// 获取货物列表分页数据
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页显示条数</param>
        /// <param name="key">查询条件货(物编号、货物名称、货物类别、供应商编号)</param>
        /// <returns></returns>
        Page<GoodsModel> GetPageList(int pageIndex = 1, int pageSize = 10, string key = "");

        /// <summary>
        /// 获取货物列表数据
        /// </summary>
        /// <param name="key">查询条件</param>
        /// <returns></returns>
        Task<List<GoodsModel>> GetList(string key = "");

        /// <summary>
        /// 添加货物信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task AddAsync(GoodsModel entity);

        /// <summary>
        /// 更新货物信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        Task EditAsync(GoodsModel entity);

        /// <summary>
        /// 批量删除货物信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        Task DeleteAsync(string[] ids,string updator);
    }
}

1.5 Service
 

using Microsoft.EntityFrameworkCore;
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using Qhbx.Tibet.Wms.Entities.Basic;
using Qhbx.Tibet.Wms.IServices;
using Qhbx.Tibet.Wms.IServices.Basic;
using Qhbx.Tibet.Wms.Models;
using Qhbx.Tibet.Wms.Models.Basic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Qhbx.Tibet.Wms.Services.Basic
{
    /// <summary>
    /// 货物的服务基类
    /// </summary>
    public class GoodsService : IGoodsService
    {
        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="dbContext"></param>
        public GoodsService(DbContext dbContext, AutoMapper.IMapper mapper)
        {
            Context = dbContext;
            Mapper = mapper;
        }
        /// <summary>
        /// 数据库上下文
        /// </summary>
        public DbContext Context { get; set; }
        public AutoMapper.IMapper Mapper { get; set; }

        /// <summary>
        /// 添加货物信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public async Task AddAsync(GoodsModel model)
        {
            if (await this.ContainsAsync(x => x.GoodsCode == model.GoodsCode && x.IsDelete == DeleteStatus.Normal))
            {
                throw new CustomException($"货物编号【{model.GoodsCode}】已存在");
            }
            if (await this.ContainsAsync(x => x.GoodsName == model.GoodsName.Trim() && x.IsDelete == DeleteStatus.Normal))
            {
                throw new CustomException($"货物名称【{model.GoodsName}】已存在");
            }
            var entity = Mapper.Map<GoodsEntity>(model);
            await this.InsertAsync(entity);
        }
        /// <summary>
        /// 修改货物信息
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task EditAsync(GoodsModel model)
        {
            if (await this.Context.Set<GoodsEntity>().CountAsync(x => x.Id == model.Id && x.IsDelete == DeleteStatus.Normal) > 0)
            {
                if (await this.ContainsAsync(x => x.GoodsCode == model.GoodsCode && x.Id != model.Id && x.IsDelete == DeleteStatus.Normal))
                {
                    throw new CustomException($"货物编号【{model.GoodsCode}】已存在");
                }
                if (await this.ContainsAsync(x => x.GoodsName == model.GoodsName.Trim() && x.Id != model.Id && x.IsDelete == DeleteStatus.Normal))
                {
                    throw new CustomException($"货物名称【{model.GoodsName}】已存在");
                }
                var entity = Mapper.Map<GoodsEntity>(model);
                await this.UpdateAsync(entity);
            }
            else
            {
                throw new CustomException("该货物不存在!");
            }
        }


        /// <summary>
        /// 获取货物列表分页数据
        /// </summary>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页显示条数</param>
        /// <param name="key">查询条件(货物编号、货物名称、货物类别、供应商编号)</param>
        /// <returns></returns>
        public Page<GoodsModel> GetPageList(int pageIndex = 1, int pageSize = 10, string key = "")
        {
            Expression<Func<GoodsEntity, bool>> predicate = e => e.IsDelete == DeleteStatus.Normal;
            if (!string.IsNullOrWhiteSpace(key))
                predicate = predicate.And(x => x.GoodsCode.Contains(key) || x.GoodsName.Contains(key) || x.GcId.Contains(key) || x.SupplierId.Contains(key));
            var goods = from good in this.Context.Set<GoodsEntity>().Where(predicate)
                        join supplier in this.Context.Set<SupplierEntity>() on good.SupplierId equals supplier.Id into suppliers
                        from supplierDefault in suppliers.DefaultIfEmpty()
                        join dic in this.Context.Set<DictionaryEntity>() on good.GcId equals dic.Id into dics
                        from dicDefault in dics.DefaultIfEmpty()
                        select new GoodsModel
                        {
                            Id = good.Id,
                            GcId = good.GcId,
                            GcName = dicDefault.Name,
                            GoodsCode = good.GoodsCode,
                            GoodsName = good.GoodsName,
                            InnerPackingQuantity = good.InnerPackingQuantity,
                            InnerPackingVolume = good.InnerPackingVolume,
                            InnerPackingWeight = good.InnerPackingWeight,
                            Material = good.Material,
                            MaxStock = good.MaxStock,
                            MinStock = good.MinStock,
                            OuterPackingQuantity = good.OuterPackingQuantity,
                            OuterPackingWeight = good.OuterPackingWeight,
                            Price = good.Price,
                            Weight = good.Weight,
                            ShelfLife = good.ShelfLife,
                            Specs = good.Specs,
                            SupplierId = good.SupplierId,
                            SupplierName = supplierDefault.SupplierName,
                            Status = good.Status,
                            IsDelete = good.IsDelete,
                            Creator = good.Creator,
                            CreateDate = good.CreateDate,
                            Updator = good.Updator,
                            UpdateDate = good.UpdateDate
                        };
            if (pageIndex <= 0) pageIndex = 1;
            if (pageSize <= 0) pageSize = 10;
            IEnumerable<GoodsModel> datas = goods.OrderByDescending(g => g.UpdateDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            Page<GoodsModel> page = new Page<GoodsModel> { Index = pageIndex, Size = pageSize, Datas = datas, Amount = goods.Count() };
            return page;
        }
        /// <summary>
        /// 获取货物列表数据
        /// </summary>
        /// <param name="key">查询条件(Name或Code或Id)</param>
        /// <returns></returns>

        public async Task<List<GoodsModel>> GetList(string key = "")
        {
            Expression<Func<GoodsEntity, bool>> predicate = e => e.IsDelete == DeleteStatus.Normal;
            if (!string.IsNullOrWhiteSpace(key))
            {
                predicate = predicate.And(e => e.GoodsName.Contains(key) || e.GoodsCode.Contains(key) || e.Id == key);
            }
            var result = await this.WhereAsync(predicate);
            var list = Mapper.Map<List<GoodsModel>>(result);
            return list;
        }

        /// <summary>
        /// 批量删除货物信息
        /// </summary>
        /// <param name="models"></param>
        /// <returns></returns>
        public async Task DeleteAsync(string[] ids, string updator)
        {
            var goodss = await this.WhereAsync(a => ids.Contains(a.Id) && a.IsDelete == Core.EnumDefinitions.DeleteStatus.Normal);
            if (goodss.Count() == 0)
            {
                throw new CustomException("货物信息已经被删除,或者不存在!");
            }
            goodss = goodss.Select(a => { a.IsDelete = Core.EnumDefinitions.DeleteStatus.HasDelete; a.UpdateDate = DateTime.Now; a.Updator = updator; return a; });
            foreach (var goods in goodss)
            {
                await this.UpdateIncludeAsync(goods, a => new { a.IsDelete, a.UpdateDate, a.Updator });
            }
        }
    }
}

1.6 更新该实例的指定属性 的方法

/// <summary>
        /// 更新该实例的指定属性
        /// </summary>
        /// <typeparam name="Tproperty">属性类型</typeparam>
        /// <typeparam name="TEntity">实例类型</typeparam>
        /// <param name="sender"></param>
        /// <param name="entity">要更新的实例</param>
        /// <param name="propertys">要更新的属性</param>
        /// <returns></returns>
        public static async Task<int> UpdateIncludeAsync<Tproperty, TEntity>(this IService<TEntity> sender, TEntity entity, Expression<Func<TEntity, Tproperty>> propertys)
            where TEntity : class
        {
            if (propertys == null) return default;
            var entry = sender.Context.Entry<TEntity>(entity);
            var propertyNames = propertys.GetPropertys();
            foreach (var propName in propertyNames)
            {
                entry.Property(propName).IsModified = true;
            }
            return await sender.Context.SaveChangesAsync();
        }

2.一次性获取 1:多(入库单:入库单明细)信息 集合 使用GroupJoin对主子表集合进行关联
2.1一次性获取 1:多(入库单:入库单明细)信息  [先查主表,然后对主表进行分页,再通过主表分页后的数据获取其入库单明细信息,最后使用GroupJoin对主子表集合进行关联]
 

            Expression<Func<InStockDemandBillEntity, bool>> predicate = e => e.IsDelete == DeleteStatus.Normal;

            if (!string.IsNullOrWhiteSpace(key))
                predicate = predicate.And(x => x.DemandNo.Contains(key) || x.Id.Contains(key) || x.SupplierId.Contains(key));
            if (inStatus >= 0)
                predicate = predicate.And(x => x.InStockStatus == (InStockStatus)inStatus);//Enum的Equals不会转换为SQL语句
            if (planStartDate != null)
                predicate = predicate.And(x => x.PlanArrivalTime >= ConvertHelper.ConvertToDateTime((long)planStartDate));
            if (planEndDate != null)
                predicate = predicate.And(x => x.PlanArrivalTime <= ConvertHelper.ConvertToDateTime((long)planEndDate));
            if (actualStartDate != null)
                predicate = predicate.And(x => x.ActualArrivalTime >= ConvertHelper.ConvertToDateTime((long)actualStartDate));
            if (actualEndDate != null)
                predicate = predicate.And(x => x.ActualArrivalTime <= ConvertHelper.ConvertToDateTime((long)actualEndDate));

            //入库单信息
            var inStocks = from instock in this.Context.Set<InStockDemandBillEntity>().Where(predicate)
                           join supplier in this.Context.Set<SupplierEntity>() on instock.SupplierId equals supplier.Id into suppliers
                           from supplierDefault in suppliers.DefaultIfEmpty()
                           join area in this.Context.Set<WareHouseAreaEntity>() on instock.AreaId equals area.Id into areas
                           from areaDefault in areas.DefaultIfEmpty()
                           join dic in this.Context.Set<DictionaryEntity>() on instock.InstockGroup equals dic.Id into dics
                           from dicInstockGroup in dics.DefaultIfEmpty()
                           join dic_a in this.Context.Set<DictionaryEntity>() on instock.ActualInstockGroup equals dic_a.Id into dic_as
                           from dicActualInstockGroup in dic_as.DefaultIfEmpty()
                           join dic_i in this.Context.Set<DictionaryEntity>() on instock.InstockNature equals dic_i.Id into dic_is
                           from dicInstockNature in dic_is.DefaultIfEmpty()
                           select new InStockDemandBillModel
                           {
                               Id = instock.Id,
                               DemandNo = instock.DemandNo,
                               InstockGroup = instock.InstockGroup,
                               InstockGroupName = dicInstockGroup.Name,
                               OrderNo = instock.OrderNo,
                               PlanArrivalTime = instock.PlanArrivalTime,
                               ActualArrivalTime = instock.ActualArrivalTime,
                               ActualInstockGroup = instock.ActualInstockGroup,
                               ActualInstockGroupName = dicActualInstockGroup.Name,
                               DeliveryCompany = instock.DeliveryCompany,
                               DeliveryMan = instock.DeliveryMan,
                               Status = instock.Status,
                               InStockStatus = instock.InStockStatus,
                               SupplierId = instock.SupplierId,
                               SupplierName = supplierDefault.SupplierName,
                               VehicleNo = instock.VehicleNo,
                               InstockNature = instock.InstockNature,
                               InstockNatureName = dicInstockNature.Name,
                               GroundingGroup = instock.GroundingGroup,
                               AppointmentUser = instock.AppointmentUser,
                               AppointmentDate = instock.AppointmentDate,
                               CheckUser = instock.CheckUser,
                               CheckTime = instock.CheckTime,
                               TaskUser = instock.TaskUser,
                               TaskTime = instock.TaskTime,
                               AreaId = instock.AreaId,
                               AreaName = areaDefault.AreaName,
                               IsDelete = instock.IsDelete,
                               Creator = instock.Creator,
                               CreateDate = instock.CreateDate,
                               Updator = instock.Updator,
                               UpdateDate = instock.UpdateDate
                           };
            if (pageIndex <= 0) pageIndex = 1;
            if (pageSize <= 0) pageSize = 10;
            IEnumerable<InStockDemandBillModel> datas = inStocks.OrderByDescending(g => g.UpdateDate).Skip((pageIndex - 1) * pageSize).Take(pageSize);
            Page<InStockDemandBillModel> page = new Page<InStockDemandBillModel> { Index = pageIndex, Size = pageSize, Datas = datas.ToList(), Amount = inStocks.Count() };

            //入库单明细信息
            var inStockItems = from instockItem in this.Context.Set<InStockDemandBillItemEntity>()
                               join goods in this.Context.Set<GoodsEntity>() on instockItem.GoodsId equals goods.Id into goodses
                               from good in goodses.DefaultIfEmpty()
                               join unloadwayDic in this.Context.Set<DictionaryEntity>() on instockItem.UnloadWay equals unloadwayDic.Id into unloadways
                               from unloadway in unloadways.DefaultIfEmpty()
                               select new InStockDemandBillItemModel
                               {
                                   Id = instockItem.Id,
                                   InstockDemandBillId = instockItem.InstockDemandBillId,
                                   PlanArrivalQuantity = instockItem.PlanArrivalQuantity,
                                   ProductBatch = instockItem.ProductBatch,
                                   ActualArrivalQuantity = instockItem.ActualArrivalQuantity,
                                   ActualProductBatch = instockItem.ActualProductBatch,
                                   GoodsId = instockItem.GoodsId,
                                   GoodsName = good.GoodsName,
                                   PackingSpecs = instockItem.PackingSpecs,
                                   UnloadWay = instockItem.UnloadWay,
                                   UnloadWayName = unloadway.Name,
                                   IsDelete = instockItem.IsDelete,
                                   Creator = instockItem.Creator,
                                   CreateDate = instockItem.CreateDate,
                                   Updator = instockItem.Updator,
                                   UpdateDate = instockItem.UpdateDate
                               };

            page.Datas = page.Datas.GroupJoin<InStockDemandBillModel, InStockDemandBillItemModel, string, InStockDemandBillModel>(
                inStockItems, idb => idb.Id, isdbtm => isdbtm.InstockDemandBillId, (instock, instockbillitems) =>
                 {
                     InStockDemandBillModel inStockDemandBillModel = instock;
                     inStockDemandBillModel.InStockItems = instockbillitems;
                     return inStockDemandBillModel;
                 }
              );
            return page;

2.2 多表同时添加 采用事务处理

 /// <summary>
        /// 添加入库单
        /// </summary>
        /// <param name="inStockModel"></param>
        /// <returns></returns>
        public async Task AddAsync(InStockDemandBillModel inStockModel)
        {
            if (inStockModel.AppointmentDate.Date < DateTime.Now.Date)
            {
                throw new CustomException("预约日期不能小于当前日期");
            }
            if (inStockModel.PlanArrivalTime < System.DateTime.Now)
            {
                throw new CustomException("计划到货时间不能小于当前时间");
            }
            //入库单 数据添加
            var inStockEntity = Mapper.Map<InStockDemandBillEntity>(inStockModel);
            inStockEntity.Id = GuidUtil.FormatN();
            inStockEntity.DemandNo = CommonConst.RK.CreateBillCode();
            this.Context.Set<InStockDemandBillEntity>().Add(inStockEntity);
            //入库明细 数据添加
            foreach (var item in inStockModel.InStockItems)
            {
                var inStockItemEntity = Mapper.Map<InStockDemandBillItemEntity>(item);
                inStockItemEntity.Id = GuidUtil.FormatN();
                inStockItemEntity.InstockDemandBillId = inStockEntity.Id;
                this.Context.Set<InStockDemandBillItemEntity>().Add(inStockItemEntity);
            }
            //事务处理
            var tran = this.Context.Database.BeginTransaction();
            try
            {
                await this.Context.SaveChangesAsync();
                tran.Commit();
            }
            catch (Exception ex)
            {
                tran.Rollback();
                throw new CustomException($"添加入库单信息异常,异常信息:" + ex.Message);
            }

        }

3.其他代码段:
 

using Microsoft.EntityFrameworkCore;
using Qhbx.Common.Core;
using Qhbx.Tibet.Wms.Core;
using Qhbx.Tibet.Wms.Core.EnumDefinitions;
using Qhbx.Tibet.Wms.Entities.Basic;
using Qhbx.Tibet.Wms.Entities.OutStock;
using Qhbx.Tibet.Wms.Entities.Stock;
using Qhbx.Tibet.Wms.IServices;
using Qhbx.Tibet.Wms.IServices.OutStock;
using Qhbx.Tibet.Wms.IServices.Stock;
using Qhbx.Tibet.Wms.Models;
using Qhbx.Tibet.Wms.Models.OutStock;
using Qhbx.Tibet.Wms.Models.Stock;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Qhbx.Tibet.Wms.Services.OutStock
{
    /// <summary>
    /// 出库单接口实现类
    /// </summary>
    public class OutStockService : IOutStockService
    {
        public OutStockService(DbContext dbContext, AutoMapper.IMapper mapper,IStockService stockService)
        {
            Context = dbContext;
            Mapper = mapper;
            _stockService = stockService;
        }
        public DbContext Context { get; set; }
        public AutoMapper.IMapper Mapper { get; set; }
        public IStockService _stockService { get; set; }
        /// <summary>
        /// 新增预约出库单
        /// </summary>
        /// <param name="outmodel"></param>
        /// <returns></returns>
        public async Task AddAsync(OutstockDemandBillModel outmodel)
        {
            if (outmodel.AppointmentDate.Date < DateTime.Now.Date)
            {
                throw new CustomException("预约日期不能小于当前日期");
            }
            if (outmodel.PlanArrivalTime <= System.DateTime.Now)
            {
                throw new CustomException("计划出库时间应大于当前时间");
            }
            //对应业务数据处理
            var outStockEntity = Mapper.Map<OutstockDemandBillEntity>(outmodel);
            outStockEntity.Id = Guid.NewGuid().ToString("N");
            outStockEntity.DemandNo = BillExtend.CreateBillCode(CommonConst.CK);
            this.Context.Set<OutstockDemandBillEntity>().Add(outStockEntity);
            //明细数据处理
            foreach (var item in outmodel.Items)
            {
                var outStockItemEntity = Mapper.Map<OutstockDemandBillItemEntity>(item);
                outStockItemEntity.Id = Guid.NewGuid().ToString("N");
                outStockItemEntity.OutstockDemandBillId = outStockEntity.Id;
                Context.Set<OutstockDemandBillItemEntity>().Add(outStockItemEntity);
            }
            //事物操作
            var tran = Context.Database.BeginTransaction();
            try
            {
                await Context.SaveChangesAsync();
                tran.Commit();
            }
            catch (Exception ex)
            {
                tran.Rollback();
                throw new CustomException(ex.Message);
            }
        }
        /// <summary>
        /// 删除预约出库单
        /// </summary>
        /// <param name="outOrderIds">预约出库单Id集合</param>
        /// <param name="userId">操作人</param>
        /// <returns></returns>
        public async Task DeleteAsync(IEnumerable<string> outOrderIds, string userId)
        {
            if (outOrderIds.Count() == 0)
            {
                throw new CustomException("请传入有效的出库单Id");
            }
            var outStockEntitys = this.Context.Set<OutstockDemandBillEntity>().Where(x => x.IsDelete == DeleteStatus.Normal && outOrderIds.Contains(x.Id)).ToList();
            if (outStockEntitys.Count() == 0)
            {
                throw new CustomException("未找到可删除的记录,请检查参数是否传递正确。");
            }
            var noDeleteItems = outStockEntitys.Where(x => x.OutStatus != OutOderStatus.TodoAllot);
            if (noDeleteItems.Count() > 0)
            {
                throw new CustomException($" { string.Join(",", noDeleteItems.Select(x => x.DemandNo))}当前状态不可删除");
            }
            await Context.SaveChangesAsync();
            foreach (var item in outStockEntitys)
            {
                item.IsDelete = Core.EnumDefinitions.DeleteStatus.HasDelete;
                item.Updator = userId;
                item.UpdateDate = DateTime.Now;
                await this.UpdateAsync(item);
            }
        }
        /// <summary>
        /// 编辑预约出库单
        /// </summary>
        /// <param name="outmodel">操作对象</param>
        /// <param name="oprerType">操作类型(0编辑预约单 1预约单任务分配,2预约出库单下架)</param>
        /// <returns></returns>
        public async Task EditAsync(OutstockDemandBillModel outmodel, OutOrderOperType operatorType)
        {
            var outStockEntitys = this.Context.Set<OutstockDemandBillEntity>().SingleOrDefault(x => x.Id == outmodel.Id && x.IsDelete == DeleteStatus.Normal);
            if (outStockEntitys == null)
            {
                throw new CustomException("请传入有效的出库单Id");
            }
            if (outmodel.AppointmentDate.Date > outmodel.PlanArrivalTime)
            {
                throw new CustomException("预约时间不能大于计划出库时间!");
            }
            Func<string, string> func = goodsId =>
            {
                return this.Context.Set<GoodsEntity>().FirstOrDefault(x => x.IsDelete == DeleteStatus.Normal && x.Id == goodsId)?.GoodsName;
            };
            switch (operatorType)
            {
                case OutOrderOperType.EditOrder:

                    if (outStockEntitys.OutStatus != OutOderStatus.TodoAllot)
                    {
                        throw new CustomException($"当前状态为【{outStockEntitys.OutStatus.GetDescription()}】不可编辑。");
                    }
                    var outstockItems = this.Context.Set<OutstockDemandBillItemEntity>().Where(x => x.OutstockDemandBillId == outmodel.Id).ToList();
                    this.Context.RemoveRange(outstockItems);
                    //outStockEntitys = Mapper.Map<OutstockDemandBillEntity>(outmodel);
                    outStockEntitys.From(outmodel);
                    var upOutStoclItemEntity = Mapper.Map<List<OutstockDemandBillItemEntity>>(outmodel.Items);
                    upOutStoclItemEntity.ForEach(x =>
                    {
                        x.Id = Guid.NewGuid().ToString("N");
                        x.OutstockDemandBillId = outmodel.Id;
                        x.ActualOutQuantity = x.PlanOutQuantity;
                        x.ActualProductBatch = x.PlanProductBatch;
                    });
                    //this.Context.Set<OutstockDemandBillEntity>().Local.Clear();
                    //this.Context.Set<OutstockDemandBillEntity>().Local.Add(outStockEntitys);
                    //this.Context.Entry(outStockEntitys).State = EntityState.Modified;
                    this.Context.UpdateRange(outStockEntitys);
                    await this.Context.AddRangeAsync(upOutStoclItemEntity);
                    break;
                case OutOrderOperType.AllotOrder:
                    if (outStockEntitys.OutStatus != OutOderStatus.TodoAllot)
                    {
                        throw new CustomException($"当前所传状态为【{outStockEntitys.OutStatus.GetDescription()}】不可进行任务分配操作。");
                    }
                    if (string.IsNullOrWhiteSpace(outmodel.OutstockGroup))
                    {
                        throw new CustomException("出库组不能为空!");
                    }
                    outmodel.Items.ForEach(x =>
                    {
                        if (string.IsNullOrWhiteSpace(x.PlanProductBatch))
                        {
                            throw new CustomException($"【{func(x.GoodsId)}】计划出库批号不能为空");
                        }
                        if (x.ActualOutQuantity <= 0)
                        {
                            throw new CustomException($"【{func(x.GoodsId)}-{x.PlanProductBatch}】实际出库数量需大于0");
                        }
                    });
                    outStockEntitys.OutstockGroup = outmodel.OutstockGroup;
                    outStockEntitys.OutStatus = OutOderStatus.DoneAllot;
                    outStockEntitys.TaskTime = System.DateTime.Now;
                    outStockEntitys.TaskUser = outmodel.Updator;
                    outStockEntitys.UpdateDate = System.DateTime.Now;
                    outStockEntitys.Updator = outmodel.Updator;
                    this.Context.Set<OutstockDemandBillEntity>().Update(outStockEntitys);
                    var upOutStockItemEntity = this.Context.Set<OutstockDemandBillItemEntity>().Where(x => x.OutstockDemandBillId == outmodel.Id).ToList();
                    upOutStockItemEntity.ForEach(x =>
                    {
                        x.PlanProductBatch = outmodel.Items.SingleOrDefault(y => y.Id == x.Id).PlanProductBatch;
                        x.ActualOutQuantity = outmodel.Items.SingleOrDefault(y => y.Id == x.Id).ActualOutQuantity;
                        x.ActualProductBatch = outmodel.Items.SingleOrDefault(y => y.Id == x.Id).ActualProductBatch;
                        if (string.IsNullOrWhiteSpace(x.ActualProductBatch))
                        {
                            x.ActualProductBatch = x.PlanProductBatch;
                        }
                        x.UpdateDate = System.DateTime.Now;
                        x.Updator = outmodel.Updator;
                    });
                    this.Context.Set<OutstockDemandBillItemEntity>().UpdateRange(upOutStockItemEntity);
                    break;
                case OutOrderOperType.OutOder:
                    if (!(outStockEntitys.OutStatus == OutOderStatus.DoneAllot || outStockEntitys.OutStatus == OutOderStatus.OutBoundIng))
                    {
                        throw new CustomException($"当前所传状态为【{outStockEntitys.OutStatus.GetDescription()}】不可进行出库下架操作。");
                    }
                    //待下架完整单据的货物
                    var outStockItems = this.Context.Set<OutstockDemandBillItemEntity>().Where(x => x.OutstockDemandBillId == outmodel.Id).ToList();
                    if (outStockItems.Where(x => x.OffshelvesStatus == OutOderItemStatus.TodoOffshelves).Count() == 0)
                    {
                        throw new CustomException("所有货物已全部下架,请勿重复操作!");
                    }
                    //待出库的货物明细
                    var todoOutitems = outmodel.Items.Where(x => !string.IsNullOrWhiteSpace(x.OutstockLocation)
                                                            && !string.IsNullOrWhiteSpace(x.ActualProductBatch) && x.ActualOutQuantity > 0).ToList();
                    if (todoOutitems.Count() == 0)
                    {
                        throw new CustomException("库位,实际出库批号,不能为空,且实际出库数量必须大于0");
                    }
                    todoOutitems = todoOutitems.Where(x => x.OffshelvesStatus == OutOderItemStatus.TodoOffshelves).ToList();
                    if (todoOutitems.Count() == 0)
                    {
                        throw new CustomException("所有货物已全部下架,请勿重复操作!");
                    }
                    //部分下架中存在部分重复出库情况验证处理
                    var offshelveseds = outStockItems.Where(x => x.OffshelvesStatus == OutOderItemStatus.DoneOffshelves);
                    if (offshelveseds.Count() > 0)
                    {
                        Func<string, string> funLocation = locationId => this.Context.Set<WareHouseLocationEntity>().SingleOrDefault(x => x.Id == locationId)?.LocationCode;
                        var reportDatas = offshelveseds.Where(y => todoOutitems.Select(x => x.Id).Contains(y.Id)).ToList();
                        if (reportDatas.Count() > 0)
                        {
                            var msg = string.Empty;
                            reportDatas.ForEach(x =>
                            {
                                msg +=$"{func(x.GoodsId)};批号:{ x.ActualProductBatch};库位:{funLocation(x.OutstockLocation)}," ;
                            });
                            throw new CustomException($"【{msg.TrimEnd(',')}】已经下架,请勿重复操作!");
                        }
                    }
                    //本次需要下架完整单据的货物
                    var upOutItems = outStockItems.Where(x => todoOutitems.Select(y => y.Id).Contains(x.Id)).ToList();
                    //判断本次操作是否整单全部下架
                    if (outStockItems.Where(x => x.OffshelvesStatus == OutOderItemStatus.DoneOffshelves).Count() + todoOutitems.Count() == outStockItems.Count())
                    {
                        outStockEntitys.OutStatus = OutOderStatus.DoneOutBound;
                    }
                    else
                    {
                        outStockEntitys.OutStatus = OutOderStatus.OutBoundIng;
                    }
                    outStockEntitys.UpdateDate = System.DateTime.Now;
                    outStockEntitys.Updator = outmodel.Updator;
                    this.Context.Update(outStockEntitys);
                    //修改出库明细下架信息
                    upOutItems.ForEach(x =>
                    {
                        x.ActualOutQuantity= todoOutitems.FirstOrDefault(y => y.Id == x.Id).ActualOutQuantity;
                        x.ActualProductBatch = todoOutitems.FirstOrDefault(y => y.Id == x.Id)?.ActualProductBatch;
                        x.OutstockLocation = todoOutitems.FirstOrDefault(y => y.Id == x.Id)?.OutstockLocation;
                        x.OffshelvesStatus = OutOderItemStatus.DoneOffshelves;
                        x.Offshelves = outmodel.Updator;
                        x.OffshelvesTime = DateTime.Now;
                    });
                    this.Context.UpdateRange(upOutItems);
                    #region 调库存接口 
                    var todoMapOutStock = Mapper.Map<List<StockModel>>(upOutItems);
                    var todoAddStock= todoMapOutStock.Select(x =>
                    {
                        x.Id = string.Empty; x.BillNo = outmodel.DemandNo; x.AreaId = outmodel.AreaId;
                        x.CreateDate = System.DateTime.Now; x.Creator = outmodel.Creator; x.UpdateDate = System.DateTime.Now; x.Updator = outmodel.Updator; return x;
                    }).ToList();
                    await _stockService.AddStock(todoAddStock, this.Context, false);
                    #endregion
                    break;
            }
            var tran = Context.Database.BeginTransaction();
            try
            {
                //提交事务操作数据
                await Context.SaveChangesAsync();
                tran.Commit();
            }
            catch (Exception ex)
            {
                tran.Rollback();
                throw new CustomException(ex.Message);
            }
        }
        /// <summary>
        /// /// <summary>
        /// 条件获取出库单信息
        /// </summary>
        /// <param name="key">出库单号,主键Id,需求商Id</param>
        /// <param name="areaId">库区编号</param>
        /// <param name="outStatus">出库单状态</param>
        /// <param name="startTime">预约开始时间</param>
        /// <param name="endTime">预约结束时间</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页显示的值</param>
        /// <returns></returns>
        /// </summary>
        public async Task<Page<OutstockDemandBillListModel>> GetPageList(string key, string areaId, int outStatus, DateTime? startTime, DateTime? endTime, int pageIndex, int pageSize)
        {
            Expression<Func<OutstockDemandBillEntity, bool>> where = m => m.IsDelete == DeleteStatus.Normal;
            if (!string.IsNullOrWhiteSpace(key))
            {
                where = where.And(x => x.Id == key || x.DemanderId == key || x.DemandNo.Contains(key));
            }
            if (!string.IsNullOrWhiteSpace(areaId))
            {
                where = where.And(x => x.AreaId == areaId);
            }
            if (outStatus >= 0)
            {
                where = where.And(x => x.OutStatus == (OutOderStatus)outStatus);
            }
            if (startTime != null && endTime != null && startTime != DateTime.MinValue && endTime != DateTime.MinValue)
            {
                if (Convert.ToDateTime(startTime).Date > Convert.ToDateTime(endTime).Date)
                {
                    throw new CustomException("开始时间不能大于结束时间");
                }
            }
            if (startTime != null && startTime != DateTime.MinValue)
            {
                where = where.And(x => x.AppointmentDate > Convert.ToDateTime(startTime).Date);
            }
            if (endTime != null && endTime != DateTime.MinValue)
            {
                where = where.And(x => x.AppointmentDate < Convert.ToDateTime(endTime).AddDays(1).Date);
            }
            var query = this.Context.Set<OutstockDemandBillEntity>().Where(where);
            pageIndex = pageIndex <= 0 ? 1 : pageIndex;
            pageSize = pageSize <= 0 ? 10 : pageSize;
            var amount = await query.CountAsync();
            var totlePage = (amount - 1) / pageSize + 1;
            if (pageIndex > totlePage)
            {
                pageIndex = totlePage;
            }
            query = query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
            List<OutstockDemandBillListModel> rlist = new List<OutstockDemandBillListModel>();
            if (query.Count() > 0)
            {
                rlist = Mapper.Map<List<OutstockDemandBillListModel>>(query.ToList());
                if (rlist.Count() > 0)
                {
                    var areaInfos = this.Context.Set<WareHouseAreaEntity>().Where(x => rlist.Select(y => y.AreaId).Contains(x.Id)).ToList();
                    var demanInfos = this.Context.Set<DemanderEntity>().Where(x => rlist.Select(y => y.DemanderId).Contains(x.Id)).ToList();
                    foreach (var item in rlist)
                    {
                        item.AreaName = areaInfos.FirstOrDefault(x => x.Id == item.AreaId)?.AreaName;
                        item.DemanderName = demanInfos.FirstOrDefault(x => x.Id == item.DemanderId)?.DemanderName;
                    }
                }
            }
            var page = new Page<OutstockDemandBillListModel>() { Size = pageSize, Index = pageIndex, Amount = amount, Datas = rlist };
            return page;
        }
        /// <summary>
        /// 获取出库单明细
        /// </summary>
        /// <param name="key">关键字</param>
        /// <returns></returns>
        public OutstockDemandBillModel GetOutStockItemList(string key)
        {
            OutstockDemandBillModel rmodel = new OutstockDemandBillModel();
            Func<string, string> funcArea = areaId =>
            {
                return this.Context.Set<WareHouseAreaEntity>().FirstOrDefault(x => x.Id.Equals(areaId))?.AreaName;
            };
            Func<string, string> funcDeman = demanId =>
            {
                return this.Context.Set<DemanderEntity>().FirstOrDefault(x => x.Id.Equals(demanId))?.DemanderName;
            };
            if (string.IsNullOrWhiteSpace(key))
            {
                throw new CustomException("传入参数不能为空!");
            }
            var rOderEntity = this.Context.Set<OutstockDemandBillEntity>().FirstOrDefault(x => x.Id == key && x.IsDelete == DeleteStatus.Normal);
            if (rOderEntity == null)
            {
                throw new CustomException("未找到对应的出库单,请传入有效的查询参数!");
            }
            rmodel = Mapper.Map<OutstockDemandBillModel>(rOderEntity);
            rmodel.AreaName = funcArea(rmodel.AreaId);
            rmodel.DemanderName = funcDeman(rmodel.DemanderId);
            var rOrderItems = this.Context.Set<OutstockDemandBillItemEntity>().Where(x => x.OutstockDemandBillId == key).ToList();
            if (rOrderItems.Count() > 0)
            {
                rmodel.Items = Mapper.Map<List<OutstockDemandBillItemModel>>(rOrderItems);
            }
            return rmodel;
        }
    }
}

 

  • 5
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值