diff --git a/README.md b/README.md
index 4222930..caaabce 100644
--- a/README.md
+++ b/README.md
@@ -6,14 +6,15 @@
### 核心特性
-- 🏢 **多租户架构**:支持多租户数据隔离,SaaS模式运营
-- 🍔 **商家管理**:完善的商家入驻、门店管理、菜品管理功能
-- 📦 **订单管理**:订单全生命周期管理,实时状态跟踪
-🚚 配送管理:配送任务、路线规划、第三方配送对接
-- 💰 **支付集成**:支持微信、支付宝等多种支付方式
-- 🎁 **营销功能**:优惠券、满减活动、会员积分
-- 📊 **数据分析**:实时数据统计、经营报表、趋势分析
-- 🔒 **安全可靠**:JWT认证、权限控制、数据加密
+- **多租户架构**:支持多租户数据隔离,SaaS模式运营
+- **商家管理**:完善的商家入驻、门店管理、菜品管理功能
+- **订单管理**:订单全生命周期管理,实时状态跟踪
+- **配送管理**:配送任务、路线规划、第三方配送对接
+- **支付集成**:支持微信、支付宝等多种支付方式
+- **营销功能**:优惠券、满减活动、会员积分
+- **字典管理**:系统字典、租户覆盖、批量导入导出、缓存监控
+- **数据分析**:实时数据统计、经营报表、趋势分析
+- **安全可靠**:JWT认证、权限控制、数据加密
## 技术栈
@@ -80,8 +81,26 @@ dotnet run
```
访问 API 文档:
-- 管理后台 AdminApi Swagger:http://localhost:5001/swagger
-- 小程序/用户端 MiniApi Swagger:http://localhost:5002/swagger
+- 管理后台 AdminApi Swagger:http://localhost:5001/api/docs
+- 小程序/用户端 MiniApi Swagger:http://localhost:5002/api/docs
+
+## 字典管理
+
+> 最后更新日期:2025-12-30
+
+### 功能概述
+
+- 系统/业务字典分组与字典项管理
+- 租户覆盖:隐藏系统项、自定义字典项、拖拽排序
+- CSV/JSON 批量导入导出
+- 两级缓存(Memory + Redis)与缓存监控指标
+
+### 配置要点
+
+- `ConnectionStrings:Redis`:Redis 连接字符串
+- `Database:DataSources:DictionaryDatabase`:字典库读写连接
+- `Dictionary:Cache:SlidingExpiration`:字典缓存滑动过期
+- `CacheWarmup:DictionaryCodes`:缓存预热字典编码列表
## 公告管理
diff --git a/src/Api/TakeoutSaaS.AdminApi/Contracts/Requests/DictionaryExportRequest.cs b/src/Api/TakeoutSaaS.AdminApi/Contracts/Requests/DictionaryExportRequest.cs
new file mode 100644
index 0000000..e8f59dc
--- /dev/null
+++ b/src/Api/TakeoutSaaS.AdminApi/Contracts/Requests/DictionaryExportRequest.cs
@@ -0,0 +1,12 @@
+namespace TakeoutSaaS.AdminApi.Contracts.Requests;
+
+///
+/// 字典导出请求。
+///
+public sealed record DictionaryExportRequest
+{
+ ///
+ /// 导出格式(csv/json)。
+ ///
+ public string? Format { get; init; }
+}
diff --git a/src/Api/TakeoutSaaS.AdminApi/Contracts/Requests/DictionaryImportFormRequest.cs b/src/Api/TakeoutSaaS.AdminApi/Contracts/Requests/DictionaryImportFormRequest.cs
new file mode 100644
index 0000000..7d24ccc
--- /dev/null
+++ b/src/Api/TakeoutSaaS.AdminApi/Contracts/Requests/DictionaryImportFormRequest.cs
@@ -0,0 +1,26 @@
+using System.ComponentModel.DataAnnotations;
+using Microsoft.AspNetCore.Http;
+
+namespace TakeoutSaaS.AdminApi.Contracts.Requests;
+
+///
+/// 字典导入表单请求。
+///
+public sealed record DictionaryImportFormRequest
+{
+ ///
+ /// 导入文件。
+ ///
+ [Required]
+ public required IFormFile File { get; init; }
+
+ ///
+ /// 冲突解决模式(Skip/Overwrite/Append)。
+ ///
+ public string? ConflictMode { get; init; }
+
+ ///
+ /// 文件格式(csv/json)。
+ ///
+ public string? Format { get; init; }
+}
diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/CacheMetricsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/CacheMetricsController.cs
new file mode 100644
index 0000000..31e66d1
--- /dev/null
+++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/CacheMetricsController.cs
@@ -0,0 +1,65 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using TakeoutSaaS.Domain.Dictionary.Entities;
+using TakeoutSaaS.Domain.Dictionary.Repositories;
+using TakeoutSaaS.Infrastructure.Dictionary.Caching;
+using TakeoutSaaS.Shared.Abstractions.Results;
+using TakeoutSaaS.Shared.Web.Api;
+
+namespace TakeoutSaaS.AdminApi.Controllers;
+
+///
+/// 缓存监控指标接口。
+///
+[ApiVersion("1.0")]
+[Authorize(Roles = "PlatformAdmin")]
+[Route("api/admin/v{version:apiVersion}/dictionary/metrics")]
+public sealed class CacheMetricsController(
+ CacheMetricsCollector metricsCollector,
+ ICacheInvalidationLogRepository invalidationLogRepository)
+ : BaseApiController
+{
+ ///
+ /// 获取缓存统计信息。
+ ///
+ [HttpGet("cache-stats")]
+ [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
+ public ApiResponse GetCacheStats([FromQuery] string? timeRange = "1h")
+ {
+ var window = timeRange?.ToLowerInvariant() switch
+ {
+ "24h" => TimeSpan.FromHours(24),
+ "7d" => TimeSpan.FromDays(7),
+ _ => TimeSpan.FromHours(1)
+ };
+
+ var snapshot = metricsCollector.GetSnapshot(window);
+ return ApiResponse.Ok(snapshot);
+ }
+
+ ///
+ /// 获取缓存失效事件列表。
+ ///
+ [HttpGet("invalidation-events")]
+ [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)]
+ public async Task>> GetInvalidationEvents(
+ [FromQuery] int page = 1,
+ [FromQuery] int pageSize = 20,
+ [FromQuery] DateTime? startDate = null,
+ [FromQuery] DateTime? endDate = null,
+ CancellationToken cancellationToken = default)
+ {
+ var safePage = page <= 0 ? 1 : page;
+ var safePageSize = pageSize <= 0 ? 20 : pageSize;
+
+ var (items, total) = await invalidationLogRepository.GetPagedAsync(
+ safePage,
+ safePageSize,
+ startDate,
+ endDate,
+ cancellationToken);
+
+ var result = new PagedResult(items, safePage, safePageSize, total);
+ return ApiResponse>.Ok(result);
+ }
+}
diff --git a/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryGroupsController.cs b/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryGroupsController.cs
new file mode 100644
index 0000000..d9f5b3a
--- /dev/null
+++ b/src/Api/TakeoutSaaS.AdminApi/Controllers/DictionaryGroupsController.cs
@@ -0,0 +1,185 @@
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Net.Http.Headers;
+using System.Net.Mime;
+using TakeoutSaaS.AdminApi.Contracts.Requests;
+using TakeoutSaaS.Application.Dictionary.Contracts;
+using TakeoutSaaS.Application.Dictionary.Models;
+using TakeoutSaaS.Application.Dictionary.Services;
+using TakeoutSaaS.Domain.Dictionary.Enums;
+using TakeoutSaaS.Module.Authorization.Attributes;
+using TakeoutSaaS.Shared.Abstractions.Constants;
+using TakeoutSaaS.Shared.Abstractions.Results;
+using TakeoutSaaS.Shared.Web.Api;
+
+namespace TakeoutSaaS.AdminApi.Controllers;
+
+///
+/// 字典分组管理。
+///
+[ApiVersion("1.0")]
+[Authorize]
+[Route("api/admin/v{version:apiVersion}/dictionary/groups")]
+public sealed class DictionaryGroupsController(
+ DictionaryCommandService commandService,
+ DictionaryQueryService queryService,
+ DictionaryImportExportService importExportService)
+ : BaseApiController
+{
+ ///
+ /// 查询字典分组。
+ ///
+ [HttpGet]
+ [PermissionAuthorize("dictionary:group:read")]
+ [ProducesResponseType(typeof(ApiResponse>), StatusCodes.Status200OK)]
+ public async Task>> List([FromQuery] DictionaryGroupQuery query, CancellationToken cancellationToken)
+ {
+ var result = await queryService.GetGroupsAsync(query, cancellationToken);
+ return ApiResponse>.Ok(result);
+ }
+
+ ///
+ /// 获取字典分组详情。
+ ///
+ [HttpGet("{groupId:long}")]
+ [PermissionAuthorize("dictionary:group:read")]
+ [ProducesResponseType(typeof(ApiResponse), StatusCodes.Status200OK)]
+ [ProducesResponseType(typeof(ApiResponse