From 541b75ecd852cdb2a9f6325c01e5b2b78f446eaf Mon Sep 17 00:00:00 2001 From: MSuMshk <2039814060@qq.com> Date: Tue, 2 Dec 2025 12:09:46 +0800 Subject: [PATCH] =?UTF-8?q?style:=20=E5=91=BD=E4=BB=A4=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E5=8F=98=E5=8C=96=E4=B8=8E=E8=A7=84=E8=8C=83=E8=A1=A5=E5=85=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 45 ++++++++++++++++++- .../Controllers/DeliveriesController.cs | 28 ++++++------ .../Controllers/MerchantsController.cs | 28 ++++++------ .../Controllers/OrdersController.cs | 28 ++++++------ .../Controllers/PaymentsController.cs | 28 ++++++------ .../Controllers/ProductsController.cs | 28 ++++++------ .../Controllers/StoresController.cs | 28 ++++++------ .../Commands/UpdateDeliveryOrderCommand.cs | 26 +++++------ .../Commands/UpdateMerchantCommand.cs | 18 ++++---- .../App/Orders/Commands/UpdateOrderCommand.cs | 44 +++++++++--------- .../Payments/Commands/UpdatePaymentCommand.cs | 22 ++++----- .../Products/Commands/UpdateProductCommand.cs | 40 ++++++++--------- .../App/Stores/Commands/UpdateStoreCommand.cs | 40 ++++++++--------- 13 files changed, 217 insertions(+), 186 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 6ff2f4f..1ed8c30 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -143,8 +143,51 @@ 6. [ ] **精度丢失**:Long 类型的 ID 是否转为了 String? 7. [ ] **配置硬编码**:是否直接写死了连接串或密钥? +## 17. .NET 10 / C# 14 现代语法最佳实践(增量) +> 2025 年推荐的 20 条语法规范,新增特性优先,保持极简。 +1. **field 关键字**:属性内直接使用 `field` 处理后备字段,`set => field = value.Trim();`。 +2. **空值条件赋值 `?.=`**:仅对象非空时赋值,减少 `if`。 +3. **未绑定泛型 nameof**:`nameof(List<>)` 获取泛型类型名,无需占位类型参数。 +4. **Lambda 参数修饰符**:在 Lambda 中可用 `ref/out/in` 与默认参数,例如 `(ref int x, int bonus = 10) => x += bonus;`。 +5. **主构造函数 (Primary Constructor)**:服务/数据类优先 `class Foo(IDep dep, ILogger logger) { }`。 +6. **record/required/init**:DTO 默认用 record;关键属性用 `required`;不可变属性用 `init`。 +7. **集合表达式与展开**:使用 `[]` 创建集合,`[..other]` 拼接,`str[1..^1]` 进行切片。 +8. **模式匹配**:列表模式 `[1, 2, .. var rest]`、属性模式 `{ IsActive: true }`、switch 表达式简化分支。 +9. **文件范围命名空间/全局 using**:减少缩进与重复引用;复杂泛型用别名。 +10. **顶级语句**:Program.cs 保持顶级语句风格。 +11. **原始/UTF-8 字面量**:多行文本用 `"""`,性能场景用 `"text"u8`。 +12. **不可变命令优先**:命令/DTO 优先用 record 和 `with` 非破坏性拷贝,例如 `command = command with { MerchantId = merchantId };`,避免直接 `command.Property = ...` 带来的副作用。 + +(其余规则继续遵循上文约束:分层、命名、异步、日志、验证、租户/ID 策略等。) + +## 18. .NET 10 极致性能优化最佳实践(增量) +> 侧重零分配、并发与底层优化,遵循 2025 推荐方案。 +1. **Span/ReadOnlySpan 优先**:API 参数尽量用 `ReadOnlySpan` 处理字符串/切片,避免 Substring/复制。 +2. **栈分配与数组池**:小缓冲用 `stackalloc`,大缓冲统一用 `ArrayPool.Shared`,禁止直接 `new` 大数组。 +3. **UTF-8 字面量**:常量字节使用 `"text"u8`,避免运行时编码。 +4. **避免装箱**:热点路径规避隐式装箱,必要时用 `ref struct` 约束栈分配。 +5. **Frozen 集合**:只读查找表用 `FrozenDictionary/FrozenSet`,初始化后不再修改。 +6. **SearchValues SIMD 查找**:Span 内多字符搜索用 `SearchValues.Create(...)` + `ContainsAny`。 +7. **预设集合容量**:`List/Dictionary` 预知规模必须指定 `Capacity`。 +8. **ValueTask 热点返回**:可能同步完成的异步返回 `ValueTask`,减少 Task 分配。 +9. **Parallel.ForEachAsync 控并发**:I/O 并发用 Parallel.ForEachAsync 控制并行度,替代粗暴 Task.WhenAll。 +10. **避免 Task.Run**:在 ASP.NET Core 请求中不使用 Task.Run 做后台工作,改用 IHostedService 或 Channel 模式。 +11. **Channel 代替锁**:多线程数据传递优先使用 Channels,实现无锁生产者-消费者。 +12. **NativeAOT/PGO/向量化**:微服务/工具开启 NativeAOT;保留动态 PGO;计算密集场景考虑 System.Runtime.Intrinsics。 +13. **System.Text.Json + 源生成器**:全面替换 Newtonsoft.Json;使用 `[JsonSerializable]` + 生成的 `JsonSerializerContext`,兼容 NativeAOT,零反射。 +14. **Pipelines 处理流**:TCP/文件流解析使用 `PipeReader/PipeWriter`,获得零拷贝与缓冲管理。 +15. **HybridCache**:内存+分布式缓存统一用 HybridCache,利用防击穿合并并发请求。 + +## 19. 架构优化(增量) +> 架构优化方案 +1. **Chiseled 容器优先**:生产镜像基于 `mcr.microsoft.com/dotnet/runtime-deps:10.0-jammy-chiseled`,无 Shell、非 root,缩小攻击面,符合零信任要求。 +2. **默认集成 OpenTelemetry**:架构内置 OTel,统一通过 OTLP 导出 Metrics/Traces/Logs,避免依赖专有 APM 探针。 +3. **内部同步调用首选 gRPC**:微服务间禁止 JSON over HTTP,同步调用统一使用 gRPC,配合 Protobuf 源生成器获取强类型契约与更小载荷。 +4. **Outbox 模式强制**:处理领域事件时,事件记录必须与业务数据同事务写入 Outbox 表;后台 Worker 轮询 Outbox 再推送 MQ(RabbitMQ/Kafka),禁止事务提交后直接发消息以避免不一致。 +5. **共享资源必加分布式锁**:涉及库存扣减、定时任务抢占等共享资源时,必须引入分布式锁(如 Redis RedLock),防止并发竞争与脏写。 + --- # Working agreements -- 严格遵循上述技术栈和命名规范。 \ No newline at end of file +- 严格遵循上述技术栈和命名规范。 diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/DeliveriesController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/DeliveriesController.cs index 45e9aa0..fe5d2cf 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/DeliveriesController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/DeliveriesController.cs @@ -16,20 +16,15 @@ namespace TakeoutSaaS.AdminApi.Controllers; /// /// 配送单管理。 /// +/// +/// 初始化控制器。 +/// [ApiVersion("1.0")] [Authorize] [Route("api/admin/v{version:apiVersion}/deliveries")] -public sealed class DeliveriesController : BaseApiController +public sealed class DeliveriesController(IMediator mediator) : BaseApiController { - private readonly IMediator _mediator; - /// - /// 初始化控制器。 - /// - public DeliveriesController(IMediator mediator) - { - _mediator = mediator; - } /// /// 创建配送单。 @@ -39,7 +34,7 @@ public sealed class DeliveriesController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> Create([FromBody] CreateDeliveryOrderCommand command, CancellationToken cancellationToken) { - var result = await _mediator.Send(command, cancellationToken); + var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } @@ -58,7 +53,7 @@ public sealed class DeliveriesController : BaseApiController [FromQuery] bool sortDesc = true, CancellationToken cancellationToken = default) { - var result = await _mediator.Send(new SearchDeliveryOrdersQuery + var result = await mediator.Send(new SearchDeliveryOrdersQuery { OrderId = orderId, Status = status, @@ -80,7 +75,7 @@ public sealed class DeliveriesController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Detail(long deliveryOrderId, CancellationToken cancellationToken) { - var result = await _mediator.Send(new GetDeliveryOrderByIdQuery { DeliveryOrderId = deliveryOrderId }, cancellationToken); + var result = await mediator.Send(new GetDeliveryOrderByIdQuery { DeliveryOrderId = deliveryOrderId }, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "配送单不存在") : ApiResponse.Ok(result); @@ -95,8 +90,11 @@ public sealed class DeliveriesController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Update(long deliveryOrderId, [FromBody] UpdateDeliveryOrderCommand command, CancellationToken cancellationToken) { - command.DeliveryOrderId = command.DeliveryOrderId == 0 ? deliveryOrderId : command.DeliveryOrderId; - var result = await _mediator.Send(command, cancellationToken); + if (command.DeliveryOrderId == 0) + { + command = command with { DeliveryOrderId = deliveryOrderId }; + } + var result = await mediator.Send(command, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "配送单不存在") : ApiResponse.Ok(result); @@ -111,7 +109,7 @@ public sealed class DeliveriesController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Delete(long deliveryOrderId, CancellationToken cancellationToken) { - var success = await _mediator.Send(new DeleteDeliveryOrderCommand { DeliveryOrderId = deliveryOrderId }, cancellationToken); + var success = await mediator.Send(new DeleteDeliveryOrderCommand { DeliveryOrderId = deliveryOrderId }, cancellationToken); return success ? ApiResponse.Ok(null) : ApiResponse.Error(ErrorCodes.NotFound, "配送单不存在"); diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs index 5bbe4bf..dd99bb6 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs @@ -16,20 +16,15 @@ namespace TakeoutSaaS.AdminApi.Controllers; /// /// 商户管理。 /// +/// +/// 初始化控制器。 +/// [ApiVersion("1.0")] [Authorize] [Route("api/admin/v{version:apiVersion}/merchants")] -public sealed class MerchantsController : BaseApiController +public sealed class MerchantsController(IMediator mediator) : BaseApiController { - private readonly IMediator _mediator; - /// - /// 初始化控制器。 - /// - public MerchantsController(IMediator mediator) - { - _mediator = mediator; - } /// /// 创建商户。 @@ -39,7 +34,7 @@ public sealed class MerchantsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> Create([FromBody] CreateMerchantCommand command, CancellationToken cancellationToken) { - var result = await _mediator.Send(command, cancellationToken); + var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } @@ -57,7 +52,7 @@ public sealed class MerchantsController : BaseApiController [FromQuery] bool sortDesc = true, CancellationToken cancellationToken = default) { - var result = await _mediator.Send(new SearchMerchantsQuery + var result = await mediator.Send(new SearchMerchantsQuery { Status = status, Page = page, @@ -77,9 +72,12 @@ public sealed class MerchantsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Update(long merchantId, [FromBody] UpdateMerchantCommand command, CancellationToken cancellationToken) { - command.MerchantId = command.MerchantId == 0 ? merchantId : command.MerchantId; + if (command.MerchantId == 0) + { + command = command with { MerchantId = merchantId }; + } - var result = await _mediator.Send(command, cancellationToken); + var result = await mediator.Send(command, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "商户不存在") : ApiResponse.Ok(result); @@ -94,7 +92,7 @@ public sealed class MerchantsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Delete(long merchantId, CancellationToken cancellationToken) { - var success = await _mediator.Send(new DeleteMerchantCommand { MerchantId = merchantId }, cancellationToken); + var success = await mediator.Send(new DeleteMerchantCommand { MerchantId = merchantId }, cancellationToken); return success ? ApiResponse.Ok(null) : ApiResponse.Error(ErrorCodes.NotFound, "商户不存在"); @@ -109,7 +107,7 @@ public sealed class MerchantsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Detail(long merchantId, CancellationToken cancellationToken) { - var result = await _mediator.Send(new GetMerchantByIdQuery { MerchantId = merchantId }, cancellationToken); + var result = await mediator.Send(new GetMerchantByIdQuery { MerchantId = merchantId }, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "商户不存在") : ApiResponse.Ok(result); diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/OrdersController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/OrdersController.cs index bfcf6b3..4d04390 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/OrdersController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/OrdersController.cs @@ -17,20 +17,15 @@ namespace TakeoutSaaS.AdminApi.Controllers; /// /// 订单管理。 /// +/// +/// 初始化控制器。 +/// [ApiVersion("1.0")] [Authorize] [Route("api/admin/v{version:apiVersion}/orders")] -public sealed class OrdersController : BaseApiController +public sealed class OrdersController(IMediator mediator) : BaseApiController { - private readonly IMediator _mediator; - /// - /// 初始化控制器。 - /// - public OrdersController(IMediator mediator) - { - _mediator = mediator; - } /// /// 创建订单。 @@ -40,7 +35,7 @@ public sealed class OrdersController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> Create([FromBody] CreateOrderCommand command, CancellationToken cancellationToken) { - var result = await _mediator.Send(command, cancellationToken); + var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } @@ -61,7 +56,7 @@ public sealed class OrdersController : BaseApiController [FromQuery] bool sortDesc = true, CancellationToken cancellationToken = default) { - var result = await _mediator.Send(new SearchOrdersQuery + var result = await mediator.Send(new SearchOrdersQuery { StoreId = storeId, Status = status, @@ -85,7 +80,7 @@ public sealed class OrdersController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Detail(long orderId, CancellationToken cancellationToken) { - var result = await _mediator.Send(new GetOrderByIdQuery { OrderId = orderId }, cancellationToken); + var result = await mediator.Send(new GetOrderByIdQuery { OrderId = orderId }, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "订单不存在") : ApiResponse.Ok(result); @@ -100,8 +95,11 @@ public sealed class OrdersController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Update(long orderId, [FromBody] UpdateOrderCommand command, CancellationToken cancellationToken) { - command.OrderId = command.OrderId == 0 ? orderId : command.OrderId; - var result = await _mediator.Send(command, cancellationToken); + if (command.OrderId == 0) + { + command = command with { OrderId = orderId }; + } + var result = await mediator.Send(command, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "订单不存在") : ApiResponse.Ok(result); @@ -116,7 +114,7 @@ public sealed class OrdersController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Delete(long orderId, CancellationToken cancellationToken) { - var success = await _mediator.Send(new DeleteOrderCommand { OrderId = orderId }, cancellationToken); + var success = await mediator.Send(new DeleteOrderCommand { OrderId = orderId }, cancellationToken); return success ? ApiResponse.Ok(null) : ApiResponse.Error(ErrorCodes.NotFound, "订单不存在"); diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/PaymentsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/PaymentsController.cs index 30d87a8..de8f322 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/PaymentsController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/PaymentsController.cs @@ -16,20 +16,15 @@ namespace TakeoutSaaS.AdminApi.Controllers; /// /// 支付记录管理。 /// +/// +/// 初始化控制器。 +/// [ApiVersion("1.0")] [Authorize] [Route("api/admin/v{version:apiVersion}/payments")] -public sealed class PaymentsController : BaseApiController +public sealed class PaymentsController(IMediator mediator) : BaseApiController { - private readonly IMediator _mediator; - /// - /// 初始化控制器。 - /// - public PaymentsController(IMediator mediator) - { - _mediator = mediator; - } /// /// 创建支付记录。 @@ -39,7 +34,7 @@ public sealed class PaymentsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> Create([FromBody] CreatePaymentCommand command, CancellationToken cancellationToken) { - var result = await _mediator.Send(command, cancellationToken); + var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } @@ -58,7 +53,7 @@ public sealed class PaymentsController : BaseApiController [FromQuery] bool sortDesc = true, CancellationToken cancellationToken = default) { - var result = await _mediator.Send(new SearchPaymentsQuery + var result = await mediator.Send(new SearchPaymentsQuery { OrderId = orderId, Status = status, @@ -80,7 +75,7 @@ public sealed class PaymentsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Detail(long paymentId, CancellationToken cancellationToken) { - var result = await _mediator.Send(new GetPaymentByIdQuery { PaymentId = paymentId }, cancellationToken); + var result = await mediator.Send(new GetPaymentByIdQuery { PaymentId = paymentId }, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "支付记录不存在") : ApiResponse.Ok(result); @@ -95,8 +90,11 @@ public sealed class PaymentsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Update(long paymentId, [FromBody] UpdatePaymentCommand command, CancellationToken cancellationToken) { - command.PaymentId = command.PaymentId == 0 ? paymentId : command.PaymentId; - var result = await _mediator.Send(command, cancellationToken); + if (command.PaymentId == 0) + { + command = command with { PaymentId = paymentId }; + } + var result = await mediator.Send(command, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "支付记录不存在") : ApiResponse.Ok(result); @@ -111,7 +109,7 @@ public sealed class PaymentsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Delete(long paymentId, CancellationToken cancellationToken) { - var success = await _mediator.Send(new DeletePaymentCommand { PaymentId = paymentId }, cancellationToken); + var success = await mediator.Send(new DeletePaymentCommand { PaymentId = paymentId }, cancellationToken); return success ? ApiResponse.Ok(null) : ApiResponse.Error(ErrorCodes.NotFound, "支付记录不存在"); diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/ProductsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/ProductsController.cs index 2064156..24e334c 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/ProductsController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/ProductsController.cs @@ -16,20 +16,15 @@ namespace TakeoutSaaS.AdminApi.Controllers; /// /// 商品管理。 /// +/// +/// 初始化控制器。 +/// [ApiVersion("1.0")] [Authorize] [Route("api/admin/v{version:apiVersion}/products")] -public sealed class ProductsController : BaseApiController +public sealed class ProductsController(IMediator mediator) : BaseApiController { - private readonly IMediator _mediator; - /// - /// 初始化控制器。 - /// - public ProductsController(IMediator mediator) - { - _mediator = mediator; - } /// /// 创建商品。 @@ -39,7 +34,7 @@ public sealed class ProductsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> Create([FromBody] CreateProductCommand command, CancellationToken cancellationToken) { - var result = await _mediator.Send(command, cancellationToken); + var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } @@ -59,7 +54,7 @@ public sealed class ProductsController : BaseApiController [FromQuery] bool sortDesc = true, CancellationToken cancellationToken = default) { - var result = await _mediator.Send(new SearchProductsQuery + var result = await mediator.Send(new SearchProductsQuery { StoreId = storeId, CategoryId = categoryId, @@ -82,7 +77,7 @@ public sealed class ProductsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Detail(long productId, CancellationToken cancellationToken) { - var result = await _mediator.Send(new GetProductByIdQuery { ProductId = productId }, cancellationToken); + var result = await mediator.Send(new GetProductByIdQuery { ProductId = productId }, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "商品不存在") : ApiResponse.Ok(result); @@ -97,8 +92,11 @@ public sealed class ProductsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Update(long productId, [FromBody] UpdateProductCommand command, CancellationToken cancellationToken) { - command.ProductId = command.ProductId == 0 ? productId : command.ProductId; - var result = await _mediator.Send(command, cancellationToken); + if (command.ProductId == 0) + { + command = command with { ProductId = productId }; + } + var result = await mediator.Send(command, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "商品不存在") : ApiResponse.Ok(result); @@ -113,7 +111,7 @@ public sealed class ProductsController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Delete(long productId, CancellationToken cancellationToken) { - var success = await _mediator.Send(new DeleteProductCommand { ProductId = productId }, cancellationToken); + var success = await mediator.Send(new DeleteProductCommand { ProductId = productId }, cancellationToken); return success ? ApiResponse.Ok(null) : ApiResponse.Error(ErrorCodes.NotFound, "商品不存在"); diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/StoresController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/StoresController.cs index 8d35bcf..6abdac2 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Controllers/StoresController.cs +++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/StoresController.cs @@ -16,20 +16,15 @@ namespace TakeoutSaaS.AdminApi.Controllers; /// /// 门店管理。 /// +/// +/// 初始化控制器。 +/// [ApiVersion("1.0")] [Authorize] [Route("api/admin/v{version:apiVersion}/stores")] -public sealed class StoresController : BaseApiController +public sealed class StoresController(IMediator mediator) : BaseApiController { - private readonly IMediator _mediator; - /// - /// 初始化控制器。 - /// - public StoresController(IMediator mediator) - { - _mediator = mediator; - } /// /// 创建门店。 @@ -39,7 +34,7 @@ public sealed class StoresController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)] public async Task> Create([FromBody] CreateStoreCommand command, CancellationToken cancellationToken) { - var result = await _mediator.Send(command, cancellationToken); + var result = await mediator.Send(command, cancellationToken); return ApiResponse.Ok(result); } @@ -58,7 +53,7 @@ public sealed class StoresController : BaseApiController [FromQuery] bool sortDesc = true, CancellationToken cancellationToken = default) { - var result = await _mediator.Send(new SearchStoresQuery + var result = await mediator.Send(new SearchStoresQuery { MerchantId = merchantId, Status = status, @@ -80,7 +75,7 @@ public sealed class StoresController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Detail(long storeId, CancellationToken cancellationToken) { - var result = await _mediator.Send(new GetStoreByIdQuery { StoreId = storeId }, cancellationToken); + var result = await mediator.Send(new GetStoreByIdQuery { StoreId = storeId }, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "门店不存在") : ApiResponse.Ok(result); @@ -95,8 +90,11 @@ public sealed class StoresController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Update(long storeId, [FromBody] UpdateStoreCommand command, CancellationToken cancellationToken) { - command.StoreId = command.StoreId == 0 ? storeId : command.StoreId; - var result = await _mediator.Send(command, cancellationToken); + if (command.StoreId == 0) + { + command = command with { StoreId = storeId }; + } + var result = await mediator.Send(command, cancellationToken); return result == null ? ApiResponse.Error(ErrorCodes.NotFound, "门店不存在") : ApiResponse.Ok(result); @@ -111,7 +109,7 @@ public sealed class StoresController : BaseApiController [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status404NotFound)] public async Task> Delete(long storeId, CancellationToken cancellationToken) { - var success = await _mediator.Send(new DeleteStoreCommand { StoreId = storeId }, cancellationToken); + var success = await mediator.Send(new DeleteStoreCommand { StoreId = storeId }, cancellationToken); return success ? ApiResponse.Ok(null) : ApiResponse.Error(ErrorCodes.NotFound, "门店不存在"); diff --git a/src/Application/TakeoutSaaS.Application/App/Deliveries/Commands/UpdateDeliveryOrderCommand.cs b/src/Application/TakeoutSaaS.Application/App/Deliveries/Commands/UpdateDeliveryOrderCommand.cs index cf57bbb..cb94be2 100644 --- a/src/Application/TakeoutSaaS.Application/App/Deliveries/Commands/UpdateDeliveryOrderCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Deliveries/Commands/UpdateDeliveryOrderCommand.cs @@ -7,65 +7,65 @@ namespace TakeoutSaaS.Application.App.Deliveries.Commands; /// /// 更新配送单命令。 /// -public sealed class UpdateDeliveryOrderCommand : IRequest +public sealed record UpdateDeliveryOrderCommand : IRequest { /// /// 配送单 ID。 /// - public long DeliveryOrderId { get; set; } + public long DeliveryOrderId { get; init; } /// /// 订单 ID。 /// - public long OrderId { get; set; } + public long OrderId { get; init; } /// /// 服务商。 /// - public DeliveryProvider Provider { get; set; } = DeliveryProvider.InHouse; + public DeliveryProvider Provider { get; init; } = DeliveryProvider.InHouse; /// /// 第三方单号。 /// - public string? ProviderOrderId { get; set; } + public string? ProviderOrderId { get; init; } /// /// 状态。 /// - public DeliveryStatus Status { get; set; } = DeliveryStatus.Pending; + public DeliveryStatus Status { get; init; } = DeliveryStatus.Pending; /// /// 配送费。 /// - public decimal? DeliveryFee { get; set; } + public decimal? DeliveryFee { get; init; } /// /// 骑手姓名。 /// - public string? CourierName { get; set; } + public string? CourierName { get; init; } /// /// 骑手电话。 /// - public string? CourierPhone { get; set; } + public string? CourierPhone { get; init; } /// /// 下发时间。 /// - public DateTime? DispatchedAt { get; set; } + public DateTime? DispatchedAt { get; init; } /// /// 取餐时间。 /// - public DateTime? PickedUpAt { get; set; } + public DateTime? PickedUpAt { get; init; } /// /// 完成时间。 /// - public DateTime? DeliveredAt { get; set; } + public DateTime? DeliveredAt { get; init; } /// /// 异常原因。 /// - public string? FailureReason { get; set; } + public string? FailureReason { get; init; } } diff --git a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/UpdateMerchantCommand.cs b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/UpdateMerchantCommand.cs index 2b73adc..feb73f9 100644 --- a/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/UpdateMerchantCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Merchants/Commands/UpdateMerchantCommand.cs @@ -7,45 +7,45 @@ namespace TakeoutSaaS.Application.App.Merchants.Commands; /// /// 更新商户命令。 /// -public sealed class UpdateMerchantCommand : IRequest +public sealed record UpdateMerchantCommand : IRequest { /// /// 商户 ID。 /// - public long MerchantId { get; set; } + public long MerchantId { get; init; } /// /// 品牌名称。 /// - public string BrandName { get; set; } = string.Empty; + public string BrandName { get; init; } = string.Empty; /// /// 品牌简称。 /// - public string? BrandAlias { get; set; } + public string? BrandAlias { get; init; } /// /// Logo 地址。 /// - public string? LogoUrl { get; set; } + public string? LogoUrl { get; init; } /// /// 品类。 /// - public string? Category { get; set; } + public string? Category { get; init; } /// /// 联系电话。 /// - public string ContactPhone { get; set; } = string.Empty; + public string ContactPhone { get; init; } = string.Empty; /// /// 联系邮箱。 /// - public string? ContactEmail { get; set; } + public string? ContactEmail { get; init; } /// /// 入驻状态。 /// - public MerchantStatus Status { get; set; } + public MerchantStatus Status { get; init; } } diff --git a/src/Application/TakeoutSaaS.Application/App/Orders/Commands/UpdateOrderCommand.cs b/src/Application/TakeoutSaaS.Application/App/Orders/Commands/UpdateOrderCommand.cs index a9c832a..12de4b7 100644 --- a/src/Application/TakeoutSaaS.Application/App/Orders/Commands/UpdateOrderCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Orders/Commands/UpdateOrderCommand.cs @@ -8,110 +8,110 @@ namespace TakeoutSaaS.Application.App.Orders.Commands; /// /// 更新订单命令。 /// -public sealed class UpdateOrderCommand : IRequest +public sealed record UpdateOrderCommand : IRequest { /// /// 订单 ID。 /// - public long OrderId { get; set; } + public long OrderId { get; init; } /// /// 订单号。 /// - public string OrderNo { get; set; } = string.Empty; + public string OrderNo { get; init; } = string.Empty; /// /// 门店 ID。 /// - public long StoreId { get; set; } + public long StoreId { get; init; } /// /// 渠道。 /// - public OrderChannel Channel { get; set; } = OrderChannel.MiniProgram; + public OrderChannel Channel { get; init; } = OrderChannel.MiniProgram; /// /// 履约方式。 /// - public DeliveryType DeliveryType { get; set; } = DeliveryType.DineIn; + public DeliveryType DeliveryType { get; init; } = DeliveryType.DineIn; /// /// 状态。 /// - public OrderStatus Status { get; set; } = OrderStatus.PendingPayment; + public OrderStatus Status { get; init; } = OrderStatus.PendingPayment; /// /// 支付状态。 /// - public PaymentStatus PaymentStatus { get; set; } = PaymentStatus.Unpaid; + public PaymentStatus PaymentStatus { get; init; } = PaymentStatus.Unpaid; /// /// 顾客姓名。 /// - public string? CustomerName { get; set; } + public string? CustomerName { get; init; } /// /// 顾客手机号。 /// - public string? CustomerPhone { get; set; } + public string? CustomerPhone { get; init; } /// /// 桌号。 /// - public string? TableNo { get; set; } + public string? TableNo { get; init; } /// /// 排队号。 /// - public string? QueueNumber { get; set; } + public string? QueueNumber { get; init; } /// /// 预约 ID。 /// - public long? ReservationId { get; set; } + public long? ReservationId { get; init; } /// /// 商品金额。 /// - public decimal ItemsAmount { get; set; } + public decimal ItemsAmount { get; init; } /// /// 优惠金额。 /// - public decimal DiscountAmount { get; set; } + public decimal DiscountAmount { get; init; } /// /// 应付金额。 /// - public decimal PayableAmount { get; set; } + public decimal PayableAmount { get; init; } /// /// 实付金额。 /// - public decimal PaidAmount { get; set; } + public decimal PaidAmount { get; init; } /// /// 支付时间。 /// - public DateTime? PaidAt { get; set; } + public DateTime? PaidAt { get; init; } /// /// 完成时间。 /// - public DateTime? FinishedAt { get; set; } + public DateTime? FinishedAt { get; init; } /// /// 取消时间。 /// - public DateTime? CancelledAt { get; set; } + public DateTime? CancelledAt { get; init; } /// /// 取消原因。 /// - public string? CancelReason { get; set; } + public string? CancelReason { get; init; } /// /// 备注。 /// - public string? Remark { get; set; } + public string? Remark { get; init; } } diff --git a/src/Application/TakeoutSaaS.Application/App/Payments/Commands/UpdatePaymentCommand.cs b/src/Application/TakeoutSaaS.Application/App/Payments/Commands/UpdatePaymentCommand.cs index 8d8263f..6b8e9ed 100644 --- a/src/Application/TakeoutSaaS.Application/App/Payments/Commands/UpdatePaymentCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Payments/Commands/UpdatePaymentCommand.cs @@ -7,55 +7,55 @@ namespace TakeoutSaaS.Application.App.Payments.Commands; /// /// 更新支付记录命令。 /// -public sealed class UpdatePaymentCommand : IRequest +public sealed record UpdatePaymentCommand : IRequest { /// /// 支付记录 ID。 /// - public long PaymentId { get; set; } + public long PaymentId { get; init; } /// /// 订单 ID。 /// - public long OrderId { get; set; } + public long OrderId { get; init; } /// /// 支付方式。 /// - public PaymentMethod Method { get; set; } = PaymentMethod.Unknown; + public PaymentMethod Method { get; init; } = PaymentMethod.Unknown; /// /// 支付状态。 /// - public PaymentStatus Status { get; set; } = PaymentStatus.Unpaid; + public PaymentStatus Status { get; init; } = PaymentStatus.Unpaid; /// /// 金额。 /// - public decimal Amount { get; set; } + public decimal Amount { get; init; } /// /// 平台交易号。 /// - public string? TradeNo { get; set; } + public string? TradeNo { get; init; } /// /// 渠道单号。 /// - public string? ChannelTransactionId { get; set; } + public string? ChannelTransactionId { get; init; } /// /// 支付时间。 /// - public DateTime? PaidAt { get; set; } + public DateTime? PaidAt { get; init; } /// /// 备注。 /// - public string? Remark { get; set; } + public string? Remark { get; init; } /// /// 原始回调。 /// - public string? Payload { get; set; } + public string? Payload { get; init; } } diff --git a/src/Application/TakeoutSaaS.Application/App/Products/Commands/UpdateProductCommand.cs b/src/Application/TakeoutSaaS.Application/App/Products/Commands/UpdateProductCommand.cs index ba3de2b..09cd056 100644 --- a/src/Application/TakeoutSaaS.Application/App/Products/Commands/UpdateProductCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Products/Commands/UpdateProductCommand.cs @@ -7,100 +7,100 @@ namespace TakeoutSaaS.Application.App.Products.Commands; /// /// 更新商品命令。 /// -public sealed class UpdateProductCommand : IRequest +public sealed record UpdateProductCommand : IRequest { /// /// 商品 ID。 /// - public long ProductId { get; set; } + public long ProductId { get; init; } /// /// 门店 ID。 /// - public long StoreId { get; set; } + public long StoreId { get; init; } /// /// 分类 ID。 /// - public long CategoryId { get; set; } + public long CategoryId { get; init; } /// /// 商品编码。 /// - public string SpuCode { get; set; } = string.Empty; + public string SpuCode { get; init; } = string.Empty; /// /// 名称。 /// - public string Name { get; set; } = string.Empty; + public string Name { get; init; } = string.Empty; /// /// 副标题。 /// - public string? Subtitle { get; set; } + public string? Subtitle { get; init; } /// /// 单位。 /// - public string? Unit { get; set; } + public string? Unit { get; init; } /// /// 现价。 /// - public decimal Price { get; set; } + public decimal Price { get; init; } /// /// 原价。 /// - public decimal? OriginalPrice { get; set; } + public decimal? OriginalPrice { get; init; } /// /// 库存数量。 /// - public int? StockQuantity { get; set; } + public int? StockQuantity { get; init; } /// /// 每单限购。 /// - public int? MaxQuantityPerOrder { get; set; } + public int? MaxQuantityPerOrder { get; init; } /// /// 状态。 /// - public ProductStatus Status { get; set; } = ProductStatus.Draft; + public ProductStatus Status { get; init; } = ProductStatus.Draft; /// /// 主图。 /// - public string? CoverImage { get; set; } + public string? CoverImage { get; init; } /// /// 图集。 /// - public string? GalleryImages { get; set; } + public string? GalleryImages { get; init; } /// /// 描述。 /// - public string? Description { get; set; } + public string? Description { get; init; } /// /// 支持堂食。 /// - public bool EnableDineIn { get; set; } = true; + public bool EnableDineIn { get; init; } = true; /// /// 支持自提。 /// - public bool EnablePickup { get; set; } = true; + public bool EnablePickup { get; init; } = true; /// /// 支持配送。 /// - public bool EnableDelivery { get; set; } = true; + public bool EnableDelivery { get; init; } = true; /// /// 是否推荐。 /// - public bool IsFeatured { get; set; } + public bool IsFeatured { get; init; } } diff --git a/src/Application/TakeoutSaaS.Application/App/Stores/Commands/UpdateStoreCommand.cs b/src/Application/TakeoutSaaS.Application/App/Stores/Commands/UpdateStoreCommand.cs index 0cecf53..63a178d 100644 --- a/src/Application/TakeoutSaaS.Application/App/Stores/Commands/UpdateStoreCommand.cs +++ b/src/Application/TakeoutSaaS.Application/App/Stores/Commands/UpdateStoreCommand.cs @@ -7,100 +7,100 @@ namespace TakeoutSaaS.Application.App.Stores.Commands; /// /// 更新门店命令。 /// -public sealed class UpdateStoreCommand : IRequest +public sealed record UpdateStoreCommand : IRequest { /// /// 门店 ID。 /// - public long StoreId { get; set; } + public long StoreId { get; init; } /// /// 商户 ID。 /// - public long MerchantId { get; set; } + public long MerchantId { get; init; } /// /// 门店编码。 /// - public string Code { get; set; } = string.Empty; + public string Code { get; init; } = string.Empty; /// /// 门店名称。 /// - public string Name { get; set; } = string.Empty; + public string Name { get; init; } = string.Empty; /// /// 电话。 /// - public string? Phone { get; set; } + public string? Phone { get; init; } /// /// 负责人。 /// - public string? ManagerName { get; set; } + public string? ManagerName { get; init; } /// /// 状态。 /// - public StoreStatus Status { get; set; } = StoreStatus.Closed; + public StoreStatus Status { get; init; } = StoreStatus.Closed; /// /// 省份。 /// - public string? Province { get; set; } + public string? Province { get; init; } /// /// 城市。 /// - public string? City { get; set; } + public string? City { get; init; } /// /// 区县。 /// - public string? District { get; set; } + public string? District { get; init; } /// /// 详细地址。 /// - public string? Address { get; set; } + public string? Address { get; init; } /// /// 经度。 /// - public double? Longitude { get; set; } + public double? Longitude { get; init; } /// /// 纬度。 /// - public double? Latitude { get; set; } + public double? Latitude { get; init; } /// /// 公告。 /// - public string? Announcement { get; set; } + public string? Announcement { get; init; } /// /// 标签。 /// - public string? Tags { get; set; } + public string? Tags { get; init; } /// /// 配送半径。 /// - public decimal DeliveryRadiusKm { get; set; } + public decimal DeliveryRadiusKm { get; init; } /// /// 支持堂食。 /// - public bool SupportsDineIn { get; set; } = true; + public bool SupportsDineIn { get; init; } = true; /// /// 支持自提。 /// - public bool SupportsPickup { get; set; } = true; + public bool SupportsPickup { get; init; } = true; /// /// 支持配送。 /// - public bool SupportsDelivery { get; set; } = true; + public bool SupportsDelivery { get; init; } = true; }