diff --git a/Core/MAX.Framework/Commons/UnifyStatusCodeMiddleware.cs b/Core/MAX.Framework/Commons/UnifyStatusCodeMiddleware.cs new file mode 100644 index 0000000..4c39f1d --- /dev/null +++ b/Core/MAX.Framework/Commons/UnifyStatusCodeMiddleware.cs @@ -0,0 +1,189 @@ +using MAX.Framework.Dtos; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.IO; +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.Json; + +namespace MAX.Framework.Commons +{ + /// + /// 统一状态码中间件 + /// 统一返回200 固定格式 + /// + internal class UnifyStatusCodeMiddleware + { + + private readonly RequestDelegate _next; + private readonly ILogger _logger; + + // 静态复用,全局唯一的内存池管理器 + private static readonly RecyclableMemoryStreamManager _streamManager = new(); + + // 需要直接透传、不做缓冲的 Content-Type 前缀 + private static readonly string[] _passthroughPrefixes = + { + "image/", + "audio/", + "video/", + "application/octet-stream", + "application/zip", + "application/pdf", + "application/x-msdownload", + "text/event-stream" + }; + + public UnifyStatusCodeMiddleware(RequestDelegate next, ILogger logger) + { + _next = next; + _logger = logger; + } + + public async Task InvokeAsync(HttpContext context) + { + // 1. 只处理 /api 路径(按需调整或删除) + if (!context.Request.Path.StartsWithSegments("/api")) + { + await _next(context); + return; + } + + // 2. 二进制 / 流式响应:不缓冲,直接透传 + var accept = context.Request.Headers.Accept.ToString(); + if (IsPassthroughByRequest(context) || IsPassthroughByAccept(accept)) + { + await _next(context); + return; + } + + var originalBody = context.Response.Body; + var buffer = _streamManager.GetStream(); + + context.Response.Body = buffer; + + try + { + await _next(context); + } + catch (Exception ex) + { + // 兜底:Filter 没抓到的异常 + _logger.LogError(ex, "未处理异常: {Path}", context.Request.Path); + + // 清空已写入的内容,准备返回 500 统一格式 + buffer.SetLength(0); + context.Response.StatusCode = StatusCodes.Status500InternalServerError; + } + + var statusCode = context.Response.StatusCode; + var contentType = context.Response.ContentType ?? string.Empty; + + // 3. 响应体如果本身就是二进制/流式,透传不处理 + if (IsPassthroughByResponseContentType(contentType)) + { + buffer.Position = 0; + context.Response.Body = originalBody; + await buffer.CopyToAsync(originalBody); + return; + } + + // 4. 2xx 且已有响应体:透传(已被 UnifyResultFilter 包装过,不再包一层) + if (statusCode >= 200 && statusCode < 300 && buffer.Length > 0) + { + buffer.Position = 0; + context.Response.Body = originalBody; + await buffer.CopyToAsync(originalBody); + return; + } + + // 5. 非 2xx:统一改写为 200 + ApiResult + var (code, msg) = MapStatusCode(statusCode); + + // 如果是 2xx 但响应体为空(少见,例如 204),也当作成功 + if (statusCode >= 200 && statusCode < 300) + { + code = (int)ResultCode.Success; + msg = "success"; + } + + var result = statusCode >= 200 && statusCode < 300 + ? ApiResult.Success() + : ApiResult.Fail(msg, code); + + // 恢复原始流并写出 + context.Response.Body = originalBody; + context.Response.StatusCode = StatusCodes.Status200OK; + context.Response.ContentType = "application/json; charset=utf-8"; + context.Response.ContentLength = null; + + // 清理可能存在的旧响应头 + context.Response.Headers.Remove("WWW-Authenticate"); + + await context.Response.WriteAsJsonAsync(result, new JsonSerializerOptions + { + PropertyNamingPolicy = JsonNamingPolicy.CamelCase + }); + + buffer.Dispose(); + } + + private static bool IsPassthroughByRequest(HttpContext context) + { + // 上传大文件等场景,请求体大,避免缓冲 + var contentLength = context.Request.ContentLength; + if (contentLength.HasValue && contentLength.Value > 1_000_000) // >1MB + { + return true; + } + + // Range 请求(断点续传)不缓冲 + if (context.Request.Headers.ContainsKey("Range")) + { + return true; + } + + return false; + } + + private static bool IsPassthroughByAccept(string accept) + { + if (string.IsNullOrEmpty(accept)) return false; + + foreach (var prefix in _passthroughPrefixes) + { + if (accept.Contains(prefix, StringComparison.OrdinalIgnoreCase)) + return true; + } + return false; + } + + private static bool IsPassthroughByResponseContentType(string contentType) + { + if (string.IsNullOrEmpty(contentType)) return false; + + foreach (var prefix in _passthroughPrefixes) + { + if (contentType.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) + return true; + } + return false; + } + + private static (int code, string msg) MapStatusCode(int statusCode) => statusCode switch + { + 400 => ((int)ResultCode.ValidationError, "请求参数错误"), + 401 => ((int)ResultCode.Unauthorized, "未授权,请先登录"), + 403 => ((int)ResultCode.Forbidden, "禁止访问"), + 404 => ((int)ResultCode.NotFound, "资源不存在"), + 405 => ((int)ResultCode.Fail, "请求方法不允许"), + 429 => ((int)ResultCode.Fail, "请求过于频繁"), + 500 => ((int)ResultCode.ServerError, "服务器内部错误"), + 502 => ((int)ResultCode.ServerError, "网关错误"), + 503 => ((int)ResultCode.ServerError, "服务暂不可用"), + 504 => ((int)ResultCode.ServerError, "网关超时"), + _ => ((int)ResultCode.Fail, $"请求失败({statusCode})") + }; + } +} diff --git a/Core/MAX.Framework/DependencyInjection/ServiceCollectionExtensions.cs b/Core/MAX.Framework/DependencyInjection/ServiceCollectionExtensions.cs index a5aa210..4087f91 100644 --- a/Core/MAX.Framework/DependencyInjection/ServiceCollectionExtensions.cs +++ b/Core/MAX.Framework/DependencyInjection/ServiceCollectionExtensions.cs @@ -211,6 +211,7 @@ namespace MAX.Framework.DependencyInjection public static IApplicationBuilder UseStore(this IApplicationBuilder app) { + app.UseMiddleware(); foreach (IStartup startup in Startups) { startup.Start((app as IHost).Services); diff --git a/Core/MAX.Framework/MAX.Framework.csproj b/Core/MAX.Framework/MAX.Framework.csproj index 7d9b264..9c4469e 100644 --- a/Core/MAX.Framework/MAX.Framework.csproj +++ b/Core/MAX.Framework/MAX.Framework.csproj @@ -15,6 +15,7 @@ + diff --git a/Directory.Build.props b/Directory.Build.props index ba7e914..9b7dfdf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -9,6 +9,7 @@ false true annotations + enable CS1591 diff --git a/Models/CloudProduct/CloudProductModule.cs b/Modules/CloudProduct/CloudProductModule.cs similarity index 82% rename from Models/CloudProduct/CloudProductModule.cs rename to Modules/CloudProduct/CloudProductModule.cs index 2983fd5..f0759e7 100644 --- a/Models/CloudProduct/CloudProductModule.cs +++ b/Modules/CloudProduct/CloudProductModule.cs @@ -12,19 +12,11 @@ using Store.Modules.CloudProduct.Services; namespace Store.Modules.CloudProduct { - /// - /// CloudProduct 模块的模块化入口():Hangfire 后台任务(商品分词同步)+ Hangfire 看板。 - /// 与 (只做 IStartup 的 Initialize/Register)分开,是因为模块注册需要配置和 app: - /// - /// builder.AddStoreHub() 执行 (注册 Hangfire 服务,此时只能拿到容器和配置); - /// app.UseStoreHubModules() 执行 (挂看板中间件 + 注册定时任务,此时才有 app)。 - /// - /// + public class CloudProductModule : IModule { /// - /// 本模块自己的配置文件(源码里是 Models/CloudProduct/appsettings.json, - /// 构建时复制到宿主输出目录并改名成这个名字,避免与宿主的 appsettings.json 冲突) + /// 本模块自己的配置文件 /// public const string ConfigurationFileName = "appsettings.CloudProduct.json"; @@ -51,8 +43,8 @@ namespace Store.Modules.CloudProduct //// 本模块的配置节(Search / RawData / Indexing / Delete)都在模块自己的配置文件里, //// 关键项缺失直接报错,避免 OpenSearch 地址为空、原始数据写到意外目录之类的隐性故障 RequireConfiguration(configuration, "Search:Url"); - //RequireConfiguration(configuration, "Search:IndexName"); - //RequireConfiguration(configuration, "RawData:Path"); + RequireConfiguration(configuration, "Search:IndexName"); + RequireConfiguration(configuration, "RawData:Path"); // ===== Hangfire 后台定时任务(商品分词同步) ===== var hangfireConnection = configuration.GetConnectionString("DefaultConnection") diff --git a/Models/CloudProduct/Controllers/GoodsController.cs b/Modules/CloudProduct/Controllers/GoodsController.cs similarity index 99% rename from Models/CloudProduct/Controllers/GoodsController.cs rename to Modules/CloudProduct/Controllers/GoodsController.cs index 7565708..f7a2758 100644 --- a/Models/CloudProduct/Controllers/GoodsController.cs +++ b/Modules/CloudProduct/Controllers/GoodsController.cs @@ -13,7 +13,7 @@ using System.Text.Json.Nodes; namespace Store.Modules.CloudProduct.Controllers { [ApiVersionNeutral] - [Route("/CloudGoods/[action]")] + [Route("api/CloudGoods/[action]")] public class GoodsController : AppControllerBase { private readonly IGoodsService _goodsService; diff --git a/Models/CloudProduct/Dtos/GoodsImportItem.cs b/Modules/CloudProduct/Dtos/GoodsImportItem.cs similarity index 100% rename from Models/CloudProduct/Dtos/GoodsImportItem.cs rename to Modules/CloudProduct/Dtos/GoodsImportItem.cs diff --git a/Models/CloudProduct/Dtos/GoodsImportResult.cs b/Modules/CloudProduct/Dtos/GoodsImportResult.cs similarity index 100% rename from Models/CloudProduct/Dtos/GoodsImportResult.cs rename to Modules/CloudProduct/Dtos/GoodsImportResult.cs diff --git a/Models/CloudProduct/Dtos/GoodsSearchDocument.cs b/Modules/CloudProduct/Dtos/GoodsSearchDocument.cs similarity index 100% rename from Models/CloudProduct/Dtos/GoodsSearchDocument.cs rename to Modules/CloudProduct/Dtos/GoodsSearchDocument.cs diff --git a/Models/CloudProduct/Dtos/GoodsSearchRequest.cs b/Modules/CloudProduct/Dtos/GoodsSearchRequest.cs similarity index 100% rename from Models/CloudProduct/Dtos/GoodsSearchRequest.cs rename to Modules/CloudProduct/Dtos/GoodsSearchRequest.cs diff --git a/Models/CloudProduct/Dtos/OpenSearchStatusDto.cs b/Modules/CloudProduct/Dtos/OpenSearchStatusDto.cs similarity index 100% rename from Models/CloudProduct/Dtos/OpenSearchStatusDto.cs rename to Modules/CloudProduct/Dtos/OpenSearchStatusDto.cs diff --git a/Models/CloudProduct/Entities/GoodsEntity.cs b/Modules/CloudProduct/Entities/GoodsEntity.cs similarity index 100% rename from Models/CloudProduct/Entities/GoodsEntity.cs rename to Modules/CloudProduct/Entities/GoodsEntity.cs diff --git a/Models/CloudProduct/Enums/GoodsSearchSortBy.cs b/Modules/CloudProduct/Enums/GoodsSearchSortBy.cs similarity index 100% rename from Models/CloudProduct/Enums/GoodsSearchSortBy.cs rename to Modules/CloudProduct/Enums/GoodsSearchSortBy.cs diff --git a/Models/CloudProduct/Enums/PlatformType.cs b/Modules/CloudProduct/Enums/PlatformType.cs similarity index 100% rename from Models/CloudProduct/Enums/PlatformType.cs rename to Modules/CloudProduct/Enums/PlatformType.cs diff --git a/Models/CloudProduct/ImportConverters/GoodsConverter.cs b/Modules/CloudProduct/ImportConverters/GoodsConverter.cs similarity index 100% rename from Models/CloudProduct/ImportConverters/GoodsConverter.cs rename to Modules/CloudProduct/ImportConverters/GoodsConverter.cs diff --git a/Models/CloudProduct/ImportConverters/GoodsConverterFactory.cs b/Modules/CloudProduct/ImportConverters/GoodsConverterFactory.cs similarity index 100% rename from Models/CloudProduct/ImportConverters/GoodsConverterFactory.cs rename to Modules/CloudProduct/ImportConverters/GoodsConverterFactory.cs diff --git a/Models/CloudProduct/ImportConverters/PddGoodsConverter.cs b/Modules/CloudProduct/ImportConverters/PddGoodsConverter.cs similarity index 100% rename from Models/CloudProduct/ImportConverters/PddGoodsConverter.cs rename to Modules/CloudProduct/ImportConverters/PddGoodsConverter.cs diff --git a/Models/CloudProduct/Repositorys/GoodsRepository.cs b/Modules/CloudProduct/Repositorys/GoodsRepository.cs similarity index 100% rename from Models/CloudProduct/Repositorys/GoodsRepository.cs rename to Modules/CloudProduct/Repositorys/GoodsRepository.cs diff --git a/Models/CloudProduct/Services/GoodsIndexJob.cs b/Modules/CloudProduct/Services/GoodsIndexJob.cs similarity index 100% rename from Models/CloudProduct/Services/GoodsIndexJob.cs rename to Modules/CloudProduct/Services/GoodsIndexJob.cs diff --git a/Models/CloudProduct/Services/GoodsService.cs b/Modules/CloudProduct/Services/GoodsService.cs similarity index 100% rename from Models/CloudProduct/Services/GoodsService.cs rename to Modules/CloudProduct/Services/GoodsService.cs diff --git a/Models/CloudProduct/Services/OpenSearchService.cs b/Modules/CloudProduct/Services/OpenSearchService.cs similarity index 100% rename from Models/CloudProduct/Services/OpenSearchService.cs rename to Modules/CloudProduct/Services/OpenSearchService.cs diff --git a/Models/CloudProduct/Services/RawDataStorage.cs b/Modules/CloudProduct/Services/RawDataStorage.cs similarity index 100% rename from Models/CloudProduct/Services/RawDataStorage.cs rename to Modules/CloudProduct/Services/RawDataStorage.cs diff --git a/Models/CloudProduct/Startup.cs b/Modules/CloudProduct/Startup.cs similarity index 100% rename from Models/CloudProduct/Startup.cs rename to Modules/CloudProduct/Startup.cs diff --git a/Models/CloudProduct/Store.Modules.CloudProduct.csproj b/Modules/CloudProduct/Store.CloudProduct.csproj similarity index 100% rename from Models/CloudProduct/Store.Modules.CloudProduct.csproj rename to Modules/CloudProduct/Store.CloudProduct.csproj diff --git a/Models/CloudProduct/appsettings.json b/Modules/CloudProduct/appsettings.json similarity index 81% rename from Models/CloudProduct/appsettings.json rename to Modules/CloudProduct/appsettings.json index 2109cc1..06b88fb 100644 --- a/Models/CloudProduct/appsettings.json +++ b/Modules/CloudProduct/appsettings.json @@ -14,5 +14,11 @@ }, "Delete": { "SoftDelete": true + }, + "Hangfire": { + "Dashboard" :{ + "User": "admin", + "Pass": "1234560" + } } } diff --git a/Modules/Store.Shops.Contracts/ShopQueryService.cs b/Modules/Store.Shops.Contracts/ShopQueryService.cs new file mode 100644 index 0000000..e3e13e7 --- /dev/null +++ b/Modules/Store.Shops.Contracts/ShopQueryService.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Shops.Contracts +{ + public interface IShopQueryService + { + DateTime GetExpireTime(string shopId); + } +} diff --git a/Modules/Store.Shops.Contracts/Store.Shops.Contracts.csproj b/Modules/Store.Shops.Contracts/Store.Shops.Contracts.csproj new file mode 100644 index 0000000..fe64e56 --- /dev/null +++ b/Modules/Store.Shops.Contracts/Store.Shops.Contracts.csproj @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Modules/Store.Shops/Entities/ShopEntity.cs b/Modules/Store.Shops/Entities/ShopEntity.cs new file mode 100644 index 0000000..d5ca731 --- /dev/null +++ b/Modules/Store.Shops/Entities/ShopEntity.cs @@ -0,0 +1,144 @@ +using FreeSql.DataAnnotations; +using System; + +namespace YourNamespace +{ + /// + /// 店铺表 + /// + [Table(Name = "wxxd.shop")] + public class ShopEntity + { + /// + /// 表id + /// + [Column(Name = "id", IsPrimary = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// login_name + /// + [Column(Name = "login_name")] + public string LoginName { get; set; } + + /// + /// login_pass + /// + [Column(Name = "login_pass")] + public string LoginPass { get; set; } + + /// + /// cookie + /// + [Column(Name = "cookie")] + public string Cookie { get; set; } + + /// + /// cookie2 + /// + [Column(Name = "cookie2")] + public string Cookie2 { get; set; } + + /// + /// anti_contents + /// + [Column(Name = "anti_contents")] + public string AntiContents { get; set; } + + /// + /// openid + /// + [Column(Name = "openid")] + public string Openid { get; set; } + + /// + /// shop_id + /// + [Column(Name = "shop_id")] + public string ShopId { get; set; } + + /// + /// shop_account + /// + [Column(Name = "shop_account")] + public string ShopAccount { get; set; } + + /// + /// sub_user_name + /// + [Column(Name = "sub_user_name")] + public string SubUserName { get; set; } + + /// + /// user_name + /// + [Column(Name = "user_name")] + public string UserName { get; set; } + + /// + /// 店铺分组名称(非子账号分组) + /// + [Column(Name = "group_name")] + public string GroupName { get; set; } + + /// + /// add_time + /// + [Column(Name = "add_time")] + public DateTime? AddTime { get; set; } + + /// + /// mdy_time + /// + [Column(Name = "mdy_time")] + public DateTime? MdyTime { get; set; } + + /// + /// 店铺所属公司 + /// + [Column(Name = "company_name")] + public string CompanyName { get; set; } + + /// + /// 备注 + /// + [Column(Name = "notes")] + public string Notes { get; set; } + + /// + /// login_status + /// + [Column(Name = "login_status")] + public string LoginStatus { get; set; } + + /// + /// 店铺每月商品上传限额剩余 + /// + [Column(Name = "add_product_remaining")] + public int AddProductRemaining { get; set; } + + /// + /// 上传限额所处月份 + /// + [Column(Name = "add_product_month")] + public byte AddProductMonth { get; set; } + + /// + /// 分配的二级超管的user_name + /// + [Column(Name = "operate_sub_sa_name")] + public string OperateSubSaName { get; set; } + + /// + /// 分配二级超管的时间 + /// + [Column(Name = "add_sub_sa_time")] + public DateTime? AddSubSaTime { get; set; } + + /// + /// login_status2 + /// + [Column(Name = "login_status2")] + public string LoginStatus2 { get; set; } + } +} \ No newline at end of file diff --git a/Modules/Store.Shops/Entities/ShopExpireEntity.cs b/Modules/Store.Shops/Entities/ShopExpireEntity.cs new file mode 100644 index 0000000..919d4d1 --- /dev/null +++ b/Modules/Store.Shops/Entities/ShopExpireEntity.cs @@ -0,0 +1,43 @@ +using FreeSql.DataAnnotations; +using System; + +namespace Store.Users.Entities +{ + /// + /// 商店过期 + /// + [Table(Name = "wxxd.user_points_shop_expire")] + public class ShopExpireEntity + { + /// + /// ID + /// + [Column(Name = "id", IsPrimary = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 商店ID + /// + [Column(Name = "shop_id")] + public string ShopId { get; set; } + + /// + /// 过期时间 + /// + // 数据库列名末尾包含 U+200C,不能改成普通 expire_time。 + [Column(Name = "expire_time")] + public int ExpireTime { get; set; } + + /// + /// 添加时间 + /// + [Column(Name = "add_time")] + public DateTime AddTime { get; set; } + + /// + /// 修改时间 + /// + [Column(Name = "mdy_time")] + public DateTime MdyTime { get; set; } + } +} \ No newline at end of file diff --git a/Modules/Store.Shops/Repositories/ShopRepository.cs b/Modules/Store.Shops/Repositories/ShopRepository.cs new file mode 100644 index 0000000..8f8679c --- /dev/null +++ b/Modules/Store.Shops/Repositories/ShopRepository.cs @@ -0,0 +1,47 @@ +using FreeSql; +using MAX.Core.DependencyInjection; +using MAX.Core.Helpers; +using Store.Users.Entities; +using System; +using System.Collections.Generic; +using System.Text; +using YourNamespace; + +namespace Store.Shops.Repositories +{ + public interface IShopRepository : IBaseRepository + { + /// + /// 获取用户商铺过期时间 + /// + /// + /// + DateTime GetExpireTime(string ShopId); + } + internal class ShopRepository : BaseRepository, IShopRepository, ITransientDependency + { + private readonly IFreeSql _freeSql; + + public ShopRepository(IFreeSql freeSql) : base(freeSql) + { + _freeSql = freeSql; + } + + /// + /// 获取用户商铺过期时间 + /// + /// + public DateTime GetExpireTime(string ShopId) + { + ShopExpireEntity currentExpire = _freeSql.Select() + .Where(a => a.ShopId == ShopId) + .ForUpdate() + .First(); + if (currentExpire == null) + { + return DateTime.MinValue; + } + return DateHelper.ConvertFromUnixTimestampInSeconds(currentExpire.ExpireTime); + } + } +} diff --git a/Modules/Store.Shops/Services/ShopQueryService.cs b/Modules/Store.Shops/Services/ShopQueryService.cs new file mode 100644 index 0000000..34415a4 --- /dev/null +++ b/Modules/Store.Shops/Services/ShopQueryService.cs @@ -0,0 +1,23 @@ +using MAX.Core.DependencyInjection; +using Store.Shops.Contracts; +using Store.Shops.Repositories; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Shops.Services +{ + internal class ShopQueryService: IShopQueryService, ITransientDependency + { + private readonly IShopRepository _shopRepository; + + public ShopQueryService(IShopRepository shopRepository) + { + _shopRepository = shopRepository; + } + public DateTime GetExpireTime(string shopId) + { + return _shopRepository.GetExpireTime(shopId); + } + } +} diff --git a/Modules/Store.Shops/Startup.cs b/Modules/Store.Shops/Startup.cs new file mode 100644 index 0000000..0ec6974 --- /dev/null +++ b/Modules/Store.Shops/Startup.cs @@ -0,0 +1,25 @@ +using MAX.Core.DependencyInjection; +using MAX.Core.Interfaces; + +namespace Store.Shops +{ + public class Startup : IStartup + { + public int Priority => IntPriority.Normal; + + public void Initialize() + { + + } + + public void Register(IServiceRegistrar registrar) + { + + } + + public void Start(IServiceProvider serviceProvider) + { + + } + } +} diff --git a/Modules/Store.Shops/Store.Shops.csproj b/Modules/Store.Shops/Store.Shops.csproj new file mode 100644 index 0000000..1c57c72 --- /dev/null +++ b/Modules/Store.Shops/Store.Shops.csproj @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/Modules/Store.Users.Contracts/Dtos/UserInfo.cs b/Modules/Store.Users.Contracts/Dtos/UserInfo.cs new file mode 100644 index 0000000..1c9990f --- /dev/null +++ b/Modules/Store.Users.Contracts/Dtos/UserInfo.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text; + +namespace Store.Users.Contracts.Dtos +{ + public class UserInfo + {/// + /// ID + /// + public int Id { get; set; } + + /// + /// 用户昵称 + /// + public string NickName { get; set; } + + /// + /// 用户名称(登录账户) + /// + public string UserName { get; set; } + + /// + /// 登录密码 + /// + public string Password { get; set; } + + /// + /// card_id + /// + public string CardId { get; set; } + + /// + /// 用户分组 3主号 4客服 5加盟 8登录 9采购 10加盟 11上货 + /// + public byte GroupId { get; set; } + + /// + /// 父账户用户名 + /// + public string ParentUserName { get; set; } + + /// + /// oem编号,仅oem用户有值 + /// + public string OemId { get; set; } + + /// + /// 手机号 + /// + public string Mobile { get; set; } + + /// + /// 添加时间 + /// + public DateTime? AddTime { get; set; } + + /// + /// 修改时间 + /// + public DateTime? MdyTime { get; set; } + + /// + /// 公司名称 + /// + public string CompanyName { get; set; } + + /// + /// 备注 + /// + public string Notes { get; set; } + + /// + /// 超管等级 0 普通用户 1 超级管理员 + /// + public short? SaLevel { get; set; } + + /// + /// 账户权限 + /// + public string Authority { get; set; } + + /// + /// 子账号被禁止展示的功能页面 + /// + public string ForbiddenPage { get; set; } + + /// + /// 账户积分,1积分=1元 + /// + public decimal Points { get; set; } + + /// + /// 积分历史累计充值金额 + /// + public decimal? RechargePointsTotal { get; set; } + + /// + /// 店铺每续费一个月需要的积分,单位元 + /// + public int ShopPointsPerMonth { get; set; } + + /// + /// 可用余额 + /// + public decimal? Balance { get; set; } + + /// + /// 累计充值金额 + /// + public decimal? RechargeAmountTotal { get; set; } + + /// + /// 每单中转仓快递费用,单位元,两位小数 + /// + public decimal? PostagePerOrder { get; set; } + + /// + /// 每单中转仓退货快递费用,单位元,两位小数 + /// + public decimal? RefundPostagePerOrder { get; set; } + + /// + /// 礼物每单额外收取费用,单位元,两位小数 + /// + public decimal? GiftOemAmountPerOrder { get; set; } + + + /// + /// 同步物流费用,单位元,两位小数 + /// + public decimal? SyncLogisticsPerOrder { get; set; } + + /// + /// 是否主账户 + /// + public bool IsMainUser + { + get => string.IsNullOrWhiteSpace(ParentUserName); + } + /// + /// 是否OEM租户 + /// + public bool IsOEMTenant => !string.IsNullOrWhiteSpace(OemId); + } +} diff --git a/Modules/Store.Users.Contracts/Enums/PaymentTypes.cs b/Modules/Store.Users.Contracts/Enums/PaymentTypes.cs new file mode 100644 index 0000000..2de3b5e --- /dev/null +++ b/Modules/Store.Users.Contracts/Enums/PaymentTypes.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Store.Users.Contracts.Enums; +/// +/// 用户付款类型 +/// +public enum UserPaymentTypes +{ + 充值 = 1, + //采购花费 = 2, + //产品退款到账 = 3, + //运费退款到账 = 4, + //采购收款 = 5, + //产品退款扣除 = 6, + //运费退款扣除 = 7, + 礼物单支出 = 16, + 中转仓扣费支出 = 20, + 中转仓作废返还收入 = 23, + 中转仓超重支出 = 24, + 退货包裹扣费支出 = 26, + 中转仓快递超重费用 = 28, + 支付宝在线充值 = 30, + 云仓退货支出 = 31, + 礼物单退费 = 34, + 同步单号 = 55, +} diff --git a/Modules/Store.Users.Contracts/IUserQueryService.cs b/Modules/Store.Users.Contracts/IUserQueryService.cs new file mode 100644 index 0000000..f6808da --- /dev/null +++ b/Modules/Store.Users.Contracts/IUserQueryService.cs @@ -0,0 +1,12 @@ +using Store.Users.Contracts.Dtos; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Users.Contracts +{ + public interface IUserQueryService + { + Task GetUser(string userName); + } +} diff --git a/Modules/Store.Users.Contracts/Store.Users.Contracts.csproj b/Modules/Store.Users.Contracts/Store.Users.Contracts.csproj new file mode 100644 index 0000000..5adef81 --- /dev/null +++ b/Modules/Store.Users.Contracts/Store.Users.Contracts.csproj @@ -0,0 +1,6 @@ + + + + + + diff --git a/Modules/Store.Users/Commands/ShopRenewCommand.cs b/Modules/Store.Users/Commands/ShopRenewCommand.cs new file mode 100644 index 0000000..510050e --- /dev/null +++ b/Modules/Store.Users/Commands/ShopRenewCommand.cs @@ -0,0 +1,81 @@ +//using MediatR; +//using Store.Framework.Models; +//using Store.Shops.Contracts; +//using Store.Users.Contracts.Dtos; +//using Store.Users.Entities; +//using Store.Users.Repositories; +//using System; +//using System.Collections.Generic; +//using System.Text; + +//namespace Store.Users.Commands +//{ +// /// +// /// 商铺续费 +// /// +// /// +// /// +// /// +// internal record class ShopRenewCommand(string UserName, string ShopId, int RenewDuration) : IRequest; +// internal class ShopRenewCommandHandler : IRequestHandler +// { +// private readonly IUserRepository _userRepository; +// private readonly IShopQueryService _shopQueryService; + +// public ShopRenewCommandHandler(IUserRepository userRepository, IShopQueryService shopQueryService) +// { +// _userRepository = userRepository; +// _shopQueryService = shopQueryService; +// } +// async Task IRequestHandler.Handle(ShopRenewCommand request, CancellationToken cancellationToken) +// { +// ShopRenewResponse response = new ShopRenewResponse(); +// var user = await _userRepository.GetUser(request.UserName); +// int shopPointsPerMonth = Math.Max(30, user.ShopPointsPerMonth); +// int deltaPoints = shopPointsPerMonth * request.RenewDuration; +// int newPoints = (int)user.Points - deltaPoints; +// DateTime expireTime = _shopQueryService.GetExpireTime(request.ShopId); + + +// if (currentExpire != null && currentExpire.ExpireTime > 0) +// { +// DateTime currentExpireTime = TimeUtils.StampToDateTime(currentExpire.ExpireTime); +// if (currentExpireTime > expireBaseTime) +// { +// expireBaseTime = currentExpireTime; +// } +// } + +// int newExpireTime = CalculateNewExpireTime(expireBaseTime, request.RenewDuration); + + + +// response.ShopId = request.ShopId; +// response.UserPoints = newPoints; +// response.ExpireTime‌ = newExpireTime; +// return response; +// } +// private int CalculateNewExpireTime(DateTime expireBaseTime, int renewDuration) +// { +// DateTime newExpireDateTime; +// try +// { +// newExpireDateTime = expireBaseTime.AddMonths(renewDuration); +// } +// catch (ArgumentOutOfRangeException) +// { +// throw new InvalidOperationException("续费时长超出允许范围"); +// } + +// if (newExpireDateTime > TimeUtils.StampToDateTime(int.MaxValue)) +// { +// throw new InvalidOperationException("续费时间超出系统支持范围"); +// } + +// return TimeUtils.DateTimeToTimestampSeconds(newExpireDateTime); +// } + +// } + + +//} diff --git a/Modules/Store.Users/Controllers/UserController.cs b/Modules/Store.Users/Controllers/UserController.cs new file mode 100644 index 0000000..add205c --- /dev/null +++ b/Modules/Store.Users/Controllers/UserController.cs @@ -0,0 +1,29 @@ +using Asp.Versioning; +using Microsoft.AspNetCore.Mvc; +using Store.Users.Contracts; +using Store.Users.Contracts.Dtos; +using Store.Users.Services; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Users.Controllers +{ + [ApiController] + [ApiVersionNeutral] + [Route("user/[action]")] + public class UserController : ControllerBase + { + private readonly IUserQueryService _userQuery; + + public UserController(IUserQueryService userQuery) + { + _userQuery = userQuery; + } + [HttpGet] + public async Task GetUser(string userName) + { + return await _userQuery.GetUser(userName); + } + } +} diff --git a/Modules/Store.Users/Dtos/ShopRenewRequest.cs b/Modules/Store.Users/Dtos/ShopRenewRequest.cs new file mode 100644 index 0000000..7c4fa77 --- /dev/null +++ b/Modules/Store.Users/Dtos/ShopRenewRequest.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Users.Dtos +{ + /// + /// 用户续费商铺 + /// + public class ShopRenewRequest + { + /// + /// 店铺ID + /// + public string ShopId { get; set; } + + /// + /// 续费时长数值,例如 3;范围 1-120 个月 + /// + public int RenewDuration { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + } +} diff --git a/Modules/Store.Users/Dtos/ShopRenewResponse.cs b/Modules/Store.Users/Dtos/ShopRenewResponse.cs new file mode 100644 index 0000000..fc63cef --- /dev/null +++ b/Modules/Store.Users/Dtos/ShopRenewResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Users.Contracts.Dtos +{ + public class ShopRenewResponse + { + public string ShopId { get; set; } + public int ExpireTime‌ { get; set; } + public int UserPoints { get; set; } + } +} diff --git a/Modules/Store.Users/Entities/OEMEntity.cs b/Modules/Store.Users/Entities/OEMEntity.cs new file mode 100644 index 0000000..7ec4892 --- /dev/null +++ b/Modules/Store.Users/Entities/OEMEntity.cs @@ -0,0 +1,93 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Store.Users.Entities; + + +/// +/// OEM贴牌表 +/// +[Table(Name = "wxxd.oem")] +public class OEMEntity +{ + /// + /// id + /// + [Column(Name = "id", IsPrimary = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// oem_id + /// + [Column(Name = "oem_id")] + public string OemId { get; set; } + + /// + /// 贴牌名称 + /// + [Column(Name = "oem_name")] + public string OemName { get; set; } + + /// + /// 贴牌管理人主账户 + /// + [Column(Name = "oem_owner")] + public string OemOwner { get; set; } + + /// + /// 图标 + /// + [Column(Name = "oem_icon")] + public string OemIcon { get; set; } + + /// + /// 题图 + /// + [Column(Name = "oem_img")] + public string OemImg { get; set; } + + /// + /// add_time + /// + [Column(Name = "add_time")] + public DateTime AddTime { get; set; } + + /// + /// mdy_time + /// + [Column(Name = "mdy_time")] + public DateTime MdyTime { get; set; } + + /// + /// is_del + /// + [Column(Name = "is_del")] + public byte IsDel { get; set; } + + /// + /// 可提现余额,单位分 + /// + [Column(Name = "available_balance")] + public long AvailableBalance { get; set; } + + /// + /// 冻结余额,单位分 + /// + [Column(Name = "frozen_balance")] + public long FrozenBalance { get; set; } + + /// + /// 累计返利金额,单位分 + /// + [Column(Name = "total_rebate_amount")] + public long TotalRebateAmount { get; set; } + + /// + /// 累计提现金额,单位分 + /// + [Column(Name = "total_withdraw_amount")] + public long TotalWithdrawAmount { get; set; } +} diff --git a/Modules/Store.Users/Entities/UserEntity.cs b/Modules/Store.Users/Entities/UserEntity.cs new file mode 100644 index 0000000..0eb517b --- /dev/null +++ b/Modules/Store.Users/Entities/UserEntity.cs @@ -0,0 +1,175 @@ +using FreeSql.DataAnnotations; +using System; + +namespace Store.Users.Entities +{ + /// + /// 用户表 + /// + [Table(Name = "wxxd.user")] + public class UserEntity + { + /// + /// ID + /// + [Column(Name = "id", IsPrimary = true, IsIdentity = true)] + public int Id { get; set; } + + /// + /// 用户昵称 + /// + [Column(Name = "nick_name")] + public string NickName { get; set; } + + /// + /// 用户名称(登录账户) + /// + [Column(Name = "user_name")] + public string UserName { get; set; } + + /// + /// 登录密码 + /// + [Column(Name = "password")] + public string Password { get; set; } + + /// + /// card_id + /// + [Column(Name = "card_id")] + public string CardId { get; set; } + + /// + /// 用户分组 3主号 4客服 5加盟 8登录 9采购 10加盟 11上货 + /// + [Column(Name = "group_id")] + public byte GroupId { get; set; } + + /// + /// 父账户用户名 + /// + [Column(Name = "parent_user_name")] + public string ParentUserName { get; set; } + + /// + /// oem编号,仅oem用户有值 + /// + [Column(Name = "oem_id")] + public string OemId { get; set; } + + /// + /// 手机号 + /// + [Column(Name = "mobile")] + public string Mobile { get; set; } + + /// + /// 添加时间 + /// + [Column(Name = "add_time")] + public DateTime? AddTime { get; set; } + + /// + /// 修改时间 + /// + [Column(Name = "mdy_time")] + public DateTime? MdyTime { get; set; } + + /// + /// 公司名称 + /// + [Column(Name = "company_name")] + public string CompanyName { get; set; } + + /// + /// 备注 + /// + [Column(Name = "notes")] + public string Notes { get; set; } + + /// + /// 超管等级 0 普通用户 1 超级管理员 + /// + [Column(Name = "sa_level")] + public short? SaLevel { get; set; } + + /// + /// 账户权限 + /// + [Column(Name = "authority")] + public string Authority { get; set; } + + /// + /// 子账号被禁止展示的功能页面 + /// + [Column(Name = "forbidden_page")] + public string ForbiddenPage { get; set; } + + /// + /// 账户积分,1积分=1元 + /// + [Column(Name = "points")] + public decimal Points { get; set; } + + /// + /// 积分历史累计充值金额 + /// + [Column(Name = "recharge_points_total")] + public decimal? RechargePointsTotal { get; set; } + + /// + /// 店铺每续费一个月需要的积分,单位元 + /// + [Column(Name = "shop_points_per_month")] + public int ShopPointsPerMonth { get; set; } + + /// + /// 可用余额 + /// + [Column(Name = "balance")] + public decimal? Balance { get; set; } + + /// + /// 累计充值金额 + /// + [Column(Name = "recharge_amount_total")] + public decimal? RechargeAmountTotal { get; set; } + + /// + /// 每单中转仓快递费用,单位元,两位小数 + /// + [Column(Name = "postage_per_order")] + public decimal? PostagePerOrder { get; set; } + + /// + /// 每单中转仓退货快递费用,单位元,两位小数 + /// + [Column(Name = "refund_postage_per_order")] + public decimal? RefundPostagePerOrder { get; set; } + + /// + /// 礼物每单额外收取费用,单位元,两位小数 + /// + [Column(Name = "gift_oem_amount_per_order")] + public decimal? GiftOemAmountPerOrder { get; set; } + + + /// + /// 同步物流费用,单位元,两位小数 + /// + [Column(Name = "sync_logistics_per_order")] + public decimal? SyncLogisticsPerOrder { get; set; } + + /// + /// 是否主账户 + /// + public bool IsMainUser + { + get => string.IsNullOrWhiteSpace(ParentUserName); + } + /// + /// 是否OEM租户 + /// + public bool IsOEMTenant => !string.IsNullOrWhiteSpace(OemId); + } +} \ No newline at end of file diff --git a/Modules/Store.Users/Entities/UserPaymentRecordEntity.cs b/Modules/Store.Users/Entities/UserPaymentRecordEntity.cs new file mode 100644 index 0000000..bb984f7 --- /dev/null +++ b/Modules/Store.Users/Entities/UserPaymentRecordEntity.cs @@ -0,0 +1,125 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Store.Users.Entities; + +[Table(Name = "wxxd.user_payment_record")] +public class UserPaymentRecordEntity +{ + /// + /// id + /// + [Column(Name = "id", IsPrimary = true, IsIdentity = true)] + public long Id { get; set; } + + /// + /// 变动类型,1:充值,2:采购花费,3:产品退款到账,4:运费退款到账,5:采购收款,6:产品退款扣除,7:运费退款扣除, 16:礼物单话费,20:中转仓扣费支出,23:中转仓退款收入 + /// + [Column(Name = "type")] + public int Type { get; set; } + + /// + /// 金额(元) + /// + [Column(Name = "amount")] + public decimal? Amount { get; set; } + + /// + /// 归属oem用户的金额 + /// + [Column(Name = "oem_amount")] + public decimal? OemAmount { get; set; } + + /// + /// 余额(元) + /// + [Column(Name = "balance")] + public decimal? Balance { get; set; } + + /// + /// 账户名 + /// + [Column(Name = "user_name")] + public string UserName { get; set; } + + /// + /// 平台编码 + /// + [Column(Name = "platform_code")] + public string PlatformCode { get; set; } + + /// + /// 订单id + /// + [Column(Name = "order_id")] + public string OrderId { get; set; } + + /// + /// 售后单id + /// + [Column(Name = "after_sale_id")] + public long? AfterSaleId { get; set; } + + /// + /// 创建人 + /// + [Column(Name = "create_by")] + public string CreateBy { get; set; } + + /// + /// 创建时间 + /// + [Column(Name = "create_time")] + public DateTime CreateTime { get; set; } + + /// + /// 修改人 + /// + [Column(Name = "update_by")] + public string UpdateBy { get; set; } + + /// + /// 修改时间 + /// + [Column(Name = "update_time")] + public DateTime? UpdateTime { get; set; } + + /// + /// 是否已删除 + /// + [Column(Name = "is_deleted")] + public int IsDeleted { get; set; } + + /// + /// 备注 + /// + [Column(Name = "remark")] + public string Remark { get; set; } + + /// + /// 扣款的对方账户名称 + /// + [Column(Name = "counterparty_account_name")] + public string CounterpartyAccountName { get; set; } + + /// + /// OEM是否结算 0未结算 1已结算 + /// + [Column(Name = "settlement")] + public byte Settlement { get; set; } = 0; + + /// + /// 退款流水号 外采&订单号 + /// + [Column(Name = "refund_flow_no")] + public string RefundFlowNo { get; set; } + + /// + /// 结算时间 + /// + [Column(Name = "settlement_time")] + public DateTime? SettlementTime { get; set; } +} \ No newline at end of file diff --git a/Modules/Store.Users/Entities/UserPointsRecordEntity.cs b/Modules/Store.Users/Entities/UserPointsRecordEntity.cs new file mode 100644 index 0000000..521e13a --- /dev/null +++ b/Modules/Store.Users/Entities/UserPointsRecordEntity.cs @@ -0,0 +1,109 @@ +using FreeSql.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace Store.Users.Entities +{ + + [Table(Name = "wxxd.user_points_record")] + public class UserPointsRecordEntity + { + /// + /// 主键(自增) + /// + [Column(Name = "id", IsPrimary = true, IsIdentity = true)] + public long Id { get; set; } + + /// + /// 用户名(NOT NULL) + /// + [Column(Name = "user_name")] + public string UserName { get; set; } + + /// + /// 用户昵称(NOT NULL) + /// + [Column(Name = "user_nick")] + public string UserNick { get; set; } + + /// + /// 操作记录金额,单位元,最小1元(NOT NULL) + /// + [Column(Name = "delta_points")] + public decimal DeltaPoints { get; set; } + + /// + /// 充值或消费后的当前金额(允许 NULL) + /// + [Column(Name = "new_points")] + public decimal? NewPoints { get; set; } + + /// + /// 操作类型 消费 充值 转入 转出(NOT NULL) + /// + [Column(Name = "option_type")] + public string OptionType { get; set; } + + /// + /// 操作者类型 管理员 用户(NOT NULL) + /// + [Column(Name = "operator_type")] + public string OperatorType { get; set; } + + /// + /// 实际操作者用户名(NOT NULL) + /// + [Column(Name = "operator_name")] + public string OperatorName { get; set; } + + /// + /// 消费店铺编号(消费才有值,充值为空,允许 NULL) + /// + [Column(Name = "shop_id")] + public string? ShopId { get; set; } + + /// + /// 消费店铺名称(消费才有值,充值为空,允许 NULL) + /// + [Column(Name = "shop_account")] + public string? ShopAccount { get; set; } + + /// + /// 备注(允许 NULL) + /// + [Column(Name = "remark")] + public string? Remark { get; set; } + + /// + /// (点数转出时的)对方账户(允许 NULL) + /// + [Column(Name = "counterparty_account_name")] + public string? CounterpartyAccountName { get; set; } + + /// + /// 支付宝订单的外部订单号(允许 NULL) + /// + [Column(Name = "out_trade_no")] + public string? OutTradeNo { get; set; } + + /// + /// 添加时间(NOT NULL,默认 CURRENT_TIMESTAMP) + /// + [Column(Name = "add_time")] + public DateTime AddTime { get; set; } + + /// + /// OEM是否结算 0未结算 1已结算 + /// + [Column(Name = "settlement")] + public bool Settlement { get; set; } + /// + /// 结算时间 + /// + [Column(Name = "settlement_time")] + public DateTime? SettlementTime { get; set; } + } + +} \ No newline at end of file diff --git a/Modules/Store.Users/Mappers/UserMapper.cs b/Modules/Store.Users/Mappers/UserMapper.cs new file mode 100644 index 0000000..b6c5071 --- /dev/null +++ b/Modules/Store.Users/Mappers/UserMapper.cs @@ -0,0 +1,15 @@ +using Riok.Mapperly.Abstractions; +using Store.Users.Contracts.Dtos; +using Store.Users.Entities; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Users.Mappers +{ + [Mapper] + internal partial class UserMapper + { + public partial UserInfo ToInfo(UserEntity entity); + } +} diff --git a/Modules/Store.Users/Repositories/UserRepository.cs b/Modules/Store.Users/Repositories/UserRepository.cs new file mode 100644 index 0000000..cbaf751 --- /dev/null +++ b/Modules/Store.Users/Repositories/UserRepository.cs @@ -0,0 +1,50 @@ +using FreeSql; +using MAX.Core.DependencyInjection; +using Store.Users.Contracts.Dtos; +using Store.Users.Entities; +using Store.Users.Mappers; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Users.Repositories +{ + public interface IUserRepository : IBaseRepository + { + Task GetUser(string userName); + } + internal class UserRepository : BaseRepository, IUserRepository, ITransientDependency + { + private readonly IFreeSql _freeSql; + + public UserRepository(IFreeSql freeSql) : base(freeSql) + { + _freeSql = freeSql; + } + + public async Task GetUser(string userName) + { + var sql = Where(a => a.UserName == userName).ToSql(); + var user = await Where(a => a.UserName == userName).FirstAsync(); + if (user != null) + { + if (user.IsMainUser == false) + { + var mainUser = await Where(a => a.UserName == user.ParentUserName).FirstAsync(); + if (mainUser != null) + { + user.OemId = mainUser.OemId; + user.PostagePerOrder = mainUser.PostagePerOrder; + user.RefundPostagePerOrder = mainUser.RefundPostagePerOrder; + user.GiftOemAmountPerOrder = mainUser.GiftOemAmountPerOrder; + user.SyncLogisticsPerOrder = mainUser.SyncLogisticsPerOrder; + } + } + } + return user; + } + + + + } +} diff --git a/Modules/Store.Users/Services/UserQueryService.cs b/Modules/Store.Users/Services/UserQueryService.cs new file mode 100644 index 0000000..6283be8 --- /dev/null +++ b/Modules/Store.Users/Services/UserQueryService.cs @@ -0,0 +1,43 @@ +using MAX.Core.DependencyInjection; +using Store.Users.Contracts; +using Store.Users.Contracts.Dtos; +using Store.Users.Entities; +using Store.Users.Mappers; +using Store.Users.Repositories; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Store.Users.Services +{ + internal class UserQueryService : IUserQueryService, ITransientDependency + { + private readonly IUserRepository _userRepository; + + public UserQueryService(IUserRepository userRepository) + { + _userRepository = userRepository; + } + public async Task GetUser(string userName) + { + var sql = _userRepository.Where(a => a.UserName == userName).ToSql(); + var user = await _userRepository.Where(a => a.UserName == userName).FirstAsync(); + if (user != null) + { + if (user.IsMainUser == false) + { + var mainUser = await _userRepository.Where(a => a.UserName == user.ParentUserName).FirstAsync(); + if (mainUser != null) + { + user.OemId = mainUser.OemId; + user.PostagePerOrder = mainUser.PostagePerOrder; + user.RefundPostagePerOrder = mainUser.RefundPostagePerOrder; + user.GiftOemAmountPerOrder = mainUser.GiftOemAmountPerOrder; + user.SyncLogisticsPerOrder = mainUser.SyncLogisticsPerOrder; + } + } + } + return new UserMapper().ToInfo(user); + } + } +} diff --git a/Modules/Store.Users/Startup.cs b/Modules/Store.Users/Startup.cs new file mode 100644 index 0000000..7cc1687 --- /dev/null +++ b/Modules/Store.Users/Startup.cs @@ -0,0 +1,22 @@ +using MAX.Core.DependencyInjection; +using MAX.Core.Interfaces; + +namespace Store.Users +{ + public class Startup : IStartup + { + public int Priority => IntPriority.Normal; + + public void Initialize() + { + } + + public void Register(IServiceRegistrar registrar) + { + } + + public void Start(IServiceProvider serviceProvider) + { + } + } +} diff --git a/Modules/Store.Users/Store.Users.csproj b/Modules/Store.Users/Store.Users.csproj new file mode 100644 index 0000000..6402cfa --- /dev/null +++ b/Modules/Store.Users/Store.Users.csproj @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/Store.API/Controllers/UserController.cs b/Store.API/Controllers/UserController.cs index 4f11b90..f339489 100644 --- a/Store.API/Controllers/UserController.cs +++ b/Store.API/Controllers/UserController.cs @@ -7,21 +7,21 @@ using System.Text.Json.Serialization; namespace Store.Api.Controllers { - [ApiController] - [ApiVersionNeutral] - [Route("wxxd_user/[action]")] - public class UserController : ControllerBase - { - private readonly IUserRepository _userRepository; + //[ApiController] + //[ApiVersionNeutral] + //[Route("wxxd_user/[action]")] + //public class UserController : ControllerBase + //{ + // private readonly IUserRepository _userRepository; - public UserController(IUserRepository userRepository) - { - _userRepository = userRepository; - } - [HttpGet] - public string GetUser() - { - return JsonSerializer.Serialize(_userRepository.Select.First()); - } - } + // public UserController(IUserRepository userRepository) + // { + // _userRepository = userRepository; + // } + // [HttpGet] + // public string GetUser() + // { + // return JsonSerializer.Serialize(_userRepository.Select.First()); + // } + //} } diff --git a/Store.API/Controllers/WeatherForecastController.cs b/Store.API/Controllers/WeatherForecastController.cs deleted file mode 100644 index 872bf92..0000000 --- a/Store.API/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Asp.Versioning; -using MAX.Framework.Dtos; -using Microsoft.AspNetCore.Mvc; -using Store.Api; -using System.ComponentModel; - -namespace Store.Api.Controllers -{ - [ApiController] - [Description("测试温度")] - [ApiVersion("1.0")] - [Route("api/v{version:apiVersion}/[controller]")] - public class WeatherForecastController : ControllerBase - { - private static readonly string[] Summaries = - [ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - ]; - - [HttpGet(Name = "GetWeatherForecast")] - public IEnumerable Get() - { - IEnumerable data = Enumerable.Range(1, 5).Select(index => new WeatherForecast - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); - - return data; - } - } -} diff --git a/Store.API/Controllers/v2/WeatherForecastController.cs b/Store.API/Controllers/v2/WeatherForecastController.cs index af8af7c..795f172 100644 --- a/Store.API/Controllers/v2/WeatherForecastController.cs +++ b/Store.API/Controllers/v2/WeatherForecastController.cs @@ -5,29 +5,29 @@ using Store.Api; namespace Store.Api.Controllers.v2 { - [ApiController] - [ApiVersion("2.0")] - [Route("api/v{version:apiVersion}/[controller]")] - public class WeatherForecastController : ControllerBase - { - private static readonly string[] Summaries = - [ - "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" - ]; + //[ApiController] + //[ApiVersion("2.0")] + //[Route("api/v{version:apiVersion}/[controller]")] + //public class WeatherForecastController : ControllerBase + //{ + // private static readonly string[] Summaries = + // [ + // "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" + // ]; - [HttpGet(Name = "GetWeatherForecastV2")] - public ApiResult> Get() - { - IEnumerable data = Enumerable.Range(1, 10).Select(index => new WeatherForecastV2 - { - Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), - TemperatureC = Random.Shared.Next(-20, 55), - FeelsLikeC = Random.Shared.Next(-20, 55), - Summary = Summaries[Random.Shared.Next(Summaries.Length)] - }) - .ToArray(); + // [HttpGet(Name = "GetWeatherForecastV2")] + // public ApiResult> Get() + // { + // IEnumerable data = Enumerable.Range(1, 10).Select(index => new WeatherForecastV2 + // { + // Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), + // TemperatureC = Random.Shared.Next(-20, 55), + // FeelsLikeC = Random.Shared.Next(-20, 55), + // Summary = Summaries[Random.Shared.Next(Summaries.Length)] + // }) + // .ToArray(); - return ApiResult>.Success(data); - } - } + // return ApiResult>.Success(data); + // } + //} } diff --git a/Store.API/Store.Api.csproj b/Store.API/Store.Api.csproj index 42eff63..bf9f376 100644 --- a/Store.API/Store.Api.csproj +++ b/Store.API/Store.Api.csproj @@ -19,7 +19,8 @@ - + + diff --git a/Store.API/WeatherForecast.cs b/Store.API/WeatherForecast.cs deleted file mode 100644 index 542efad..0000000 --- a/Store.API/WeatherForecast.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Store.Api -{ - public class WeatherForecast - { - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - - public string? Summary { get; set; } - } -} diff --git a/Store.API/WeatherForecastV2.cs b/Store.API/WeatherForecastV2.cs deleted file mode 100644 index 058a9e1..0000000 --- a/Store.API/WeatherForecastV2.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace Store.Api -{ - public class WeatherForecastV2 - { - public DateOnly Date { get; set; } - - public int TemperatureC { get; set; } - - public int TemperatureF => 32 + (int)(TemperatureC / 0.5556); - - public int FeelsLikeC { get; set; } - - public string? Summary { get; set; } - } -} diff --git a/Store.Api.slnx b/Store.Api.slnx index 79df559..27d1543 100644 --- a/Store.Api.slnx +++ b/Store.Api.slnx @@ -4,7 +4,11 @@ - + + + + + diff --git a/Store.Framework/Repositorys/SqlRepository.cs b/Store.Framework/Repositorys/SqlRepository.cs index 36c06d1..e992e09 100644 --- a/Store.Framework/Repositorys/SqlRepository.cs +++ b/Store.Framework/Repositorys/SqlRepository.cs @@ -8,11 +8,8 @@ using System.Text; namespace Store.Framework.Repositorys { - public interface IUserRepository : IBaseRepository - { - } - public class SqlRepository : WxRepository, IUserRepository, IScopedDependency + public class SqlRepository : WxRepository, IScopedDependency { public SqlRepository([FromKeyedServices("KJDDB")] IFreeSql fsql) : base(fsql) {