feat(product): add product label management backend
All checks were successful
Build and Deploy TenantApi / build-and-deploy (push) Successful in 43s

This commit is contained in:
2026-02-21 10:18:48 +08:00
parent 93bc072b8d
commit ad65ef3bf6
21 changed files with 9480 additions and 6 deletions

View File

@@ -0,0 +1,34 @@
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Products.Entities;
/// <summary>
/// 商品标签模板(门店维度)。
/// </summary>
public sealed class ProductLabel : MultiTenantEntityBase
{
/// <summary>
/// 所属门店。
/// </summary>
public long StoreId { get; set; }
/// <summary>
/// 标签名称。
/// </summary>
public string Name { get; set; } = string.Empty;
/// <summary>
/// 标签颜色HEX
/// </summary>
public string Color { get; set; } = "#1890ff";
/// <summary>
/// 排序值。
/// </summary>
public int SortOrder { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool IsEnabled { get; set; } = true;
}

View File

@@ -0,0 +1,24 @@
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Products.Entities;
/// <summary>
/// 标签与商品关联关系。
/// </summary>
public sealed class ProductLabelProduct : MultiTenantEntityBase
{
/// <summary>
/// 所属门店。
/// </summary>
public long StoreId { get; set; }
/// <summary>
/// 标签 ID。
/// </summary>
public long LabelId { get; set; }
/// <summary>
/// 商品 ID。
/// </summary>
public long ProductId { get; set; }
}

View File

@@ -53,6 +53,11 @@ public interface IProductRepository
/// </summary>
Task<IReadOnlyList<ProductSpecTemplate>> GetAddonTemplatesByStoreAsync(long tenantId, long storeId, CancellationToken cancellationToken = default);
/// <summary>
/// 按门店读取商品标签。
/// </summary>
Task<IReadOnlyList<ProductLabel>> GetLabelsByStoreAsync(long tenantId, long storeId, CancellationToken cancellationToken = default);
/// <summary>
/// 依据标识读取规格做法模板。
/// </summary>
@@ -63,6 +68,11 @@ public interface IProductRepository
/// </summary>
Task<ProductSpecTemplate?> FindAddonTemplateByIdAsync(long templateId, long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 依据标识读取商品标签。
/// </summary>
Task<ProductLabel?> FindLabelByIdAsync(long labelId, long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 判断门店内模板名称是否已存在。
/// </summary>
@@ -73,6 +83,11 @@ public interface IProductRepository
/// </summary>
Task<bool> ExistsAddonTemplateNameAsync(long tenantId, long storeId, string name, long? excludeTemplateId = null, CancellationToken cancellationToken = default);
/// <summary>
/// 判断门店内商品标签名称是否已存在。
/// </summary>
Task<bool> ExistsLabelNameAsync(long tenantId, long storeId, string name, long? excludeLabelId = null, CancellationToken cancellationToken = default);
/// <summary>
/// 按模板读取规格做法选项。
/// </summary>
@@ -83,6 +98,11 @@ public interface IProductRepository
/// </summary>
Task<IReadOnlyList<ProductSpecTemplateProduct>> GetSpecTemplateProductsByTemplateIdsAsync(IReadOnlyCollection<long> templateIds, long tenantId, long storeId, CancellationToken cancellationToken = default);
/// <summary>
/// 统计标签关联商品数量。
/// </summary>
Task<Dictionary<long, int>> CountLabelProductsByLabelIdsAsync(long tenantId, long storeId, IReadOnlyCollection<long> labelIds, CancellationToken cancellationToken = default);
/// <summary>
/// 过滤门店内真实存在的商品 ID。
/// </summary>
@@ -220,6 +240,11 @@ public interface IProductRepository
/// </summary>
Task AddSpecTemplateProductsAsync(IEnumerable<ProductSpecTemplateProduct> relations, CancellationToken cancellationToken = default);
/// <summary>
/// 新增商品标签。
/// </summary>
Task AddLabelAsync(ProductLabel label, CancellationToken cancellationToken = default);
/// <summary>
/// 新增商品。
/// </summary>
@@ -307,6 +332,11 @@ public interface IProductRepository
/// </summary>
Task UpdateSpecTemplateAsync(ProductSpecTemplate template, CancellationToken cancellationToken = default);
/// <summary>
/// 更新商品标签。
/// </summary>
Task UpdateLabelAsync(ProductLabel label, CancellationToken cancellationToken = default);
/// <summary>
/// 删除分类。
/// </summary>
@@ -321,6 +351,11 @@ public interface IProductRepository
/// </summary>
Task DeleteSpecTemplateAsync(long templateId, long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 删除商品标签。
/// </summary>
Task DeleteLabelAsync(long labelId, long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 删除商品下的 SKU。
/// </summary>
@@ -340,6 +375,11 @@ public interface IProductRepository
/// </summary>
Task RemoveSpecTemplateProductsAsync(long templateId, long tenantId, long storeId, CancellationToken cancellationToken = default);
/// <summary>
/// 删除标签关联商品。
/// </summary>
Task RemoveLabelProductsAsync(long labelId, long tenantId, long storeId, CancellationToken cancellationToken = default);
/// <summary>
/// 删除商品下的加料组及选项。
/// </summary>