diff --git a/src/Api/TakeoutSaaS.TenantApi/Contracts/Product/ProductLabelContracts.cs b/src/Api/TakeoutSaaS.TenantApi/Contracts/Product/ProductLabelContracts.cs
new file mode 100644
index 0000000..6c57378
--- /dev/null
+++ b/src/Api/TakeoutSaaS.TenantApi/Contracts/Product/ProductLabelContracts.cs
@@ -0,0 +1,136 @@
+namespace TakeoutSaaS.TenantApi.Contracts.Product;
+
+///
+/// 商品标签列表查询请求。
+///
+public sealed class ProductLabelListRequest
+{
+ ///
+ /// 门店 ID。
+ ///
+ public string StoreId { get; set; } = string.Empty;
+
+ ///
+ /// 关键字。
+ ///
+ public string? Keyword { get; set; }
+
+ ///
+ /// 状态(enabled/disabled)。
+ ///
+ public string? Status { get; set; }
+}
+
+///
+/// 保存商品标签请求。
+///
+public sealed class SaveProductLabelRequest
+{
+ ///
+ /// 门店 ID。
+ ///
+ public string StoreId { get; set; } = string.Empty;
+
+ ///
+ /// 标签 ID(编辑时传)。
+ ///
+ public string? Id { get; set; }
+
+ ///
+ /// 标签名称。
+ ///
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// 标签颜色(HEX)。
+ ///
+ public string Color { get; set; } = "#1890ff";
+
+ ///
+ /// 排序值。
+ ///
+ public int Sort { get; set; }
+
+ ///
+ /// 状态(enabled/disabled)。
+ ///
+ public string Status { get; set; } = "enabled";
+}
+
+///
+/// 删除商品标签请求。
+///
+public sealed class DeleteProductLabelRequest
+{
+ ///
+ /// 门店 ID。
+ ///
+ public string StoreId { get; set; } = string.Empty;
+
+ ///
+ /// 标签 ID。
+ ///
+ public string LabelId { get; set; } = string.Empty;
+}
+
+///
+/// 修改商品标签状态请求。
+///
+public sealed class ChangeProductLabelStatusRequest
+{
+ ///
+ /// 门店 ID。
+ ///
+ public string StoreId { get; set; } = string.Empty;
+
+ ///
+ /// 标签 ID。
+ ///
+ public string LabelId { get; set; } = string.Empty;
+
+ ///
+ /// 状态(enabled/disabled)。
+ ///
+ public string Status { get; set; } = "enabled";
+}
+
+///
+/// 商品标签列表项响应。
+///
+public sealed class ProductLabelItemResponse
+{
+ ///
+ /// 标签 ID。
+ ///
+ public string Id { get; set; } = string.Empty;
+
+ ///
+ /// 标签名称。
+ ///
+ public string Name { get; set; } = string.Empty;
+
+ ///
+ /// 标签颜色(HEX)。
+ ///
+ public string Color { get; set; } = "#1890ff";
+
+ ///
+ /// 排序值。
+ ///
+ public int Sort { get; set; }
+
+ ///
+ /// 状态(enabled/disabled)。
+ ///
+ public string Status { get; set; } = "enabled";
+
+ ///
+ /// 关联商品数量。
+ ///
+ public int ProductCount { get; set; }
+
+ ///
+ /// 更新时间。
+ ///
+ public string UpdatedAt { get; set; } = string.Empty;
+}
diff --git a/src/Api/TakeoutSaaS.TenantApi/Controllers/ProductLabelController.cs b/src/Api/TakeoutSaaS.TenantApi/Controllers/ProductLabelController.cs
new file mode 100644
index 0000000..bc3d45e
--- /dev/null
+++ b/src/Api/TakeoutSaaS.TenantApi/Controllers/ProductLabelController.cs
@@ -0,0 +1,135 @@
+using MediatR;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using TakeoutSaaS.Application.App.Products.Commands;
+using TakeoutSaaS.Application.App.Products.Dto;
+using TakeoutSaaS.Application.App.Products.Queries;
+using TakeoutSaaS.Application.App.Stores.Services;
+using TakeoutSaaS.Infrastructure.App.Persistence;
+using TakeoutSaaS.Shared.Abstractions.Results;
+using TakeoutSaaS.Shared.Web.Api;
+using TakeoutSaaS.TenantApi.Contracts.Product;
+
+namespace TakeoutSaaS.TenantApi.Controllers;
+
+///
+/// 租户端商品标签管理。
+///
+[ApiVersion("1.0")]
+[Authorize]
+[Route("api/tenant/v{version:apiVersion}/product")]
+public sealed class ProductLabelController(
+ IMediator mediator,
+ TakeoutAppDbContext dbContext,
+ StoreContextService storeContextService) : BaseApiController
+{
+ ///
+ /// 商品标签列表。
+ ///
+ [HttpGet("label/list")]
+ [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)]
+ public async Task>> GetLabelList(
+ [FromQuery] ProductLabelListRequest request,
+ CancellationToken cancellationToken)
+ {
+ var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
+ await EnsureStoreAccessibleAsync(storeId, cancellationToken);
+
+ var result = await mediator.Send(new GetProductLabelListQuery
+ {
+ StoreId = storeId,
+ Keyword = request.Keyword,
+ Status = request.Status
+ }, cancellationToken);
+
+ return ApiResponse>.Ok(result.Select(MapLabelItem).ToList());
+ }
+
+ ///
+ /// 保存商品标签。
+ ///
+ [HttpPost("label/save")]
+ [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
+ public async Task> SaveLabel(
+ [FromBody] SaveProductLabelRequest request,
+ CancellationToken cancellationToken)
+ {
+ var storeId = StoreApiHelpers.ParseRequiredSnowflake(request.StoreId, nameof(request.StoreId));
+ await EnsureStoreAccessibleAsync(storeId, cancellationToken);
+
+ var result = await mediator.Send(new SaveProductLabelCommand
+ {
+ StoreId = storeId,
+ LabelId = StoreApiHelpers.ParseSnowflakeOrNull(request.Id),
+ Name = request.Name,
+ Color = request.Color,
+ Sort = request.Sort,
+ Status = request.Status
+ }, cancellationToken);
+
+ return ApiResponse.Ok(MapLabelItem(result));
+ }
+
+ ///
+ /// 删除商品标签。
+ ///
+ [HttpPost("label/delete")]
+ [ProducesResponseType(typeof(ApiResponse