修改代码
增加云商品数据
This commit is contained in:
1 parent
2f406c840f
commit
db4f030c17
58 files changed
+1550
-120
No files matched your search
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 统一状态码中间件
|
||||
/// 统一返回200 固定格式
|
||||
/// </summary>
|
||||
internal class UnifyStatusCodeMiddleware
|
||||
{
|
||||
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly ILogger<UnifyStatusCodeMiddleware> _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<UnifyStatusCodeMiddleware> 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})")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -211,6 +211,7 @@ namespace MAX.Framework.DependencyInjection
|
||||
|
||||
public static IApplicationBuilder UseStore(this IApplicationBuilder app)
|
||||
{
|
||||
app.UseMiddleware<UnifyStatusCodeMiddleware>();
|
||||
foreach (IStartup startup in Startups)
|
||||
{
|
||||
startup.Start((app as IHost).Services);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<PackageReference Include="FreeSql.Provider.MySql" Version="3.5.311" />
|
||||
<PackageReference Include="FreeSql.Repository" Version="3.5.311" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageReference Include="NLog.Web.AspNetCore" Version="6.2.0" />
|
||||
<PackageReference Include="Riok.Mapperly" Version="4.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<CheckEolTargetFramework>false</CheckEolTargetFramework>
|
||||
<SuppressNETCoreSdkPreviewMessage>true</SuppressNETCoreSdkPreviewMessage>
|
||||
<Nullable>annotations</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<NoWarn>CS1591</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
+4
-12
@@ -12,19 +12,11 @@ using Store.Modules.CloudProduct.Services;
|
||||
|
||||
namespace Store.Modules.CloudProduct
|
||||
{
|
||||
/// <summary>
|
||||
/// CloudProduct 模块的模块化入口(<see cref="IModule"/>):Hangfire 后台任务(商品分词同步)+ Hangfire 看板。
|
||||
/// 与 <see cref="Startup"/>(只做 IStartup 的 Initialize/Register)分开,是因为模块注册需要配置和 app:
|
||||
/// <list type="bullet">
|
||||
/// <item><c>builder.AddStoreHub()</c> 执行 <see cref="AddModule"/>(注册 Hangfire 服务,此时只能拿到容器和配置);</item>
|
||||
/// <item><c>app.UseStoreHubModules()</c> 执行 <see cref="UseModule"/>(挂看板中间件 + 注册定时任务,此时才有 app)。</item>
|
||||
/// </list>
|
||||
/// </summary>
|
||||
|
||||
public class CloudProductModule : IModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 本模块自己的配置文件(源码里是 Models/CloudProduct/appsettings.json,
|
||||
/// 构建时复制到宿主输出目录并改名成这个名字,避免与宿主的 appsettings.json 冲突)
|
||||
/// 本模块自己的配置文件
|
||||
/// </summary>
|
||||
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")
|
||||
+1
-1
@@ -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;
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -14,5 +14,11 @@
|
||||
},
|
||||
"Delete": {
|
||||
"SoftDelete": true
|
||||
},
|
||||
"Hangfire": {
|
||||
"Dashboard" :{
|
||||
"User": "admin",
|
||||
"Pass": "1234560"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Store.Shops.Contracts
|
||||
{
|
||||
public interface IShopQueryService
|
||||
{
|
||||
DateTime GetExpireTime(string shopId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,144 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
|
||||
namespace YourNamespace
|
||||
{
|
||||
/// <summary>
|
||||
/// 店铺表
|
||||
/// </summary>
|
||||
[Table(Name = "wxxd.shop")]
|
||||
public class ShopEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// 表id
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// login_name
|
||||
/// </summary>
|
||||
[Column(Name = "login_name")]
|
||||
public string LoginName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// login_pass
|
||||
/// </summary>
|
||||
[Column(Name = "login_pass")]
|
||||
public string LoginPass { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// cookie
|
||||
/// </summary>
|
||||
[Column(Name = "cookie")]
|
||||
public string Cookie { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// cookie2
|
||||
/// </summary>
|
||||
[Column(Name = "cookie2")]
|
||||
public string Cookie2 { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// anti_contents
|
||||
/// </summary>
|
||||
[Column(Name = "anti_contents")]
|
||||
public string AntiContents { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// openid
|
||||
/// </summary>
|
||||
[Column(Name = "openid")]
|
||||
public string Openid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// shop_id
|
||||
/// </summary>
|
||||
[Column(Name = "shop_id")]
|
||||
public string ShopId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// shop_account
|
||||
/// </summary>
|
||||
[Column(Name = "shop_account")]
|
||||
public string ShopAccount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// sub_user_name
|
||||
/// </summary>
|
||||
[Column(Name = "sub_user_name")]
|
||||
public string SubUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// user_name
|
||||
/// </summary>
|
||||
[Column(Name = "user_name")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺分组名称(非子账号分组)
|
||||
/// </summary>
|
||||
[Column(Name = "group_name")]
|
||||
public string GroupName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// add_time
|
||||
/// </summary>
|
||||
[Column(Name = "add_time")]
|
||||
public DateTime? AddTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// mdy_time
|
||||
/// </summary>
|
||||
[Column(Name = "mdy_time")]
|
||||
public DateTime? MdyTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺所属公司
|
||||
/// </summary>
|
||||
[Column(Name = "company_name")]
|
||||
public string CompanyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[Column(Name = "notes")]
|
||||
public string Notes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// login_status
|
||||
/// </summary>
|
||||
[Column(Name = "login_status")]
|
||||
public string LoginStatus { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺每月商品上传限额剩余
|
||||
/// </summary>
|
||||
[Column(Name = "add_product_remaining")]
|
||||
public int AddProductRemaining { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上传限额所处月份
|
||||
/// </summary>
|
||||
[Column(Name = "add_product_month")]
|
||||
public byte AddProductMonth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分配的二级超管的user_name
|
||||
/// </summary>
|
||||
[Column(Name = "operate_sub_sa_name")]
|
||||
public string OperateSubSaName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分配二级超管的时间
|
||||
/// </summary>
|
||||
[Column(Name = "add_sub_sa_time")]
|
||||
public DateTime? AddSubSaTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// login_status2
|
||||
/// </summary>
|
||||
[Column(Name = "login_status2")]
|
||||
public string LoginStatus2 { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
|
||||
namespace Store.Users.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// 商店过期
|
||||
/// </summary>
|
||||
[Table(Name = "wxxd.user_points_shop_expire")]
|
||||
public class ShopExpireEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 商店ID
|
||||
/// </summary>
|
||||
[Column(Name = "shop_id")]
|
||||
public string ShopId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 过期时间
|
||||
/// </summary>
|
||||
// 数据库列名末尾包含 U+200C,不能改成普通 expire_time。
|
||||
[Column(Name = "expire_time")]
|
||||
public int ExpireTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加时间
|
||||
/// </summary>
|
||||
[Column(Name = "add_time")]
|
||||
public DateTime AddTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 修改时间
|
||||
/// </summary>
|
||||
[Column(Name = "mdy_time")]
|
||||
public DateTime MdyTime { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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<ShopEntity>
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取用户商铺过期时间
|
||||
/// </summary>
|
||||
/// <param name="ShopId"></param>
|
||||
/// <returns></returns>
|
||||
DateTime GetExpireTime(string ShopId);
|
||||
}
|
||||
internal class ShopRepository : BaseRepository<ShopEntity>, IShopRepository, ITransientDependency
|
||||
{
|
||||
private readonly IFreeSql _freeSql;
|
||||
|
||||
public ShopRepository(IFreeSql freeSql) : base(freeSql)
|
||||
{
|
||||
_freeSql = freeSql;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户商铺过期时间
|
||||
/// </summary>
|
||||
/// <param name="ShopId"></param>
|
||||
public DateTime GetExpireTime(string ShopId)
|
||||
{
|
||||
ShopExpireEntity currentExpire = _freeSql.Select<ShopExpireEntity>()
|
||||
.Where(a => a.ShopId == ShopId)
|
||||
.ForUpdate()
|
||||
.First();
|
||||
if (currentExpire == null)
|
||||
{
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
return DateHelper.ConvertFromUnixTimestampInSeconds(currentExpire.ExpireTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Store.Framework\Store.Framework.csproj" />
|
||||
<ProjectReference Include="..\Store.Shops.Contracts\Store.Shops.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -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
|
||||
{/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户昵称
|
||||
/// </summary>
|
||||
public string NickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名称(登录账户)
|
||||
/// </summary>
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录密码
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// card_id
|
||||
/// </summary>
|
||||
public string CardId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户分组 3主号 4客服 5加盟 8登录 9采购 10加盟 11上货
|
||||
/// </summary>
|
||||
public byte GroupId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父账户用户名
|
||||
/// </summary>
|
||||
public string ParentUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// oem编号,仅oem用户有值
|
||||
/// </summary>
|
||||
public string OemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
public string Mobile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加时间
|
||||
/// </summary>
|
||||
public DateTime? AddTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 修改时间
|
||||
/// </summary>
|
||||
public DateTime? MdyTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 公司名称
|
||||
/// </summary>
|
||||
public string CompanyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Notes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 超管等级 0 普通用户 1 超级管理员
|
||||
/// </summary>
|
||||
public short? SaLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账户权限
|
||||
/// </summary>
|
||||
public string Authority { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子账号被禁止展示的功能页面
|
||||
/// </summary>
|
||||
public string ForbiddenPage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账户积分,1积分=1元
|
||||
/// </summary>
|
||||
public decimal Points { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 积分历史累计充值金额
|
||||
/// </summary>
|
||||
public decimal? RechargePointsTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺每续费一个月需要的积分,单位元
|
||||
/// </summary>
|
||||
public int ShopPointsPerMonth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可用余额
|
||||
/// </summary>
|
||||
public decimal? Balance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 累计充值金额
|
||||
/// </summary>
|
||||
public decimal? RechargeAmountTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 每单中转仓快递费用,单位元,两位小数
|
||||
/// </summary>
|
||||
public decimal? PostagePerOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 每单中转仓退货快递费用,单位元,两位小数
|
||||
/// </summary>
|
||||
public decimal? RefundPostagePerOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 礼物每单额外收取费用,单位元,两位小数
|
||||
/// </summary>
|
||||
public decimal? GiftOemAmountPerOrder { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 同步物流费用,单位元,两位小数
|
||||
/// </summary>
|
||||
public decimal? SyncLogisticsPerOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否主账户
|
||||
/// </summary>
|
||||
public bool IsMainUser
|
||||
{
|
||||
get => string.IsNullOrWhiteSpace(ParentUserName);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否OEM租户
|
||||
/// </summary>
|
||||
public bool IsOEMTenant => !string.IsNullOrWhiteSpace(OemId);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
/// <summary>
|
||||
/// 用户付款类型
|
||||
/// </summary>
|
||||
public enum UserPaymentTypes
|
||||
{
|
||||
充值 = 1,
|
||||
//采购花费 = 2,
|
||||
//产品退款到账 = 3,
|
||||
//运费退款到账 = 4,
|
||||
//采购收款 = 5,
|
||||
//产品退款扣除 = 6,
|
||||
//运费退款扣除 = 7,
|
||||
礼物单支出 = 16,
|
||||
中转仓扣费支出 = 20,
|
||||
中转仓作废返还收入 = 23,
|
||||
中转仓超重支出 = 24,
|
||||
退货包裹扣费支出 = 26,
|
||||
中转仓快递超重费用 = 28,
|
||||
支付宝在线充值 = 30,
|
||||
云仓退货支出 = 31,
|
||||
礼物单退费 = 34,
|
||||
同步单号 = 55,
|
||||
}
|
||||
@@ -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<UserInfo> GetUser(string userName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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
|
||||
//{
|
||||
// /// <summary>
|
||||
// /// 商铺续费
|
||||
// /// </summary>
|
||||
// /// <param name="UserName"></param>
|
||||
// /// <param name="ShopId"></param>
|
||||
// /// <param name="RenewDuration"></param>
|
||||
// internal record class ShopRenewCommand(string UserName, string ShopId, int RenewDuration) : IRequest<ShopRenewResponse>;
|
||||
// internal class ShopRenewCommandHandler : IRequestHandler<ShopRenewCommand, ShopRenewResponse>
|
||||
// {
|
||||
// private readonly IUserRepository _userRepository;
|
||||
// private readonly IShopQueryService _shopQueryService;
|
||||
|
||||
// public ShopRenewCommandHandler(IUserRepository userRepository, IShopQueryService shopQueryService)
|
||||
// {
|
||||
// _userRepository = userRepository;
|
||||
// _shopQueryService = shopQueryService;
|
||||
// }
|
||||
// async Task<ShopRenewResponse> IRequestHandler<ShopRenewCommand, ShopRenewResponse>.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);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
|
||||
//}
|
||||
@@ -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<UserInfo> GetUser(string userName)
|
||||
{
|
||||
return await _userQuery.GetUser(userName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Store.Users.Dtos
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户续费商铺
|
||||
/// </summary>
|
||||
public class ShopRenewRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 店铺ID
|
||||
/// </summary>
|
||||
public string ShopId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 续费时长数值,例如 3;范围 1-120 个月
|
||||
/// </summary>
|
||||
public int RenewDuration { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
|
||||
namespace Store.Users.Entities;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// OEM贴牌表
|
||||
/// </summary>
|
||||
[Table(Name = "wxxd.oem")]
|
||||
public class OEMEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// oem_id
|
||||
/// </summary>
|
||||
[Column(Name = "oem_id")]
|
||||
public string OemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 贴牌名称
|
||||
/// </summary>
|
||||
[Column(Name = "oem_name")]
|
||||
public string OemName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 贴牌管理人主账户
|
||||
/// </summary>
|
||||
[Column(Name = "oem_owner")]
|
||||
public string OemOwner { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 图标
|
||||
/// </summary>
|
||||
[Column(Name = "oem_icon")]
|
||||
public string OemIcon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 题图
|
||||
/// </summary>
|
||||
[Column(Name = "oem_img")]
|
||||
public string OemImg { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// add_time
|
||||
/// </summary>
|
||||
[Column(Name = "add_time")]
|
||||
public DateTime AddTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// mdy_time
|
||||
/// </summary>
|
||||
[Column(Name = "mdy_time")]
|
||||
public DateTime MdyTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// is_del
|
||||
/// </summary>
|
||||
[Column(Name = "is_del")]
|
||||
public byte IsDel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可提现余额,单位分
|
||||
/// </summary>
|
||||
[Column(Name = "available_balance")]
|
||||
public long AvailableBalance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 冻结余额,单位分
|
||||
/// </summary>
|
||||
[Column(Name = "frozen_balance")]
|
||||
public long FrozenBalance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 累计返利金额,单位分
|
||||
/// </summary>
|
||||
[Column(Name = "total_rebate_amount")]
|
||||
public long TotalRebateAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 累计提现金额,单位分
|
||||
/// </summary>
|
||||
[Column(Name = "total_withdraw_amount")]
|
||||
public long TotalWithdrawAmount { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
using FreeSql.DataAnnotations;
|
||||
using System;
|
||||
|
||||
namespace Store.Users.Entities
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户表
|
||||
/// </summary>
|
||||
[Table(Name = "wxxd.user")]
|
||||
public class UserEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// ID
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户昵称
|
||||
/// </summary>
|
||||
[Column(Name = "nick_name")]
|
||||
public string NickName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名称(登录账户)
|
||||
/// </summary>
|
||||
[Column(Name = "user_name")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 登录密码
|
||||
/// </summary>
|
||||
[Column(Name = "password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// card_id
|
||||
/// </summary>
|
||||
[Column(Name = "card_id")]
|
||||
public string CardId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户分组 3主号 4客服 5加盟 8登录 9采购 10加盟 11上货
|
||||
/// </summary>
|
||||
[Column(Name = "group_id")]
|
||||
public byte GroupId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 父账户用户名
|
||||
/// </summary>
|
||||
[Column(Name = "parent_user_name")]
|
||||
public string ParentUserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// oem编号,仅oem用户有值
|
||||
/// </summary>
|
||||
[Column(Name = "oem_id")]
|
||||
public string OemId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
[Column(Name = "mobile")]
|
||||
public string Mobile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加时间
|
||||
/// </summary>
|
||||
[Column(Name = "add_time")]
|
||||
public DateTime? AddTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 修改时间
|
||||
/// </summary>
|
||||
[Column(Name = "mdy_time")]
|
||||
public DateTime? MdyTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 公司名称
|
||||
/// </summary>
|
||||
[Column(Name = "company_name")]
|
||||
public string CompanyName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[Column(Name = "notes")]
|
||||
public string Notes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 超管等级 0 普通用户 1 超级管理员
|
||||
/// </summary>
|
||||
[Column(Name = "sa_level")]
|
||||
public short? SaLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账户权限
|
||||
/// </summary>
|
||||
[Column(Name = "authority")]
|
||||
public string Authority { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 子账号被禁止展示的功能页面
|
||||
/// </summary>
|
||||
[Column(Name = "forbidden_page")]
|
||||
public string ForbiddenPage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账户积分,1积分=1元
|
||||
/// </summary>
|
||||
[Column(Name = "points")]
|
||||
public decimal Points { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 积分历史累计充值金额
|
||||
/// </summary>
|
||||
[Column(Name = "recharge_points_total")]
|
||||
public decimal? RechargePointsTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 店铺每续费一个月需要的积分,单位元
|
||||
/// </summary>
|
||||
[Column(Name = "shop_points_per_month")]
|
||||
public int ShopPointsPerMonth { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 可用余额
|
||||
/// </summary>
|
||||
[Column(Name = "balance")]
|
||||
public decimal? Balance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 累计充值金额
|
||||
/// </summary>
|
||||
[Column(Name = "recharge_amount_total")]
|
||||
public decimal? RechargeAmountTotal { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 每单中转仓快递费用,单位元,两位小数
|
||||
/// </summary>
|
||||
[Column(Name = "postage_per_order")]
|
||||
public decimal? PostagePerOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 每单中转仓退货快递费用,单位元,两位小数
|
||||
/// </summary>
|
||||
[Column(Name = "refund_postage_per_order")]
|
||||
public decimal? RefundPostagePerOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 礼物每单额外收取费用,单位元,两位小数
|
||||
/// </summary>
|
||||
[Column(Name = "gift_oem_amount_per_order")]
|
||||
public decimal? GiftOemAmountPerOrder { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 同步物流费用,单位元,两位小数
|
||||
/// </summary>
|
||||
[Column(Name = "sync_logistics_per_order")]
|
||||
public decimal? SyncLogisticsPerOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否主账户
|
||||
/// </summary>
|
||||
public bool IsMainUser
|
||||
{
|
||||
get => string.IsNullOrWhiteSpace(ParentUserName);
|
||||
}
|
||||
/// <summary>
|
||||
/// 是否OEM租户
|
||||
/// </summary>
|
||||
public bool IsOEMTenant => !string.IsNullOrWhiteSpace(OemId);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// id
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 变动类型,1:充值,2:采购花费,3:产品退款到账,4:运费退款到账,5:采购收款,6:产品退款扣除,7:运费退款扣除, 16:礼物单话费,20:中转仓扣费支出,23:中转仓退款收入
|
||||
/// </summary>
|
||||
[Column(Name = "type")]
|
||||
public int Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 金额(元)
|
||||
/// </summary>
|
||||
[Column(Name = "amount")]
|
||||
public decimal? Amount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 归属oem用户的金额
|
||||
/// </summary>
|
||||
[Column(Name = "oem_amount")]
|
||||
public decimal? OemAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 余额(元)
|
||||
/// </summary>
|
||||
[Column(Name = "balance")]
|
||||
public decimal? Balance { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账户名
|
||||
/// </summary>
|
||||
[Column(Name = "user_name")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平台编码
|
||||
/// </summary>
|
||||
[Column(Name = "platform_code")]
|
||||
public string PlatformCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单id
|
||||
/// </summary>
|
||||
[Column(Name = "order_id")]
|
||||
public string OrderId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 售后单id
|
||||
/// </summary>
|
||||
[Column(Name = "after_sale_id")]
|
||||
public long? AfterSaleId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建人
|
||||
/// </summary>
|
||||
[Column(Name = "create_by")]
|
||||
public string CreateBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 创建时间
|
||||
/// </summary>
|
||||
[Column(Name = "create_time")]
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 修改人
|
||||
/// </summary>
|
||||
[Column(Name = "update_by")]
|
||||
public string UpdateBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 修改时间
|
||||
/// </summary>
|
||||
[Column(Name = "update_time")]
|
||||
public DateTime? UpdateTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否已删除
|
||||
/// </summary>
|
||||
[Column(Name = "is_deleted")]
|
||||
public int IsDeleted { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
[Column(Name = "remark")]
|
||||
public string Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 扣款的对方账户名称
|
||||
/// </summary>
|
||||
[Column(Name = "counterparty_account_name")]
|
||||
public string CounterpartyAccountName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OEM是否结算 0未结算 1已结算
|
||||
/// </summary>
|
||||
[Column(Name = "settlement")]
|
||||
public byte Settlement { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 退款流水号 外采&订单号
|
||||
/// </summary>
|
||||
[Column(Name = "refund_flow_no")]
|
||||
public string RefundFlowNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结算时间
|
||||
/// </summary>
|
||||
[Column(Name = "settlement_time")]
|
||||
public DateTime? SettlementTime { get; set; }
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// 主键(自增)
|
||||
/// </summary>
|
||||
[Column(Name = "id", IsPrimary = true, IsIdentity = true)]
|
||||
public long Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户名(NOT NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "user_name")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户昵称(NOT NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "user_nick")]
|
||||
public string UserNick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作记录金额,单位元,最小1元(NOT NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "delta_points")]
|
||||
public decimal DeltaPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 充值或消费后的当前金额(允许 NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "new_points")]
|
||||
public decimal? NewPoints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作类型 消费 充值 转入 转出(NOT NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "option_type")]
|
||||
public string OptionType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 操作者类型 管理员 用户(NOT NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "operator_type")]
|
||||
public string OperatorType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实际操作者用户名(NOT NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "operator_name")]
|
||||
public string OperatorName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 消费店铺编号(消费才有值,充值为空,允许 NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "shop_id")]
|
||||
public string? ShopId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 消费店铺名称(消费才有值,充值为空,允许 NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "shop_account")]
|
||||
public string? ShopAccount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 备注(允许 NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "remark")]
|
||||
public string? Remark { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// (点数转出时的)对方账户(允许 NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "counterparty_account_name")]
|
||||
public string? CounterpartyAccountName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付宝订单的外部订单号(允许 NULL)
|
||||
/// </summary>
|
||||
[Column(Name = "out_trade_no")]
|
||||
public string? OutTradeNo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 添加时间(NOT NULL,默认 CURRENT_TIMESTAMP)
|
||||
/// </summary>
|
||||
[Column(Name = "add_time")]
|
||||
public DateTime AddTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// OEM是否结算 0未结算 1已结算
|
||||
/// </summary>
|
||||
[Column(Name = "settlement")]
|
||||
public bool Settlement { get; set; }
|
||||
/// <summary>
|
||||
/// 结算时间
|
||||
/// </summary>
|
||||
[Column(Name = "settlement_time")]
|
||||
public DateTime? SettlementTime { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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<UserEntity>
|
||||
{
|
||||
Task<UserEntity> GetUser(string userName);
|
||||
}
|
||||
internal class UserRepository : BaseRepository<UserEntity>, IUserRepository, ITransientDependency
|
||||
{
|
||||
private readonly IFreeSql _freeSql;
|
||||
|
||||
public UserRepository(IFreeSql freeSql) : base(freeSql)
|
||||
{
|
||||
_freeSql = freeSql;
|
||||
}
|
||||
|
||||
public async Task<UserEntity> 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<UserInfo> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Store.Framework\Store.Framework.csproj" />
|
||||
<ProjectReference Include="..\Store.Shops.Contracts\Store.Shops.Contracts.csproj" />
|
||||
<ProjectReference Include="..\Store.Users.Contracts\Store.Users.Contracts.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -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());
|
||||
// }
|
||||
//}
|
||||
}
|
||||
@@ -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<WeatherForecast> Get()
|
||||
{
|
||||
IEnumerable<WeatherForecast> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<IEnumerable<WeatherForecastV2>> Get()
|
||||
{
|
||||
IEnumerable<WeatherForecastV2> 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<IEnumerable<WeatherForecastV2>> Get()
|
||||
// {
|
||||
// IEnumerable<WeatherForecastV2> 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<IEnumerable<WeatherForecastV2>>.Success(data);
|
||||
}
|
||||
}
|
||||
// return ApiResult<IEnumerable<WeatherForecastV2>>.Success(data);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
@@ -19,7 +19,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Models\CloudProduct\Store.Modules.CloudProduct.csproj" />
|
||||
<ProjectReference Include="..\Modules\CloudProduct\Store.CloudProduct.csproj" />
|
||||
<ProjectReference Include="..\Modules\Store.Users\Store.Users.csproj" />
|
||||
<ProjectReference Include="..\Store.Framework\Store.Framework.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -4,7 +4,11 @@
|
||||
<Project Path="Core/MAX.Framework/MAX.Framework.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/Modules/">
|
||||
<Project Path="Models/CloudProduct/Store.Modules.CloudProduct.csproj" Id="9720597a-661b-47d8-90c7-83e17c6d5920" />
|
||||
<Project Path="Modules/CloudProduct/Store.CloudProduct.csproj" />
|
||||
<Project Path="Modules/Store.Shops.Contracts/Store.Shops.Contracts.csproj" Id="7d313823-f86a-450a-be29-8f915fc4b5b3" />
|
||||
<Project Path="Modules/Store.Shops/Store.Shops.csproj" Id="b1c06d62-9cfb-4e87-b495-7077dd0c088d" />
|
||||
<Project Path="Modules/Store.Users.Contracts/Store.Users.Contracts.csproj" Id="d4a8177b-503c-4205-96ce-da0e01c855db" />
|
||||
<Project Path="Modules/Store.Users/Store.Users.csproj" />
|
||||
</Folder>
|
||||
<Folder Name="/_SolutionItems/">
|
||||
<File Path="Directory.Build.props" />
|
||||
|
||||
@@ -8,11 +8,8 @@ using System.Text;
|
||||
|
||||
namespace Store.Framework.Repositorys
|
||||
{
|
||||
public interface IUserRepository : IBaseRepository<User>
|
||||
{
|
||||
|
||||
}
|
||||
public class SqlRepository : WxRepository<User>, IUserRepository, IScopedDependency
|
||||
public class SqlRepository : WxRepository<User>, IScopedDependency
|
||||
{
|
||||
public SqlRepository([FromKeyedServices("KJDDB")] IFreeSql fsql) : base(fsql)
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user