diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c0e417a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "TakeoutSaaS.BuildingBlocks"] + path = TakeoutSaaS.BuildingBlocks + url = git@github.com:msumshk/TakeoutSaaS.BuildingBlocks.git +[submodule "TakeoutSaaS.Docs"] + path = TakeoutSaaS.Docs + url = git@github.com:msumshk/TakeoutSaaS.Docs.git diff --git a/Directory.Build.props b/Directory.Build.props index da983d4..e175c9b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -10,7 +10,7 @@ - + diff --git a/Document/01_项目概述.md b/Document/01_项目概述.md deleted file mode 100644 index 3d8920c..0000000 --- a/Document/01_项目概述.md +++ /dev/null @@ -1,188 +0,0 @@ -# 外卖SaaS系统 - 项目概述 - -## 1. 项目简介 - -### 1.1 项目背景 -外卖SaaS系统是一个面向餐饮企业的多租户外卖管理平台,旨在为中小型餐饮企业提供完整的外卖业务解决方案。系统支持商家入驻、菜品管理、订单处理、配送管理等核心功能。 - -### 1.2 项目目标 -- 提供稳定、高效的外卖业务管理平台 -- 支持多租户架构,实现数据隔离和资源共享 -- 提供完善的商家管理和运营工具 -- 支持灵活的配送模式(自配送、第三方配送) -- 提供实时数据分析和报表功能 - -### 1.3 核心价值 -- **降低成本**:SaaS模式降低企业IT投入成本 -- **快速上线**:开箱即用,快速开展外卖业务 -- **灵活扩展**:支持业务增长和功能定制 -- **数据驱动**:提供数据分析,辅助经营决策 - -## 2. 业务模块 - -### 2.1 租户管理模块 -- 租户注册与认证 -- 租户信息管理 -- 套餐订阅管理 -- 权限与配额管理 - -### 2.2 商家管理模块 -- 商家入驻审核 -- 商家信息管理 -- 门店管理(支持多门店) -- 营业时间设置 -- 配送范围设置 - -### 2.3 菜品管理模块 -- 菜品分类管理 -- 菜品信息管理(名称、价格、图片、描述) -- 菜品规格管理(大份、小份等) -- 菜品库存管理 -- 菜品上下架管理 - -### 2.4 订单管理模块 -- 订单创建与支付 -- 订单状态流转(待支付、待接单、制作中、配送中、已完成、已取消) -- 订单查询与筛选 -- 订单退款处理 -- 订单统计分析 - -### 2.5 配送管理模块 -- 配送员管理 -- 配送任务分配 -- 配送路线规划 -- 配送状态跟踪 -- 配送费用计算 - -### 2.6 用户管理模块 -- 用户注册与登录 -- 用户信息管理 -- 收货地址管理 -- 用户订单历史 -- 用户评价管理 - -### 2.7 支付管理模块 -- 多支付方式支持(微信、支付宝、余额) -- 支付回调处理 -- 退款处理 -- 账单管理 - -### 2.8 营销管理模块 -- 优惠券管理 -- 满减活动 -- 会员积分 -- 推广活动 - -### 2.9 数据分析模块 -- 销售数据统计 -- 订单趋势分析 -- 用户行为分析 -- 商家经营报表 -- 平台运营大盘 - -### 2.10 系统管理模块 -- 系统配置管理 -- 日志管理 -- 权限管理 -- 消息通知管理 - -## 3. 用户角色 - -### 3.1 平台管理员(Web管理端) -- 管理所有租户和商家 -- 系统配置和维护 -- 数据监控和分析 -- 审核商家入驻 -- 平台运营管理 - -### 3.2 租户管理员(Web管理端) -- 管理租户下的所有商家 -- 查看租户数据报表 -- 管理租户套餐和权限 -- 租户配置管理 - -### 3.3 商家管理员(Web管理端) -- 管理门店信息 -- 管理菜品和订单 -- 查看经营数据 -- 管理配送(自配送或第三方配送对接) -- 营销活动管理 - -### 3.4 商家员工(Web管理端) -- 处理订单(接单/出餐/发货) -- 更新菜品状态 -- 订单打印与出餐看板 - -### 3.5 普通用户/消费者(小程序端 + Web用户端) -- 浏览商家和菜品 -- 下单和支付 -- 查看订单状态 -- 评价和反馈 -- 收货地址管理 -- 优惠券领取和使用 - -## 4. 系统特性 - -### 4.1 多租户架构 -- 数据隔离:每个租户数据完全隔离 -- 资源共享:共享基础设施,降低成本 -- 灵活配置:支持租户级别的个性化配置 - -### 4.2 高可用性 -- 服务高可用:支持集群部署 -- 数据高可用:数据库主从复制 -- 故障自动恢复 - -### 4.3 高性能 -- 缓存策略:Redis缓存热点数据 -- 数据库优化:索引优化、查询优化 -- 异步处理:消息队列处理耗时任务 - -### 4.4 安全性 -- 身份认证:JWT Token认证 -- 权限控制:基于角色的访问控制(RBAC) -- 数据加密:敏感数据加密存储 -- 接口防护:限流、防重放攻击 - -### 4.5 可扩展性 -- 微服务架构:支持服务独立扩展 -- 插件化设计:支持功能模块插拔 -- API开放:提供开放API接口 - -## 5. 技术选型 - -- **后端框架**:.NET 10 -- **ORM框架**:Entity Framework Core 10 + Dapper -- **数据库**:PostgreSQL 16+ -- **缓存**:Redis 7.0+ -- **消息队列**:RabbitMQ 3.12+ -- **API文档**:Swagger/OpenAPI -- **日志**:Serilog -- **认证授权**:JWT + OAuth2.0 - -## 6. 项目里程碑 - -### Phase 1:基础功能(1-2个月) -- 租户管理 -- 商家管理 -- 菜品管理 -- 订单管理(基础流程) - -### Phase 2:核心功能(2-3个月) -- 配送管理 -- 支付集成 -- 用户管理 -- 基础营销功能 - -### Phase 3:高级功能(3-4个月) -- 数据分析 -- 高级营销 -- 系统优化 -- 性能调优 - -### Phase 4:完善与上线(1个月) -- 测试与修复 -- 文档完善 -- 部署上线 -- 运维监控 - diff --git a/Document/02_技术架构.md b/Document/02_技术架构.md deleted file mode 100644 index e7d1861..0000000 --- a/Document/02_技术架构.md +++ /dev/null @@ -1,253 +0,0 @@ -# 外卖SaaS系统 - 技术架构 - -## 1. 技术栈 - -### 1.1 后端技术栈 -- **.NET 10**:最新的.NET平台,提供高性能和现代化开发体验 -- **ASP.NET Core Web API**:构建RESTful API服务 -- **Entity Framework Core 10**:最新ORM框架,用于复杂查询和实体管理 -- **Dapper 2.1+**:轻量级ORM,用于高性能查询和批量操作 -- **PostgreSQL 16+**:主数据库,支持JSON、全文搜索等高级特性 -- **Redis 7.0+**:缓存和会话存储 -- **RabbitMQ 3.12+**:消息队列,处理异步任务 - -### 1.2 开发工具和框架 -- **AutoMapper**:对象映射 -- **FluentValidation**:数据验证 -- **Serilog**:结构化日志 -- **MediatR**:CQRS和中介者模式实现 -- **Hangfire**:后台任务调度 -- **Polly**:弹性和瞬态故障处理 -- **Swagger/Swashbuckle**:API文档生成 - -### 1.3 认证授权 -- **JWT (JSON Web Token)**:无状态身份认证 -- **IdentityServer/Duende IdentityServer**:OAuth2.0和OpenID Connect -- **ASP.NET Core Identity**:用户身份管理 - -### 1.4 测试框架 -- **xUnit**:单元测试框架 -- **Moq**:Mock框架 -- **FluentAssertions**:断言库 -- **Testcontainers**:集成测试容器化 - -### 1.5 DevOps工具 -- **Docker**:容器化部署 -- **Docker Compose**:本地开发环境 -- **GitHub Actions/GitLab CI**:CI/CD流水线 -- **Nginx**:反向代理和负载均衡 - -## 2. 系统架构 - -### 2.1 整体架构 -``` -┌─────────────────────────────────────────────────────────────┐ -│ 客户端层 │ -│ ┌──────────┐ ┌──────────┐ ┌──────────────┐ │ -│ │ Web管理端 │ │ Web用户端 │ │ 小程序端(用户) │ │ -│ └──────────┘ └──────────┘ └──────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ API网关层 │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ Nginx / API Gateway (路由、限流、认证、日志) │ │ -│ └──────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ 应用服务层 │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ -│ │租户服务 │ │商家服务 │ │订单服务 │ │配送服务 │ │ -│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ -│ │用户服务 │ │支付服务 │ │营销服务 │ │通知服务 │ │ -│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ 基础设施层 │ -│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ -│ │PostgreSQL │ │ Redis │ │ RabbitMQ │ │ MinIO │ │ -│ │ (主库) │ │ (缓存) │ │ (消息队列)│ │(对象存储) │ │ -│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -### 2.2 分层架构 - -#### 2.2.1 表现层 (Presentation Layer) -- **TakeoutSaaS.AdminApi**:管理后台 Web API 项目(/api/admin/v1) - - Controllers:后台管理API控制器 - - Filters:过滤器(异常处理、日志、验证) - - Middleware:中间件(认证、租户识别、RBAC) - - Models:请求/响应DTO -- **TakeoutSaaS.MiniApi**:小程序/用户端 Web API 项目(/api/mini/v1) - - Controllers:用户端API控制器 - - Filters:过滤器(异常处理、限流、签名校验) - - Middleware:中间件(小程序登录态、租户识别、CORS) - - Models:请求/响应DTO - -#### 2.2.2 应用层 (Application Layer) -- **TakeoutSaaS.Application**:应用逻辑 - - Services:应用服务 - - DTOs:数据传输对象 - - Interfaces:服务接口 - - Validators:FluentValidation验证器 - - Mappings:AutoMapper配置 - - Commands/Queries:CQRS命令和查询 - -#### 2.2.3 领域层 (Domain Layer) -- **TakeoutSaaS.Domain**:领域模型 - - Entities:实体类 - - ValueObjects:值对象 - - Enums:枚举 - - Events:领域事件 - - Interfaces:仓储接口 - - Specifications:规约模式 - -#### 2.2.4 基础设施层 (Infrastructure Layer) -- **TakeoutSaaS.Infrastructure**:基础设施实现 - - Data:数据访问 - - EFCore:EF Core DbContext和配置 - - Dapper:Dapper查询实现 - - Repositories:仓储实现 - - Migrations:数据库迁移 - - Cache:Redis缓存实现 - - MessageQueue:RabbitMQ实现 - - ExternalServices:第三方服务集成 - -#### 2.2.5 共享层 (Shared Layer) -- **TakeoutSaaS.Shared**:共享组件 - - Constants:常量定义 - - Exceptions:自定义异常 - - Extensions:扩展方法 - - Helpers:辅助类 - - Results:统一返回结果 - -## 3. 核心设计模式 - -### 3.1 多租户模式 -- **数据隔离策略**:每个租户独立Schema -- **租户识别**:通过HTTP Header或JWT Token识别租户 -- **动态切换**:运行时动态切换数据库连接 - -### 3.2 CQRS模式 -- **命令(Command)**:处理写操作,修改数据 -- **查询(Query)**:处理读操作,不修改数据 -- **分离优势**:读写分离,优化性能 - -### 3.3 仓储模式 -- **抽象数据访问**:统一数据访问接口 -- **EF Core仓储**:复杂查询和事务处理 -- **Dapper仓储**:高性能查询和批量操作 - -### 3.4 工作单元模式 -- **事务管理**:统一管理数据库事务 -- **批量提交**:减少数据库往返次数 - -### 3.5 领域驱动设计(DDD) -- **聚合根**:定义实体边界 -- **值对象**:不可变对象 -- **领域事件**:解耦业务逻辑 - -## 4. 数据访问策略 - -### 4.1 EF Core使用场景 -- 复杂的实体关系查询 -- 需要变更跟踪的操作 -- 事务性操作 -- 数据库迁移管理 - -### 4.2 Dapper使用场景 -- 高性能查询(大数据量) -- 复杂SQL查询 -- 批量插入/更新 -- 报表统计查询 -- 存储过程调用 - -### 4.3 混合使用策略 -```csharp -// EF Core - 复杂查询和实体管理 -public async Task GetOrderWithDetailsAsync(Guid orderId) -{ - return await _dbContext.Orders - .Include(o => o.OrderItems) - .Include(o => o.Customer) - .FirstOrDefaultAsync(o => o.Id == orderId); -} - -// Dapper - 高性能统计查询 -public async Task GetOrderStatisticsAsync(DateTime startDate, DateTime endDate) -{ - var sql = @" - SELECT - COUNT(*) as TotalOrders, - SUM(total_amount) as TotalAmount, - AVG(total_amount) as AvgAmount - FROM orders - WHERE created_at BETWEEN @StartDate AND @EndDate"; - - return await _connection.QueryFirstOrDefaultAsync(sql, - new { StartDate = startDate, EndDate = endDate }); -} -``` - -## 5. 缓存策略 - -### 5.1 缓存层次 -- **L1缓存**:内存缓存(IMemoryCache)- 进程内缓存 -- **L2缓存**:Redis缓存 - 分布式缓存 - -### 5.2 缓存场景 -- 商家信息缓存(30分钟) -- 菜品信息缓存(15分钟) -- 用户会话缓存(2小时) -- 配置信息缓存(1小时) -- 热点数据缓存(动态过期) - -### 5.3 缓存更新策略 -- **Cache-Aside**:旁路缓存,先查缓存,未命中查数据库 -- **Write-Through**:写入时同步更新缓存 -- **Write-Behind**:异步更新缓存 - -## 6. 消息队列应用 - -### 6.1 异步任务 -- 订单状态变更通知 -- 短信/邮件发送 -- 数据统计计算 -- 日志持久化 - -### 6.2 事件驱动 -- 订单创建事件 -- 支付成功事件 -- 配送状态变更事件 - -## 7. 安全设计 - -### 7.1 认证机制 -- JWT Token认证 -- Refresh Token刷新 -- Token过期管理 - -### 7.2 授权机制 -- 基于角色的访问控制(RBAC) -- 基于策略的授权 -- 资源级权限控制 - -### 7.3 数据安全 -- 敏感数据加密(密码、支付信息) -- HTTPS传输加密 -- SQL注入防护 -- XSS防护 - -### 7.4 接口安全 -- 请求签名验证 -- 接口限流(Rate Limiting) -- 防重放攻击 -- CORS跨域配置 - diff --git a/Document/03_数据库设计.md b/Document/03_数据库设计.md deleted file mode 100644 index 93074df..0000000 --- a/Document/03_数据库设计.md +++ /dev/null @@ -1,641 +0,0 @@ -# 外卖SaaS系统 - 数据库设计 - -## 1. 数据库设计原则 - -### 1.1 命名规范 -- **表名**:小写字母,下划线分隔,复数形式(如:`orders`, `order_items`) -- **字段名**:小写字母,下划线分隔(如:`created_at`, `total_amount`) -- **主键**:统一使用 `id`,类型为 UUID -- **外键**:`表名_id`(如:`order_id`, `merchant_id`) -- **索引**:`idx_表名_字段名`(如:`idx_orders_merchant_id`) - -### 1.2 通用字段 -所有表都包含以下字段: -- `id`:UUID,主键 -- `created_at`:TIMESTAMP,创建时间 -- `updated_at`:TIMESTAMP,更新时间 -- `deleted_at`:TIMESTAMP,软删除时间(可选) -- `tenant_id`:UUID,租户ID(多租户隔离) - -### 1.3 数据类型规范 -- **金额**:DECIMAL(18,2) -- **时间**:TIMESTAMP WITH TIME ZONE -- **布尔**:BOOLEAN -- **枚举**:VARCHAR 或 INTEGER -- **JSON数据**:JSONB - -## 2. 核心表结构 - -### 2.1 租户管理 - -#### tenants(租户表) -```sql -CREATE TABLE tenants ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - name VARCHAR(100) NOT NULL, - code VARCHAR(50) UNIQUE NOT NULL, - contact_name VARCHAR(50), - contact_phone VARCHAR(20), - contact_email VARCHAR(100), - status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:冻结 3:过期 - subscription_plan VARCHAR(50), -- 订阅套餐 - subscription_start_date TIMESTAMP WITH TIME ZONE, - subscription_end_date TIMESTAMP WITH TIME ZONE, - max_merchants INTEGER DEFAULT 10, -- 最大商家数 - max_orders_per_day INTEGER DEFAULT 1000, -- 每日订单限额 - settings JSONB, -- 租户配置 - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_tenants_code ON tenants(code); -CREATE INDEX idx_tenants_status ON tenants(status); -``` - -### 2.2 商家管理 - -#### merchants(商家表) -```sql -CREATE TABLE merchants ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - name VARCHAR(100) NOT NULL, - logo_url VARCHAR(500), - description TEXT, - contact_phone VARCHAR(20), - contact_person VARCHAR(50), - business_license VARCHAR(100), -- 营业执照号 - status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:休息 3:停业 - rating DECIMAL(3,2) DEFAULT 0, -- 评分 - total_sales INTEGER DEFAULT 0, -- 总销量 - settings JSONB, -- 商家配置 - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_merchants_tenant_id ON merchants(tenant_id); -CREATE INDEX idx_merchants_status ON merchants(status); -``` - -#### merchant_stores(门店表) -```sql -CREATE TABLE merchant_stores ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - merchant_id UUID NOT NULL REFERENCES merchants(id), - name VARCHAR(100) NOT NULL, - address VARCHAR(500) NOT NULL, - latitude DECIMAL(10,7), -- 纬度 - longitude DECIMAL(10,7), -- 经度 - phone VARCHAR(20), - business_hours JSONB, -- 营业时间 {"monday": {"open": "09:00", "close": "22:00"}} - delivery_range INTEGER DEFAULT 3000, -- 配送范围(米) - min_order_amount DECIMAL(18,2) DEFAULT 0, -- 起送价 - delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费 - status INTEGER NOT NULL DEFAULT 1, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_merchant_stores_merchant_id ON merchant_stores(merchant_id); -CREATE INDEX idx_merchant_stores_location ON merchant_stores USING GIST(point(longitude, latitude)); -``` - -### 2.3 菜品管理 - -#### categories(菜品分类表) -```sql -CREATE TABLE categories ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - merchant_id UUID NOT NULL REFERENCES merchants(id), - name VARCHAR(50) NOT NULL, - sort_order INTEGER DEFAULT 0, - status INTEGER NOT NULL DEFAULT 1, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_categories_merchant_id ON categories(merchant_id); -``` - -#### dishes(菜品表) -```sql -CREATE TABLE dishes ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - merchant_id UUID NOT NULL REFERENCES merchants(id), - category_id UUID REFERENCES categories(id), - name VARCHAR(100) NOT NULL, - description TEXT, - image_url VARCHAR(500), - price DECIMAL(18,2) NOT NULL, - original_price DECIMAL(18,2), -- 原价 - unit VARCHAR(20) DEFAULT '份', -- 单位 - stock INTEGER, -- 库存(NULL表示不限) - sales_count INTEGER DEFAULT 0, -- 销量 - rating DECIMAL(3,2) DEFAULT 0, -- 评分 - sort_order INTEGER DEFAULT 0, - status INTEGER NOT NULL DEFAULT 1, -- 1:上架 2:下架 - tags JSONB, -- 标签 ["热销", "新品"] - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_dishes_merchant_id ON dishes(merchant_id); -CREATE INDEX idx_dishes_category_id ON dishes(category_id); -CREATE INDEX idx_dishes_status ON dishes(status); -``` - -#### dish_specs(菜品规格表) -```sql -CREATE TABLE dish_specs ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - dish_id UUID NOT NULL REFERENCES dishes(id), - name VARCHAR(50) NOT NULL, -- 规格名称(如:大份、小份) - price DECIMAL(18,2) NOT NULL, - stock INTEGER, - status INTEGER NOT NULL DEFAULT 1, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_dish_specs_dish_id ON dish_specs(dish_id); -``` - -### 2.4 用户管理 - -#### users(用户表) -```sql -CREATE TABLE users ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - phone VARCHAR(20) UNIQUE NOT NULL, - nickname VARCHAR(50), - avatar_url VARCHAR(500), - gender INTEGER, -- 0:未知 1:男 2:女 - birthday DATE, - balance DECIMAL(18,2) DEFAULT 0, -- 余额 - points INTEGER DEFAULT 0, -- 积分 - status INTEGER NOT NULL DEFAULT 1, - last_login_at TIMESTAMP WITH TIME ZONE, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_users_phone ON users(phone); -``` - -#### user_addresses(用户地址表) -```sql -CREATE TABLE user_addresses ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - user_id UUID NOT NULL REFERENCES users(id), - contact_name VARCHAR(50) NOT NULL, - contact_phone VARCHAR(20) NOT NULL, - province VARCHAR(50), - city VARCHAR(50), - district VARCHAR(50), - address VARCHAR(500) NOT NULL, - house_number VARCHAR(50), -- 门牌号 - latitude DECIMAL(10,7), - longitude DECIMAL(10,7), - is_default BOOLEAN DEFAULT FALSE, - label VARCHAR(20), -- 标签:家、公司等 - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_user_addresses_user_id ON user_addresses(user_id); -``` - -### 2.5 订单管理 - -#### orders(订单表) -```sql -CREATE TABLE orders ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - order_no VARCHAR(50) UNIQUE NOT NULL, -- 订单号 - merchant_id UUID NOT NULL REFERENCES merchants(id), - store_id UUID NOT NULL REFERENCES merchant_stores(id), - user_id UUID NOT NULL REFERENCES users(id), - - -- 收货信息 - delivery_address VARCHAR(500) NOT NULL, - delivery_latitude DECIMAL(10,7), - delivery_longitude DECIMAL(10,7), - contact_name VARCHAR(50) NOT NULL, - contact_phone VARCHAR(20) NOT NULL, - - -- 金额信息 - dish_amount DECIMAL(18,2) NOT NULL, -- 菜品金额 - delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费 - package_fee DECIMAL(18,2) DEFAULT 0, -- 打包费 - discount_amount DECIMAL(18,2) DEFAULT 0, -- 优惠金额 - total_amount DECIMAL(18,2) NOT NULL, -- 总金额 - actual_amount DECIMAL(18,2) NOT NULL, -- 实付金额 - - -- 订单状态 - status INTEGER NOT NULL DEFAULT 1, -- 1:待支付 2:待接单 3:制作中 4:待配送 5:配送中 6:已完成 7:已取消 - payment_status INTEGER DEFAULT 0, -- 0:未支付 1:已支付 2:已退款 - payment_method VARCHAR(20), -- 支付方式 - payment_time TIMESTAMP WITH TIME ZONE, - - -- 时间信息 - estimated_delivery_time TIMESTAMP WITH TIME ZONE, -- 预计送达时间 - accepted_at TIMESTAMP WITH TIME ZONE, -- 接单时间 - cooking_at TIMESTAMP WITH TIME ZONE, -- 开始制作时间 - delivered_at TIMESTAMP WITH TIME ZONE, -- 送达时间 - completed_at TIMESTAMP WITH TIME ZONE, -- 完成时间 - cancelled_at TIMESTAMP WITH TIME ZONE, -- 取消时间 - - remark TEXT, -- 备注 - cancel_reason TEXT, -- 取消原因 - - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_orders_tenant_id ON orders(tenant_id); -CREATE INDEX idx_orders_order_no ON orders(order_no); -CREATE INDEX idx_orders_merchant_id ON orders(merchant_id); -CREATE INDEX idx_orders_user_id ON orders(user_id); -CREATE INDEX idx_orders_status ON orders(status); -CREATE INDEX idx_orders_created_at ON orders(created_at); -``` - -#### order_items(订单明细表) -```sql -CREATE TABLE order_items ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - order_id UUID NOT NULL REFERENCES orders(id), - dish_id UUID NOT NULL REFERENCES dishes(id), - dish_name VARCHAR(100) NOT NULL, -- 冗余字段,防止菜品被删除 - dish_image_url VARCHAR(500), - spec_id UUID REFERENCES dish_specs(id), - spec_name VARCHAR(50), - price DECIMAL(18,2) NOT NULL, -- 单价 - quantity INTEGER NOT NULL, -- 数量 - amount DECIMAL(18,2) NOT NULL, -- 小计 - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_order_items_order_id ON order_items(order_id); -CREATE INDEX idx_order_items_dish_id ON order_items(dish_id); -``` - -### 2.6 配送管理 - -#### delivery_drivers(配送员表) -```sql -CREATE TABLE delivery_drivers ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - merchant_id UUID REFERENCES merchants(id), -- NULL表示平台配送员 - name VARCHAR(50) NOT NULL, - phone VARCHAR(20) UNIQUE NOT NULL, - id_card VARCHAR(18), -- 身份证号 - vehicle_type VARCHAR(20), -- 车辆类型:电动车、摩托车 - vehicle_number VARCHAR(20), -- 车牌号 - status INTEGER NOT NULL DEFAULT 1, -- 1:空闲 2:配送中 3:休息 4:离线 - current_latitude DECIMAL(10,7), -- 当前位置 - current_longitude DECIMAL(10,7), - rating DECIMAL(3,2) DEFAULT 0, - total_deliveries INTEGER DEFAULT 0, -- 总配送单数 - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_delivery_drivers_merchant_id ON delivery_drivers(merchant_id); -CREATE INDEX idx_delivery_drivers_status ON delivery_drivers(status); -``` - -#### delivery_tasks(配送任务表) -```sql -CREATE TABLE delivery_tasks ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - order_id UUID NOT NULL REFERENCES orders(id), - driver_id UUID REFERENCES delivery_drivers(id), - pickup_address VARCHAR(500) NOT NULL, -- 取餐地址 - pickup_latitude DECIMAL(10,7), - pickup_longitude DECIMAL(10,7), - delivery_address VARCHAR(500) NOT NULL, -- 送餐地址 - delivery_latitude DECIMAL(10,7), - delivery_longitude DECIMAL(10,7), - distance INTEGER, -- 配送距离(米) - estimated_time INTEGER, -- 预计时长(分钟) - status INTEGER NOT NULL DEFAULT 1, -- 1:待分配 2:待取餐 3:配送中 4:已送达 5:异常 - assigned_at TIMESTAMP WITH TIME ZONE, -- 分配时间 - picked_at TIMESTAMP WITH TIME ZONE, -- 取餐时间 - delivered_at TIMESTAMP WITH TIME ZONE, -- 送达时间 - delivery_fee DECIMAL(18,2) DEFAULT 0, -- 配送费 - remark TEXT, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_delivery_tasks_order_id ON delivery_tasks(order_id); -CREATE INDEX idx_delivery_tasks_driver_id ON delivery_tasks(driver_id); -CREATE INDEX idx_delivery_tasks_status ON delivery_tasks(status); -``` - -### 2.7 支付管理 - -#### payments(支付记录表) -```sql -CREATE TABLE payments ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - order_id UUID NOT NULL REFERENCES orders(id), - user_id UUID NOT NULL REFERENCES users(id), - payment_no VARCHAR(50) UNIQUE NOT NULL, -- 支付单号 - payment_method VARCHAR(20) NOT NULL, -- 支付方式:wechat、alipay、balance - amount DECIMAL(18,2) NOT NULL, - status INTEGER NOT NULL DEFAULT 0, -- 0:待支付 1:支付中 2:成功 3:失败 4:已退款 - third_party_no VARCHAR(100), -- 第三方支付单号 - paid_at TIMESTAMP WITH TIME ZONE, - callback_data JSONB, -- 回调数据 - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_payments_order_id ON payments(order_id); -CREATE INDEX idx_payments_payment_no ON payments(payment_no); -CREATE INDEX idx_payments_user_id ON payments(user_id); -``` - -#### refunds(退款记录表) -```sql -CREATE TABLE refunds ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - order_id UUID NOT NULL REFERENCES orders(id), - payment_id UUID NOT NULL REFERENCES payments(id), - refund_no VARCHAR(50) UNIQUE NOT NULL, - amount DECIMAL(18,2) NOT NULL, - reason TEXT, - status INTEGER NOT NULL DEFAULT 0, -- 0:待审核 1:退款中 2:成功 3:失败 - third_party_no VARCHAR(100), - refunded_at TIMESTAMP WITH TIME ZONE, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_refunds_order_id ON refunds(order_id); -CREATE INDEX idx_refunds_payment_id ON refunds(payment_id); -``` - -### 2.8 营销管理 - -#### coupons(优惠券表) -```sql -CREATE TABLE coupons ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - merchant_id UUID REFERENCES merchants(id), -- NULL表示平台券 - name VARCHAR(100) NOT NULL, - type INTEGER NOT NULL, -- 1:满减券 2:折扣券 3:代金券 - discount_type INTEGER NOT NULL, -- 1:固定金额 2:百分比 - discount_value DECIMAL(18,2) NOT NULL, -- 优惠值 - min_order_amount DECIMAL(18,2) DEFAULT 0, -- 最低消费 - max_discount_amount DECIMAL(18,2), -- 最大优惠金额(折扣券用) - total_quantity INTEGER NOT NULL, -- 总数量 - received_quantity INTEGER DEFAULT 0, -- 已领取数量 - used_quantity INTEGER DEFAULT 0, -- 已使用数量 - valid_start_time TIMESTAMP WITH TIME ZONE NOT NULL, - valid_end_time TIMESTAMP WITH TIME ZONE NOT NULL, - status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:停用 - description TEXT, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_coupons_merchant_id ON coupons(merchant_id); -CREATE INDEX idx_coupons_status ON coupons(status); -``` - -#### user_coupons(用户优惠券表) -```sql -CREATE TABLE user_coupons ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - user_id UUID NOT NULL REFERENCES users(id), - coupon_id UUID NOT NULL REFERENCES coupons(id), - status INTEGER NOT NULL DEFAULT 1, -- 1:未使用 2:已使用 3:已过期 - used_order_id UUID REFERENCES orders(id), - received_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - used_at TIMESTAMP WITH TIME ZONE, - expired_at TIMESTAMP WITH TIME ZONE NOT NULL -); - -CREATE INDEX idx_user_coupons_user_id ON user_coupons(user_id); -CREATE INDEX idx_user_coupons_coupon_id ON user_coupons(coupon_id); -CREATE INDEX idx_user_coupons_status ON user_coupons(status); -``` - -### 2.9 评价管理 - -#### reviews(评价表) -```sql -CREATE TABLE reviews ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID NOT NULL REFERENCES tenants(id), - order_id UUID NOT NULL REFERENCES orders(id), - user_id UUID NOT NULL REFERENCES users(id), - merchant_id UUID NOT NULL REFERENCES merchants(id), - rating INTEGER NOT NULL, -- 评分 1-5 - taste_rating INTEGER, -- 口味评分 - package_rating INTEGER, -- 包装评分 - delivery_rating INTEGER, -- 配送评分 - content TEXT, - images JSONB, -- 评价图片 - is_anonymous BOOLEAN DEFAULT FALSE, - reply_content TEXT, -- 商家回复 - reply_at TIMESTAMP WITH TIME ZONE, - status INTEGER NOT NULL DEFAULT 1, -- 1:正常 2:隐藏 - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_reviews_order_id ON reviews(order_id); -CREATE INDEX idx_reviews_user_id ON reviews(user_id); -CREATE INDEX idx_reviews_merchant_id ON reviews(merchant_id); -``` - -### 2.10 系统管理 - -#### system_users(系统用户表) -```sql -CREATE TABLE system_users ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID REFERENCES tenants(id), -- NULL表示平台管理员 - merchant_id UUID REFERENCES merchants(id), -- NULL表示租户管理员 - username VARCHAR(50) UNIQUE NOT NULL, - password_hash VARCHAR(255) NOT NULL, - real_name VARCHAR(50), - phone VARCHAR(20), - email VARCHAR(100), - role_id UUID REFERENCES roles(id), - status INTEGER NOT NULL DEFAULT 1, - last_login_at TIMESTAMP WITH TIME ZONE, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_system_users_username ON system_users(username); -CREATE INDEX idx_system_users_tenant_id ON system_users(tenant_id); -``` - -#### roles(角色表) -```sql -CREATE TABLE roles ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID REFERENCES tenants(id), - name VARCHAR(50) NOT NULL, - code VARCHAR(50) NOT NULL, - description TEXT, - permissions JSONB, -- 权限列表 - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, - deleted_at TIMESTAMP WITH TIME ZONE -); - -CREATE INDEX idx_roles_tenant_id ON roles(tenant_id); -``` - -#### operation_logs(操作日志表) -```sql -CREATE TABLE operation_logs ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - tenant_id UUID REFERENCES tenants(id), - user_id UUID, - user_type VARCHAR(20), -- system_user, merchant_user, customer - module VARCHAR(50), -- 模块 - action VARCHAR(50), -- 操作 - description TEXT, - ip_address VARCHAR(50), - user_agent TEXT, - request_data JSONB, - response_data JSONB, - created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP -); - -CREATE INDEX idx_operation_logs_tenant_id ON operation_logs(tenant_id); -CREATE INDEX idx_operation_logs_user_id ON operation_logs(user_id); -CREATE INDEX idx_operation_logs_created_at ON operation_logs(created_at); -``` - -## 3. 数据库索引策略 - -### 3.1 主键索引 -- 所有表使用UUID作为主键,自动创建主键索引 - -### 3.2 外键索引 -- 所有外键字段创建索引,提升关联查询性能 - -### 3.3 业务索引 -- 订单号、支付单号等唯一业务字段创建唯一索引 -- 状态字段创建普通索引 -- 时间字段(created_at)创建索引,支持时间范围查询 - -### 3.4 复合索引 -```sql --- 订单查询常用复合索引 -CREATE INDEX idx_orders_merchant_status_created ON orders(merchant_id, status, created_at DESC); - --- 用户订单查询 -CREATE INDEX idx_orders_user_status_created ON orders(user_id, status, created_at DESC); -``` - -### 3.5 地理位置索引 -```sql --- 使用PostGIS扩展支持地理位置查询 -CREATE EXTENSION IF NOT EXISTS postgis; - --- 门店位置索引 -CREATE INDEX idx_merchant_stores_location ON merchant_stores - USING GIST(ST_MakePoint(longitude, latitude)); -``` - -## 4. 数据库优化 - -### 4.1 分区策略 -```sql --- 订单表按月分区 -CREATE TABLE orders_2024_01 PARTITION OF orders - FOR VALUES FROM ('2024-01-01') TO ('2024-02-01'); - -CREATE TABLE orders_2024_02 PARTITION OF orders - FOR VALUES FROM ('2024-02-01') TO ('2024-03-01'); -``` - -### 4.2 物化视图 -```sql --- 商家统计物化视图 -CREATE MATERIALIZED VIEW merchant_statistics AS -SELECT - m.id as merchant_id, - m.name, - COUNT(DISTINCT o.id) as total_orders, - SUM(o.actual_amount) as total_revenue, - AVG(r.rating) as avg_rating -FROM merchants m -LEFT JOIN orders o ON m.id = o.merchant_id AND o.status = 6 -LEFT JOIN reviews r ON m.id = r.merchant_id -GROUP BY m.id, m.name; - -CREATE UNIQUE INDEX ON merchant_statistics(merchant_id); -``` - -### 4.3 查询优化建议 -- 避免SELECT *,只查询需要的字段 -- 使用EXPLAIN分析查询计划 -- 合理使用JOIN,避免过多关联 -- 大数据量查询使用分页 -- 使用prepared statement防止SQL注入 - -## 5. 数据备份策略 - -### 5.1 备份方案 -- **全量备份**:每天凌晨2点执行 -- **增量备份**:每4小时执行一次 -- **WAL归档**:实时归档,支持PITR - -### 5.2 备份脚本示例 -```bash -#!/bin/bash -# 全量备份 -pg_dump -h localhost -U postgres -d takeout_saas -F c -f /backup/full_$(date +%Y%m%d).dump - -# 保留最近30天的备份 -find /backup -name "full_*.dump" -mtime +30 -delete -``` - -## 6. 数据迁移 - -### 6.1 EF Core Migrations -```bash -# 添加迁移 -dotnet ef migrations add InitialCreate --project TakeoutSaaS.Infrastructure - -# 更新数据库 -dotnet ef database update --project TakeoutSaaS.Infrastructure -``` - -### 6.2 版本控制 -- 所有数据库变更通过Migration管理 -- Migration文件纳入版本控制 -- 生产环境变更需要审核 - diff --git a/Document/04_API接口设计.md b/Document/04_API接口设计.md deleted file mode 100644 index 1f3735d..0000000 --- a/Document/04_API接口设计.md +++ /dev/null @@ -1,885 +0,0 @@ -# 外卖SaaS系统 - API接口设计 - -## 1. API设计规范 - -### 1.1 RESTful规范 -- 使用标准HTTP方法:GET、POST、PUT、DELETE、PATCH -- URL使用名词复数形式,如:`/api/orders` -- 使用HTTP状态码表示请求结果 -- 版本控制:`/api/v1/orders` - -### 1.2 请求规范 -- **Content-Type**:`application/json` -- **认证方式**:Bearer Token (JWT) -- **租户识别**:通过Header `X-Tenant-Id` 或从Token中解析 - -### 1.3 响应规范 -```json -{ - "success": true, - "code": 200, - "message": "操作成功", - "data": {}, - "timestamp": "2024-01-01T12:00:00Z" -} -``` - -### 1.4 错误响应 -```json -{ - "success": false, - "code": 400, - "message": "参数错误", - "errors": [ - { - "field": "phone", - "message": "手机号格式不正确" - } - ], - "timestamp": "2024-01-01T12:00:00Z" -} -``` - -### 1.5 HTTP状态码 -- **200 OK**:请求成功 -- **201 Created**:创建成功 -- **204 No Content**:删除成功 -- **400 Bad Request**:参数错误 -- **401 Unauthorized**:未认证 -- **403 Forbidden**:无权限 -- **404 Not Found**:资源不存在 -- **409 Conflict**:资源冲突 -- **422 Unprocessable Entity**:业务逻辑错误 -- **500 Internal Server Error**:服务器错误 - -### 1.6 分页规范 -```json -// 请求参数 -{ - "pageIndex": 1, - "pageSize": 20, - "sortBy": "createdAt", - "sortOrder": "desc" -} - -// 响应格式 -{ - "success": true, - "data": { - "items": [], - "totalCount": 100, - "pageIndex": 1, - "pageSize": 20, - "totalPages": 5 - } -} -``` - -## 2. 认证授权接口 - -### 2.1 用户登录 -```http -POST /api/v1/auth/login -Content-Type: application/json - -{ - "phone": "13800138000", - "password": "password123", - "loginType": "customer" // customer, merchant, system -} - -Response: -{ - "success": true, - "data": { - "accessToken": "eyJhbGciOiJIUzI1NiIs...", - "refreshToken": "eyJhbGciOiJIUzI1NiIs...", - "expiresIn": 7200, - "tokenType": "Bearer", - "userInfo": { - "id": "uuid", - "phone": "13800138000", - "nickname": "张三", - "avatar": "https://..." - } - } -} -``` - -### 2.2 刷新Token -```http -POST /api/v1/auth/refresh -Content-Type: application/json - -{ - "refreshToken": "eyJhbGciOiJIUzI1NiIs..." -} - -Response: -{ - "success": true, - "data": { - "accessToken": "eyJhbGciOiJIUzI1NiIs...", - "expiresIn": 7200 - } -} -``` - -### 2.3 用户注册 -```http -POST /api/v1/auth/register -Content-Type: application/json - -{ - "phone": "13800138000", - "password": "password123", - "verificationCode": "123456", - "nickname": "张三" -} -``` - -### 2.4 发送验证码 -```http -POST /api/v1/auth/send-code -Content-Type: application/json - -{ - "phone": "13800138000", - "type": "register" // register, login, reset_password -} -``` - -## 3. 商家管理接口 - -### 3.1 获取商家列表 -```http -GET /api/v1/merchants?pageIndex=1&pageSize=20&keyword=&status=1 -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "items": [ - { - "id": "uuid", - "name": "美味餐厅", - "logo": "https://...", - "rating": 4.5, - "totalSales": 1000, - "status": 1, - "createdAt": "2024-01-01T12:00:00Z" - } - ], - "totalCount": 50, - "pageIndex": 1, - "pageSize": 20 - } -} -``` - -### 3.2 获取商家详情 -```http -GET /api/v1/merchants/{id} -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "id": "uuid", - "name": "美味餐厅", - "logo": "https://...", - "description": "专注美食20年", - "contactPhone": "400-123-4567", - "rating": 4.5, - "totalSales": 1000, - "status": 1, - "stores": [ - { - "id": "uuid", - "name": "总店", - "address": "北京市朝阳区...", - "phone": "010-12345678" - } - ] - } -} -``` - -### 3.3 创建商家 -```http -POST /api/v1/merchants -Authorization: Bearer {token} -Content-Type: application/json - -{ - "name": "美味餐厅", - "logo": "https://...", - "description": "专注美食20年", - "contactPhone": "400-123-4567", - "contactPerson": "张三", - "businessLicense": "91110000..." -} -``` - -### 3.4 更新商家信息 -```http -PUT /api/v1/merchants/{id} -Authorization: Bearer {token} -Content-Type: application/json - -{ - "name": "美味餐厅", - "logo": "https://...", - "description": "专注美食20年" -} -``` - -### 3.5 删除商家 -```http -DELETE /api/v1/merchants/{id} -Authorization: Bearer {token} -``` - -## 4. 菜品管理接口 - -### 4.1 获取菜品列表 -```http -GET /api/v1/dishes?merchantId={merchantId}&categoryId={categoryId}&keyword=&status=1&pageIndex=1&pageSize=20 -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "items": [ - { - "id": "uuid", - "name": "宫保鸡丁", - "description": "经典川菜", - "image": "https://...", - "price": 38.00, - "originalPrice": 48.00, - "salesCount": 500, - "rating": 4.8, - "status": 1, - "tags": ["热销", "招牌菜"] - } - ], - "totalCount": 100 - } -} -``` - -### 4.2 获取菜品详情 -```http -GET /api/v1/dishes/{id} -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "id": "uuid", - "name": "宫保鸡丁", - "description": "经典川菜,选用优质鸡肉...", - "image": "https://...", - "price": 38.00, - "originalPrice": 48.00, - "unit": "份", - "stock": 100, - "salesCount": 500, - "rating": 4.8, - "status": 1, - "tags": ["热销", "招牌菜"], - "specs": [ - { - "id": "uuid", - "name": "大份", - "price": 48.00, - "stock": 50 - }, - { - "id": "uuid", - "name": "小份", - "price": 28.00, - "stock": 50 - } - ] - } -} -``` - -### 4.3 创建菜品 -```http -POST /api/v1/dishes -Authorization: Bearer {token} -Content-Type: application/json - -{ - "merchantId": "uuid", - "categoryId": "uuid", - "name": "宫保鸡丁", - "description": "经典川菜", - "image": "https://...", - "price": 38.00, - "originalPrice": 48.00, - "unit": "份", - "stock": 100, - "tags": ["热销", "招牌菜"], - "specs": [ - { - "name": "大份", - "price": 48.00, - "stock": 50 - } - ] -} -``` - -### 4.4 更新菜品 -```http -PUT /api/v1/dishes/{id} -Authorization: Bearer {token} -Content-Type: application/json - -{ - "name": "宫保鸡丁", - "price": 38.00, - "stock": 100, - "status": 1 -} -``` - -### 4.5 批量上下架 -```http -PATCH /api/v1/dishes/batch-status -Authorization: Bearer {token} -Content-Type: application/json - -{ - "dishIds": ["uuid1", "uuid2"], - "status": 1 // 1:上架 2:下架 -} -``` - -## 5. 订单管理接口 - -### 5.1 创建订单 -```http -POST /api/v1/orders -Authorization: Bearer {token} -Content-Type: application/json - -{ - "merchantId": "uuid", - "storeId": "uuid", - "items": [ - { - "dishId": "uuid", - "specId": "uuid", - "quantity": 2, - "price": 38.00 - } - ], - "deliveryAddress": { - "contactName": "张三", - "contactPhone": "13800138000", - "address": "北京市朝阳区...", - "latitude": 39.9042, - "longitude": 116.4074 - }, - "remark": "少辣", - "couponId": "uuid" -} - -Response: -{ - "success": true, - "data": { - "orderId": "uuid", - "orderNo": "202401010001", - "totalAmount": 76.00, - "deliveryFee": 5.00, - "discountAmount": 10.00, - "actualAmount": 71.00, - "paymentInfo": { - "paymentNo": "PAY202401010001", - "qrCode": "https://..." // 支付二维码 - } - } -} -``` - -### 5.2 获取订单列表 -```http -GET /api/v1/orders?status=&startDate=&endDate=&pageIndex=1&pageSize=20 -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "items": [ - { - "id": "uuid", - "orderNo": "202401010001", - "merchantName": "美味餐厅", - "totalAmount": 76.00, - "actualAmount": 71.00, - "status": 2, - "statusText": "待接单", - "createdAt": "2024-01-01T12:00:00Z", - "items": [ - { - "dishName": "宫保鸡丁", - "specName": "大份", - "quantity": 2, - "price": 38.00 - } - ] - } - ], - "totalCount": 50 - } -} -``` - -### 5.3 获取订单详情 -```http -GET /api/v1/orders/{id} -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "id": "uuid", - "orderNo": "202401010001", - "merchant": { - "id": "uuid", - "name": "美味餐厅", - "phone": "400-123-4567" - }, - "items": [ - { - "dishName": "宫保鸡丁", - "dishImage": "https://...", - "specName": "大份", - "quantity": 2, - "price": 38.00, - "amount": 76.00 - } - ], - "deliveryAddress": { - "contactName": "张三", - "contactPhone": "13800138000", - "address": "北京市朝阳区..." - }, - "dishAmount": 76.00, - "deliveryFee": 5.00, - "packageFee": 2.00, - "discountAmount": 10.00, - "totalAmount": 83.00, - "actualAmount": 73.00, - "status": 2, - "statusText": "待接单", - "paymentStatus": 1, - "paymentMethod": "wechat", - "estimatedDeliveryTime": "2024-01-01T13:00:00Z", - "createdAt": "2024-01-01T12:00:00Z", - "paidAt": "2024-01-01T12:05:00Z", - "remark": "少辣", - "timeline": [ - { - "status": "created", - "statusText": "订单创建", - "time": "2024-01-01T12:00:00Z" - }, - { - "status": "paid", - "statusText": "支付成功", - "time": "2024-01-01T12:05:00Z" - } - ] - } -} -``` - -### 5.4 商家接单 -```http -POST /api/v1/orders/{id}/accept -Authorization: Bearer {token} -Content-Type: application/json - -{ - "estimatedTime": 30 // 预计制作时长(分钟) -} -``` - -### 5.5 开始制作 -```http -POST /api/v1/orders/{id}/cooking -Authorization: Bearer {token} -``` - -### 5.6 订单完成 -```http -POST /api/v1/orders/{id}/complete -Authorization: Bearer {token} -``` - -### 5.7 取消订单 -```http -POST /api/v1/orders/{id}/cancel -Authorization: Bearer {token} -Content-Type: application/json - -{ - "reason": "用户取消", - "cancelBy": "customer" // customer, merchant, system -} -``` - -## 6. 支付接口 - -### 6.1 创建支付 -```http -POST /api/v1/payments -Authorization: Bearer {token} -Content-Type: application/json - -{ - "orderId": "uuid", - "paymentMethod": "wechat", // wechat, alipay, balance - "amount": 71.00 -} - -Response: -{ - "success": true, - "data": { - "paymentNo": "PAY202401010001", - "qrCode": "https://...", // 支付二维码 - "deepLink": "weixin://..." // 唤起支付的深度链接 - } -} -``` - -### 6.2 查询支付状态 -```http -GET /api/v1/payments/{paymentNo} -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "paymentNo": "PAY202401010001", - "status": 2, // 0:待支付 1:支付中 2:成功 3:失败 - "amount": 71.00, - "paidAt": "2024-01-01T12:05:00Z" - } -} -``` - -### 6.3 支付回调(第三方调用) -```http -POST /api/v1/payments/callback/wechat -Content-Type: application/json - -{ - "out_trade_no": "PAY202401010001", - "transaction_id": "4200001234567890", - "total_fee": 7100, - "result_code": "SUCCESS" -} -``` - -### 6.4 申请退款 -```http -POST /api/v1/refunds -Authorization: Bearer {token} -Content-Type: application/json - -{ - "orderId": "uuid", - "amount": 71.00, - "reason": "不想要了" -} -``` - -## 7. 配送管理接口 - -### 7.1 获取配送任务列表 -```http -GET /api/v1/delivery-tasks?status=&driverId=&pageIndex=1&pageSize=20 -Authorization: Bearer {token} -``` - -### 7.2 分配配送员 -```http -POST /api/v1/delivery-tasks/{id}/assign -Authorization: Bearer {token} -Content-Type: application/json - -{ - "driverId": "uuid" -} -``` - -### 7.3 配送员接单 -```http -POST /api/v1/delivery-tasks/{id}/accept -Authorization: Bearer {token} -``` - -### 7.4 确认取餐 -```http -POST /api/v1/delivery-tasks/{id}/pickup -Authorization: Bearer {token} -``` - -### 7.5 确认送达 -```http -POST /api/v1/delivery-tasks/{id}/deliver -Authorization: Bearer {token} -Content-Type: application/json - -{ - "deliveryCode": "123456" // 取餐码 -} -``` - -### 7.6 更新配送员位置 -```http -POST /api/v1/delivery-drivers/location -Authorization: Bearer {token} -Content-Type: application/json - -{ - "latitude": 39.9042, - "longitude": 116.4074 -} -``` - -## 8. 营销管理接口 - -### 8.1 获取优惠券列表 -```http -GET /api/v1/coupons?merchantId=&status=1&pageIndex=1&pageSize=20 -Authorization: Bearer {token} -``` - -### 8.2 领取优惠券 -```http -POST /api/v1/coupons/{id}/receive -Authorization: Bearer {token} -``` - -### 8.3 获取用户优惠券 -```http -GET /api/v1/user-coupons?status=1&pageIndex=1&pageSize=20 -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "items": [ - { - "id": "uuid", - "couponName": "满50减10", - "discountValue": 10.00, - "minOrderAmount": 50.00, - "status": 1, - "expiredAt": "2024-12-31T23:59:59Z" - } - ] - } -} -``` - -### 8.4 获取可用优惠券 -```http -GET /api/v1/user-coupons/available?merchantId={merchantId}&amount={amount} -Authorization: Bearer {token} -``` - -## 9. 评价管理接口 - -### 9.1 创建评价 -```http -POST /api/v1/reviews -Authorization: Bearer {token} -Content-Type: application/json - -{ - "orderId": "uuid", - "rating": 5, - "tasteRating": 5, - "packageRating": 5, - "deliveryRating": 5, - "content": "非常好吃", - "images": ["https://...", "https://..."], - "isAnonymous": false -} -``` - -### 9.2 获取商家评价列表 -```http -GET /api/v1/reviews?merchantId={merchantId}&rating=&pageIndex=1&pageSize=20 - -Response: -{ - "success": true, - "data": { - "items": [ - { - "id": "uuid", - "userName": "张三", - "userAvatar": "https://...", - "rating": 5, - "content": "非常好吃", - "images": ["https://..."], - "createdAt": "2024-01-01T12:00:00Z", - "replyContent": "感谢支持", - "replyAt": "2024-01-01T13:00:00Z" - } - ], - "totalCount": 100, - "statistics": { - "avgRating": 4.8, - "totalReviews": 100, - "rating5Count": 80, - "rating4Count": 15, - "rating3Count": 3, - "rating2Count": 1, - "rating1Count": 1 - } - } -} -``` - -### 9.3 商家回复评价 -```http -POST /api/v1/reviews/{id}/reply -Authorization: Bearer {token} -Content-Type: application/json - -{ - "replyContent": "感谢您的支持" -} -``` - -## 10. 数据统计接口 - -### 10.1 商家数据概览 -```http -GET /api/v1/statistics/merchant/overview?merchantId={merchantId}&startDate=&endDate= -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "totalOrders": 1000, - "totalRevenue": 50000.00, - "avgOrderAmount": 50.00, - "completionRate": 0.95, - "todayOrders": 50, - "todayRevenue": 2500.00, - "orderTrend": [ - { - "date": "2024-01-01", - "orders": 50, - "revenue": 2500.00 - } - ], - "topDishes": [ - { - "dishId": "uuid", - "dishName": "宫保鸡丁", - "salesCount": 200, - "revenue": 7600.00 - } - ] - } -} -``` - -### 10.2 平台数据大盘 -```http -GET /api/v1/statistics/platform/dashboard?startDate=&endDate= -Authorization: Bearer {token} - -Response: -{ - "success": true, - "data": { - "totalMerchants": 100, - "totalUsers": 10000, - "totalOrders": 50000, - "totalRevenue": 2500000.00, - "activeMerchants": 80, - "activeUsers": 5000, - "todayOrders": 500, - "todayRevenue": 25000.00 - } -} -``` - -## 11. 文件上传接口 - -### 11.1 上传图片 -```http -POST /api/v1/files/upload -Authorization: Bearer {token} -Content-Type: multipart/form-data - -file: -type: dish_image // dish_image, merchant_logo, user_avatar, review_image - -Response: -{ - "success": true, - "data": { - "url": "https://cdn.example.com/images/xxx.jpg", - "fileName": "xxx.jpg", - "fileSize": 102400 - } -} -``` - -## 12. WebSocket实时通知 - -### 12.1 连接WebSocket -```javascript -// 连接地址 -ws://api.example.com/ws?token={jwt_token} - -// 订阅主题 -{ - "action": "subscribe", - "topics": ["order.new", "order.status", "delivery.location"] -} - -// 接收消息 -{ - "topic": "order.new", - "data": { - "orderId": "uuid", - "orderNo": "202401010001", - "merchantId": "uuid" - }, - "timestamp": "2024-01-01T12:00:00Z" -} -``` - -### 12.2 消息主题 -- `order.new`:新订单通知 -- `order.status`:订单状态变更 -- `delivery.location`:配送员位置更新 -- `payment.success`:支付成功通知 - diff --git a/Document/05_部署运维.md b/Document/05_部署运维.md deleted file mode 100644 index f92e303..0000000 --- a/Document/05_部署运维.md +++ /dev/null @@ -1,1058 +0,0 @@ -# 外卖SaaS系统 - 部署运维 - -## 1. 环境要求 - -### 1.1 开发环境 -- **.NET SDK**:10.0 或更高版本 -- **IDE**:Visual Studio 2022 / JetBrains Rider / VS Code -- **数据库**:PostgreSQL 16+ -- **缓存**:Redis 7.0+ -- **消息队列**:RabbitMQ 3.12+ -- **Git**:版本控制 -- **Docker Desktop**:容器化开发(可选) - -### 1.2 生产环境 -- **操作系统**:Linux (Ubuntu 22.04 LTS / CentOS 8+) -- **运行时**:.NET Runtime 10.0 -- **Web服务器**:Nginx 1.24+ -- **数据库**:PostgreSQL 16+ (主从复制) -- **缓存**:Redis 7.0+ (哨兵模式) -- **消息队列**:RabbitMQ 3.12+ (集群模式) -- **对象存储**:MinIO / 阿里云OSS / 腾讯云COS -- **监控**:Prometheus + Grafana -- **日志**:ELK Stack (Elasticsearch + Logstash + Kibana) - -### 1.3 硬件要求(生产环境) -- **应用服务器**:4核8GB内存(最低),推荐8核16GB -- **数据库服务器**:8核16GB内存,SSD存储 -- **Redis服务器**:4核8GB内存 -- **负载均衡器**:2核4GB内存 - -## 2. 本地开发环境搭建 - -### 2.1 安装.NET SDK -```bash -# Windows -# 从官网下载安装:https://dotnet.microsoft.com/download - -# Linux (Ubuntu) -wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -sudo dpkg -i packages-microsoft-prod.deb -sudo apt-get update -sudo apt-get install -y dotnet-sdk-10.0 - -# 验证安装 -dotnet --version -``` - -### 2.2 安装PostgreSQL -```bash -# Ubuntu -sudo apt-get update -sudo apt-get install -y postgresql-16 postgresql-contrib-16 - -# 启动服务 -sudo systemctl start postgresql -sudo systemctl enable postgresql - -# 创建数据库 -sudo -u postgres psql -CREATE DATABASE takeout_saas; -CREATE USER takeout_user WITH PASSWORD 'your_password'; -GRANT ALL PRIVILEGES ON DATABASE takeout_saas TO takeout_user; -\q -``` - -### 2.3 安装Redis -```bash -# Ubuntu -sudo apt-get install -y redis-server - -# 启动服务 -sudo systemctl start redis-server -sudo systemctl enable redis-server - -# 测试连接 -redis-cli ping -``` - -### 2.4 安装RabbitMQ -```bash -# Ubuntu -sudo apt-get install -y rabbitmq-server - -# 启动服务 -sudo systemctl start rabbitmq-server -sudo systemctl enable rabbitmq-server - -# 启用管理插件 -sudo rabbitmq-plugins enable rabbitmq_management - -# 创建用户 -sudo rabbitmqctl add_user admin password -sudo rabbitmqctl set_user_tags admin administrator -sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*" - -# 访问管理界面:http://localhost:15672 -``` - -### 2.5 使用Docker Compose(推荐) -```yaml -# docker-compose.yml -version: '3.8' - -services: - postgres: - image: postgres:16 - container_name: takeout_postgres - environment: - POSTGRES_DB: takeout_saas - POSTGRES_USER: takeout_user - POSTGRES_PASSWORD: your_password - ports: - - "5432:5432" - volumes: - - postgres_data:/var/lib/postgresql/data - - redis: - image: redis:7-alpine - container_name: takeout_redis - ports: - - "6379:6379" - volumes: - - redis_data:/data - - rabbitmq: - image: rabbitmq:3.12-management - container_name: takeout_rabbitmq - environment: - RABBITMQ_DEFAULT_USER: admin - RABBITMQ_DEFAULT_PASS: password - ports: - - "5672:5672" - - "15672:15672" - volumes: - - rabbitmq_data:/var/lib/rabbitmq - - minio: - image: minio/minio:latest - container_name: takeout_minio - command: server /data --console-address ":9001" - environment: - MINIO_ROOT_USER: admin - MINIO_ROOT_PASSWORD: password123 - ports: - - "9000:9000" - - "9001:9001" - volumes: - - minio_data:/data - -volumes: - postgres_data: - redis_data: - rabbitmq_data: - minio_data: -``` - -```bash -# 启动所有服务 -docker-compose up -d - -# 查看服务状态 -docker-compose ps - -# 停止服务 -docker-compose down -``` - -### 2.6 配置项目 -```bash -# 克隆项目 -git clone https://github.com/your-org/takeout-saas.git -cd takeout-saas - -# 还原依赖 -dotnet restore - -# 配置appsettings.Development.json -{ - "ConnectionStrings": { - "DefaultConnection": "Host=localhost;Port=5432;Database=takeout_saas;Username=takeout_user;Password=your_password" - }, - "Redis": { - "Configuration": "localhost:6379" - }, - "RabbitMQ": { - "Host": "localhost", - "Port": 5672, - "Username": "admin", - "Password": "password" - } -} - -# 执行数据库迁移 -cd src/TakeoutSaaS.Api -dotnet ef database update - -# 运行项目 -dotnet run -``` - -### 2.7 EF Core 迁移基线 - -现已内置 `dotnet-ef` 本地工具与设计时 DbContext 工厂,可直接在命令行生成/更新数据库。运行前可通过环境变量 `TAKEOUTSAAS_APP_CONNECTION`、`TAKEOUTSAAS_IDENTITY_CONNECTION` 覆盖默认连接串(默认指向本地 PostgreSQL)。 - -```powershell -# 业务主库(TakeoutAppDbContext,含租户/商户/门店/商品/订单等) -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --context TakeoutSaaS.Infrastructure.App.Persistence.TakeoutAppDbContext - -# 身份库(IdentityDbContext) -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --context TakeoutSaaS.Infrastructure.Identity.Persistence.IdentityDbContext - -# 业务/字典库(DictionaryDbContext,归属 AppDatabase) -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --context TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext -``` - -> Hangfire 使用 Scheduler.ConnectionString 指向的数据库,首次启动服务会自动建表;只需提前创建空数据库并授予账号权限。 - -## 3. Docker部署 - -### 3.1 创建Dockerfile -```dockerfile -# Dockerfile -FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base -WORKDIR /app -EXPOSE 80 -EXPOSE 443 - -FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build -WORKDIR /src -COPY ["src/TakeoutSaaS.Api/TakeoutSaaS.Api.csproj", "src/TakeoutSaaS.Api/"] -COPY ["src/TakeoutSaaS.Application/TakeoutSaaS.Application.csproj", "src/TakeoutSaaS.Application/"] -COPY ["src/TakeoutSaaS.Domain/TakeoutSaaS.Domain.csproj", "src/TakeoutSaaS.Domain/"] -COPY ["src/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj", "src/TakeoutSaaS.Infrastructure/"] -COPY ["src/TakeoutSaaS.Shared/TakeoutSaaS.Shared.csproj", "src/TakeoutSaaS.Shared/"] -RUN dotnet restore "src/TakeoutSaaS.Api/TakeoutSaaS.Api.csproj" -COPY . . -WORKDIR "/src/src/TakeoutSaaS.Api" -RUN dotnet build "TakeoutSaaS.Api.csproj" -c Release -o /app/build - -FROM build AS publish -RUN dotnet publish "TakeoutSaaS.Api.csproj" -c Release -o /app/publish /p:UseAppHost=false - -FROM base AS final -WORKDIR /app -COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "TakeoutSaaS.Api.dll"] -``` - -### 3.2 构建镜像 -```bash -# 构建镜像 -docker build -t takeout-saas-api:latest . - -# 查看镜像 -docker images | grep takeout-saas - -# 运行容器 -docker run -d \ - --name takeout-api \ - -p 8080:80 \ - -e ASPNETCORE_ENVIRONMENT=Production \ - -e ConnectionStrings__DefaultConnection="Host=postgres;Port=5432;Database=takeout_saas;Username=takeout_user;Password=your_password" \ - takeout-saas-api:latest -``` - -### 3.3 生产环境Docker Compose -```yaml -# docker-compose.prod.yml -version: '3.8' - -services: - api: - image: takeout-saas-api:latest - container_name: takeout_api - restart: always - environment: - ASPNETCORE_ENVIRONMENT: Production - ConnectionStrings__DefaultConnection: "Host=postgres;Port=5432;Database=takeout_saas;Username=takeout_user;Password=${DB_PASSWORD}" - Redis__Configuration: "redis:6379" - RabbitMQ__Host: "rabbitmq" - ports: - - "8080:80" - depends_on: - - postgres - - redis - - rabbitmq - networks: - - takeout_network - - nginx: - image: nginx:latest - container_name: takeout_nginx - restart: always - ports: - - "80:80" - - "443:443" - volumes: - - ./nginx/nginx.conf:/etc/nginx/nginx.conf - - ./nginx/ssl:/etc/nginx/ssl - depends_on: - - api - networks: - - takeout_network - -networks: - takeout_network: - driver: bridge -``` - -## 4. Nginx配置 - -### 4.1 基础配置 -```nginx -# /etc/nginx/nginx.conf -user nginx; -worker_processes auto; -error_log /var/log/nginx/error.log warn; -pid /var/run/nginx.pid; - -events { - worker_connections 1024; -} - -http { - include /etc/nginx/mime.types; - default_type application/octet-stream; - - log_format main '$remote_addr - $remote_user [$time_local] "$request" ' - '$status $body_bytes_sent "$http_referer" ' - '"$http_user_agent" "$http_x_forwarded_for"'; - - access_log /var/log/nginx/access.log main; - - sendfile on; - tcp_nopush on; - tcp_nodelay on; - keepalive_timeout 65; - types_hash_max_size 2048; - - # Gzip压缩 - gzip on; - gzip_vary on; - gzip_proxied any; - gzip_comp_level 6; - gzip_types text/plain text/css text/xml text/javascript - application/json application/javascript application/xml+rss - application/rss+xml font/truetype font/opentype - application/vnd.ms-fontobject image/svg+xml; - - # 限流配置 - limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s; - limit_conn_zone $binary_remote_addr zone=conn_limit:10m; - - include /etc/nginx/conf.d/*.conf; -} -``` - -### 4.2 API服务配置 -```nginx -# /etc/nginx/conf.d/api.conf -upstream api_backend { - least_conn; - server api1:80 weight=1 max_fails=3 fail_timeout=30s; - server api2:80 weight=1 max_fails=3 fail_timeout=30s; - keepalive 32; -} - -server { - listen 80; - server_name api.example.com; - - # 重定向到HTTPS - return 301 https://$server_name$request_uri; -} - -server { - listen 443 ssl http2; - server_name api.example.com; - - # SSL证书配置 - ssl_certificate /etc/nginx/ssl/cert.pem; - ssl_certificate_key /etc/nginx/ssl/key.pem; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers HIGH:!aNULL:!MD5; - ssl_prefer_server_ciphers on; - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 10m; - - # 安全头 - add_header X-Frame-Options "SAMEORIGIN" always; - add_header X-Content-Type-Options "nosniff" always; - add_header X-XSS-Protection "1; mode=block" always; - add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; - - # 客户端请求体大小限制 - client_max_body_size 10M; - - # API接口 - location /api/ { - # 限流 - limit_req zone=api_limit burst=20 nodelay; - limit_conn conn_limit 10; - - proxy_pass http://api_backend; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - - # 超时设置 - proxy_connect_timeout 60s; - proxy_send_timeout 60s; - proxy_read_timeout 60s; - - # 缓冲设置 - proxy_buffering on; - proxy_buffer_size 4k; - proxy_buffers 8 4k; - proxy_busy_buffers_size 8k; - } - - # WebSocket - location /ws { - proxy_pass http://api_backend; - proxy_http_version 1.1; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - # WebSocket超时 - proxy_read_timeout 3600s; - proxy_send_timeout 3600s; - } - - # 健康检查 - location /health { - proxy_pass http://api_backend; - access_log off; - } - - # 静态文件缓存 - location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff|woff2|ttf|eot)$ { - proxy_pass http://api_backend; - expires 30d; - add_header Cache-Control "public, immutable"; - } -} -``` - -## 5. 数据库部署 - -### 5.1 PostgreSQL主从复制 -```bash -# 主库配置 (postgresql.conf) -listen_addresses = '*' -wal_level = replica -max_wal_senders = 10 -wal_keep_size = 64MB -hot_standby = on - -# 主库配置 (pg_hba.conf) -host replication replicator 192.168.1.0/24 md5 - -# 创建复制用户 -CREATE USER replicator WITH REPLICATION ENCRYPTED PASSWORD 'repl_password'; - -# 从库配置 -# 1. 停止从库 -sudo systemctl stop postgresql - -# 2. 清空从库数据目录 -rm -rf /var/lib/postgresql/16/main/* - -# 3. 从主库复制数据 -pg_basebackup -h master_ip -D /var/lib/postgresql/16/main -U replicator -P -v -R -X stream -C -S replica1 - -# 4. 启动从库 -sudo systemctl start postgresql - -# 5. 验证复制状态 -# 主库执行 -SELECT * FROM pg_stat_replication; -``` - -### 5.2 数据库备份脚本 -```bash -#!/bin/bash -# backup_db.sh - -BACKUP_DIR="/backup/postgres" -DATE=$(date +%Y%m%d_%H%M%S) -DB_NAME="takeout_saas" -DB_USER="takeout_user" -RETENTION_DAYS=30 - -# 创建备份目录 -mkdir -p $BACKUP_DIR - -# 全量备份 -pg_dump -h localhost -U $DB_USER -d $DB_NAME -F c -f $BACKUP_DIR/full_$DATE.dump - -# 压缩备份 -gzip $BACKUP_DIR/full_$DATE.dump - -# 删除过期备份 -find $BACKUP_DIR -name "full_*.dump.gz" -mtime +$RETENTION_DAYS -delete - -# 上传到对象存储(可选) -# aws s3 cp $BACKUP_DIR/full_$DATE.dump.gz s3://your-bucket/backups/ - -echo "Backup completed: full_$DATE.dump.gz" -``` - -### 5.3 定时备份(Crontab) -```bash -# 编辑crontab -crontab -e - -# 每天凌晨2点执行备份 -0 2 * * * /path/to/backup_db.sh >> /var/log/backup.log 2>&1 -``` - -## TODO:基础设施部署脚本 - -- [ ] PostgreSQL 主从:整理主库/从库初始化脚本、basebackup 步骤与故障切换手册。 -- [ ] Redis 哨兵/集群:补充 redis.conf/sentinel.conf 模板以及一主两从搭建命令。 -- [ ] RabbitMQ:编写单节点到镜像队列的安装脚本,记录 VHost、用户、权限、监控等操作。 -- [ ] 腾讯云 COS:整理桶创建、ACL、CDN 绑定与密钥轮换流程,并提供 coscmd/SDK 示例。 -- [ ] Hangfire 存储:确认 PostgreSQL Schema 初始化脚本,补充定期备份、清理、监控的 SOP。 - -## 6. Redis部署 - -### 6.1 Redis哨兵模式 -```bash -# redis.conf (主节点) -bind 0.0.0.0 -port 6379 -requirepass your_password -masterauth your_password - -# sentinel.conf -port 26379 -sentinel monitor mymaster 192.168.1.100 6379 2 -sentinel auth-pass mymaster your_password -sentinel down-after-milliseconds mymaster 5000 -sentinel parallel-syncs mymaster 1 -sentinel failover-timeout mymaster 10000 -``` - -### 6.2 Redis持久化配置 -```bash -# redis.conf -# RDB持久化 -save 900 1 -save 300 10 -save 60 10000 -rdbcompression yes -rdbchecksum yes -dbfilename dump.rdb - -# AOF持久化 -appendonly yes -appendfilename "appendonly.aof" -appendfsync everysec -no-appendfsync-on-rewrite no -auto-aof-rewrite-percentage 100 -auto-aof-rewrite-min-size 64mb -``` - -## 7. CI/CD配置 - -### 7.1 GitHub Actions -```yaml -# .github/workflows/deploy.yml -name: Deploy to Production - -on: - push: - branches: [ main ] - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - - name: Setup .NET - uses: actions/setup-dotnet@v3 - with: - dotnet-version: '10.0.x' - - - name: Restore dependencies - run: dotnet restore - - - name: Build - run: dotnet build --configuration Release --no-restore - - - name: Test - run: dotnet test --no-build --verbosity normal - - - name: Publish - run: dotnet publish src/TakeoutSaaS.Api/TakeoutSaaS.Api.csproj -c Release -o ./publish - - - name: Build Docker image - run: | - docker build -t takeout-saas-api:${{ github.sha }} . - docker tag takeout-saas-api:${{ github.sha }} takeout-saas-api:latest - - - name: Push to Registry - run: | - echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin - docker push takeout-saas-api:${{ github.sha }} - docker push takeout-saas-api:latest - - - name: Deploy to Server - uses: appleboy/ssh-action@master - with: - host: ${{ secrets.SERVER_HOST }} - username: ${{ secrets.SERVER_USER }} - key: ${{ secrets.SSH_PRIVATE_KEY }} - script: | - cd /opt/takeout-saas - docker-compose pull - docker-compose up -d - docker system prune -f -``` - -### 7.2 GitLab CI -```yaml -# .gitlab-ci.yml -stages: - - build - - test - - deploy - -variables: - DOCKER_IMAGE: registry.example.com/takeout-saas-api - -build: - stage: build - image: mcr.microsoft.com/dotnet/sdk:10.0 - script: - - dotnet restore - - dotnet build --configuration Release - artifacts: - paths: - - src/*/bin/Release/ - -test: - stage: test - image: mcr.microsoft.com/dotnet/sdk:10.0 - script: - - dotnet test --configuration Release - -deploy: - stage: deploy - image: docker:latest - services: - - docker:dind - script: - - docker build -t $DOCKER_IMAGE:$CI_COMMIT_SHA . - - docker tag $DOCKER_IMAGE:$CI_COMMIT_SHA $DOCKER_IMAGE:latest - - docker push $DOCKER_IMAGE:$CI_COMMIT_SHA - - docker push $DOCKER_IMAGE:latest - only: - - main -``` - -## 8. 监控告警 - -### 8.1 Prometheus配置 -```yaml -# prometheus.yml -global: - scrape_interval: 15s - evaluation_interval: 15s - -scrape_configs: - - job_name: 'takeout-api' - static_configs: - - targets: ['api:80'] - metrics_path: '/metrics' - - - job_name: 'postgres' - static_configs: - - targets: ['postgres-exporter:9187'] - - - job_name: 'redis' - static_configs: - - targets: ['redis-exporter:9121'] - - - job_name: 'node' - static_configs: - - targets: ['node-exporter:9100'] -``` - -### 8.2 应用监控指标(OpenTelemetry + Prometheus Exporter) -```csharp -// Program.cs - 指标与探针 -builder.Services.AddHealthChecks(); -builder.Services.AddOpenTelemetry() - .WithMetrics(metrics => - { - metrics - .AddAspNetCoreInstrumentation() - .AddHttpClientInstrumentation() - .AddRuntimeInstrumentation() - .AddPrometheusExporter(); // /metrics - }); - -var app = builder.Build(); -app.MapHealthChecks("/healthz"); // 存活/就绪探针 -app.MapPrometheusScrapingEndpoint(); // 默认 /metrics -``` - -自定义业务指标(使用 `System.Diagnostics.Metrics`,由 Prometheus Exporter 暴露): -```csharp -internal static class BusinessMetrics -{ - private static readonly Meter Meter = new("TakeoutSaaS.App", "1.0.0"); - public static readonly Counter OrdersCreated = Meter.CreateCounter("orders_created_total", "个", "订单创建计数"); - public static readonly Histogram OrderProcessingSeconds = Meter.CreateHistogram("order_processing_duration_seconds", "s", "订单处理耗时"); -} -``` - -Prometheus 抓取示例:见 `deploy/prometheus/prometheus.yml`,默认拉取 `/metrics`,告警规则见 `deploy/prometheus/alert.rules.yml`。 - -### 8.3 Grafana仪表板 -```json -{ - "dashboard": { - "title": "外卖SaaS系统监控", - "panels": [ - { - "title": "API请求速率", - "targets": [ - { - "expr": "rate(http_requests_total[5m])" - } - ] - }, - { - "title": "订单创建数", - "targets": [ - { - "expr": "increase(orders_created_total[1h])" - } - ] - }, - { - "title": "数据库连接数", - "targets": [ - { - "expr": "pg_stat_activity_count" - } - ] - } - ] - } -} -``` - -### 8.4 告警规则 -```yaml -# alert.rules.yml -groups: - - name: takeout_alerts - interval: 30s - rules: - - alert: HighErrorRate - expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05 - for: 5m - labels: - severity: critical - annotations: - summary: "高错误率告警" - description: "API错误率超过5%" - - - alert: DatabaseDown - expr: up{job="postgres"} == 0 - for: 1m - labels: - severity: critical - annotations: - summary: "数据库宕机" - description: "PostgreSQL数据库不可用" - - - alert: HighMemoryUsage - expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes > 0.9 - for: 5m - labels: - severity: warning - annotations: - summary: "内存使用率过高" - description: "内存使用率超过90%" -``` - -## 9. 日志管理 - -### 9.1 Serilog配置 -```json -{ - "Serilog": { - "Using": ["Serilog.Sinks.Console", "Serilog.Sinks.File", "Serilog.Sinks.Elasticsearch"], - "MinimumLevel": { - "Default": "Information", - "Override": { - "Microsoft": "Warning", - "System": "Warning" - } - }, - "WriteTo": [ - { - "Name": "Console", - "Args": { - "outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}" - } - }, - { - "Name": "File", - "Args": { - "path": "logs/log-.txt", - "rollingInterval": "Day", - "retainedFileCountLimit": 30 - } - }, - { - "Name": "Elasticsearch", - "Args": { - "nodeUris": "http://elasticsearch:9200", - "indexFormat": "takeout-logs-{0:yyyy.MM.dd}", - "autoRegisterTemplate": true - } - } - ], - "Enrich": ["FromLogContext", "WithMachineName", "WithThreadId"] - } -} -``` - -### 9.2 ELK Stack部署 -```yaml -# docker-compose.elk.yml -version: '3.8' - -services: - elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:8.11.0 - environment: - - discovery.type=single-node - - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - ports: - - "9200:9200" - volumes: - - es_data:/usr/share/elasticsearch/data - - logstash: - image: docker.elastic.co/logstash/logstash:8.11.0 - volumes: - - ./logstash/pipeline:/usr/share/logstash/pipeline - ports: - - "5044:5044" - depends_on: - - elasticsearch - - kibana: - image: docker.elastic.co/kibana/kibana:8.11.0 - ports: - - "5601:5601" - environment: - ELASTICSEARCH_HOSTS: http://elasticsearch:9200 - depends_on: - - elasticsearch - -volumes: - es_data: -``` - -## 10. 安全加固 - -### 10.1 防火墙配置 -```bash -# UFW防火墙 -sudo ufw enable -sudo ufw allow 22/tcp # SSH -sudo ufw allow 80/tcp # HTTP -sudo ufw allow 443/tcp # HTTPS -sudo ufw deny 5432/tcp # 禁止外部访问数据库 -sudo ufw deny 6379/tcp # 禁止外部访问Redis -``` - -### 10.2 SSL证书(Let's Encrypt) -```bash -# 安装Certbot -sudo apt-get install certbot python3-certbot-nginx - -# 获取证书 -sudo certbot --nginx -d api.example.com - -# 自动续期 -sudo certbot renew --dry-run - -# 添加定时任务 -0 3 * * * certbot renew --quiet -``` - -### 10.3 应用安全配置 -```csharp -// Program.cs -builder.Services.AddHsts(options => -{ - options.MaxAge = TimeSpan.FromDays(365); - options.IncludeSubDomains = true; - options.Preload = true; -}); - -builder.Services.AddHttpsRedirection(options => -{ - options.RedirectStatusCode = StatusCodes.Status308PermanentRedirect; - options.HttpsPort = 443; -}); - -// 添加安全头 -app.Use(async (context, next) => -{ - context.Response.Headers.Add("X-Content-Type-Options", "nosniff"); - context.Response.Headers.Add("X-Frame-Options", "DENY"); - context.Response.Headers.Add("X-XSS-Protection", "1; mode=block"); - context.Response.Headers.Add("Referrer-Policy", "no-referrer"); - await next(); -}); -``` - -## 11. 性能优化 - -### 11.1 数据库连接池 -```json -{ - "ConnectionStrings": { - "DefaultConnection": "Host=localhost;Port=5432;Database=takeout_saas;Username=user;Password=pass;Pooling=true;MinPoolSize=5;MaxPoolSize=100;ConnectionLifetime=300" - } -} -``` - -### 11.2 Redis连接池 -```csharp -services.AddStackExchangeRedisCache(options => -{ - options.Configuration = configuration["Redis:Configuration"]; - options.InstanceName = "TakeoutSaaS:"; -}); -``` - -### 11.3 响应压缩 -```csharp -builder.Services.AddResponseCompression(options => -{ - options.EnableForHttps = true; - options.Providers.Add(); - options.Providers.Add(); -}); -``` - -## 12. 故障恢复 - -### 12.1 数据库恢复 -```bash -# 从备份恢复 -pg_restore -h localhost -U takeout_user -d takeout_saas -v /backup/full_20240101.dump - -# PITR恢复到指定时间点 -# 1. 停止数据库 -sudo systemctl stop postgresql - -# 2. 恢复基础备份 -rm -rf /var/lib/postgresql/16/main/* -tar -xzf /backup/base_backup.tar.gz -C /var/lib/postgresql/16/main/ - -# 3. 配置recovery.conf -restore_command = 'cp /backup/wal_archive/%f %p' -recovery_target_time = '2024-01-01 12:00:00' - -# 4. 启动数据库 -sudo systemctl start postgresql -``` - -### 12.2 应用回滚 -```bash -# Docker回滚到上一个版本 -docker-compose down -docker-compose up -d --force-recreate --no-deps api - -# 或使用特定版本 -docker pull takeout-saas-api:previous-version -docker-compose up -d -``` - -## 13. 网关 TakeoutSaaS.ApiGateway 部署 - -1. **部署拓扑** - - Nginx 负责域名 `kjkj.qiyuesns.cn`(含后续 HTTPS 证书),并将所有流量反代到本机 `http://127.0.0.1:5000`。 - - .NET 网关容器(TakeoutSaaS.ApiGateway)负责 YARP 路由、限流、日志与 OpenTelemetry 埋点,向下游 49.7.179.246 的 Admin/User/Mini API 转发。 - -2. **构建与运行** - ```bash - # 构建镜像 - docker build -f src/Gateway/TakeoutSaaS.ApiGateway/Dockerfile -t takeoutsaas/apigateway:latest . - - # 启动容器(生产环境建议挂载独立配置) - docker run -d --name takeout-gateway -p 5000:5000 ^ - -e ASPNETCORE_ENVIRONMENT=Production ^ - -v /opt/takeoutsaas/gateway/appsettings.Production.json:/app/appsettings.Production.json ^ - takeoutsaas/apigateway:latest - ``` - - `appsettings.json` 默认将 `/api/admin|mini|user/**` 指向主应用服务器(7801/7701/7901 端口)。 - - `appsettings.Development.json` 可在本地覆盖为 `localhost:5001/5002/5003`,无需改代码。 - -3. **Nginx 参考配置** - ```nginx - server { - listen 80; - server_name kjkj.qiyuesns.cn; - - location / { - proxy_pass http://127.0.0.1:5000; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - } - } - ``` - - 后续启用 HTTPS 时,将 `listen 443 ssl` 与证书配置加入同一 `server`,其余保持不变。 - -4. **关键配置项说明** - - `Gateway:RateLimiting`:按客户端 IP 固定窗口限流(默认 300 次/60 秒),可通过配置文件调整或关闭。 - - `ReverseProxy`:集中声明路由规则(`/api/{service}/**`),后端地址变更时只需改配置即可。 - - `OpenTelemetry`:默认开启 OTLP 导出,Collector 地址通过 `OpenTelemetry:OtlpEndpoint` 指定。 - - `Serilog`:统一输出到控制台,日志采集器可以直接收集 Docker stdout。 - -5. **健康检查** - - `GET /healthz`:基础健康,用于探活或监控告警。 - - `GET /`:返回服务元信息,可作为简易诊断接口。 diff --git a/Document/06_开发规范.md b/Document/06_开发规范.md deleted file mode 100644 index f558dfb..0000000 --- a/Document/06_开发规范.md +++ /dev/null @@ -1,395 +0,0 @@ -# 外卖SaaS系统 - 开发规范 - -## 1. 代码规范 - -### 1.1 命名规范 - -#### C#命名规范 -```csharp -// 类名:PascalCase -public class OrderService { } - -// 接口:I + PascalCase -public interface IOrderRepository { } - -// 方法:PascalCase -public async Task CreateOrderAsync() { } - -// 私有字段:_camelCase -private readonly IOrderRepository _orderRepository; - -// 公共属性:PascalCase -public string OrderNo { get; set; } - -// 局部变量:camelCase -var orderTotal = 100.00m; - -// 常量:PascalCase -public const int MaxOrderItems = 50; - -// 枚举:PascalCase -public enum OrderStatus -{ - Pending = 1, - Confirmed = 2, - Completed = 3 -} -``` - -#### 数据库命名规范 -```sql --- 表名:小写,下划线分隔,复数 -orders -order_items -merchant_stores - --- 字段名:小写,下划线分隔 -order_no -created_at -total_amount - --- 索引:idx_表名_字段名 -idx_orders_merchant_id -idx_orders_created_at - --- 外键:fk_表名_引用表名 -fk_orders_merchants -``` - -### 1.2 代码组织 - -#### 项目结构 -``` -TakeoutSaaS/ -├── src/ -│ ├── TakeoutSaaS.Api/ # Web API层 -│ │ ├── Controllers/ # 控制器 -│ │ ├── Filters/ # 过滤器 -│ │ ├── Middleware/ # 中间件 -│ │ ├── Models/ # DTO模型 -│ │ └── Program.cs -│ ├── TakeoutSaaS.Application/ # 应用层 -│ │ ├── Services/ # 应用服务 -│ │ ├── DTOs/ # 数据传输对象 -│ │ ├── Interfaces/ # 服务接口 -│ │ ├── Validators/ # 验证器 -│ │ ├── Mappings/ # 对象映射 -│ │ └── Commands/ # CQRS命令 -│ │ └── Queries/ # CQRS查询 -│ ├── TakeoutSaaS.Domain/ # 领域层 -│ │ ├── Entities/ # 实体 -│ │ ├── ValueObjects/ # 值对象 -│ │ ├── Enums/ # 枚举 -│ │ ├── Events/ # 领域事件 -│ │ └── Interfaces/ # 仓储接口 -│ ├── TakeoutSaaS.Infrastructure/ # 基础设施层 -│ │ ├── Data/ # 数据访问 -│ │ │ ├── EFCore/ # EF Core实现 -│ │ │ ├── Dapper/ # Dapper实现 -│ │ │ └── Repositories/ # 仓储实现 -│ │ ├── Cache/ # 缓存实现 -│ │ ├── MessageQueue/ # 消息队列 -│ │ └── ExternalServices/ # 外部服务 -│ └── TakeoutSaaS.Shared/ # 共享层 -│ ├── Constants/ # 常量 -│ ├── Exceptions/ # 异常 -│ ├── Extensions/ # 扩展方法 -│ └── Results/ # 统一返回结果 -├── tests/ -│ ├── TakeoutSaaS.UnitTests/ # 单元测试 -│ ├── TakeoutSaaS.IntegrationTests/ # 集成测试 -│ └── TakeoutSaaS.PerformanceTests/ # 性能测试 -└── docs/ # 文档 -``` - -### 1.3 代码注释 - -```csharp -/// -/// 订单服务接口 -/// -public interface IOrderService -{ - /// - /// 创建订单 - /// - /// 订单创建请求 - /// 订单信息 - /// 业务异常 - Task CreateOrderAsync(CreateOrderRequest request); -} - -// 复杂业务逻辑添加注释 -public async Task CalculateOrderAmount(Order order) -{ - // 1. 计算菜品总金额 - var dishAmount = order.Items.Sum(x => x.Price * x.Quantity); - - // 2. 计算配送费(距离 > 3km,每公里加收2元) - var deliveryFee = CalculateDeliveryFee(order.Distance); - - // 3. 应用优惠券折扣 - var discount = await ApplyCouponDiscountAsync(order.CouponId, dishAmount); - - // 4. 计算最终金额 - return dishAmount + deliveryFee - discount; -} -``` - -### 1.4 异常处理 - -```csharp -// 自定义业务异常 -public class BusinessException : Exception -{ - public int ErrorCode { get; } - - public BusinessException(int errorCode, string message) - : base(message) - { - ErrorCode = errorCode; - } -} - -// 全局异常处理中间件 -public class ExceptionHandlingMiddleware -{ - private readonly RequestDelegate _next; - private readonly ILogger _logger; - - public async Task InvokeAsync(HttpContext context) - { - try - { - await _next(context); - } - catch (BusinessException ex) - { - _logger.LogWarning(ex, "业务异常:{Message}", ex.Message); - await HandleBusinessExceptionAsync(context, ex); - } - catch (Exception ex) - { - _logger.LogError(ex, "系统异常:{Message}", ex.Message); - await HandleSystemExceptionAsync(context, ex); - } - } - - private static Task HandleBusinessExceptionAsync(HttpContext context, BusinessException ex) - { - context.Response.StatusCode = StatusCodes.Status422UnprocessableEntity; - return context.Response.WriteAsJsonAsync(new - { - success = false, - code = ex.ErrorCode, - message = ex.Message - }); - } -} - -// 使用示例 -public async Task GetOrderAsync(Guid orderId) -{ - var order = await _orderRepository.GetByIdAsync(orderId); - if (order == null) - { - throw new BusinessException(404, "订单不存在"); - } - return order; -} -``` - -## 2. Git工作流 - -### 2.1 分支管理 - -``` -main # 主分支,生产环境代码 -├── develop # 开发分支 -│ ├── feature/order-management # 功能分支 -│ ├── feature/payment-integration # 功能分支 -│ └── bugfix/order-calculation # 修复分支 -└── hotfix/critical-bug # 紧急修复分支 -``` - -### 2.2 分支命名规范 - -- **功能分支**:`feature/功能名称`(如:`feature/order-management`) -- **修复分支**:`bugfix/问题描述`(如:`bugfix/order-calculation`) -- **紧急修复**:`hotfix/问题描述`(如:`hotfix/payment-error`) -- **发布分支**:`release/版本号`(如:`release/v1.0.0`) - -### 2.3 提交信息规范 - -```bash -# 格式:(): - -# type类型: -# feat: 新功能 -# fix: 修复bug -# docs: 文档更新 -# style: 代码格式调整 -# refactor: 重构 -# perf: 性能优化 -# test: 测试相关 -# chore: 构建/工具相关 - -# 示例 -git commit -m "feat(order): 添加订单创建功能" -git commit -m "fix(payment): 修复支付回调处理错误" -git commit -m "docs(api): 更新API文档" -git commit -m "refactor(service): 重构订单服务" -``` - -### 2.4 工作流程 - -```bash -# 1. 从develop创建功能分支 -git checkout develop -git pull origin develop -git checkout -b feature/order-management - -# 2. 开发并提交 -git add . -git commit -m "feat(order): 添加订单创建功能" - -# 3. 推送到远程 -git push origin feature/order-management - -# 4. 创建Pull Request到develop分支 - -# 5. 代码审查通过后合并 - -# 6. 删除功能分支 -git branch -d feature/order-management -git push origin --delete feature/order-management -``` - -## 3. 代码审查 - -### 3.1 审查清单 - -- [ ] 代码符合命名规范 -- [ ] 代码逻辑清晰,易于理解 -- [ ] 适当的注释和文档 -- [ ] 异常处理完善 -- [ ] 单元测试覆盖 -- [ ] 性能考虑(N+1查询、大数据量处理) -- [ ] 安全性考虑(SQL注入、XSS、权限校验) -- [ ] 日志记录完善 -- [ ] 无硬编码配置 -- [ ] 符合SOLID原则 - -### 3.2 审查重点 - -```csharp -// ❌ 不好的实践 -public class OrderService -{ - public Order CreateOrder(CreateOrderRequest request) - { - // 直接在服务层操作DbContext - var order = new Order(); - _dbContext.Orders.Add(order); - _dbContext.SaveChanges(); - - // 硬编码配置 - var deliveryFee = 5.0m; - - // 没有异常处理 - // 没有日志记录 - - return order; - } -} - -// ✅ 好的实践 -public class OrderService : IOrderService -{ - private readonly IOrderRepository _orderRepository; - private readonly IUnitOfWork _unitOfWork; - private readonly ILogger _logger; - private readonly IOptions _settings; - - public async Task CreateOrderAsync(CreateOrderRequest request) - { - try - { - // 参数验证 - if (request == null) - throw new ArgumentNullException(nameof(request)); - - _logger.LogInformation("创建订单:{@Request}", request); - - // 业务逻辑 - var order = new Order - { - // ... 初始化订单 - DeliveryFee = _settings.Value.DefaultDeliveryFee - }; - - // 使用仓储 - await _orderRepository.AddAsync(order); - await _unitOfWork.SaveChangesAsync(); - - _logger.LogInformation("订单创建成功:{OrderId}", order.Id); - - return _mapper.Map(order); - } - catch (Exception ex) - { - _logger.LogError(ex, "创建订单失败:{@Request}", request); - throw; - } - } -} -``` - - - -## 4. 单元测试规范 - -### 4.1 测试命名 -- 命名格式:`MethodName_Scenario_ExpectedResult` -- 测试覆盖率要求:核心业务逻辑 >= 80% - -### 4.2 测试示例 - -```csharp -[Fact] -public async Task CreateOrder_ValidRequest_ReturnsOrderDto() -{ - // Arrange - var request = new CreateOrderRequest { /* ... */ }; - - // Act - var result = await _orderService.CreateOrderAsync(request); - - // Assert - result.Should().NotBeNull(); - result.OrderNo.Should().NotBeNullOrEmpty(); -} -``` - -## 5. 性能优化规范 - -### 5.1 数据库查询优化 -- 避免N+1查询,使用Include预加载 -- 大数据量查询使用Dapper -- 合理使用索引 - -### 5.2 缓存策略 -- 商家信息:30分钟 -- 菜品信息:15分钟 -- 配置信息:1小时 -- 用户会话:2小时 - -## 6. 文档要求 - -### 6.1 代码文档 -- 所有公共API必须有XML文档注释 -- 复杂业务逻辑添加详细注释 -- README.md说明项目结构和运行方式 - -### 6.2 变更日志 -维护CHANGELOG.md记录版本变更 \ No newline at end of file diff --git a/Document/07_系统架构图.md b/Document/07_系统架构图.md deleted file mode 100644 index 3a5a350..0000000 --- a/Document/07_系统架构图.md +++ /dev/null @@ -1,321 +0,0 @@ -# 外卖SaaS系统 - 系统架构图 - -## 1. 整体架构图 - -``` -┌─────────────────────────────────────────────────────────────────────┐ -│ 客户端层 │ -│ ┌──────────────┐ ┌──────────────┐ ┌─────────────────┐ │ -│ │ Web管理端 │ │ Web用户端 │ │ 小程序端(用户) │ │ -│ │ (React/Vue) │ │ (React/Vue) │ │ (微信/支付宝) │ │ -│ └──────────────┘ └──────────────┘ └─────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ API网关层 │ -│ ┌───────────────────────────────────────────────────────────────┐ │ -│ │ Nginx / API Gateway │ │ -│ │ - 路由转发 │ │ -│ │ - 负载均衡 │ │ -│ │ - 限流熔断 │ │ -│ │ - SSL终止 │ │ -│ └───────────────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 应用服务层 │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ 租户服务 │ │ 商家服务 │ │ 菜品服务 │ │ -│ │ - 租户管理 │ │ - 商家管理 │ │ - 菜品管理 │ │ -│ │ - 权限管理 │ │ - 门店管理 │ │ - 分类管理 │ │ -│ └──────────────┘ └──────────────┘ └──────────────┘ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ 订单服务 │ │ 配送服务 │ │ 用户服务 │ │ -│ │ - 订单管理 │ │ - 配送员管理 │ │ - 用户管理 │ │ -│ │ - 订单流转 │ │ - 任务分配 │ │ - 地址管理 │ │ -│ └──────────────┘ └──────────────┘ └──────────────┘ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ 支付服务 │ │ 营销服务 │ │ 通知服务 │ │ -│ │ - 支付处理 │ │ - 优惠券 │ │ - 短信通知 │ │ -│ │ - 退款处理 │ │ - 活动管理 │ │ - 推送通知 │ │ -│ └──────────────┘ └──────────────┘ └──────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────────────┐ -│ 基础设施层 │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ PostgreSQL │ │ Redis │ │ RabbitMQ │ │ -│ │ - 主数据库 │ │ - 缓存 │ │ - 消息队列 │ │ -│ │ - 主从复制 │ │ - 会话存储 │ │ - 异步任务 │ │ -│ └──────────────┘ └──────────────┘ └──────────────┘ │ -│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ -│ │ MinIO/OSS │ │ Elasticsearch│ │ Prometheus │ │ -│ │ - 对象存储 │ │ - 日志存储 │ │ - 监控告警 │ │ -│ └──────────────┘ └──────────────┘ └──────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ -``` - -## 2. 应用分层架构 - -``` -┌─────────────────────────────────────────────────────────────┐ -│ Presentation Layer │ -│ (表现层) │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ TakeoutSaaS.Api │ │ -│ │ - Controllers (控制器) │ │ -│ │ - Filters (过滤器) │ │ -│ │ - Middleware (中间件) │ │ -│ │ - Models (DTO模型) │ │ -│ └──────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Application Layer │ -│ (应用层) │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ TakeoutSaaS.Application │ │ -│ │ - Services (应用服务) │ │ -│ │ - DTOs (数据传输对象) │ │ -│ │ - Interfaces (服务接口) │ │ -│ │ - Validators (验证器) │ │ -│ │ - Mappings (对象映射) │ │ -│ │ - Commands/Queries (CQRS) │ │ -│ └──────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Domain Layer │ -│ (领域层) │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ TakeoutSaaS.Domain │ │ -│ │ - Entities (实体) │ │ -│ │ - ValueObjects (值对象) │ │ -│ │ - Enums (枚举) │ │ -│ │ - Events (领域事件) │ │ -│ │ - Interfaces (仓储接口) │ │ -│ │ - Specifications (规约) │ │ -│ └──────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────────┐ -│ Infrastructure Layer │ -│ (基础设施层) │ -│ ┌──────────────────────────────────────────────────────┐ │ -│ │ TakeoutSaaS.Infrastructure │ │ -│ │ - Data (数据访问) │ │ -│ │ - EFCore (EF Core实现) │ │ -│ │ - Dapper (Dapper实现) │ │ -│ │ - Repositories (仓储实现) │ │ -│ │ - Cache (缓存实现) │ │ -│ │ - MessageQueue (消息队列) │ │ -│ │ - ExternalServices (外部服务) │ │ -│ └──────────────────────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────┘ -``` - -## 3. 订单处理流程图 - -``` -用户下单 → 创建订单 → 支付 → 商家接单 → 制作 → 配送 → 完成 - │ │ │ │ │ │ │ - │ │ │ │ │ │ └─→ 订单完成 - │ │ │ │ │ └─→ 配送中 - │ │ │ │ └─→ 制作中 - │ │ │ └─→ 待制作 - │ │ └─→ 待接单 - │ └─→ 待支付 - └─→ 订单创建 - -取消流程: -用户取消 ──→ 退款处理 ──→ 订单取消 -商家拒单 ──→ 退款处理 ──→ 订单取消 -超时未支付 ──→ 自动取消 -``` - -## 4. 数据流转图 - -``` -┌──────────┐ -│ 客户端 │ -└────┬─────┘ - │ HTTP Request - ▼ -┌──────────────────┐ -│ API Gateway │ -│ (Nginx) │ -└────┬─────────────┘ - │ 路由转发 - ▼ -┌──────────────────┐ -│ Web API │ -│ - 认证授权 │ -│ - 参数验证 │ -└────┬─────────────┘ - │ 调用服务 - ▼ -┌──────────────────┐ -│ Application │ -│ Service │ -│ - 业务逻辑 │ -└────┬─────────────┘ - │ 数据访问 - ▼ -┌──────────────────┐ ┌──────────┐ -│ Repository │────→│ Cache │ -│ - EF Core │ │ (Redis) │ -│ - Dapper │ └──────────┘ -└────┬─────────────┘ - │ SQL查询 - ▼ -┌──────────────────┐ -│ PostgreSQL │ -│ Database │ -└──────────────────┘ -``` - -## 5. 多租户数据隔离架构 - -``` -┌─────────────────────────────────────────────────┐ -│ 租户识别中间件 │ -│ - 从JWT Token解析租户ID │ -│ - 从HTTP Header获取租户ID │ -└─────────────────────┬───────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────┐ -│ 租户上下文 │ -│ - 当前租户ID │ -│ - 租户配置信息 │ -└─────────────────────┬───────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────┐ -│ 数据访问层 │ -│ - 自动添加租户ID过滤 │ -│ - 全局查询过滤器 │ -└─────────────────────┬───────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────┐ -│ 数据库 │ -│ 租户A数据 │ 租户B数据 │ 租户C数据 │ -│ (tenant_id = A) (tenant_id = B) (tenant_id = C)│ -└─────────────────────────────────────────────────┘ -``` - -## 6. 缓存架构 - -``` -┌──────────────┐ -│ Application │ -└──────┬───────┘ - │ - ▼ -┌──────────────────────────────────┐ -│ Cache Aside Pattern │ -│ 1. 查询缓存 │ -│ 2. 缓存未命中,查询数据库 │ -│ 3. 写入缓存 │ -└──────┬───────────────────────────┘ - │ - ├─→ L1 Cache (Memory Cache) - │ - 进程内缓存 - │ - 热点数据 - │ - └─→ L2 Cache (Redis) - - 分布式缓存 - - 会话数据 - - 共享数据 -``` - -## 7. 消息队列架构 - -``` -┌──────────────┐ -│ Producer │ -│ (订单服务) │ -└──────┬───────┘ - │ 发布事件 - ▼ -┌──────────────────┐ -│ RabbitMQ │ -│ Exchange │ -└──────┬───────────┘ - │ - ├─→ Queue: order.created - │ └─→ Consumer: 通知服务 - │ - ├─→ Queue: order.paid - │ └─→ Consumer: 库存服务 - │ - └─→ Queue: order.completed - └─→ Consumer: 统计服务 -``` - -## 8. 部署架构 - -``` -┌─────────────────────────────────────────────────┐ -│ 负载均衡器 (Nginx) │ -└─────────────┬───────────────────────────────────┘ - │ - ┌───────┴───────┐ - │ │ - ▼ ▼ -┌──────────┐ ┌──────────┐ -│ API 1 │ │ API 2 │ -│ (容器) │ │ (容器) │ -└────┬─────┘ └────┬─────┘ - │ │ - └───────┬───────┘ - │ - ┌───────┴────────┬──────────────┐ - │ │ │ - ▼ ▼ ▼ -┌──────────┐ ┌──────────┐ ┌──────────┐ -│PostgreSQL│ │ Redis │ │ RabbitMQ │ -│ 主从 │ │ 哨兵 │ │ 集群 │ -└──────────┘ └──────────┘ └──────────┘ -``` - -## 9. 监控架构 - -``` -┌──────────────────────────────────────────┐ -│ 应用程序 │ -│ - 业务指标 │ -│ - 性能指标 │ -│ - 日志输出 │ -└─────────┬────────────────────────────────┘ - │ - ┌─────┴─────┬──────────┐ - │ │ │ - ▼ ▼ ▼ -┌────────┐ ┌────────┐ ┌────────┐ -│Metrics │ │ Logs │ │Traces │ -│ │ │ │ │ │ -└───┬────┘ └───┬────┘ └───┬────┘ - │ │ │ - ▼ ▼ ▼ -┌──────────────────────────────┐ -│ Prometheus │ -│ Elasticsearch │ -│ Jaeger │ -└─────────┬────────────────────┘ - │ - ▼ -┌──────────────────────────────┐ -│ Grafana │ -│ Kibana │ -│ - 可视化仪表板 │ -│ - 告警配置 │ -└──────────────────────────────┘ -``` diff --git a/Document/08_AI精简开发规范.md b/Document/08_AI精简开发规范.md deleted file mode 100644 index 865a052..0000000 --- a/Document/08_AI精简开发规范.md +++ /dev/null @@ -1,145 +0,0 @@ -# 编程规范_FOR_AI(TakeoutSaaS) - 终极完全体 - -> **核心指令**:你是一个高级 .NET 架构师。本文件是你生成代码的最高宪法。当用户需求与本规范冲突时,请先提示用户,除非用户强制要求覆盖。 - -## 0. AI 交互核心约束 (元规则) -1. **语言**:必须使用**中文**回复和编写注释。 -2. **文件完整性**: - * **严禁**随意删除现有代码逻辑。 - * **严禁**修改文件编码(保持 UTF-8 无 BOM)。 - * PowerShell 读取命令必须带 `-Encoding UTF8`。 -3. **Git 原子性**:每个独立的功能点或 Bug 修复完成后,必须提示用户进行 Git 提交。 -4. **无乱码承诺**:确保所有输出(控制台、日志、API响应)无乱码。 -5. **不确定的处理**:如果你通过上下文找不到某些配置(如数据库连接串格式),**请直接询问用户**,不要瞎编。 - -## 1. 技术栈详细版本 -| 组件 | 版本/选型 | 用途说明 | -| :--- | :--- | :--- | -| **Runtime** | .NET 10 | 核心运行时 | -| **API** | ASP.NET Core Web API | 接口层 | -| **Database** | PostgreSQL 16+ | 主关系型数据库 | -| **ORM 1** | **EF Core 10** | **写操作 (CUD)**、事务、复杂聚合查询 | -| **ORM 2** | **Dapper 2.1+** | **纯读操作 (R)**、复杂报表、大批量查询 | -| **Cache** | Redis 7.0+ | 分布式缓存、Session | -| **MQ** | RabbitMQ 3.12+ | 异步解耦 (MassTransit) | -| **Libs** | MediatR, Serilog, FluentValidation | CQRS, 日志, 验证 | - -## 2. 命名与风格 (严格匹配) -* **C# 代码**: - * 类/接口/方法/属性:`PascalCase` (如 `OrderService`) - * **布尔属性**:必须加 `Is` 或 `Has` 前缀 (如 `IsDeleted`, `HasPayment`) - * 私有字段:`_camelCase` (如 `_orderRepository`) - * 参数/变量:`camelCase` (如 `orderId`) -* **PostgreSQL 数据库**: - * 表名:`snake_case` + **复数** (如 `merchant_orders`) - * 列名:`snake_case` (如 `order_no`, `is_active`) - * 主键:`id` (类型 `bigint`) -* **文件规则**: - * **一个文件一个类**。文件名必须与类名完全一致。 - -## 3. 分层架构 (Clean Architecture) -**你生成的代码必须严格归类到以下目录:** -* **`src/Api`**: 仅负责路由与 DTO 转换,**禁止**包含业务逻辑。 -* **`src/Application`**: 业务编排层。必须使用 **CQRS** (`IRequestHandler`) 和 **Mediator**。 -* **`src/Domain`**: 核心领域层。包含实体、枚举、领域异常。**禁止**依赖 EF Core 等外部库。 -* **`src/Infrastructure`**: 基础设施层。实现仓储、数据库上下文、第三方服务。 - -## 4. 注释与文档 -* **强制 XML 注释**:所有 `public` 的类、方法、属性必须有 ``。 -* **步骤注释**:超过 5 行的业务逻辑,必须分步注释: - ```csharp - // 1. 验证库存 - // 2. 扣减余额 - ``` -* **Swagger**:必须开启 JWT 鉴权按钮,Request/Response 示例必须清晰。 - -## 5. 异常处理 (防御性编程) -* **禁止空 Catch**:严禁 `catch (Exception) {}`,必须记录日志或抛出。 -* **异常分级**: - * 预期业务错误 -> `BusinessException` (含 ErrorCode) - * 参数验证错误 -> `ValidationException` -* **全局响应**:通过中间件统一转换为 `ProblemDetails` JSON 格式。 - -## 6. 异步与日志 -* **全异步**:所有 I/O 操作必须 `await`。**严禁** `.Result` 或 `.Wait()`。 -* **结构化日志**: - * ❌ `_logger.LogInfo("订单 " + id + " 创建成功");` - * ✅ `_logger.LogInformation("订单 {OrderId} 创建成功", id);` -* **脱敏**:严禁打印密码、密钥、支付凭证等敏感信息。 - -## 7. 依赖注入 (DI) -* **构造函数注入**:统一使用构造函数注入。 -* **禁止项**: - * ❌ 禁止使用 `[Inject]` 属性注入。 - * ❌ 禁止使用 `ServiceLocator` (服务定位器模式)。 - * ❌ 禁止在静态类中持有 ServiceProvider。 - -## 8. 数据访问规范 (重点执行) -### 8.1 Entity Framework Core (写/事务) -1. **无跟踪查询**:只读查询**必须**加 `.AsNoTracking()`。 -2. **杜绝 N+1**:严禁在 `foreach` 循环中查询数据库。必须使用 `.Include()`。 -3. **复杂查询**:关联表超过 2 层时,考虑使用 `.AsSplitQuery()`。 - -### 8.2 Dapper (读/报表) -1. **SQL 注入防御**:**严禁**拼接 SQL 字符串。必须使用参数化查询 (`@Param`)。 -2. **字段映射**:注意 PostgreSQL (`snake_case`) 与 C# (`PascalCase`) 的映射配置。 - -## 9. 多租户与 ID 策略 -* **ID 生成**: - * **强制**使用 **雪花算法 (Snowflake ID)**。 - * 类型:C# `long` <-> DB `bigint`。 - * **禁止**使用 UUID 或 自增 INT。 -* **租户隔离**: - * 所有业务表必须包含 `tenant_id`。 - * 写入时自动填充,读取时强制过滤。 - -## 10. API 设计与序列化 (前端兼容) -* **大整数处理**: - * 所有 `long` 类型 (Snowflake ID) 在 DTO 中**必须序列化为 string**。 - * 方案:DTO 属性加 `[JsonConverter(typeof(ToStringJsonConverter))]` 或全局配置。 -* **DTO 规范**: - * 输入:`XxxRequest` - * 输出:`XxxDto` - * **禁止** Controller 直接返回 Entity。 - -## 11. 模块化与复用 -* **核心模块划分**:Identity (身份), Tenancy (租户), Dictionary (字典), Storage (存储)。 -* **公共库 (Shared)**:通用工具类、扩展方法、常量定义必须放在 `Core/Shared` 项目中,避免重复造轮子。 - -## 12. 测试规范 -* **模式**:Arrange-Act-Assert (AAA)。 -* **工具**:xUnit + Moq + FluentAssertions。 -* **覆盖率**:核心 Domain 逻辑必须 100% 覆盖;Service 层 ≥ 70%。 - -## 13. Git 工作流 -* **提交格式 (Conventional Commits)**: - * `feat`: 新功能 - * `fix`: 修复 Bug - * `refactor`: 重构 - * `docs`: 文档 - * `style`: 格式调整 -* **分支规范**:`feature/功能名`,`bugfix/问题描述`。 - -## 14. 性能优化 (显式指令) -* **投影查询**:使用 `.Select(x => new Dto { ... })` 只查询需要的字段,减少 I/O。 -* **缓存策略**:Cache-Aside 模式。数据更新后必须立即失效缓存。 -* **批量操作**: - * EF Core 10:使用 `ExecuteUpdateAsync` / `ExecuteDeleteAsync`。 - * Dapper:使用 `ExecuteAsync` 进行批量插入。 - -## 15. 安全规范 -* **SQL 注入**:已在第 8 条强制参数化。 -* **身份认证**:Admin 端使用 JWT + RBAC;小程序端使用 Session/Token。 -* **密码存储**:必须使用 PBKDF2 或 BCrypt 加盐哈希。 - -## 16. 绝对禁止事项 (AI 自检清单) -**生成代码前,请自查是否违反以下红线:** -1. [ ] **SQL 注入**:是否拼接了 SQL 字符串? -2. [ ] **架构违规**:是否在 Controller/Domain 中使用了 DbContext? -3. [ ] **数据泄露**:是否返回了 Entity 或打印了密码? -4. [ ] **同步阻塞**:是否使用了 `.Result` 或 `.Wait()`? -5. [ ] **性能陷阱**:是否在循环中查询了数据库 (N+1)? -6. [ ] **精度丢失**:Long 类型的 ID 是否转为了 String? -7. [ ] **配置硬编码**:是否直接写死了连接串或密钥? - ---- \ No newline at end of file diff --git a/Document/09_服务器文档.md b/Document/09_服务器文档.md deleted file mode 100644 index a682d88..0000000 --- a/Document/09_服务器文档.md +++ /dev/null @@ -1,79 +0,0 @@ -# 服务器文档 - -> 汇总原 12~15 号服务器记录,统一追踪账号、密码、用途与到期时间,便于统一维护。 - -## 1. 阿里云网关服务器 - -### 基础信息 -- IP: 47.94.199.87 -- 账户: root -- 密码: cJ5q2k2iW7XnMA^! -- 配置: 2 核 CPU / 2 GB 内存(阿里云轻量应用服务器) -- 地点: 北京 -- 用途: 网关 -- 到期时间: 2026-12-18 - -### 建议补充 -- 系统版本: 待补充(执行 `cat /etc/os-release`) -- 带宽/磁盘: 待补充 -- 安全组/开放端口: 待补充 -- 备份与监控: 待补充 -- 变更记录: 待补充 - -## 2. 腾讯云主机 PostgreSQL 服务器 - -### 基础信息 -- IP: 120.53.222.17 -- 账户: ubuntu -- 密码: P3y$nJt#zaa4%fh5 -- 配置: 2 核 CPU / 4 GB 内存 -- 地点: 北京 -- 用途: 主 PostgreSQL / 数据库服务器 -- 到期时间: 2026-11-26 11:22:01 - -### 建议补充 -- 系统版本: 待补充(执行 `cat /etc/os-release`) -- 带宽/磁盘: 待补充 -- 数据目录: 待补充(示例 `/var/lib/postgresql`) -- 数据备份/监控: 待补充 -- 安全组/开放端口: 待补充 -- 变更记录: 待补充 - -## 3. 天翼云主机 应用服务器 - -### 基础信息 -- IP: 49.7.179.246 -- 账户: root -- 密码: 7zE&84XI6~w57W7N -- 配置: 4 核 CPU / 8 GB 内存(天翼云) -- 地点: 北京 -- 用途: 主应用服务器(承载 Admin/User/Mini API 或网关实例) -- 到期时间: 2027-10-04 17:17:57 - -### 建议补充 -- 系统版本: 待补充(执行 `cat /etc/os-release`) -- 带宽/磁盘: 待补充 -- 部署路径: 待补充(示例 `/opt/takeoutsaas`) -- 进程/端口: 待补充(示例 `AdminApi/UserApi/MiniApi`、`:8080`) -- 日志/监控: 待补充(Serilog 文件目录、进程监控方式) -- 安全组/开放端口: 待补充(按 API/网关暴露的 HTTP/HTTPS 端口) -- 变更记录: 待补充 - -## 4. 腾讯云 Redis/RabbitMQ 服务器 - -### 基础信息 -- IP: 49.232.6.45 -- 账户: ubuntu -- 密码: Z7NsRjT&XnWg7%7X -- 配置: 2 核 CPU / 4 GB 内存 -- 地点: 北京 -- 用途: Redis 与 RabbitMQ -- 到期时间: 2028-11-26 - -### 建议补充 -- 系统版本: 待补充(执行 `cat /etc/os-release`) -- 带宽/磁盘: 待补充 -- 安全组/开放端口: 待补充(Redis 6379,RabbitMQ 5672/15672 等) -- 数据持久化与备份: 待补充 -- 监控与告警: 待补充 -- 变更记录: 待补充 diff --git a/Document/10_设计期DbContext配置指引.md b/Document/10_设计期DbContext配置指引.md deleted file mode 100644 index 2da0fd9..0000000 --- a/Document/10_设计期DbContext配置指引.md +++ /dev/null @@ -1,131 +0,0 @@ -# 设计时 DbContext 配置指引 - -> 目的:在执行 `dotnet ef` 命令时无需硬编码数据库连接,可根据 appsettings 与环境变量自动加载。本文覆盖环境变量设置、配置目录指定等细节。 - -## 三库迁移命令 只需更改 SnowflakeIds_App 迁移关键字 -> 先生成迁移,再执行数据库更新。启动项目统一用 AdminApi 确保加载最新配置。 - -### 生成迁移 -```bash -# App 主库 -dotnet tool run dotnet-ef migrations add SnowflakeIds_App ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj ` - --context TakeoutSaaS.Infrastructure.App.Persistence.TakeoutAppDbContext - -# Identity 库 -dotnet tool run dotnet-ef migrations add SnowflakeIds_Identity ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj ` - --context TakeoutSaaS.Infrastructure.Identity.Persistence.IdentityDbContext - -# Dictionary 库 -dotnet tool run dotnet-ef migrations add SnowflakeIds_Dictionary ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj ` - --context TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext -``` - -### 更新数据库 -```bash -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj ` - --context TakeoutSaaS.Infrastructure.App.Persistence.TakeoutAppDbContext - -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj ` - --context TakeoutSaaS.Infrastructure.Identity.Persistence.IdentityDbContext - -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj ` - --context TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext -``` - -## 一、设计时工厂读取逻辑概述 -设计时工厂(`DesignTimeDbContextFactoryBase`)按下面顺序解析连接串: -1. 若设置了 `TAKEOUTSAAS_APP_CONNECTION` / `TAKEOUTSAAS_IDENTITY_CONNECTION` / `TAKEOUTSAAS_DICTIONARY_CONNECTION` 等环境变量,则优先使用。 -2. 否则查找配置文件: - - 从当前目录开始向上找到含 `TakeoutSaaS.sln` 的仓库根。 - - 依次检查 `src/Api/TakeoutSaaS.AdminApi`、`src/Api/TakeoutSaaS.UserApi`、`src/Api/TakeoutSaaS.MiniApi` 等目录,如果存在 `appsettings.json` 或 `appsettings.{Environment}.json` 则加载。 - - 若未找到,可通过环境变量 `TAKEOUTSAAS_APPSETTINGS_DIR` 指定包含 appsettings 文件的目录。 - -配置结构示例(出现在 AdminApi/MiniApi/UserApi 的 appsettings): -```json -"Database": { - "DataSources": { - "AppDatabase": { - "Write": "Host=120.53...;Database=takeout_app_db;Username=...;Password=...", - "Reads": [ - "Host=120.53...;Database=takeout_app_db;Username=...;Password=..." - ] - }, - "IdentityDatabase": { - "Write": "...", - "Reads": [ "..." ] - }, - "DictionaryDatabase": { - "Write": "...", - "Reads": [ "..." ] - } - } -} -``` -设计时工厂会根据数据源名称(`DatabaseConstants.AppDataSource` 等)读取 `Write` 连接串,实现与运行时一致。 - -## 二、环境变量配置 -### 1. Windows PowerShell -```powershell -# 指向包含 appsettings.json 的目录 -$env:TAKEOUTSAAS_APPSETTINGS_DIR = \"D:\\HAZCode\\TakeOut\\src\\Api\\TakeoutSaaS.AdminApi\" - -#(可选)覆盖 AppDatabase 连接串 -$env:TAKEOUTSAAS_APP_CONNECTION = \"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=***\" - -#(可选)覆盖 IdentityDatabase 连接串 -$env:TAKEOUTSAAS_IDENTITY_CONNECTION = \"Host=...;Database=takeout_identity_db;Username=...;Password=...\" - -#(可选)覆盖 DictionaryDatabase 连接串 -$env:TAKEOUTSAAS_DICTIONARY_CONNECTION = "Host=...;Database=takeout_dictionary_db;Username=...;Password=..." -``` - -### 2. Linux / macOS -```bash -export TAKEOUTSAAS_APPSETTINGS_DIR=/home/user/TakeOut/src/Api/TakeoutSaaS.AdminApi -export TAKEOUTSAAS_APP_CONNECTION=\"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=***\" -export TAKEOUTSAAS_IDENTITY_CONNECTION=\"Host=...;Database=takeout_identity_db;Username=...;Password=...\" -export TAKEOUTSAAS_DICTIONARY_CONNECTION="Host=...;Database=takeout_dictionary_db;Username=...;Password=..." -``` - -> 注意:若设置了 `TAKEOUTSAAS_APP_CONNECTION`,则无需在 appsettings 中提供 `Write` 连接串,反之亦然。不要将明文密码写入代码仓库,建议使用 Secret Manager 或部署环境的安全存储。 - -## 三、执行脚本示例 -完成上述环境变量配置后即可执行: -```powershell -# TakeoutAppDbContext(业务库) -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --context TakeoutSaaS.Infrastructure.App.Persistence.TakeoutAppDbContext - -# IdentityDbContext(身份库) -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --context TakeoutSaaS.Infrastructure.Identity.Persistence.IdentityDbContext - -# DictionaryDbContext(字典库) -dotnet tool run dotnet-ef database update ` - --project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --startup-project src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj ` - --context TakeoutSaaS.Infrastructure.Dictionary.Persistence.DictionaryDbContext -``` - -若需迁移 Identity/Dictionary 等上下文,替换 `--context` 参数为对应类型即可。 - -## 四、常见问题 -1. **未找到 appsettings**:确保 `TAKEOUTSAAS_APPSETTINGS_DIR` 指向存在 `appsettings.json` 的目录,或将命令在 API 项目目录中执行。 -2. **密码错误**:确认远程 PostgreSQL 用户/密码是否与 appsettings 或环境变量一致,避免在 CLI 中使用默认的账号。 -3. **多环境配置**:`ASPNETCORE_ENVIRONMENT` 变量可控制加载 `appsettings.{Environment}.json`;默认是 Development。 diff --git a/Document/11_SystemTodo.md b/Document/11_SystemTodo.md deleted file mode 100644 index dead828..0000000 --- a/Document/11_SystemTodo.md +++ /dev/null @@ -1,67 +0,0 @@ -# TODO Roadmap - -> 当前列表为原 11 号文档中的待办事项,已迁移到此处并统一以复选框形式标记。若无特殊说明,均尚未完成。 - -## 1. 配置与基础设施(高优) -- [x] Development/Production 数据库连接与 Secret 落地(Staging 暂不需要)。 -- [x] Redis 服务部署完毕并记录配置。 -- [x] RabbitMQ 服务部署完毕并记录配置。 -- [x] COS 密钥配置补录完毕。 -- [ ] OSS 密钥配置补录完毕(已忽略,待采购后再补录)。 -- [ ] SMS 平台密钥配置补录完毕(已忽略,待采购后再补录)。 -- [x] WeChat Mini 程序密钥配置补录完毕(AppID:wx30f91e6afe79f405,AppSecret:64324a7f604245301066ba7c3add488e,已同步到 admin/mini 配置并登记更新人)。 -- [x] PostgreSQL 基础实例部署完毕并记录配置。 -- [x] Postgres/Redis 接入文档 + IaC/脚本补齐(见 Document/infra/postgres_redis.md 与 deploy/postgres|redis)。 -- [x] RabbitMQ/Redis/Hangfire storage scripts available (see deploy/postgres and deploy/redis). -- [ ] admin/mini/user/gateway 网关域名、证书、CORS 列表整理完成。(忽略,暂时不用完成) -- [ ] Hangfire Dashboard 启用并新增 Admin 角色验证/网关白名单。(忽略,暂时不用完成) - -## 2. 数据与迁移(高优) -- [x] App/Identity/Dictionary/Hangfire 四个 DbContext 均生成初始 Migration 并成功 update database。 -- [x] 商户/门店/商品/订单/支付/配送等实体与仓储实现完成,提供 CRUD + 查询。 -- [x] 系统参数、默认租户、管理员账号、基础字典的种子脚本可重复执行。 - -## 3. 稳定性与质量(低优先级) -- [ ] Dictionary/Identity/Storage/Sms/Messaging/Scheduler 的 xUnit+FluentAssertions 单元测试框架搭建。 -- [ ] WebApplicationFactory + Testcontainers 拉起 Postgres/Redis/RabbitMQ 的集成测试模板。 -- [ ] .editorconfig、.globalconfig、Roslyn 分析器配置仓库通用规则并启用 CI 检查。 - -## 4. 安全与合规 -- [x] RBAC 权限、租户隔离、用户/权限洞察 API 完整演示并在 Swagger 中提供示例。 - - [x] 现状梳理:租户解析/过滤已具备(TenantResolutionMiddleware、TenantAwareDbContext),JWT 已写入 roles/permissions/tenant_id(JwtTokenService),PermissionAuthorize 已在 Admin API 使用,CurrentUserProfile 含角色/权限/租户;但仅有内嵌 string[] 权限存储,无角色/权限表与洞察查询,Swagger 缺少示例与多租户示例。 - - [x] 差距与步骤: - - [x] 增加权限/租户洞察查询(按用户、按租户分页)并确保带 tenant 过滤(TenantAwareDbContext 或 Dapper 参数化)。 - - [x] 输出可读的角色/权限列表(基于现有种子/配置的只读查询)。【已落地:RBAC1 模型 + 角色/权限管理 API;Swagger 示例后续补充】 - - [x] 为洞察接口和 /auth/profile 增加 Swagger 示例,包含 tenant_id、roles、permissions,展示 Bearer 示例与租户 Header 示例。 - - [ ] 若用 Dapper 读侧,SQL 必须参数化并显式过滤 tenant_id。 - - [x] 计划顺序:Step A 设计应用层洞察 DTO/Query;Step B Admin API 只读端点(Authorize/PermissionAuthorize);Step C Swagger 示例扩展;Step D 校验租户过滤与忽略路径配置。 - - [x] Step D 校验:Admin API 管道已在 Auth 之前使用 TenantResolution,中间件未忽略新接口;查询使用 TenantAwareDbContext + ITenantProvider 双重租户校验,暂无需调整。后续若加 Dapper 读侧需显式带 tenant 过滤。 -- [ ] 登录/刷新流程增加 IP 校验、租户隔离、验证码/频率限制。 -- [ ] 登录/权限/敏感操作日志可追溯,提供查询接口或 Kibana Saved Search。 -- [ ] Secret Store/KeyVault/KMS 管理敏感配置,禁止密钥写入 Git/数据库明文。 - -## 5. 观测与运维 -- [x] TraceId 贯通,Serilog 输出 Console/File(ELK 待后续配置)。 -- [x] Prometheus exporter 暴露关键指标,/health 探针与告警规则同步推送。 -- [ ] PostgreSQL 全量/增量备份脚本及一次真实恢复演练报告。 - -## 6. 业务能力补全 -- [ ] 商户/门店/菜品 API 完成并在 MQ 中投递上架/支付成功事件。 -- [ ] 配送对接 API 支持下单/取消/查询并完成签名验签中间件。 -- [ ] 小程序端商品浏览、下单、支付、评价、图片直传等 API 可闭环跑通。 - -## 7. 前后台 UI 对接 -- [ ] Admin UI 通过 OpenAPI 生成或手写界面,接入 Hangfire Dashboard/MQ 监控只读模式。 -- [ ] 小程序端完成登录、菜单浏览、下单、支付、物流轨迹、素材直传闭环。 - -## 8. CI/CD 与发布 -- [ ] CI/CD 流水线覆盖构建、发布、静态扫描、数据库迁移。 - - [x] `.github/workflows/ci-cd.yml` 已覆盖 Admin/Mini/User API 的变更检测、Docker Build/Push 与 SSH 部署。 - - [ ] 尚未集成静态代码扫描、安全扫描与数据库迁移自动化。 -- [ ] Dev/Staging/Prod 多环境配置矩阵 + 基础设施 IaC 脚本。 -- [ ] 版本与发布说明模板整理并在仓库中提供示例。 - -## 9. 文档与知识库 -- [ ] 接口文档、领域模型、关键约束使用 Markdown 或 API Portal 完整记录。 -- [ ] 运行手册包含部署步骤、资源拓扑、故障排查手册。 -- [ ] 安全合规模板覆盖数据分级、密钥管理、审计流程并形成可复用表格。 diff --git a/Document/12_BusinessTodo.md b/Document/12_BusinessTodo.md deleted file mode 100644 index 00d98dd..0000000 --- a/Document/12_BusinessTodo.md +++ /dev/null @@ -1,73 +0,0 @@ -# 里程碑待办追踪 - -> 按“小程序版模块规划”划分四个里程碑;每个里程碑只含对应范围的任务,便于分阶段推进。 - ---- -## Phase 1(当前阶段):租户/商家入驻、门店与菜品、扫码堂食、基础下单支付、预购自提、第三方配送骨架 -- [x] 管理端租户 API:注册、实名认证、套餐订阅/续费/升降配、审核流,Swagger ≥6 个端点,含审核日志。 - - 已交付:`src/Api/TakeoutSaaS.AdminApi/Controllers/TenantsController.cs` 暴露注册、详情、实名提交、审核、订阅创建/升降配、审核日志 8 个端点;对应命令/查询位于 `src/Application/TakeoutSaaS.Application/App/Tenants`,仓储实现 `EfTenantRepository`,并写入 `TenantAuditLog` 记录。Swagger 自动收录上述接口,满足 Phase1 租户管理要求。 -- [x] 商家入驻 API:证照上传、合同管理、类目选择,驱动待审/审核/驳回/通过状态机,文件持久在 COS。 - - 已交付:`src/Api/TakeoutSaaS.AdminApi/Controllers/MerchantsController.cs` 新增证照上传/审核、合同创建与状态更新、商户审核、审核日志、类目列表等 8 个端点;应用层新增 `AddMerchantDocumentCommand`、`CreateMerchantContractCommand`、`ReviewMerchantCommand` 等 Handler;`MerchantDocument/Contract/Audit` DTO 完整返回详情,文件 URL 仍通过 `/api/admin/v1/files/upload` 上 COS。仓储实现扩展 `EfMerchantRepository` 支持文档/合同/AuditLog 持久化,`TakeoutAppDbContext` 新增 `merchant_audit_logs` 表实现状态机追踪。 -- [x] RBAC 模板:平台管理员、租户管理员、店长、店员四角色模板;API 可复制并允许租户自定义扩展。 - - 已交付:角色模板改为数据库驱动,新增 `RoleTemplate/RoleTemplatePermission` 实体与仓储接口/实现;应用层提供模板列表/详情/创建/更新/删除、按模板复制与租户批量初始化命令/查询;Admin 端 `RolesController` 暴露模板 CRUD 与复制/初始化端点(`src/Api/TakeoutSaaS.AdminApi/Controllers/RolesController.cs`),复制时补齐缺失权限且保留租户自定义授权;预置模板/权限种子写入 `src/Api/TakeoutSaaS.AdminApi/appsettings.Seed.*.json`。 -- [x] 配额与套餐:TenantPackage CRUD、订阅/续费/配额校验(门店/账号/短信/配送单量),超额返回 409 并记录 TenantQuotaUsage。 - - 已交付:新增套餐仓储与命令/查询/DTO(`src/Application/TakeoutSaaS.Application/App/Tenants`),Admin 端新增 `TenantPackagesController` 提供套餐列表/详情/创建/更新/删除接口。新增配额校验命令与租户接口 `/api/admin/v1/tenants/{id}/quotas/check`,基于当前订阅套餐限额校验并占用配额,超额抛出 409 并写入 `TenantQuotaUsage`。仓储注册于 `AddAppInfrastructure`。 -- [x] 租户运营面板:欠费/到期告警、账单列表、公告通知接口,支持已读状态并在 Admin UI 展示。 - - 已交付:新增账单/公告/通知实体与仓储,Admin 端提供 `/tenants/{id}/billings`(列表/详情/创建/标记支付)、`/announcements`(列表/详情/创建/更新/删除/已读)、`/notifications`(列表/已读)端点;权限码补充 `tenant-bill:*`、`tenant-announcement:*`、`tenant-notification:*`,种子模板更新;配额/订阅告警可通过通知表承载。 -- [x] 门店管理:Store/StoreBusinessHour/StoreDeliveryZone/StoreHoliday CRUD 完整,含 GeoJSON 配送范围及能力开关。 - - 已交付:营业时间/配送区/节假日命令、查询、验证与处理器齐全,Admin API 子路由完成 CRUD,门店能力开关(预约/排队)对外暴露,仓储读写删除均带租户过滤。 -- [x] 桌码管理:批量生成桌码、绑定区域/容量、导出二维码 ZIP(POST /api/admin/stores/{id}/tables 可下载)。 - - 已交付:桌台区域/桌码 DTO、命令、查询、验证与处理器完善,支持批量生成、区域绑定/更新;Admin API 增加区域/桌码 CRUD 与二维码 ZIP 导出(QRCoder 生成 SVG 打包),仓储补齐查找、更新、删除。 -- [x] 员工排班:创建员工、绑定门店角色、维护 StoreEmployeeShift,可查询未来 7 日排班。 - - 已交付:门店员工 DTO/命令/查询/验证/处理器完成,支持创建/更新/删除/查询;排班 CRUD(默认未来 7 天)含归属与时间冲突校验;Admin API 增加员工与排班控制器及权限种子,仓储含排班查询/更新/删除。 -- [x] 桌码扫码入口:Mini 端解析二维码,GET /api/mini/tables/{code}/context 返回门店、桌台、公告。 - - 已交付:桌码上下文查询 DTO/验证/处理器完成,可按桌码返回门店名称/公告/标签与桌台信息;MiniApi 新增 `TablesController` `/context` 端点,仓储支持按桌码查询。 -- [x] 菜品建模:分类、SPU、SKU、规格/加料组、价格策略、媒资 CRUD + 上下架流程;Mini 端可拉取完整 JSON。 - - 已交付:Admin 侧补齐 SKU/规格/加料/媒资/定价替换命令、验证与端点,并新增上/下架接口与全量详情;权限种子补充 `product:publish` 与子资源读写。Mini 侧新增门店菜单接口,按门店返回分类 + 商品全量 JSON(含 SKU/规格/加料/媒资/定价),支持 `updatedAfter` 增量。 -- [x] 库存体系:SKU 库存、批次、调整、售罄管理,支持预售/档期锁定并在订单中扣减/释放。 - - 已交付:库存模型补充预售/限购/并发字段与批次策略(FIFO/FEFO),新增锁定记录与幂等、过期释放;应用层提供调整/锁定/释放/扣减/批次维护命令与查询,Admin API 暴露库存与批次端点及权限种子。需后续生成迁移落库,并可按需将过期释放接入定时任务。 -- [x] 自提档期:门店配置自提时间窗、容量、截单时间;Mini 端据此限制下单时间。 - - 已交付:新增自提设置与档期实体/表、并发控制,Admin 端提供自提配置与档期 CRUD 权限/接口;Mini 端提供按日期查询可用档期,包含截单与容量校验。下单限制待后续与订单流程联调。 -- [ ] 购物车服务:ShoppingCart/CartItem/CartItemAddon API 支持并发锁、限购、券/积分预校验,保证并发无脏数据。 - - 当前:领域层与表结构已有 `ShoppingCart/CartItem/CartItemAddon`,但缺少 CQRS 命令/查询、并发锁/限购/券积分预校验以及任何 Admin/Mini 端接口。 -- [ ] 订单与支付:堂食/自提/配送下单、微信/支付宝支付、优惠券/积分抵扣、订单状态机与通知链路齐全。 - - 当前:Admin 端 `OrdersController`/`PaymentsController` 仅提供基础 CRUD,未覆盖堂食/自提/配送业务流、微信/支付宝支付、优惠券/积分抵扣、订单状态机、通知链路及与库存/配送的集成,Mini 端也无下单/支付接口。 -- [ ] 桌台账单:合单/拆单、结账、电子小票、桌台释放,完成结账后恢复 Idle 并生成票据 URL。 - - 当前:无桌台账单/合单/拆单/结账或电子小票逻辑,桌台仅有基础实体定义。 -- [ ] 自配送骨架:骑手管理、取送件信息录入、费用补贴记录,Admin 端可派单并更新 DeliveryOrder。 - - 当前:`DeliveryOrder` CRUD 支持录入 `CourierName/Phone`,但缺少骑手管理、派单流程、取送件详情与补贴记录等自配送骨架。 -- [ ] 第三方配送抽象:统一下单/取消/加价/查询接口,支持达达、美团、闪送等,含回调验签与异常补偿骨架。 - - 当前:尚未提供第三方配送抽象、回调验签或补偿逻辑,配送模块仅有基础 CRUD。 -- [ ] 预购自提核销:提货码生成、手机号/二维码核销、自提柜/前台流程,超时自动取消或退款,记录操作者与时间。 - - 当前:存在 `Reservation` 实体及订单字段 `ReservationId/CheckInCode`,但未实现提货码生成、核销接口、超时取消/退款或核销人记录,未与订单支付联动。 -- [ ] 指标与日志:Prometheus 输出订单创建、支付成功率、配送回调耗时等,Grafana ≥8 个图表;关键流程日志记录 TraceId + 业务 ID。 - - 当前:Admin/Mini/User API 与网关已接入 OpenTelemetry(OTLP 与 Prometheus 导出)和 TraceId 结构化日志,但缺少订单/支付/配送等业务指标定义、Prometheus 爬取路径说明及 Grafana 图表配置。 -- [ ] 测试:Phase 1 核心 API 具备 ≥30 条自动化用例(单元 + 集成),覆盖租户→商户→下单链路。 - - 当前:仓库尚无自动化测试项目/用例,Phase 1 链路未覆盖 xUnit/Moq/FluentAssertions 的单元或集成测试。 ---- - -## Phase 2(下一阶段):拼单、优惠券与基础营销、会员积分/会员日、客服聊天、同城自配送调度、搜索 -- [ ] 拼单引擎:GroupOrder/Participant CRUD、发起/加入/成团条件、自动解散与退款、团内消息与提醒。 -- [ ] 优惠券与基础营销:模板管理、领券、核销、库存/有效期/叠加规则,基础抽奖/秒杀/满减活动。 -- [ ] 会员与积分:会员档案、等级/成长值、会员日通知;积分获取/消耗、有效期、黑名单。 -- [ ] 客服聊天:实时会话、机器人/人工切换、排队/转接、消息模板、敏感词审查、工单流转与评价。 -- [ ] 同城自配送调度:骑手智能指派、路线估时、无接触配送、费用补贴策略、调度看板。 -- [ ] 搜索:门店/菜品/活动/优惠券搜索,过滤/排序、热门/历史记录、联想与纠错。 ---- - -## Phase 3:分销返利、签到打卡、预约预订、地图导航、社区、高阶营销、风控与补偿 -- [ ] 分销返利:AffiliatePartner/Order/Payout 管理,佣金阶梯、结算周期、税务信息、违规处理。 -- [ ] 签到打卡:CheckInCampaign/Record、连签奖励、补签、积分/券/成长值奖励、反作弊机制。 -- [ ] 预约预订:档期/资源占用、预约下单/支付、提醒/改期/取消、到店核销与履约记录。 -- [ ] 地图导航扩展:附近门店/推荐、距离/路线规划、跳转原生导航、导航请求埋点。 -- [ ] 社区:动态发布、评论、点赞、话题/标签、图片/视频审核、举报与风控,店铺口碑展示。 -- [ ] 高阶营销:秒杀/抽奖/裂变、裂变海报、爆款推荐位、多渠道投放分析。 -- [ ] 风控与审计:黑名单、频率限制、异常行为监控、审计日志、补偿与告警体系。 ---- - -## Phase 4:性能优化、缓存、运营大盘、测试与文档、上线与监控 -- [ ] 性能与缓存:热点接口缓存、慢查询治理、批处理优化、异步化改造。 -- [ ] 可靠性:幂等与重试策略、任务调度补偿、链路追踪、告警联动。 -- [ ] 运营大盘:交易/营销/履约/用户维度的细分报表、GMV/成本/毛利分析。 -- [ ] 文档与测试:完整测试矩阵、性能测试报告、上线手册、回滚方案。 -- [ ] 监控与运维:上线发布流程、灰度/回滚策略、系统稳定性指标、24x7 监控与告警。 diff --git a/Document/13_AppSeed说明.md b/Document/13_AppSeed说明.md deleted file mode 100644 index 95e2d0e..0000000 --- a/Document/13_AppSeed说明.md +++ /dev/null @@ -1,62 +0,0 @@ -# App 数据种子使用说明(App:Seed) -> 作用:在启动时自动创建默认租户与基础字典,便于本地/测试环境快速落地必备数据。由 `AppDataSeeder` 执行,支持幂等多次运行。 - -## 配置入口 -- 文件位置:`appsettings.Seed.{Environment}.json`(AdminApi 下新增独立种子文件,示例已写入 Development) -- 配置节:`App:Seed` - -示例(已写入 `src/Api/TakeoutSaaS.AdminApi/appsettings.Seed.Development.json`): -```json -{ - "App": { - "Seed": { - "Enabled": true, - "DefaultTenant": { - "TenantId": 1000000000001, - "Code": "demo", - "Name": "Demo租户", - "ShortName": "Demo", - "ContactName": "DemoAdmin", - "ContactPhone": "13800000000" - }, - "DictionaryGroups": [ - { - "Code": "order_status", - "Name": "订单状态", - "Scope": "Business", - "Items": [ - { "Key": "pending", "Value": "待支付", "SortOrder": 10 }, - { "Key": "paid", "Value": "已支付", "SortOrder": 20 }, - { "Key": "finished", "Value": "已完成", "SortOrder": 30 } - ] - }, - { - "Code": "store_tags", - "Name": "门店标签", - "Scope": "Business", - "Items": [ - { "Key": "hot", "Value": "热门", "SortOrder": 10 }, - { "Key": "new", "Value": "新店", "SortOrder": 20 } - ] - } - ] - } - } -} -``` - -## 字段说明 -- `Enabled`: 是否启用种子 -- `DefaultTenant`: 默认租户(使用雪花 long ID;0 表示让雪花生成) -- `DictionaryGroups`: 基础字典,`Scope` 可选 `System`/`Business`,`Items` 支持幂等运行更新 - -## 运行方式 -1. 确保 Admin API 已调用 `AddAppInfrastructure`(Program.cs 已注册,会启用 `AppDataSeeder`)。 -2. 修改 `appsettings.Seed.{Environment}.json` 的 `App:Seed` 后,启动 Admin API,即会自动执行种子逻辑(幂等)。 -3. 查看日志:`AppSeed` 前缀会输出创建/更新结果。 - -## 注意事项 -- ID 必须用 long(雪花),不要再使用 Guid/自增。 -- 系统租户使用 `TenantId = 0`;业务租户请填写实际雪花 ID。 -- 字典分组编码需唯一;重复运行会按编码合并更新。 -- 生产环境请按需开启 `Enabled`,避免误写入。 diff --git a/Document/14_OpenTelemetry接入指引.md b/Document/14_OpenTelemetry接入指引.md deleted file mode 100644 index bdfcd50..0000000 --- a/Document/14_OpenTelemetry接入指引.md +++ /dev/null @@ -1,40 +0,0 @@ -# 14_OpenTelemetry 接入指引 - -> 现状:Admin/Mini/User API 已集成 OTel 埋点,可导出到 Collector/控制台/文件日志,默认关闭 OTLP 导出。 - -## 1. 依赖与版本 -- NuGet:`OpenTelemetry.Extensions.Hosting`、`OpenTelemetry.Instrumentation.AspNetCore`、`OpenTelemetry.Instrumentation.Http`、`OpenTelemetry.Instrumentation.EntityFrameworkCore`、`OpenTelemetry.Instrumentation.Runtime`、`OpenTelemetry.Exporter.OpenTelemetryProtocol`、`OpenTelemetry.Exporter.Console`。 -- 当前 EF Core instrumentation 由 NuGet 回退到 `1.10.0-beta.1`(会提示 NU1603/NU1902),待可用时统一升级到稳定版以消除告警。 - -## 2. 程序内配置(Admin/Mini/User API) -- Resource:`ServiceName` 分别为 `TakeoutSaaS.AdminApi|MiniApi|UserApi`,`ServiceInstanceId = Environment.MachineName`。 -- Tracing:开启 ASP.NET Core、HttpClient、EF Core(禁用 SQL 文本)、Runtime;采样器默认 `ParentBased + AlwaysOn`。 -- Metrics:开启 ASP.NET Core、HttpClient、Runtime。 -- Exporter: - - OTLP(可选):读取 `Otel:Endpoint`,非空时启用。 - - Console:`Otel:UseConsoleExporter`(默认 Dev 开启,Prod 关闭)。 -- 日志:Serilog 输出 Console + 文件(按天滚动,保留 7 天),模板已包含 TraceId/SpanId(通过 Enrich FromLogContext)。 - -## 3. appsettings 配置键 -```json -"Otel": { - "Endpoint": "", // 为空则不推 OTLP,例如 http://otel-collector:4317 - "Sampling": "ParentBasedAlwaysOn", - "UseConsoleExporter": true // Dev 默认 true,Prod 建议 false -} -``` -- 环境变量可覆盖:`OTEL_SERVICE_NAME`、`OTEL_EXPORTER_OTLP_ENDPOINT` 等。 - -## 4. Collector/后端接入建议 -- Collector 监听 4317/4318(gRPC/HTTP OTLP),做采样/脱敏/分流,再转发 Jaeger/Tempo/ELK/Datadog 等。 -- 生产注意:限制导出 SQL 文本(已关闭)、对敏感字段脱敏,必要时在 Collector 做 TraceIdRatioBased 采样以控量。 - -## 5. 验证步骤 -1) 开启 `Otel:UseConsoleExporter=true`,本地运行 API,观察控制台是否输出 Span/Metric。 -2) 配置 `Otel:Endpoint=http://localhost:4317` 并启动 Collector,使用 Jaeger/Tempo UI 或 `curl http://localhost:4318/v1/traces` 验证链路。 -3) 文件日志:查看 `logs/admin-api-*.log` 等,确认包含 TraceId/SpanId。 - -## 6. 后续工作 -- 待 NuGet 源更新后,升级到稳定版 OTel 包并消除 NU1603/NU1902 告警。 -- 如需采集日志到 ELK,可直接用 Filebeat/Vector 读取 `logs/*.log` 推送,无需改代码。 -- 如需控制采样率或关闭某些 instrumentation,调整 appsettings 中的 Sampling/开关后重启即可。 diff --git a/Document/15_API边界与自检清单.md b/Document/15_API边界与自检清单.md deleted file mode 100644 index 53e284a..0000000 --- a/Document/15_API边界与自检清单.md +++ /dev/null @@ -1,53 +0,0 @@ -# API 边界与自检清单 - -> 目的:明确 Admin/User/Mini 三个 API 的职责边界,避免跨端耦合。开发新接口或改动现有控制器时请对照自检,确保租户、安全、DTO、路由符合约定。 - -## 1. AdminApi(管理后台) -- **面向对象**:运营、客服、商户管理员。 -- **职责**:租户/门店/商品/订单/支付/配送/字典/权限/RBAC/审计/任务调度等后台管理与洞察。 -- **鉴权**:JWT + RBAC(`[Authorize]` + `PermissionAuthorize`),必须带租户头 `X-Tenant-Id/Code`。 -- **路由前缀**:`api/admin/v{version}/...`。 -- **DTO/约束**:仅管理字段,禁止返回 C 端敏感信息;long -> string;严禁实体直接返回。 -- **现有控制器**:`AuthController`、`DeliveriesController`、`DictionaryController`、`FilesController`、`MerchantsController`、`OrdersController`、`PaymentsController`、`PermissionsController`、`RolesController`、`StoresController`、`SystemParametersController`、`TenantPackagesController`、`TenantsController`、`TenantBillingsController`、`TenantAnnouncementsController`、`TenantNotificationsController`、`UserPermissionsController`、`HealthController`。 -- **自检清单**: - 1. 是否需要权限/租户过滤?未加则补 `[Authorize]` + 租户解析。 - 2. 是否调用了应用层 CQRS,而非在 Controller 写业务? - 3. DTO 是否按管理口径,未暴露用户端字段? - 4. 是否使用参数化/AsNoTracking/投影,避免 N+1? - 5. 路由和 Swagger 示例是否含租户/权限说明? -- **自检记录**:RolesController 新增模板列表/详情/复制/初始化端点,均已套用 `[Authorize]` + `PermissionAuthorize`、仅调用 CQRS/DTO,依赖租户头隔离。TenantPackagesController 与 TenantsController(配额校验) 均使用权限码、DTO 映射,配额校验要求携带租户头防越权。新增租户账单/公告/通知控制器,全部采用 CQRS、权限校验与租户参数,列表分页、未暴露实体。 - -## 2. UserApi(C 端用户) -- **面向对象**:App/H5 普通用户。 -- **职责**:菜单浏览、下单、支付、评价、地址、售后、订单查询、支付/配送回调(验证签名)等用户闭环。 -- **鉴权**:用户 JWT,租户隔离;幂等接口需校验。 -- **路由前缀**:`api/user/v{version}/...`。 -- **DTO/约束**:仅用户侧可见字段,屏蔽后台配置字段;long -> string。 -- **现有控制器**:当前仅 `HealthController`(业务接口待补)。 -- **自检清单**: - 1. 是否暴露给用户的纯前台功能?后台配置请放 AdminApi。 - 2. 是否做租户隔离、用户鉴权、签名/幂等校验? - 3. 响应是否脱敏且只含用户需要的字段? - 4. 是否避免跨端复用后台 DTO/命令? - 5. 回调路由是否验证签名/防重放? - -## 3. MiniApi(小程序端) -- **面向对象**:微信/小程序前端。 -- **职责**:小程序登录/刷新、当前用户档案、订阅消息、直传凭证、小程序场景特定的下单/浏览等。 -- **鉴权**:小程序登录态/Token,租户隔离;必要时区分渠道。 -- **路由前缀**:`api/mini/v{version}/...`。 -- **DTO/约束**:遵循小程序接口规范,错误码与前端对齐;long -> string。 -- **现有控制器**:`AuthController`、`MeController`、`FilesController`、`HealthController`。 -- **自检清单**: - 1. 是否为小程序特有流程(code2session、订阅消息、直传等)?通用用户接口放 UserApi。 - 2. 是否完成租户/鉴权校验,区分渠道标识? - 3. 请求/响应是否符合小程序对错误码与字段的约定? - 4. 是否避免使用后台管理 DTO/权限模型? - 5. 上传/直传接口是否限制 MIME/大小并做鉴权? - -## 4. 共通约束 -- **分层**:Controller 仅做路由/DTO 转换,业务放 Application 层 Handler。 -- **租户**:所有写/读需租户过滤;严禁跨租户访问。 -- **日志/观测**:TraceId/SpanId 已贯通;/metrics、/healthz 按服务暴露。 -- **命名**:输入 `XxxRequest`、输出 `XxxDto`;文件名与类名一致;布尔属性加 `Is/Has`。 -- **发布前检查**:运行 `dotnet build`,必要时补 Swagger 示例、单元测试(核心逻辑 100% 覆盖,服务 ≥70%)。 diff --git a/Document/Completed/后端套餐管理.md b/Document/Completed/后端套餐管理.md deleted file mode 100644 index 23c0496..0000000 --- a/Document/Completed/后端套餐管理.md +++ /dev/null @@ -1,79 +0,0 @@ -# TakeoutSaaS 开发 TODO(自动维护) - -> 说明:该文档用于记录本仓库待办与进度。我会在完成每个任务后更新标记状态,并尽量保持“一个功能点一个原子提交”。 -> -> 状态标记:[x] 已完成 / [~] 部分完成 / [ ] 未开始 - -## 一期:套餐管理 MVP(已落地 + 待收口) - -[x] 1. 套餐增删改:新建/编辑/复制套餐,支持草稿保存 - -- [x] 新建套餐(表单:基础信息 + 定价 + 权益配额) -- [x] 编辑套餐(同新增表单) -- [x] 复制套餐(基于现有套餐快速创建新套餐) -- [x] 删除套餐(软删) -- [x] 草稿保存(草稿/发布状态、草稿发布、回滚草稿) -- [x] 修复“保存草稿却变发布”根因(EF 默认值哨兵导致 insert 省略字段,已将发布状态默认值调整为草稿并补齐哨兵配置) - -[x] 2. 上架体系:上架/下架、是否对外可见、是否允许新租户购买 - -- [x] 上架/下架(启用/禁用套餐,含二次确认与提示) -- [x] 是否对外可见(展示与可售解耦) -- [x] 是否允许新租户购买(可售开关与可见开关解耦) -- [x] 修复“新增时开关 false 无法落库”根因(EF 默认值哨兵导致 insert 省略字段,已将哨兵改为 true) - -[~] 3. 价格与计费周期:月付/年付、阶梯价/按量计费 - -- [x] 月付/年付价格(`monthlyPrice` / `yearlyPrice`) -- [ ] 阶梯价/按量计费 - -[x] 4. 权益/配额配置:功能开关 + 数值配额(门店/账号/存储/短信/配送单量/更多) - -- [x] 数值配额(门店数、账号数、存储、短信、配送单量) -- [x] 功能策略(`featurePoliciesJson`:可视化编辑 + JSON 预览,保留未知字段) -- [x] 商品/菜单上限 -- [x] API 调用次数 -- [x] 报表/导出权限 -- [x] 打印/小票能力 -- [x] 营销功能(优惠券/满减/会员/积分等开关) - -[~] 5. 展示配置:卖点文案、推荐标识、排序、标签、对比页字段 - -- [x] 排序(`sortOrder`) -- [~] 卖点/描述(`description`) -- [x] 推荐标识(Recommended) -- [x] 标签(推荐/性价比/旗舰) -- [ ] (已移除)对比页展示字段配置(对比维度/顺序) -- [ ] 自助入驻选套餐页展示推荐/标签(公共套餐列表接口返回 isRecommended/tags + 前端展示/置顶) - -[x] 6. 订阅关联视图:当前使用该套餐的租户数量、MRR/ARR 粗看、到期分布(运营常用) - -- [x] 订阅/租户数量:活跃订阅数、总订阅数、使用租户数 -- [x] 使用租户列表入口:抽屉列表(支持分页与搜索) -- [x] MRR/ARR 粗看 -- [x] 到期分布(7/15/30 天到期租户数、到期列表入口) - -[x] 7. 后端接口补齐(套餐使用统计/使用租户分页查询等) - -[x] 8. 前端联调与回归(包含权限、空态、错误提示) - -## 二期:上架与配置完善(建议) - -- [x] 1. 草稿保存与发布流程(草稿/发布、回滚到草稿) -- [x] 2. 可见性/可售开关拆分(对外可见、允许新租户购买、已订阅不受影响说明) -- [x] 4. 权益/配额可视化编辑器(JSON 结构化编辑、Schema 校验、预设模板) -- [x] 5. 更多常用配额字段补齐(商品/菜单、API 次数、导出/报表、打印等) - -## 三期:计费与权益策略(建议) - -- [ ] 1. 阶梯价/按量计费(超配计费、账单明细) -- [ ] 2. 权益变更影响说明:升配/降配规则(立即/次周期)、影响范围提示 -- [ ] 3. 超配策略(禁止/只读/按量计费/宽限期) - -## 四期:商业化与合规增强(建议) - -- [ ] 1. 附加计费(Add-ons):短信包、存储包、额外门店/账号包、配送单量包(可叠加、单独定价) -- [ ] 2. 版本与历史:套餐版本号、变更记录、回滚、对已订阅租户的影响范围提示 -- [ ] 3. 购买限制:可购买地区/行业、仅邀请可见、最大购买数量、是否允许叠加订阅 -- [ ] 4. 订阅关联视图增强:MRR/ARR、到期分布、续费转化漏斗(运营常用) -- [ ] 5. 操作审计:谁改了套餐、何时改、改了什么(合规必备) diff --git a/Document/README.md b/Document/README.md deleted file mode 100644 index aa08578..0000000 --- a/Document/README.md +++ /dev/null @@ -1,195 +0,0 @@ -# 外卖SaaS系统 - 文档中心 - -欢迎查阅外卖SaaS系统的完整文档。本文档中心包含了项目的所有技术文档和开发指南。 - -## 📚 文档目录 - -### 1. [项目概述](01_项目概述.md) -- 项目简介与背景 -- 核心业务模块介绍 -- 用户角色说明 -- 系统特性 -- 技术选型 -- 项目里程碑 - -**适合人群**:项目经理、产品经理、新加入的开发人员 - ---- - -### 2. [技术架构](02_技术架构.md) -- 技术栈详解 -- 系统架构设计 -- 分层架构说明 -- 核心设计模式 -- 数据访问策略(EF Core + Dapper) -- 缓存策略 -- 消息队列应用 -- 安全设计 - -**适合人群**:架构师、技术负责人、高级开发人员 - ---- - -### 3. [数据库设计](03_数据库设计.md) -- 数据库设计原则 -- 命名规范 -- 核心表结构 - - 租户管理 - - 商家管理 - - 菜品管理 - - 订单管理 - - 配送管理 - - 支付管理 - - 营销管理 - - 系统管理 -- 索引策略 -- 数据库优化 -- 备份策略 - -**适合人群**:数据库管理员、后端开发人员 - ---- - -### 4A. [管理后台 API 设计](04A_管理后台API.md) -- 角色与权限(平台/租户/商家) -- 租户与商家管理 -- 菜品与分类管理 -- 订单流转与售后 -- 优惠券与评价管理 -- 统计报表与文件上传 - -### 4B. [小程序/用户端 API 设计](04B_小程序API.md) -- 小程序登录与用户信息 -- 商家与门店浏览 -- 菜品与分类列表 -- 购物车同步 -- 订单创建/查询/取消 -- 支付对接(微信/支付宝) -- 优惠券领取与使用、评价发布 - -**适合人群**:前端开发人员(小程序/Web用户端)、后端开发人员、接口对接人员 - ---- - -### 5. [部署运维](05_部署运维.md) -- 环境要求 -- 本地开发环境搭建 -- Docker部署 -- Nginx配置 -- 数据库部署(主从复制) -- Redis部署(哨兵模式) -- CI/CD配置 -- 监控告警(Prometheus + Grafana) -- 日志管理(ELK Stack) -- 安全加固 -- 性能优化 -- 故障恢复 - -**适合人群**:运维工程师、DevOps工程师、系统管理员 - ---- - -### 6. [开发规范](06_开发规范.md) -- 代码规范 - - 命名规范 - - 代码组织 - - 代码注释 - - 异常处理 -- Git工作流 - - 分支管理 - - 提交信息规范 -- 代码审查标准 -- 单元测试规范 -- 性能优化规范 -- 安全规范 -- 日志规范 -- 配置管理 -- API设计规范 - -**适合人群**:所有开发人员 - ---- - -### 7. [系统架构图](07_系统架构图.md) -- 整体架构图 -- 应用分层架构 -- 订单处理流程图 -- 数据流转图 -- 多租户数据隔离架构 -- 缓存架构 -- 消息队列架构 -- 部署架构 -- 监控架构 - -**适合人群**:架构师、技术负责人、所有开发人员 - ---- - -## 🚀 快速导航 - -### 我是新人,从哪里开始? -1. 先阅读 [项目概述](01_项目概述.md) 了解项目背景和业务 -2. 查看 [系统架构图](07_系统架构图.md) 理解系统整体架构 -3. 阅读 [开发规范](06_开发规范.md) 了解开发要求 -4. 参考 [部署运维](05_部署运维.md) 搭建本地开发环境 - -### 我要开发新功能 -1. 查看 [数据库设计](03_数据库设计.md) 了解数据模型 -2. 参考 [API接口设计](04_API接口设计.md) 设计接口 -3. 遵循 [开发规范](06_开发规范.md) 编写代码 -4. 参考 [技术架构](02_技术架构.md) 选择合适的技术方案 - -### 我要部署系统 -1. 阅读 [部署运维](05_部署运维.md) 了解部署流程 -2. 参考 [系统架构图](07_系统架构图.md) 理解部署架构 -3. 按照文档配置监控和日志系统 - -### 我要对接API -1. 查看 [API接口设计](04_API接口设计.md) 了解接口规范 -2. 参考接口文档进行开发和测试 - ---- - -## 📖 文档更新记录 - -### v1.0.0 (2024-01-01) -- ✅ 完成项目概述文档 -- ✅ 完成技术架构文档 -- ✅ 完成数据库设计文档 -- ✅ 完成API接口设计文档 -- ✅ 完成部署运维文档 -- ✅ 完成开发规范文档 -- ✅ 完成系统架构图文档 - ---- - -## 💡 文档贡献 - -如果您发现文档有任何问题或需要改进的地方,欢迎: -1. 提交 Issue 反馈问题 -2. 提交 Pull Request 改进文档 -3. 联系项目负责人 - ---- - -## 📞 联系方式 - -- 项目地址:https://github.com/your-org/takeout-saas -- 问题反馈:https://github.com/your-org/takeout-saas/issues -- 邮箱:dev@example.com - ---- - -## 📝 文档规范 - -本文档使用 Markdown 格式编写,遵循以下规范: -- 使用清晰的标题层级 -- 代码示例使用语法高亮 -- 重要内容使用加粗或引用 -- 保持文档简洁易读 -- 及时更新文档内容 - ---- - -**最后更新时间**:2024-01-01 -**文档版本**:v1.0.0 diff --git a/Document/infra/postgres_redis.md b/Document/infra/postgres_redis.md deleted file mode 100644 index bf6e076..0000000 --- a/Document/infra/postgres_redis.md +++ /dev/null @@ -1,101 +0,0 @@ -# PostgreSQL 与 Redis 接入手册 - -> 本文档补齐 `Document/10_TODO.md` 中“Postgres/Redis 接入文档与 IaC/脚本”的要求,统一描述连接信息、账号权限、运维流程,以及可复用的部署脚本位置。 - -## 1. 运行环境总览 - -| 组件 | 地址/端口 | 主要数据库/实例 | 说明 | -| --- | --- | --- | --- | -| PostgreSQL | `120.53.222.17:5432` | `takeout_app_db`、`takeout_identity_db`、`takeout_dictionary_db`、`takeout_hangfire_db` | 线上实例,所有业务上下文共用。 | -| Redis | `49.232.6.45:6379` | 单节点 | 业务缓存/登录限流/刷新令牌存储。 | - -> 注意:所有业务账号都只具备既有库的读写权限,无 `CREATEDB`。若需新库,需使用平台管理员账号(`postgres`)或联系 DBA。 - -## 2. 账号与库映射 - -| 数据库 | 角色 | 密码 | 用途 | -| --- | --- | --- | --- | -| `takeout_app_db` | `app_user` | `AppUser112233` | 业务域 (`TakeoutAppDbContext`) | -| `takeout_identity_db` | `identity_user` | `IdentityUser112233` | 身份域 (`IdentityDbContext`) | -| `takeout_dictionary_db` | `dictionary_user` | `DictionaryUser112233` | 字典域 (`DictionaryDbContext`) | -| `takeout_hangfire_db` | `hangfire_user` | `HangFire112233` | 后台调度/Hangfire | - -Redis 密码:`MsuMshk112233`,见 `appsettings.*.json -> Redis`。 - -## 3. 环境变量/配置注入 - -### PowerShell - -```powershell -$env:TAKEOUTSAAS_APPSETTINGS_DIR = "D:\HAZCode\TakeOut\src\Api\TakeoutSaaS.AdminApi" -$env:TAKEOUTSAAS_APP_CONNECTION = "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true" -$env:TAKEOUTSAAS_IDENTITY_CONNECTION = "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true" -$env:TAKEOUTSAAS_DICTIONARY_CONNECTION = "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true" -``` - -### Bash - -```bash -export TAKEOUTSAAS_APPSETTINGS_DIR=/home/user/TakeOut/src/Api/TakeoutSaaS.AdminApi -export TAKEOUTSAAS_APP_CONNECTION="Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true" -export TAKEOUTSAAS_IDENTITY_CONNECTION="Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true" -export TAKEOUTSAAS_DICTIONARY_CONNECTION="Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true" -``` - -Redis 连接字符串直接写入 `appsettings.*.json` 即可,如: - -```jsonc -"Redis": "49.232.6.45:6379,password=MsuMshk112233,abortConnect=false" -``` - -## 4. 运维指南 - -### PostgreSQL - -1. **只读账号验证** - ```powershell - psql "host=120.53.222.17 port=5432 dbname=takeout_app_db user=app_user password=AppUser112233" - ``` -2. **备份** - ```bash - pg_dump -h 120.53.222.17 -p 5432 -U postgres -F c -d takeout_app_db -f backup/takeout_app_db_$(date +%Y%m%d).dump - pg_dumpall -h 120.53.222.17 -p 5432 -U postgres > backup/all_$(date +%Y%m%d).sql - ``` -3. **恢复** - ```bash - pg_restore -h 120.53.222.17 -p 5432 -U postgres -d takeout_app_db backup/takeout_app_db_xxx.dump - psql -h 120.53.222.17 -p 5432 -U postgres -f backup/all_yyyymmdd.sql - ``` -4. **账号/权限策略** - - `app_user` / `identity_user` / `dictionary_user` 拥有 `CONNECT`、`TEMP`、Schema `public` 的 CRUD 权限。 - - `hangfire_user` 仅能访问 `takeout_hangfire_db`,不可访问业务库。 - - 创建新表/列时,通过 EF Migration 自动添加 COMMENT。 - -### Redis - -1. **连接验证** - ```bash - redis-cli -h 49.232.6.45 -p 6379 -a MsuMshk112233 ping - ``` -2. **备份** - ```bash - redis-cli -h 49.232.6.45 -p 6379 -a MsuMshk112233 save # 触发 RDB - redis-cli -h 49.232.6.45 -p 6379 -a MsuMshk112233 bgsave # 后台 - ``` - RDB/AOF 文件在服务器 `redis.conf` 定义的目录(默认 `/var/lib/redis`)。 -3. **常见运维项** - - `CONFIG GET dir` / `CONFIG GET dbfilename` 可查看持久化路径。 - - `INFO memory` 监控内存;开启 `maxmemory` + `allkeys-lru` 保护。 - -## 5. IaC / 脚本 - -| 文件 | 说明 | -| --- | --- | -| `deploy/postgres/create_databases.sql` | 基于 `postgres` 管理员执行,创建四个业务库及角色、授予权限、补 COMMENT。 | -| `deploy/postgres/bootstrap.ps1` | PowerShell 包装脚本,调用 `psql` 执行上面的 SQL(默认读取 `postgres` 管理员账号)。 | -| `deploy/postgres/README.md` | 介绍如何在本地/测试环境执行 bootstrap 并校验连接。 | -| `deploy/redis/docker-compose.yml` | 可复用的 Redis 部署(Redis 7 + AOF),便于本地或测试环境一键拉起。 | -| `deploy/redis/redis.conf` | compose/裸机均可共用的配置(`requirepass`、持久化等已写好)。 | -| `deploy/redis/README.md` | 说明如何使用 compose 或将 `redis.conf` 部署到现有实例。 | - -> 线上目前为裸机安装(非容器),如需创建新环境/快速恢复,可直接运行上述脚本达到同样配置;即使在现有机器上,也可把 SQL/配置当作“最终规范”确保环境一致性。 diff --git a/Document/swagger/swagger20251215095917.json b/Document/swagger/swagger20251215095917.json deleted file mode 100644 index d1efe82..0000000 --- a/Document/swagger/swagger20251215095917.json +++ /dev/null @@ -1,19254 +0,0 @@ -{ - "openapi": "3.0.4", - "info": { - "title": "外卖SaaS - 管理后台 1.0", - "description": "管理后台 API 文档", - "version": "1.0" - }, - "paths": { - "/api/admin/v1/auth/login": { - "post": { - "tags": [ - "Auth" - ], - "summary": "登录获取 Token", - "requestBody": { - "description": "登录请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/AdminLoginRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AdminLoginRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AdminLoginRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/AdminLoginRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TokenResponseApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/auth/login/simple": { - "post": { - "tags": [ - "Auth" - ], - "summary": "免租户号登录(仅账号+密码)。", - "description": "用于前端简化登录,无需额外传递租户号。", - "requestBody": { - "description": "登录请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/AdminLoginRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AdminLoginRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AdminLoginRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/AdminLoginRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TokenResponseApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/auth/refresh": { - "post": { - "tags": [ - "Auth" - ], - "summary": "刷新 Token", - "requestBody": { - "description": "刷新令牌请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/RefreshTokenRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/RefreshTokenRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/RefreshTokenRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/RefreshTokenRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TokenResponseApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/auth/profile": { - "get": { - "tags": [ - "Auth" - ], - "summary": "获取当前用户信息", - "description": "示例:\n```\nGET /api/admin/v1/auth/profile\nHeader: Authorization: Bearer \n响应:\n{\n \"success\": true,\n \"code\": 200,\n \"message\": \"操作成功\",\n \"data\": {\n \"userId\": \"900123456789012345\",\n \"account\": \"admin@tenant1\",\n \"displayName\": \"租户管理员\",\n \"tenantId\": \"100000000000000001\",\n \"merchantId\": null,\n \"roles\": [\"TenantAdmin\"],\n \"permissions\": [\"identity:permission:read\", \"merchant:read\", \"order:read\"],\n \"avatar\": \"https://cdn.example.com/avatar.png\"\n }\n}\n```", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CurrentUserProfileApiResponse" - } - } - } - }, - "401": { - "description": "Unauthorized", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/CurrentUserProfileApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/auth/menu": { - "get": { - "tags": [ - "Auth" - ], - "summary": "获取当前用户的菜单树(按权限过滤)。", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MenuNodeDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/auth/permissions/{userId}": { - "get": { - "tags": [ - "Auth" - ], - "summary": "查询指定用户的角色与权限概览(当前租户范围)。", - "description": "示例:\n```\nGET /api/admin/v1/auth/permissions/900123456789012346\nHeader: Authorization: Bearer \n响应:\n{\n \"success\": true,\n \"code\": 200,\n \"data\": {\n \"userId\": \"900123456789012346\",\n \"tenantId\": \"100000000000000001\",\n \"merchantId\": \"200000000000000001\",\n \"account\": \"ops.manager\",\n \"displayName\": \"运营经理\",\n \"roles\": [\"OpsManager\", \"Reporter\"],\n \"permissions\": [\"delivery:read\", \"order:read\", \"payment:read\"],\n \"createdAt\": \"2025-12-01T08:30:00Z\"\n }\n}\n```", - "parameters": [ - { - "name": "userId", - "in": "path", - "description": "目标用户 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserPermissionDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserPermissionDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/deliveries": { - "post": { - "tags": [ - "Deliveries" - ], - "summary": "创建配送单。", - "requestBody": { - "description": "创建命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateDeliveryOrderCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateDeliveryOrderCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateDeliveryOrderCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateDeliveryOrderCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeliveryOrderDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Deliveries" - ], - "summary": "查询配送单列表。", - "parameters": [ - { - "name": "orderId", - "in": "query", - "description": "订单 ID。", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "status", - "in": "query", - "description": "配送状态。", - "schema": { - "$ref": "#/components/schemas/DeliveryStatus" - } - }, - { - "name": "page", - "in": "query", - "description": "页码。", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "description": "每页大小。", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - }, - { - "name": "sortBy", - "in": "query", - "description": "排序字段。", - "schema": { - "type": "string" - } - }, - { - "name": "sortDesc", - "in": "query", - "description": "是否倒序。", - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeliveryOrderDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/deliveries/{deliveryOrderId}": { - "get": { - "tags": [ - "Deliveries" - ], - "summary": "获取配送单详情。", - "parameters": [ - { - "name": "deliveryOrderId", - "in": "path", - "description": "配送单 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeliveryOrderDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "Deliveries" - ], - "summary": "更新配送单。", - "parameters": [ - { - "name": "deliveryOrderId", - "in": "path", - "description": "配送单 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "更新命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateDeliveryOrderCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateDeliveryOrderCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateDeliveryOrderCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateDeliveryOrderCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeliveryOrderDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Deliveries" - ], - "summary": "删除配送单。", - "parameters": [ - { - "name": "deliveryOrderId", - "in": "path", - "description": "配送单 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/dictionaries": { - "get": { - "tags": [ - "Dictionary" - ], - "summary": "查询字典分组。", - "parameters": [ - { - "name": "Scope", - "in": "query", - "description": "参数字典作用域。", - "schema": { - "$ref": "#/components/schemas/DictionaryScope" - } - }, - { - "name": "IncludeItems", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DictionaryGroupDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "Dictionary" - ], - "summary": "创建字典分组。", - "requestBody": { - "description": "创建分组请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateDictionaryGroupRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateDictionaryGroupRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateDictionaryGroupRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateDictionaryGroupRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DictionaryGroupDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/dictionaries/{groupId}": { - "put": { - "tags": [ - "Dictionary" - ], - "summary": "更新字典分组。", - "parameters": [ - { - "name": "groupId", - "in": "path", - "description": "分组 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "更新请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateDictionaryGroupRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateDictionaryGroupRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateDictionaryGroupRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateDictionaryGroupRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DictionaryGroupDtoApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Dictionary" - ], - "summary": "删除字典分组。", - "parameters": [ - { - "name": "groupId", - "in": "path", - "description": "分组 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/dictionaries/{groupId}/items": { - "post": { - "tags": [ - "Dictionary" - ], - "summary": "创建字典项。", - "parameters": [ - { - "name": "groupId", - "in": "path", - "description": "分组 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "创建请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateDictionaryItemRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateDictionaryItemRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateDictionaryItemRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateDictionaryItemRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DictionaryItemDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/dictionaries/items/{itemId}": { - "put": { - "tags": [ - "Dictionary" - ], - "summary": "更新字典项。", - "parameters": [ - { - "name": "itemId", - "in": "path", - "description": "字典项 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "更新请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateDictionaryItemRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateDictionaryItemRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateDictionaryItemRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateDictionaryItemRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DictionaryItemDtoApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Dictionary" - ], - "summary": "删除字典项。", - "parameters": [ - { - "name": "itemId", - "in": "path", - "description": "字典项 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/dictionaries/batch": { - "post": { - "tags": [ - "Dictionary" - ], - "summary": "批量获取字典项(命中缓存)。", - "requestBody": { - "description": "批量查询请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/DictionaryBatchQueryRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DictionaryBatchQueryRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DictionaryBatchQueryRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DictionaryBatchQueryRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StringDictionaryItemDtoIReadOnlyListIReadOnlyDictionaryApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/files/upload": { - "post": { - "tags": [ - "Files" - ], - "summary": "上传图片或文件。", - "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "required": [ - "File" - ], - "type": "object", - "properties": { - "File": { - "type": "string", - "description": "上传文件。", - "format": "binary" - }, - "Type": { - "type": "string", - "description": "上传类型。" - } - } - }, - "encoding": { - "File": { - "style": "form" - }, - "Type": { - "style": "form" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FileUploadResponseApiResponse" - } - } - } - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/FileUploadResponseApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/Health": { - "get": { - "tags": [ - "Health" - ], - "summary": "获取服务健康状态。", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/inventory/{productSkuId}": { - "get": { - "tags": [ - "Inventory" - ], - "summary": "查询库存。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "productSkuId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InventoryItemDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/inventory/adjust": { - "post": { - "tags": [ - "Inventory" - ], - "summary": "调整库存(入库/盘点/报损)。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/AdjustInventoryCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AdjustInventoryCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AdjustInventoryCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/AdjustInventoryCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InventoryItemDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/inventory/lock": { - "post": { - "tags": [ - "Inventory" - ], - "summary": "锁定库存(下单占用)。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/LockInventoryCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/LockInventoryCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/LockInventoryCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/LockInventoryCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InventoryItemDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/inventory/release": { - "post": { - "tags": [ - "Inventory" - ], - "summary": "释放库存(取消订单等)。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReleaseInventoryCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReleaseInventoryCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReleaseInventoryCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReleaseInventoryCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InventoryItemDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/inventory/deduct": { - "post": { - "tags": [ - "Inventory" - ], - "summary": "扣减库存(支付或履约成功)。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/DeductInventoryCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DeductInventoryCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DeductInventoryCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DeductInventoryCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InventoryItemDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/inventory/{productSkuId}/batches": { - "get": { - "tags": [ - "Inventory" - ], - "summary": "查询批次列表。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "productSkuId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InventoryBatchDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "Inventory" - ], - "summary": "新增或更新批次。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "productSkuId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpsertInventoryBatchCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpsertInventoryBatchCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpsertInventoryBatchCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpsertInventoryBatchCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InventoryBatchDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/inventory/locks/expire": { - "post": { - "tags": [ - "Inventory" - ], - "summary": "释放过期锁定。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/Int32ApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/menus": { - "get": { - "tags": [ - "Menus" - ], - "summary": "获取当前租户的菜单列表(平铺)。", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MenuDefinitionDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "Menus" - ], - "summary": "创建菜单。", - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateMenuCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateMenuCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateMenuCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateMenuCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MenuDefinitionDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/menus/{menuId}": { - "get": { - "tags": [ - "Menus" - ], - "summary": "获取菜单详情。", - "parameters": [ - { - "name": "menuId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MenuDefinitionDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MenuDefinitionDtoApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "Menus" - ], - "summary": "更新菜单。", - "parameters": [ - { - "name": "menuId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateMenuCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateMenuCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateMenuCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateMenuCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MenuDefinitionDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MenuDefinitionDtoApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Menus" - ], - "summary": "删除菜单。", - "parameters": [ - { - "name": "menuId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BooleanApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchant-categories": { - "get": { - "tags": [ - "MerchantCategories" - ], - "summary": "列出所有类目。", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantCategoryDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "MerchantCategories" - ], - "summary": "新增类目。", - "requestBody": { - "description": "创建命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantCategoryCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantCategoryCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantCategoryCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantCategoryCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantCategoryDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchant-categories/{categoryId}": { - "delete": { - "tags": [ - "MerchantCategories" - ], - "summary": "删除类目。", - "parameters": [ - { - "name": "categoryId", - "in": "path", - "description": "类目 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchant-categories/reorder": { - "post": { - "tags": [ - "MerchantCategories" - ], - "summary": "批量调整类目排序。", - "requestBody": { - "description": "排序命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReorderMerchantCategoriesCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReorderMerchantCategoriesCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReorderMerchantCategoriesCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReorderMerchantCategoriesCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants": { - "post": { - "tags": [ - "Merchants" - ], - "summary": "创建商户。", - "requestBody": { - "description": "创建命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Merchants" - ], - "summary": "查询商户列表。", - "parameters": [ - { - "name": "status", - "in": "query", - "description": "状态筛选。", - "schema": { - "$ref": "#/components/schemas/MerchantStatus" - } - }, - { - "name": "page", - "in": "query", - "description": "页码。", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "description": "每页大小。", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - }, - { - "name": "sortBy", - "in": "query", - "description": "排序字段。", - "schema": { - "type": "string" - } - }, - { - "name": "sortDesc", - "in": "query", - "description": "是否倒序。", - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/{merchantId}": { - "put": { - "tags": [ - "Merchants" - ], - "summary": "更新商户。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "description": "商户 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "更新命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateMerchantCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateMerchantCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateMerchantCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateMerchantCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Merchants" - ], - "summary": "删除商户。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "description": "商户 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Merchants" - ], - "summary": "获取商户概览。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "description": "商户 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/{merchantId}/detail": { - "get": { - "tags": [ - "Merchants" - ], - "summary": "获取商户详细资料(含证照、合同)。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDetailDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/{merchantId}/documents": { - "post": { - "tags": [ - "Merchants" - ], - "summary": "上传商户证照信息(先通过文件上传接口获取 COS 地址)。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/AddMerchantDocumentCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AddMerchantDocumentCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AddMerchantDocumentCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/AddMerchantDocumentCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDocumentDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Merchants" - ], - "summary": "商户证照列表。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDocumentDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/{merchantId}/documents/{documentId}/review": { - "post": { - "tags": [ - "Merchants" - ], - "summary": "审核指定证照。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "documentId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReviewMerchantDocumentCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReviewMerchantDocumentCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReviewMerchantDocumentCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReviewMerchantDocumentCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDocumentDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/{merchantId}/contracts": { - "post": { - "tags": [ - "Merchants" - ], - "summary": "新增商户合同。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantContractCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantContractCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantContractCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateMerchantContractCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantContractDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Merchants" - ], - "summary": "合同列表。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantContractDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/{merchantId}/contracts/{contractId}/status": { - "put": { - "tags": [ - "Merchants" - ], - "summary": "更新合同状态(生效/终止等)。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "contractId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateMerchantContractStatusCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateMerchantContractStatusCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateMerchantContractStatusCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateMerchantContractStatusCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantContractDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/{merchantId}/review": { - "post": { - "tags": [ - "Merchants" - ], - "summary": "审核商户(通过/驳回)。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReviewMerchantCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReviewMerchantCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReviewMerchantCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReviewMerchantCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/{merchantId}/audits": { - "get": { - "tags": [ - "Merchants" - ], - "summary": "审核日志。", - "parameters": [ - { - "name": "merchantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/MerchantAuditLogDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/merchants/categories": { - "get": { - "tags": [ - "Merchants" - ], - "summary": "可选商户类目列表。", - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StringIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/orders": { - "post": { - "tags": [ - "Orders" - ], - "summary": "创建订单。", - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateOrderCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateOrderCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateOrderCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateOrderCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrderDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Orders" - ], - "summary": "查询订单列表。", - "parameters": [ - { - "name": "storeId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "status", - "in": "query", - "description": "订单状态。", - "schema": { - "$ref": "#/components/schemas/OrderStatus" - } - }, - { - "name": "paymentStatus", - "in": "query", - "description": "支付记录状态。", - "schema": { - "$ref": "#/components/schemas/PaymentStatus" - } - }, - { - "name": "orderNo", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - }, - { - "name": "sortBy", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "sortDesc", - "in": "query", - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrderDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/orders/{orderId}": { - "get": { - "tags": [ - "Orders" - ], - "summary": "获取订单详情。", - "parameters": [ - { - "name": "orderId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrderDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "Orders" - ], - "summary": "更新订单。", - "parameters": [ - { - "name": "orderId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateOrderCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateOrderCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateOrderCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateOrderCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OrderDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Orders" - ], - "summary": "删除订单。", - "parameters": [ - { - "name": "orderId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/payments": { - "post": { - "tags": [ - "Payments" - ], - "summary": "创建支付记录。", - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreatePaymentCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreatePaymentCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreatePaymentCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreatePaymentCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PaymentDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Payments" - ], - "summary": "查询支付记录列表。", - "parameters": [ - { - "name": "orderId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "status", - "in": "query", - "description": "支付记录状态。", - "schema": { - "$ref": "#/components/schemas/PaymentStatus" - } - }, - { - "name": "page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - }, - { - "name": "sortBy", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "sortDesc", - "in": "query", - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PaymentDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/payments/{paymentId}": { - "get": { - "tags": [ - "Payments" - ], - "summary": "获取支付记录详情。", - "parameters": [ - { - "name": "paymentId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PaymentDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "Payments" - ], - "summary": "更新支付记录。", - "parameters": [ - { - "name": "paymentId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdatePaymentCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdatePaymentCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdatePaymentCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdatePaymentCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PaymentDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Payments" - ], - "summary": "删除支付记录。", - "parameters": [ - { - "name": "paymentId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/permissions": { - "get": { - "tags": [ - "Permissions" - ], - "summary": "分页查询权限。", - "description": "示例:GET /api/admin/v1/permissions?keyword=order&page=1&pageSize=20", - "parameters": [ - { - "name": "Keyword", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "SortBy", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "SortDescending", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PermissionDtoPagedResultApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "Permissions" - ], - "summary": "创建权限。", - "requestBody": { - "description": "创建命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreatePermissionCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreatePermissionCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreatePermissionCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreatePermissionCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PermissionDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/permissions/tree": { - "get": { - "tags": [ - "Permissions" - ], - "summary": "获取权限树。", - "parameters": [ - { - "name": "keyword", - "in": "query", - "description": "关键字(可选)。", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PermissionTreeDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/permissions/{permissionId}": { - "put": { - "tags": [ - "Permissions" - ], - "summary": "更新权限。", - "parameters": [ - { - "name": "permissionId", - "in": "path", - "description": "权限 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "更新命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdatePermissionCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdatePermissionCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdatePermissionCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdatePermissionCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PermissionDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PermissionDtoApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Permissions" - ], - "summary": "删除权限。", - "parameters": [ - { - "name": "permissionId", - "in": "path", - "description": "权限 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BooleanApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products": { - "post": { - "tags": [ - "Products" - ], - "summary": "创建商品。", - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateProductCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateProductCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateProductCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateProductCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Products" - ], - "summary": "查询商品列表。", - "parameters": [ - { - "name": "storeId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "categoryId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "status", - "in": "query", - "description": "商品状态。", - "schema": { - "$ref": "#/components/schemas/ProductStatus" - } - }, - { - "name": "page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - }, - { - "name": "sortBy", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "sortDesc", - "in": "query", - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}": { - "get": { - "tags": [ - "Products" - ], - "summary": "获取商品详情。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "Products" - ], - "summary": "更新商品。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateProductCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateProductCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateProductCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateProductCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Products" - ], - "summary": "删除商品。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}/detail": { - "get": { - "tags": [ - "Products" - ], - "summary": "获取商品全量详情。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductDetailDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}/publish": { - "post": { - "tags": [ - "Products" - ], - "summary": "上架商品。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/PublishProductCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/PublishProductCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/PublishProductCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/PublishProductCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}/unpublish": { - "post": { - "tags": [ - "Products" - ], - "summary": "下架商品。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UnpublishProductCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UnpublishProductCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UnpublishProductCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UnpublishProductCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}/skus": { - "put": { - "tags": [ - "Products" - ], - "summary": "替换商品 SKU。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductSkusCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductSkusCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductSkusCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductSkusCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductSkuDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}/attributes": { - "put": { - "tags": [ - "Products" - ], - "summary": "替换商品规格。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductAttributesCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductAttributesCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductAttributesCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductAttributesCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductAttributeGroupDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}/addons": { - "put": { - "tags": [ - "Products" - ], - "summary": "替换商品加料。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductAddonsCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductAddonsCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductAddonsCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductAddonsCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductAddonGroupDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}/media": { - "put": { - "tags": [ - "Products" - ], - "summary": "替换商品媒资。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductMediaCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductMediaCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductMediaCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductMediaCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductMediaAssetDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/products/{productId}/pricing-rules": { - "put": { - "tags": [ - "Products" - ], - "summary": "替换商品价格策略。", - "parameters": [ - { - "name": "productId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductPricingRulesCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductPricingRulesCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductPricingRulesCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReplaceProductPricingRulesCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProductPricingRuleDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/public/v1/tenant-packages": { - "get": { - "tags": [ - "PublicTenantPackages" - ], - "summary": "分页获取已启用的租户套餐。", - "parameters": [ - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantPackageDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/public/v1/tenants/self-register": { - "post": { - "tags": [ - "PublicTenants" - ], - "summary": "自助注册租户并生成初始管理员。", - "requestBody": { - "description": "自助注册命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SelfRegisterTenantCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SelfRegisterTenantCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SelfRegisterTenantCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SelfRegisterTenantCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SelfRegisterResultDtoApiResponse" - } - } - } - } - } - } - }, - "/api/public/v1/tenants/{tenantId}/verification": { - "post": { - "tags": [ - "PublicTenants" - ], - "summary": "自助提交或更新实名资料。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "description": "租户 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "实名资料。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SubmitTenantVerificationCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubmitTenantVerificationCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SubmitTenantVerificationCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SubmitTenantVerificationCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantVerificationDtoApiResponse" - } - } - } - } - } - } - }, - "/api/public/v1/tenants/{tenantId}/status": { - "get": { - "tags": [ - "PublicTenants" - ], - "summary": "查询租户入住进度。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "description": "租户 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantProgressDtoApiResponse" - } - } - } - } - } - } - }, - "/api/public/v1/tenants/{tenantId}/subscriptions/initial": { - "post": { - "tags": [ - "PublicTenantSubscriptions" - ], - "summary": "初次绑定租户订阅(默认 0 个月)。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "description": "租户 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "绑定请求。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/BindInitialTenantSubscriptionCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BindInitialTenantSubscriptionCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BindInitialTenantSubscriptionCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/BindInitialTenantSubscriptionCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantSubscriptionDtoApiResponse" - } - } - } - }, - "400": { - "description": "Bad Request", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantSubscriptionDtoApiResponse" - } - } - } - }, - "403": { - "description": "Forbidden", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantSubscriptionDtoApiResponse" - } - } - } - }, - "409": { - "description": "Conflict", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantSubscriptionDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/role-templates": { - "get": { - "tags": [ - "RoleTemplates" - ], - "summary": "分页查询角色模板。", - "parameters": [ - { - "name": "isActive", - "in": "query", - "description": "是否启用筛选。", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleTemplateDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "RoleTemplates" - ], - "summary": "创建角色模板。", - "requestBody": { - "description": "创建命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleTemplateCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleTemplateCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleTemplateCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleTemplateCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleTemplateDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/role-templates/{templateCode}/clone": { - "post": { - "tags": [ - "RoleTemplates" - ], - "summary": "克隆角色模板。", - "parameters": [ - { - "name": "templateCode", - "in": "path", - "description": "源模板编码。", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "description": "克隆命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CloneRoleTemplateCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CloneRoleTemplateCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CloneRoleTemplateCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CloneRoleTemplateCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleTemplateDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/role-templates/{templateCode}": { - "get": { - "tags": [ - "RoleTemplates" - ], - "summary": "获取角色模板详情。", - "parameters": [ - { - "name": "templateCode", - "in": "path", - "description": "模板编码。", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleTemplateDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleTemplateDtoApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "RoleTemplates" - ], - "summary": "更新角色模板。", - "parameters": [ - { - "name": "templateCode", - "in": "path", - "description": "模板编码。", - "required": true, - "schema": { - "type": "string" - } - } - ], - "requestBody": { - "description": "更新命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleTemplateCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleTemplateCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleTemplateCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleTemplateCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleTemplateDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleTemplateDtoApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "RoleTemplates" - ], - "summary": "删除角色模板。", - "parameters": [ - { - "name": "templateCode", - "in": "path", - "description": "模板编码。", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BooleanApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/role-templates/{templateCode}/permissions": { - "get": { - "tags": [ - "RoleTemplates" - ], - "summary": "获取模板的权限列表。", - "parameters": [ - { - "name": "templateCode", - "in": "path", - "description": "模板编码。", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PermissionTemplateDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/role-templates/init": { - "post": { - "tags": [ - "RoleTemplates" - ], - "summary": "为当前租户批量初始化预置角色模板。", - "requestBody": { - "description": "初始化命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/InitializeRoleTemplatesCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/InitializeRoleTemplatesCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/InitializeRoleTemplatesCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/InitializeRoleTemplatesCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/role-templates/{templateCode}/initialize-tenant": { - "post": { - "tags": [ - "RoleTemplates" - ], - "summary": "将单个模板初始化到当前租户。", - "parameters": [ - { - "name": "templateCode", - "in": "path", - "description": "模板编码。", - "required": true, - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/pickup/settings": { - "get": { - "tags": [ - "StorePickup" - ], - "summary": "获取自提配置。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StorePickupSettingDtoApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "StorePickup" - ], - "summary": "更新自提配置。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpsertStorePickupSettingCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpsertStorePickupSettingCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpsertStorePickupSettingCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpsertStorePickupSettingCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StorePickupSettingDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/pickup/slots": { - "get": { - "tags": [ - "StorePickup" - ], - "summary": "查询档期列表。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StorePickupSlotDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "StorePickup" - ], - "summary": "创建档期。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateStorePickupSlotCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStorePickupSlotCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateStorePickupSlotCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateStorePickupSlotCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StorePickupSlotDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/pickup/slots/{slotId}": { - "put": { - "tags": [ - "StorePickup" - ], - "summary": "更新档期。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "slotId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStorePickupSlotCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStorePickupSlotCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStorePickupSlotCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStorePickupSlotCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StorePickupSlotDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "StorePickup" - ], - "summary": "删除档期。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "slotId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores": { - "post": { - "tags": [ - "Stores" - ], - "summary": "创建门店。", - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Stores" - ], - "summary": "查询门店列表。", - "parameters": [ - { - "name": "merchantId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "status", - "in": "query", - "description": "门店运营状态。", - "schema": { - "$ref": "#/components/schemas/StoreStatus" - } - }, - { - "name": "page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - }, - { - "name": "sortBy", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "sortDesc", - "in": "query", - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}": { - "get": { - "tags": [ - "Stores" - ], - "summary": "获取门店详情。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "Stores" - ], - "summary": "更新门店。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Stores" - ], - "summary": "删除门店。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/business-hours": { - "get": { - "tags": [ - "Stores" - ], - "summary": "查询门店营业时段。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreBusinessHourDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "Stores" - ], - "summary": "新增营业时段。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreBusinessHourCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreBusinessHourCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreBusinessHourCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreBusinessHourCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreBusinessHourDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/business-hours/{businessHourId}": { - "put": { - "tags": [ - "Stores" - ], - "summary": "更新营业时段。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "businessHourId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreBusinessHourCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreBusinessHourCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreBusinessHourCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreBusinessHourCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreBusinessHourDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Stores" - ], - "summary": "删除营业时段。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "businessHourId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/delivery-zones": { - "get": { - "tags": [ - "Stores" - ], - "summary": "查询配送区域。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreDeliveryZoneDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "Stores" - ], - "summary": "新增配送区域。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreDeliveryZoneCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreDeliveryZoneCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreDeliveryZoneCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreDeliveryZoneCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreDeliveryZoneDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/delivery-zones/{deliveryZoneId}": { - "put": { - "tags": [ - "Stores" - ], - "summary": "更新配送区域。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "deliveryZoneId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreDeliveryZoneCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreDeliveryZoneCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreDeliveryZoneCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreDeliveryZoneCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreDeliveryZoneDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Stores" - ], - "summary": "删除配送区域。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "deliveryZoneId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/holidays": { - "get": { - "tags": [ - "Stores" - ], - "summary": "查询门店节假日。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreHolidayDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "Stores" - ], - "summary": "新增节假日配置。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreHolidayCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreHolidayCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreHolidayCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreHolidayCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreHolidayDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/holidays/{holidayId}": { - "put": { - "tags": [ - "Stores" - ], - "summary": "更新节假日配置。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "holidayId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreHolidayCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreHolidayCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreHolidayCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreHolidayCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreHolidayDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Stores" - ], - "summary": "删除节假日配置。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "holidayId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/shifts": { - "get": { - "tags": [ - "StoreShifts" - ], - "summary": "查询排班(默认未来 7 天)。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "from", - "in": "query", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "to", - "in": "query", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "staffId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreEmployeeShiftDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "StoreShifts" - ], - "summary": "创建排班。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreEmployeeShiftCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreEmployeeShiftCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreEmployeeShiftCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreEmployeeShiftCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreEmployeeShiftDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/shifts/{shiftId}": { - "put": { - "tags": [ - "StoreShifts" - ], - "summary": "更新排班。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "shiftId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreEmployeeShiftCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreEmployeeShiftCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreEmployeeShiftCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreEmployeeShiftCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreEmployeeShiftDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "StoreShifts" - ], - "summary": "删除排班。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "shiftId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/staffs": { - "get": { - "tags": [ - "StoreStaffs" - ], - "summary": "查询门店员工列表。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "role", - "in": "query", - "description": "商户员工角色。", - "schema": { - "$ref": "#/components/schemas/StaffRoleType" - } - }, - { - "name": "status", - "in": "query", - "description": "员工账号状态。", - "schema": { - "$ref": "#/components/schemas/StaffStatus" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreStaffDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "StoreStaffs" - ], - "summary": "创建门店员工。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreStaffCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreStaffCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreStaffCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreStaffCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreStaffDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/staffs/{staffId}": { - "put": { - "tags": [ - "StoreStaffs" - ], - "summary": "更新门店员工。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "staffId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreStaffCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreStaffCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreStaffCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreStaffCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreStaffDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "StoreStaffs" - ], - "summary": "删除门店员工。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "staffId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/table-areas": { - "get": { - "tags": [ - "StoreTableAreas" - ], - "summary": "查询区域列表。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreTableAreaDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "StoreTableAreas" - ], - "summary": "创建区域。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreTableAreaCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreTableAreaCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreTableAreaCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateStoreTableAreaCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreTableAreaDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/table-areas/{areaId}": { - "put": { - "tags": [ - "StoreTableAreas" - ], - "summary": "更新区域。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "areaId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreTableAreaCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreTableAreaCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreTableAreaCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreTableAreaCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreTableAreaDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "StoreTableAreas" - ], - "summary": "删除区域。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "areaId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/tables": { - "get": { - "tags": [ - "StoreTables" - ], - "summary": "查询桌码列表。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "areaId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "status", - "in": "query", - "description": "桌台占用状态。", - "schema": { - "$ref": "#/components/schemas/StoreTableStatus" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreTableDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "StoreTables" - ], - "summary": "批量生成桌码。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/GenerateStoreTablesCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/GenerateStoreTablesCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/GenerateStoreTablesCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/GenerateStoreTablesCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreTableDtoIReadOnlyListApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/tables/{tableId}": { - "put": { - "tags": [ - "StoreTables" - ], - "summary": "更新桌码。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "tableId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreTableCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreTableCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreTableCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateStoreTableCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/StoreTableDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "StoreTables" - ], - "summary": "删除桌码。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "tableId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/stores/{storeId}/tables/export": { - "post": { - "tags": [ - "StoreTables" - ], - "summary": "导出桌码二维码 ZIP。", - "parameters": [ - { - "name": "storeId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ExportStoreTableQRCodesQuery" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ExportStoreTableQRCodesQuery" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ExportStoreTableQRCodesQuery" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ExportStoreTableQRCodesQuery" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/system-parameters": { - "post": { - "tags": [ - "SystemParameters" - ], - "summary": "创建系统参数。", - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateSystemParameterCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateSystemParameterCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateSystemParameterCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateSystemParameterCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SystemParameterDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "SystemParameters" - ], - "summary": "查询系统参数列表。", - "parameters": [ - { - "name": "keyword", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "isEnabled", - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - }, - { - "name": "sortBy", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "sortDesc", - "in": "query", - "schema": { - "type": "boolean", - "default": true - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SystemParameterDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/system-parameters/{parameterId}": { - "get": { - "tags": [ - "SystemParameters" - ], - "summary": "获取系统参数详情。", - "parameters": [ - { - "name": "parameterId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SystemParameterDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "SystemParameters" - ], - "summary": "更新系统参数。", - "parameters": [ - { - "name": "parameterId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateSystemParameterCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateSystemParameterCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateSystemParameterCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateSystemParameterCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SystemParameterDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "SystemParameters" - ], - "summary": "删除系统参数。", - "parameters": [ - { - "name": "parameterId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ObjectApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/announcements": { - "get": { - "tags": [ - "TenantAnnouncements" - ], - "summary": "分页查询公告。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "TenantId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "AnnouncementType", - "in": "query", - "description": "租户公告类型。", - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementType" - } - }, - { - "name": "IsActive", - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "OnlyEffective", - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementDtoPagedResultApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "TenantAnnouncements" - ], - "summary": "创建公告。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantAnnouncementCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantAnnouncementCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantAnnouncementCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantAnnouncementCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/announcements/{announcementId}": { - "get": { - "tags": [ - "TenantAnnouncements" - ], - "summary": "公告详情。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "announcementId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementDtoApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "TenantAnnouncements" - ], - "summary": "更新公告。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "announcementId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateTenantAnnouncementCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateTenantAnnouncementCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateTenantAnnouncementCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateTenantAnnouncementCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementDtoApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "TenantAnnouncements" - ], - "summary": "删除公告。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "announcementId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BooleanApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/announcements/{announcementId}/read": { - "post": { - "tags": [ - "TenantAnnouncements" - ], - "summary": "标记公告已读。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "announcementId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAnnouncementDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/billings": { - "get": { - "tags": [ - "TenantBillings" - ], - "summary": "分页查询账单。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "TenantId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "Status", - "in": "query", - "description": "账单状态。", - "schema": { - "$ref": "#/components/schemas/TenantBillingStatus" - } - }, - { - "name": "From", - "in": "query", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "To", - "in": "query", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantBillingDtoPagedResultApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "TenantBillings" - ], - "summary": "创建账单。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantBillingCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantBillingCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantBillingCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantBillingCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantBillingDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/billings/{billingId}": { - "get": { - "tags": [ - "TenantBillings" - ], - "summary": "账单详情。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "billingId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantBillingDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantBillingDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/billings/{billingId}/pay": { - "post": { - "tags": [ - "TenantBillings" - ], - "summary": "标记账单已支付。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "billingId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/MarkTenantBillingPaidCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/MarkTenantBillingPaidCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/MarkTenantBillingPaidCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/MarkTenantBillingPaidCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantBillingDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantBillingDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/notifications": { - "get": { - "tags": [ - "TenantNotifications" - ], - "summary": "分页查询通知。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "TenantId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "Severity", - "in": "query", - "description": "租户通知的重要程度。", - "schema": { - "$ref": "#/components/schemas/TenantNotificationSeverity" - } - }, - { - "name": "UnreadOnly", - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantNotificationDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/notifications/{notificationId}/read": { - "post": { - "tags": [ - "TenantNotifications" - ], - "summary": "标记通知已读。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "notificationId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantNotificationDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantNotificationDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenant-packages": { - "get": { - "tags": [ - "TenantPackages" - ], - "summary": "分页查询租户套餐。", - "parameters": [ - { - "name": "Keyword", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "IsActive", - "in": "query", - "schema": { - "type": "boolean" - } - }, - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantPackageDtoPagedResultApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "TenantPackages" - ], - "summary": "创建套餐。", - "requestBody": { - "description": "创建命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantPackageCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantPackageCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantPackageCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantPackageCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantPackageDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenant-packages/{tenantPackageId}": { - "get": { - "tags": [ - "TenantPackages" - ], - "summary": "查看套餐详情。", - "parameters": [ - { - "name": "tenantPackageId", - "in": "path", - "description": "套餐 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantPackageDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantPackageDtoApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "TenantPackages" - ], - "summary": "更新套餐。", - "parameters": [ - { - "name": "tenantPackageId", - "in": "path", - "description": "套餐 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "更新命令。", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateTenantPackageCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateTenantPackageCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateTenantPackageCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateTenantPackageCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantPackageDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantPackageDtoApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "TenantPackages" - ], - "summary": "删除套餐。", - "parameters": [ - { - "name": "tenantPackageId", - "in": "path", - "description": "套餐 ID。", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BooleanApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/roles": { - "get": { - "tags": [ - "TenantRoles" - ], - "summary": "租户角色分页。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "TenantId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "Keyword", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "SortBy", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "SortDescending", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDtoPagedResultApiResponse" - } - } - } - } - } - }, - "post": { - "tags": [ - "TenantRoles" - ], - "summary": "创建角色。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateRoleCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/roles/{roleId}": { - "get": { - "tags": [ - "TenantRoles" - ], - "summary": "角色详情(含权限)。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "roleId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDetailDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDetailDtoApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "TenantRoles" - ], - "summary": "更新角色。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "roleId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/UpdateRoleCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDtoApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RoleDtoApiResponse" - } - } - } - } - } - }, - "delete": { - "tags": [ - "TenantRoles" - ], - "summary": "删除角色。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "roleId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BooleanApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/roles/{roleId}/permissions": { - "get": { - "tags": [ - "TenantRoles" - ], - "summary": "获取角色权限列表。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "roleId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PermissionDtoIReadOnlyListApiResponse" - } - } - } - }, - "404": { - "description": "Not Found", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PermissionDtoIReadOnlyListApiResponse" - } - } - } - } - } - }, - "put": { - "tags": [ - "TenantRoles" - ], - "summary": "覆盖角色权限。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "roleId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/BindRolePermissionsCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BindRolePermissionsCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BindRolePermissionsCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/BindRolePermissionsCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/BooleanApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants": { - "post": { - "tags": [ - "Tenants" - ], - "summary": "注册租户并初始化套餐。", - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/RegisterTenantCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegisterTenantCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/RegisterTenantCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/RegisterTenantCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantDtoApiResponse" - } - } - } - } - } - }, - "get": { - "tags": [ - "Tenants" - ], - "summary": "分页查询租户。", - "parameters": [ - { - "name": "Status", - "in": "query", - "description": "租户服务状态。", - "schema": { - "$ref": "#/components/schemas/TenantStatus" - } - }, - { - "name": "VerificationStatus", - "in": "query", - "description": "租户实名认证状态。", - "schema": { - "$ref": "#/components/schemas/TenantVerificationStatus" - } - }, - { - "name": "Name", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "ContactName", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "ContactPhone", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "Keyword", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}": { - "get": { - "tags": [ - "Tenants" - ], - "summary": "查看租户详情。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantDetailDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/verification": { - "post": { - "tags": [ - "Tenants" - ], - "summary": "提交或更新实名认证资料。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SubmitTenantVerificationCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SubmitTenantVerificationCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SubmitTenantVerificationCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SubmitTenantVerificationCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantVerificationDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/review": { - "post": { - "tags": [ - "Tenants" - ], - "summary": "审核租户。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReviewTenantCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReviewTenantCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReviewTenantCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReviewTenantCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/subscriptions": { - "post": { - "tags": [ - "Tenants" - ], - "summary": "创建或续费租户订阅。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantSubscriptionCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantSubscriptionCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantSubscriptionCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CreateTenantSubscriptionCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantSubscriptionDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/subscriptions/{subscriptionId}/plan": { - "put": { - "tags": [ - "Tenants" - ], - "summary": "套餐升降配。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "subscriptionId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ChangeTenantSubscriptionPlanCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ChangeTenantSubscriptionPlanCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ChangeTenantSubscriptionPlanCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ChangeTenantSubscriptionPlanCommand" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantSubscriptionDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/audits": { - "get": { - "tags": [ - "Tenants" - ], - "summary": "查询审核日志。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "pageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 20 - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/TenantAuditLogDtoPagedResultApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/tenants/{tenantId}/quotas/check": { - "post": { - "tags": [ - "Tenants" - ], - "summary": "配额校验并占用额度(门店/账号/短信/配送)。", - "description": "需在请求头携带 X-Tenant-Id 对应的租户。", - "parameters": [ - { - "name": "tenantId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CheckTenantQuotaCommand" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CheckTenantQuotaCommand" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CheckTenantQuotaCommand" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CheckTenantQuotaCommand" - } - } - }, - "required": true - }, - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuotaCheckResultDtoApiResponse" - } - } - } - } - } - } - }, - "/api/admin/v1/users/permissions": { - "get": { - "tags": [ - "UserPermissions" - ], - "summary": "分页查询当前租户用户的角色与权限概览。", - "description": "示例:\n```\nGET /api/admin/v1/users/permissions?keyword=ops&page=1&pageSize=20&sortBy=createdAt&sortDescending=true\nHeader: Authorization: Bearer \n响应:\n{\n \"success\": true,\n \"code\": 200,\n \"data\": {\n \"items\": [\n {\n \"userId\": \"900123456789012346\",\n \"tenantId\": \"100000000000000001\",\n \"merchantId\": \"200000000000000001\",\n \"account\": \"ops.manager\",\n \"displayName\": \"运营经理\",\n \"roles\": [\"OpsManager\", \"Reporter\"],\n \"permissions\": [\"delivery:read\", \"order:read\", \"payment:read\"],\n \"createdAt\": \"2025-12-01T08:30:00Z\"\n }\n ],\n \"page\": 1,\n \"pageSize\": 20,\n \"totalCount\": 1,\n \"totalPages\": 1\n }\n}\n```", - "parameters": [ - { - "name": "Keyword", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "Page", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "SortBy", - "in": "query", - "schema": { - "type": "string" - } - }, - { - "name": "SortDescending", - "in": "query", - "schema": { - "type": "boolean" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UserPermissionDtoPagedResultApiResponse" - } - } - } - } - } - } - } - }, - "components": { - "schemas": { - "AddMerchantDocumentCommand": { - "required": [ - "documentType", - "fileUrl", - "merchantId" - ], - "type": "object", - "properties": { - "merchantId": { - "type": "integer", - "format": "int64" - }, - "documentType": { - "$ref": "#/components/schemas/MerchantDocumentType" - }, - "fileUrl": { - "maxLength": 512, - "minLength": 1, - "type": "string" - }, - "documentNumber": { - "maxLength": 64, - "type": "string", - "nullable": true - }, - "issuedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "expiresAt": { - "type": "string", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "AdjustInventoryCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "productSkuId": { - "type": "integer", - "format": "int64" - }, - "quantityDelta": { - "type": "integer", - "format": "int32" - }, - "adjustmentType": { - "$ref": "#/components/schemas/InventoryAdjustmentType" - }, - "reason": { - "type": "string", - "nullable": true - }, - "safetyStock": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "isSoldOut": { - "type": "boolean", - "nullable": true - } - }, - "additionalProperties": false - }, - "AdminLoginRequest": { - "required": [ - "account", - "password" - ], - "type": "object", - "properties": { - "account": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "password": { - "maxLength": 128, - "minLength": 1, - "type": "string" - } - }, - "additionalProperties": false - }, - "BindInitialTenantSubscriptionCommand": { - "required": [ - "tenantId", - "tenantPackageId" - ], - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "tenantPackageId": { - "type": "integer", - "format": "int64" - }, - "autoRenew": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "BindRolePermissionsCommand": { - "type": "object", - "properties": { - "roleId": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "permissionIds": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "BooleanApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "boolean", - "description": "业务数据。" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "BusinessHourType": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "营业时段类型。", - "format": "int32" - }, - "ChangeTenantSubscriptionPlanCommand": { - "required": [ - "targetPackageId", - "tenantId", - "tenantSubscriptionId" - ], - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "tenantSubscriptionId": { - "type": "integer", - "format": "int64" - }, - "targetPackageId": { - "type": "integer", - "format": "int64" - }, - "immediate": { - "type": "boolean" - }, - "notes": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CheckTenantQuotaCommand": { - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "quotaType": { - "$ref": "#/components/schemas/TenantQuotaType" - }, - "delta": { - "type": "number", - "format": "double" - } - }, - "additionalProperties": false - }, - "CloneRoleTemplateCommand": { - "type": "object", - "properties": { - "sourceTemplateCode": { - "type": "string", - "nullable": true - }, - "newTemplateCode": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "isActive": { - "type": "boolean", - "nullable": true - }, - "permissionCodes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ContractStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "商户合同状态。", - "format": "int32" - }, - "CreateDeliveryOrderCommand": { - "type": "object", - "properties": { - "orderId": { - "type": "integer", - "format": "int64" - }, - "provider": { - "$ref": "#/components/schemas/DeliveryProvider" - }, - "providerOrderId": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/DeliveryStatus" - }, - "deliveryFee": { - "type": "number", - "format": "double", - "nullable": true - }, - "courierName": { - "type": "string", - "nullable": true - }, - "courierPhone": { - "type": "string", - "nullable": true - }, - "dispatchedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "pickedUpAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "deliveredAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "failureReason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateDictionaryGroupRequest": { - "required": [ - "code", - "name", - "scope" - ], - "type": "object", - "properties": { - "code": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "name": { - "maxLength": 128, - "minLength": 1, - "type": "string" - }, - "scope": { - "$ref": "#/components/schemas/DictionaryScope" - }, - "description": { - "maxLength": 512, - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateDictionaryItemRequest": { - "required": [ - "groupId", - "key", - "value" - ], - "type": "object", - "properties": { - "groupId": { - "type": "integer", - "format": "int64" - }, - "key": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "value": { - "maxLength": 256, - "minLength": 1, - "type": "string" - }, - "isDefault": { - "type": "boolean" - }, - "isEnabled": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "description": { - "maxLength": 512, - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateMenuCommand": { - "type": "object", - "properties": { - "parentId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "path": { - "type": "string", - "nullable": true - }, - "component": { - "type": "string", - "nullable": true - }, - "title": { - "type": "string", - "nullable": true - }, - "icon": { - "type": "string", - "nullable": true - }, - "isIframe": { - "type": "boolean" - }, - "link": { - "type": "string", - "nullable": true - }, - "keepAlive": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "requiredPermissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "metaPermissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "metaRoles": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "authList": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MenuAuthItemDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateMerchantCategoryCommand": { - "required": [ - "name" - ], - "type": "object", - "properties": { - "name": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "displayOrder": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "isActive": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "CreateMerchantCommand": { - "required": [ - "brandName", - "contactPhone" - ], - "type": "object", - "properties": { - "brandName": { - "maxLength": 128, - "minLength": 1, - "type": "string" - }, - "brandAlias": { - "maxLength": 64, - "type": "string", - "nullable": true - }, - "logoUrl": { - "maxLength": 256, - "type": "string", - "nullable": true - }, - "category": { - "maxLength": 64, - "type": "string", - "nullable": true - }, - "contactPhone": { - "maxLength": 32, - "minLength": 1, - "type": "string" - }, - "contactEmail": { - "maxLength": 128, - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/MerchantStatus" - } - }, - "additionalProperties": false - }, - "CreateMerchantContractCommand": { - "required": [ - "contractNumber", - "fileUrl", - "merchantId" - ], - "type": "object", - "properties": { - "merchantId": { - "type": "integer", - "format": "int64" - }, - "contractNumber": { - "maxLength": 64, - "minLength": 1, - "type": "string" - }, - "startDate": { - "type": "string", - "format": "date-time" - }, - "endDate": { - "type": "string", - "format": "date-time" - }, - "fileUrl": { - "maxLength": 512, - "minLength": 1, - "type": "string" - } - }, - "additionalProperties": false - }, - "CreateOrderCommand": { - "type": "object", - "properties": { - "orderNo": { - "type": "string", - "nullable": true - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "channel": { - "$ref": "#/components/schemas/OrderChannel" - }, - "deliveryType": { - "$ref": "#/components/schemas/DeliveryType" - }, - "status": { - "$ref": "#/components/schemas/OrderStatus" - }, - "paymentStatus": { - "$ref": "#/components/schemas/PaymentStatus" - }, - "customerName": { - "type": "string", - "nullable": true - }, - "customerPhone": { - "type": "string", - "nullable": true - }, - "tableNo": { - "type": "string", - "nullable": true - }, - "queueNumber": { - "type": "string", - "nullable": true - }, - "reservationId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "itemsAmount": { - "type": "number", - "format": "double" - }, - "discountAmount": { - "type": "number", - "format": "double" - }, - "payableAmount": { - "type": "number", - "format": "double" - }, - "paidAmount": { - "type": "number", - "format": "double" - }, - "paidAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "finishedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "cancelledAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "cancelReason": { - "type": "string", - "nullable": true - }, - "remark": { - "type": "string", - "nullable": true - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderItemRequest" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "CreatePaymentCommand": { - "type": "object", - "properties": { - "orderId": { - "type": "integer", - "format": "int64" - }, - "method": { - "$ref": "#/components/schemas/PaymentMethod" - }, - "status": { - "$ref": "#/components/schemas/PaymentStatus" - }, - "amount": { - "type": "number", - "format": "double" - }, - "tradeNo": { - "type": "string", - "nullable": true - }, - "channelTransactionId": { - "type": "string", - "nullable": true - }, - "paidAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "remark": { - "type": "string", - "nullable": true - }, - "payload": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreatePermissionCommand": { - "type": "object", - "properties": { - "parentId": { - "type": "integer", - "format": "int64" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "type": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "code": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateProductCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "categoryId": { - "type": "integer", - "format": "int64" - }, - "spuCode": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "subtitle": { - "type": "string", - "nullable": true - }, - "unit": { - "type": "string", - "nullable": true - }, - "price": { - "type": "number", - "format": "double" - }, - "originalPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "stockQuantity": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxQuantityPerOrder": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/ProductStatus" - }, - "coverImage": { - "type": "string", - "nullable": true - }, - "galleryImages": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "enableDineIn": { - "type": "boolean" - }, - "enablePickup": { - "type": "boolean" - }, - "enableDelivery": { - "type": "boolean" - }, - "isFeatured": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "CreateRoleCommand": { - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "code": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateRoleTemplateCommand": { - "type": "object", - "properties": { - "templateCode": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "isActive": { - "type": "boolean" - }, - "permissionCodes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateStoreBusinessHourCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "dayOfWeek": { - "$ref": "#/components/schemas/DayOfWeek" - }, - "hourType": { - "$ref": "#/components/schemas/BusinessHourType" - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "capacityLimit": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "notes": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateStoreCommand": { - "type": "object", - "properties": { - "merchantId": { - "type": "integer", - "format": "int64" - }, - "code": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "phone": { - "type": "string", - "nullable": true - }, - "managerName": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/StoreStatus" - }, - "province": { - "type": "string", - "nullable": true - }, - "city": { - "type": "string", - "nullable": true - }, - "district": { - "type": "string", - "nullable": true - }, - "address": { - "type": "string", - "nullable": true - }, - "longitude": { - "type": "number", - "format": "double", - "nullable": true - }, - "latitude": { - "type": "number", - "format": "double", - "nullable": true - }, - "announcement": { - "type": "string", - "nullable": true - }, - "tags": { - "type": "string", - "nullable": true - }, - "deliveryRadiusKm": { - "type": "number", - "format": "double" - }, - "supportsDineIn": { - "type": "boolean" - }, - "supportsPickup": { - "type": "boolean" - }, - "supportsDelivery": { - "type": "boolean" - }, - "supportsReservation": { - "type": "boolean" - }, - "supportsQueueing": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "CreateStoreDeliveryZoneCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "zoneName": { - "type": "string", - "nullable": true - }, - "polygonGeoJson": { - "type": "string", - "nullable": true - }, - "minimumOrderAmount": { - "type": "number", - "format": "double", - "nullable": true - }, - "deliveryFee": { - "type": "number", - "format": "double", - "nullable": true - }, - "estimatedMinutes": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "CreateStoreEmployeeShiftCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "staffId": { - "type": "integer", - "format": "int64" - }, - "shiftDate": { - "type": "string", - "format": "date-time" - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "roleType": { - "$ref": "#/components/schemas/StaffRoleType" - }, - "notes": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateStoreHolidayCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "date": { - "type": "string", - "format": "date-time" - }, - "isClosed": { - "type": "boolean" - }, - "reason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateStorePickupSlotCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "cutoffMinutes": { - "type": "integer", - "format": "int32" - }, - "capacity": { - "type": "integer", - "format": "int32" - }, - "weekdays": { - "type": "string", - "nullable": true - }, - "isEnabled": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "CreateStoreStaffCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "phone": { - "type": "string", - "nullable": true - }, - "email": { - "type": "string", - "nullable": true - }, - "roleType": { - "$ref": "#/components/schemas/StaffRoleType" - } - }, - "additionalProperties": false - }, - "CreateStoreTableAreaCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "CreateSystemParameterCommand": { - "type": "object", - "properties": { - "key": { - "type": "string", - "nullable": true - }, - "value": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "isEnabled": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "CreateTenantAnnouncementCommand": { - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "title": { - "type": "string", - "nullable": true - }, - "content": { - "type": "string", - "nullable": true - }, - "announcementType": { - "$ref": "#/components/schemas/TenantAnnouncementType" - }, - "priority": { - "type": "integer", - "format": "int32" - }, - "effectiveFrom": { - "type": "string", - "format": "date-time" - }, - "effectiveTo": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "isActive": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "CreateTenantBillingCommand": { - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "statementNo": { - "type": "string", - "nullable": true - }, - "periodStart": { - "type": "string", - "format": "date-time" - }, - "periodEnd": { - "type": "string", - "format": "date-time" - }, - "amountDue": { - "type": "number", - "format": "double" - }, - "amountPaid": { - "type": "number", - "format": "double" - }, - "status": { - "$ref": "#/components/schemas/TenantBillingStatus" - }, - "dueDate": { - "type": "string", - "format": "date-time" - }, - "lineItemsJson": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CreateTenantPackageCommand": { - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "packageType": { - "$ref": "#/components/schemas/TenantPackageType" - }, - "monthlyPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "yearlyPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "maxStoreCount": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxAccountCount": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxStorageGb": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxSmsCredits": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxDeliveryOrders": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "featurePoliciesJson": { - "type": "string", - "nullable": true - }, - "isActive": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "CreateTenantSubscriptionCommand": { - "required": [ - "tenantId", - "tenantPackageId" - ], - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "tenantPackageId": { - "type": "integer", - "format": "int64" - }, - "durationMonths": { - "type": "integer", - "format": "int32" - }, - "autoRenew": { - "type": "boolean" - }, - "notes": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CurrentUserProfile": { - "type": "object", - "properties": { - "userId": { - "type": "integer", - "format": "int64" - }, - "account": { - "type": "string", - "nullable": true - }, - "displayName": { - "type": "string", - "nullable": true - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "merchantId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "roles": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "permissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "avatar": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "CurrentUserProfileApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/CurrentUserProfile" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "DayOfWeek": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "type": "integer", - "format": "int32" - }, - "DeductInventoryCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "productSkuId": { - "type": "integer", - "format": "int64" - }, - "quantity": { - "type": "integer", - "format": "int32" - }, - "isPresaleOrder": { - "type": "boolean" - }, - "idempotencyKey": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "DeliveryEventDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "deliveryOrderId": { - "type": "integer", - "format": "int64" - }, - "eventType": { - "$ref": "#/components/schemas/DeliveryEventType" - }, - "message": { - "type": "string", - "nullable": true - }, - "occurredAt": { - "type": "string", - "format": "date-time" - }, - "payload": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "DeliveryEventType": { - "enum": [ - 0, - 1, - 2 - ], - "type": "integer", - "description": "配送事件类型。", - "format": "int32" - }, - "DeliveryOrderDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "orderId": { - "type": "integer", - "format": "int64" - }, - "provider": { - "$ref": "#/components/schemas/DeliveryProvider" - }, - "providerOrderId": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/DeliveryStatus" - }, - "deliveryFee": { - "type": "number", - "format": "double", - "nullable": true - }, - "courierName": { - "type": "string", - "nullable": true - }, - "courierPhone": { - "type": "string", - "nullable": true - }, - "dispatchedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "pickedUpAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "deliveredAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "failureReason": { - "type": "string", - "nullable": true - }, - "events": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DeliveryEventDto" - }, - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "DeliveryOrderDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/DeliveryOrderDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "DeliveryOrderDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DeliveryOrderDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "DeliveryOrderDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/DeliveryOrderDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "DeliveryProvider": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5 - ], - "type": "integer", - "description": "配送服务商类型。", - "format": "int32" - }, - "DeliveryStatus": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6 - ], - "type": "integer", - "description": "配送状态。", - "format": "int32" - }, - "DeliveryType": { - "enum": [ - 0, - 1, - 2 - ], - "type": "integer", - "description": "履约/交付方式。", - "format": "int32" - }, - "DictionaryBatchQueryRequest": { - "required": [ - "codes" - ], - "type": "object", - "properties": { - "codes": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "additionalProperties": false - }, - "DictionaryGroupDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "code": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "scope": { - "$ref": "#/components/schemas/DictionaryScope" - }, - "description": { - "type": "string", - "nullable": true - }, - "isEnabled": { - "type": "boolean" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DictionaryItemDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "DictionaryGroupDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/DictionaryGroupDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "DictionaryGroupDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DictionaryGroupDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "DictionaryItemDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "groupId": { - "type": "integer", - "format": "int64" - }, - "key": { - "type": "string", - "nullable": true - }, - "value": { - "type": "string", - "nullable": true - }, - "isDefault": { - "type": "boolean" - }, - "isEnabled": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "description": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "DictionaryItemDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/DictionaryItemDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "DictionaryScope": { - "enum": [ - 1, - 2 - ], - "type": "integer", - "description": "参数字典作用域。", - "format": "int32" - }, - "ExportStoreTableQRCodesQuery": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "areaId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "qrContentTemplate": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "FileUploadResponse": { - "type": "object", - "properties": { - "url": { - "type": "string", - "nullable": true - }, - "fileName": { - "type": "string", - "nullable": true - }, - "fileSize": { - "type": "integer", - "format": "int64" - } - }, - "additionalProperties": false - }, - "FileUploadResponseApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/FileUploadResponse" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "GenerateStoreTablesCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "tableCodePrefix": { - "type": "string", - "nullable": true - }, - "startNumber": { - "type": "integer", - "format": "int32" - }, - "count": { - "type": "integer", - "format": "int32" - }, - "defaultCapacity": { - "type": "integer", - "format": "int32" - }, - "areaId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "tags": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "InitializeRoleTemplatesCommand": { - "type": "object", - "properties": { - "templateCodes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "Int32ApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "integer", - "description": "业务数据。", - "format": "int32" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "InventoryAdjustmentType": { - "enum": [ - 0, - 1, - 2, - 3, - 4 - ], - "type": "integer", - "description": "库存调整类型。", - "format": "int32" - }, - "InventoryBatchDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "productSkuId": { - "type": "integer", - "format": "int64" - }, - "batchNumber": { - "type": "string", - "nullable": true - }, - "productionDate": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "expireDate": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "quantity": { - "type": "integer", - "format": "int32" - }, - "remainingQuantity": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "InventoryBatchDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/InventoryBatchDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "InventoryBatchDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/InventoryBatchDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "InventoryItemDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "productSkuId": { - "type": "integer", - "format": "int64" - }, - "batchNumber": { - "type": "string", - "nullable": true - }, - "quantityOnHand": { - "type": "integer", - "format": "int32" - }, - "quantityReserved": { - "type": "integer", - "format": "int32" - }, - "safetyStock": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "location": { - "type": "string", - "nullable": true - }, - "expireDate": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "isPresale": { - "type": "boolean" - }, - "presaleStartTime": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "presaleEndTime": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "presaleCapacity": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "presaleLocked": { - "type": "integer", - "format": "int32" - }, - "maxQuantityPerOrder": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "isSoldOut": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "InventoryItemDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/InventoryItemDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "LockInventoryCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "productSkuId": { - "type": "integer", - "format": "int64" - }, - "quantity": { - "type": "integer", - "format": "int32" - }, - "isPresaleOrder": { - "type": "boolean" - }, - "expiresAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "idempotencyKey": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "MarkTenantBillingPaidCommand": { - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "billingId": { - "type": "integer", - "format": "int64" - }, - "amountPaid": { - "type": "number", - "format": "double" - }, - "paidAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "MediaAssetType": { - "enum": [ - 0, - 1, - 2 - ], - "type": "integer", - "description": "商品媒资类型。", - "format": "int32" - }, - "MenuAuthItemDto": { - "required": [ - "authMark", - "title" - ], - "type": "object", - "properties": { - "title": { - "type": "string", - "nullable": true - }, - "authMark": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "MenuDefinitionDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "parentId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "path": { - "type": "string", - "nullable": true - }, - "component": { - "type": "string", - "nullable": true - }, - "title": { - "type": "string", - "nullable": true - }, - "icon": { - "type": "string", - "nullable": true - }, - "isIframe": { - "type": "boolean" - }, - "link": { - "type": "string", - "nullable": true - }, - "keepAlive": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "requiredPermissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "metaPermissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "metaRoles": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "authList": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MenuAuthItemDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "MenuDefinitionDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/MenuDefinitionDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MenuDefinitionDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MenuDefinitionDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MenuMetaDto": { - "required": [ - "title" - ], - "type": "object", - "properties": { - "title": { - "type": "string", - "nullable": true - }, - "icon": { - "type": "string", - "nullable": true - }, - "keepAlive": { - "type": "boolean" - }, - "isIframe": { - "type": "boolean" - }, - "link": { - "type": "string", - "nullable": true - }, - "roles": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "authList": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MenuAuthItemDto" - }, - "nullable": true - }, - "permissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "MenuNodeDto": { - "required": [ - "component", - "meta", - "name", - "path" - ], - "type": "object", - "properties": { - "name": { - "type": "string", - "nullable": true - }, - "path": { - "type": "string", - "nullable": true - }, - "component": { - "type": "string", - "nullable": true - }, - "meta": { - "$ref": "#/components/schemas/MenuMetaDto" - }, - "children": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MenuNodeDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "MenuNodeDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MenuNodeDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantAuditAction": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5 - ], - "type": "integer", - "description": "商户审核日志动作。", - "format": "int32" - }, - "MerchantAuditLogDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "merchantId": { - "type": "integer", - "format": "int64" - }, - "action": { - "$ref": "#/components/schemas/MerchantAuditAction" - }, - "title": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "operatorName": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "MerchantAuditLogDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MerchantAuditLogDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "MerchantAuditLogDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/MerchantAuditLogDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantCategoryDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "displayOrder": { - "type": "integer", - "format": "int32" - }, - "isActive": { - "type": "boolean" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "MerchantCategoryDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/MerchantCategoryDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantCategoryDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MerchantCategoryDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantCategoryOrderItem": { - "required": [ - "categoryId" - ], - "type": "object", - "properties": { - "categoryId": { - "type": "integer", - "format": "int64" - }, - "displayOrder": { - "maximum": 100000, - "minimum": -1000, - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "MerchantContractDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "merchantId": { - "type": "integer", - "format": "int64" - }, - "contractNumber": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/ContractStatus" - }, - "startDate": { - "type": "string", - "format": "date-time" - }, - "endDate": { - "type": "string", - "format": "date-time" - }, - "fileUrl": { - "type": "string", - "nullable": true - }, - "signedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "terminatedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "terminationReason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "MerchantContractDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/MerchantContractDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantContractDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MerchantContractDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantDetailDto": { - "type": "object", - "properties": { - "merchant": { - "$ref": "#/components/schemas/MerchantDto" - }, - "documents": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MerchantDocumentDto" - }, - "nullable": true - }, - "contracts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MerchantContractDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "MerchantDetailDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/MerchantDetailDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantDocumentDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "merchantId": { - "type": "integer", - "format": "int64" - }, - "documentType": { - "$ref": "#/components/schemas/MerchantDocumentType" - }, - "status": { - "$ref": "#/components/schemas/MerchantDocumentStatus" - }, - "fileUrl": { - "type": "string", - "nullable": true - }, - "documentNumber": { - "type": "string", - "nullable": true - }, - "issuedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "expiresAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "remarks": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "MerchantDocumentDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/MerchantDocumentDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantDocumentDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MerchantDocumentDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantDocumentStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "证照审核状态。", - "format": "int32" - }, - "MerchantDocumentType": { - "enum": [ - 0, - 1, - 2, - 99 - ], - "type": "integer", - "description": "商户证照类型。", - "format": "int32" - }, - "MerchantDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "brandName": { - "type": "string", - "nullable": true - }, - "brandAlias": { - "type": "string", - "nullable": true - }, - "logoUrl": { - "type": "string", - "nullable": true - }, - "category": { - "type": "string", - "nullable": true - }, - "contactPhone": { - "type": "string", - "nullable": true - }, - "contactEmail": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/MerchantStatus" - }, - "joinedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "MerchantDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/MerchantDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MerchantDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "MerchantStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "商户入驻状态。", - "format": "int32" - }, - "ObjectApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "OrderChannel": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5 - ], - "type": "integer", - "description": "下单渠道。", - "format": "int32" - }, - "OrderDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "orderNo": { - "type": "string", - "nullable": true - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "channel": { - "$ref": "#/components/schemas/OrderChannel" - }, - "deliveryType": { - "$ref": "#/components/schemas/DeliveryType" - }, - "status": { - "$ref": "#/components/schemas/OrderStatus" - }, - "paymentStatus": { - "$ref": "#/components/schemas/PaymentStatus" - }, - "customerName": { - "type": "string", - "nullable": true - }, - "customerPhone": { - "type": "string", - "nullable": true - }, - "tableNo": { - "type": "string", - "nullable": true - }, - "queueNumber": { - "type": "string", - "nullable": true - }, - "reservationId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "itemsAmount": { - "type": "number", - "format": "double" - }, - "discountAmount": { - "type": "number", - "format": "double" - }, - "payableAmount": { - "type": "number", - "format": "double" - }, - "paidAmount": { - "type": "number", - "format": "double" - }, - "paidAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "finishedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "cancelledAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "cancelReason": { - "type": "string", - "nullable": true - }, - "remark": { - "type": "string", - "nullable": true - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderItemDto" - }, - "nullable": true - }, - "statusHistory": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderStatusHistoryDto" - }, - "nullable": true - }, - "refunds": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RefundRequestDto" - }, - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "OrderDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/OrderDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "OrderDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "OrderDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/OrderDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "OrderItemDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "orderId": { - "type": "integer", - "format": "int64" - }, - "productId": { - "type": "integer", - "format": "int64" - }, - "productName": { - "type": "string", - "nullable": true - }, - "skuName": { - "type": "string", - "nullable": true - }, - "unit": { - "type": "string", - "nullable": true - }, - "quantity": { - "type": "integer", - "format": "int32" - }, - "unitPrice": { - "type": "number", - "format": "double" - }, - "discountAmount": { - "type": "number", - "format": "double" - }, - "subTotal": { - "type": "number", - "format": "double" - }, - "attributesJson": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "OrderItemRequest": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "productName": { - "type": "string", - "nullable": true - }, - "skuName": { - "type": "string", - "nullable": true - }, - "unit": { - "type": "string", - "nullable": true - }, - "quantity": { - "type": "integer", - "format": "int32" - }, - "unitPrice": { - "type": "number", - "format": "double" - }, - "discountAmount": { - "type": "number", - "format": "double" - }, - "subTotal": { - "type": "number", - "format": "double" - }, - "attributesJson": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "OrderStatus": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5 - ], - "type": "integer", - "description": "订单状态。", - "format": "int32" - }, - "OrderStatusHistoryDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "orderId": { - "type": "integer", - "format": "int64" - }, - "status": { - "$ref": "#/components/schemas/OrderStatus" - }, - "operatorId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "notes": { - "type": "string", - "nullable": true - }, - "occurredAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "PaymentDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "orderId": { - "type": "integer", - "format": "int64" - }, - "method": { - "$ref": "#/components/schemas/PaymentMethod" - }, - "status": { - "$ref": "#/components/schemas/PaymentStatus" - }, - "amount": { - "type": "number", - "format": "double" - }, - "tradeNo": { - "type": "string", - "nullable": true - }, - "channelTransactionId": { - "type": "string", - "nullable": true - }, - "paidAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "remark": { - "type": "string", - "nullable": true - }, - "payload": { - "type": "string", - "nullable": true - }, - "refunds": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentRefundDto" - }, - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "PaymentDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/PaymentDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "PaymentDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "PaymentDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/PaymentDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "PaymentMethod": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5 - ], - "type": "integer", - "description": "支付方式。", - "format": "int32" - }, - "PaymentRefundDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "paymentRecordId": { - "type": "integer", - "format": "int64" - }, - "orderId": { - "type": "integer", - "format": "int64" - }, - "amount": { - "type": "number", - "format": "double" - }, - "channelRefundId": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/PaymentRefundStatus" - }, - "payload": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "PaymentRefundStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "支付退款状态。", - "format": "int32" - }, - "PaymentStatus": { - "enum": [ - 0, - 1, - 2, - 3, - 4 - ], - "type": "integer", - "description": "支付记录状态。", - "format": "int32" - }, - "PermissionDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "parentId": { - "type": "integer", - "format": "int64" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "type": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "code": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "PermissionDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/PermissionDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "PermissionDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "PermissionDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "PermissionDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/PermissionDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "PermissionTemplateDto": { - "type": "object", - "properties": { - "code": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "PermissionTemplateDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionTemplateDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "PermissionTreeDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "parentId": { - "type": "integer", - "format": "int64" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "type": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "code": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "children": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionTreeDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "PermissionTreeDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionTreeDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "PricingRuleType": { - "enum": [ - 0, - 1, - 2, - 3, - 4 - ], - "type": "integer", - "description": "价格策略类型。", - "format": "int32" - }, - "ProductAddonGroupDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "productId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "minSelect": { - "type": "integer", - "format": "int32" - }, - "maxSelect": { - "type": "integer", - "format": "int32" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "options": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductAddonOptionDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ProductAddonGroupDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductAddonGroupDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "ProductAddonOptionDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "addonGroupId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "extraPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "ProductAttributeGroupDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "productId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "selectionType": { - "type": "integer", - "format": "int32" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "options": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductAttributeOptionDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ProductAttributeGroupDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductAttributeGroupDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "ProductAttributeOptionDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "attributeGroupId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "ProductDetailDto": { - "type": "object", - "properties": { - "product": { - "$ref": "#/components/schemas/ProductDto" - }, - "skus": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductSkuDto" - }, - "nullable": true - }, - "attributeGroups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductAttributeGroupDto" - }, - "nullable": true - }, - "addonGroups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductAddonGroupDto" - }, - "nullable": true - }, - "pricingRules": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductPricingRuleDto" - }, - "nullable": true - }, - "mediaAssets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductMediaAssetDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ProductDetailDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/ProductDetailDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "ProductDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "categoryId": { - "type": "integer", - "format": "int64" - }, - "spuCode": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "subtitle": { - "type": "string", - "nullable": true - }, - "unit": { - "type": "string", - "nullable": true - }, - "price": { - "type": "number", - "format": "double" - }, - "originalPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "stockQuantity": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxQuantityPerOrder": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/ProductStatus" - }, - "coverImage": { - "type": "string", - "nullable": true - }, - "galleryImages": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "enableDineIn": { - "type": "boolean" - }, - "enablePickup": { - "type": "boolean" - }, - "enableDelivery": { - "type": "boolean" - }, - "isFeatured": { - "type": "boolean" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "ProductDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/ProductDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "ProductDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "ProductDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/ProductDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "ProductMediaAssetDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "productId": { - "type": "integer", - "format": "int64" - }, - "mediaType": { - "$ref": "#/components/schemas/MediaAssetType" - }, - "url": { - "type": "string", - "nullable": true - }, - "caption": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "ProductMediaAssetDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductMediaAssetDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "ProductPricingRuleDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "productId": { - "type": "integer", - "format": "int64" - }, - "ruleType": { - "$ref": "#/components/schemas/PricingRuleType" - }, - "price": { - "type": "number", - "format": "double" - }, - "conditionsJson": { - "type": "string", - "nullable": true - }, - "weekdaysJson": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "ProductPricingRuleDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductPricingRuleDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "ProductSkuDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "productId": { - "type": "integer", - "format": "int64" - }, - "skuCode": { - "type": "string", - "nullable": true - }, - "barcode": { - "type": "string", - "nullable": true - }, - "price": { - "type": "number", - "format": "double" - }, - "originalPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "stockQuantity": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "weight": { - "type": "number", - "format": "double", - "nullable": true - }, - "attributesJson": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "ProductSkuDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductSkuDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "ProductStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "商品状态。", - "format": "int32" - }, - "PublishProductCommand": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "reason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "QuotaCheckResultDto": { - "type": "object", - "properties": { - "quotaType": { - "$ref": "#/components/schemas/TenantQuotaType" - }, - "limit": { - "type": "number", - "format": "double", - "nullable": true - }, - "used": { - "type": "number", - "format": "double" - }, - "remaining": { - "type": "number", - "format": "double", - "nullable": true - } - }, - "additionalProperties": false - }, - "QuotaCheckResultDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/QuotaCheckResultDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "RefreshTokenRequest": { - "required": [ - "refreshToken" - ], - "type": "object", - "properties": { - "refreshToken": { - "maxLength": 256, - "minLength": 1, - "type": "string" - } - }, - "additionalProperties": false - }, - "RefundRequestDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "orderId": { - "type": "integer", - "format": "int64" - }, - "refundNo": { - "type": "string", - "nullable": true - }, - "amount": { - "type": "number", - "format": "double" - }, - "reason": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/RefundStatus" - }, - "requestedAt": { - "type": "string", - "format": "date-time" - }, - "processedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "reviewNotes": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "RefundStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "退款申请状态。", - "format": "int32" - }, - "RegisterTenantCommand": { - "required": [ - "code", - "name", - "tenantPackageId" - ], - "type": "object", - "properties": { - "code": { - "maxLength": 64, - "minLength": 0, - "type": "string" - }, - "name": { - "maxLength": 128, - "minLength": 0, - "type": "string" - }, - "shortName": { - "type": "string", - "nullable": true - }, - "industry": { - "type": "string", - "nullable": true - }, - "contactName": { - "type": "string", - "nullable": true - }, - "contactPhone": { - "type": "string", - "nullable": true - }, - "contactEmail": { - "type": "string", - "nullable": true - }, - "tenantPackageId": { - "type": "integer", - "format": "int64" - }, - "durationMonths": { - "type": "integer", - "format": "int32" - }, - "autoRenew": { - "type": "boolean" - }, - "effectiveFrom": { - "type": "string", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "ReleaseInventoryCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "productSkuId": { - "type": "integer", - "format": "int64" - }, - "quantity": { - "type": "integer", - "format": "int32" - }, - "isPresaleOrder": { - "type": "boolean" - }, - "idempotencyKey": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "ReorderMerchantCategoriesCommand": { - "required": [ - "items" - ], - "type": "object", - "properties": { - "items": { - "minItems": 1, - "type": "array", - "items": { - "$ref": "#/components/schemas/MerchantCategoryOrderItem" - } - } - }, - "additionalProperties": false - }, - "ReplaceProductAddonsCommand": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "addonGroups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductAddonGroupDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ReplaceProductAttributesCommand": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "attributeGroups": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductAttributeGroupDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ReplaceProductMediaCommand": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "mediaAssets": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductMediaAssetDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ReplaceProductPricingRulesCommand": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "pricingRules": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductPricingRuleDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ReplaceProductSkusCommand": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "skus": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProductSkuDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "ReviewMerchantCommand": { - "required": [ - "merchantId" - ], - "type": "object", - "properties": { - "merchantId": { - "type": "integer", - "format": "int64" - }, - "approve": { - "type": "boolean" - }, - "remarks": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "ReviewMerchantDocumentCommand": { - "required": [ - "documentId", - "merchantId" - ], - "type": "object", - "properties": { - "merchantId": { - "type": "integer", - "format": "int64" - }, - "documentId": { - "type": "integer", - "format": "int64" - }, - "approve": { - "type": "boolean" - }, - "remarks": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "ReviewTenantCommand": { - "required": [ - "tenantId" - ], - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "approve": { - "type": "boolean" - }, - "reason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "RoleDetailDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "code": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "permissions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "RoleDetailDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/RoleDetailDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "RoleDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "code": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "RoleDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/RoleDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "RoleDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RoleDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "RoleDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RoleDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "RoleDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/RoleDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "RoleTemplateDto": { - "type": "object", - "properties": { - "templateCode": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "isActive": { - "type": "boolean" - }, - "permissions": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PermissionTemplateDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "RoleTemplateDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/RoleTemplateDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "RoleTemplateDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RoleTemplateDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "SelfRegisterResultDto": { - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "code": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/TenantStatus" - }, - "verificationStatus": { - "$ref": "#/components/schemas/TenantVerificationStatus" - }, - "effectiveFrom": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "effectiveTo": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "adminAccount": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "SelfRegisterResultDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/SelfRegisterResultDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "SelfRegisterTenantCommand": { - "required": [ - "adminAccount", - "adminPassword", - "adminPhone" - ], - "type": "object", - "properties": { - "adminAccount": { - "maxLength": 64, - "minLength": 0, - "pattern": "^[A-Za-z0-9]+$", - "type": "string" - }, - "adminDisplayName": { - "maxLength": 64, - "minLength": 0, - "type": "string", - "nullable": true - }, - "adminEmail": { - "maxLength": 128, - "minLength": 0, - "type": "string", - "format": "email", - "nullable": true - }, - "adminPhone": { - "maxLength": 32, - "minLength": 0, - "type": "string" - }, - "adminPassword": { - "maxLength": 128, - "minLength": 8, - "type": "string" - } - }, - "additionalProperties": false - }, - "StaffRoleType": { - "enum": [ - 0, - 1, - 2, - 3, - 4 - ], - "type": "integer", - "description": "商户员工角色。", - "format": "int32" - }, - "StaffStatus": { - "enum": [ - 0, - 1, - 2 - ], - "type": "integer", - "description": "员工账号状态。", - "format": "int32" - }, - "StoreBusinessHourDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "dayOfWeek": { - "$ref": "#/components/schemas/DayOfWeek" - }, - "hourType": { - "$ref": "#/components/schemas/BusinessHourType" - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "capacityLimit": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "notes": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "StoreBusinessHourDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreBusinessHourDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreBusinessHourDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StoreBusinessHourDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreDeliveryZoneDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "zoneName": { - "type": "string", - "nullable": true - }, - "polygonGeoJson": { - "type": "string", - "nullable": true - }, - "minimumOrderAmount": { - "type": "number", - "format": "double", - "nullable": true - }, - "deliveryFee": { - "type": "number", - "format": "double", - "nullable": true - }, - "estimatedMinutes": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "StoreDeliveryZoneDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreDeliveryZoneDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreDeliveryZoneDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StoreDeliveryZoneDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "merchantId": { - "type": "integer", - "format": "int64" - }, - "code": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "phone": { - "type": "string", - "nullable": true - }, - "managerName": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/StoreStatus" - }, - "province": { - "type": "string", - "nullable": true - }, - "city": { - "type": "string", - "nullable": true - }, - "district": { - "type": "string", - "nullable": true - }, - "address": { - "type": "string", - "nullable": true - }, - "longitude": { - "type": "number", - "format": "double", - "nullable": true - }, - "latitude": { - "type": "number", - "format": "double", - "nullable": true - }, - "announcement": { - "type": "string", - "nullable": true - }, - "tags": { - "type": "string", - "nullable": true - }, - "deliveryRadiusKm": { - "type": "number", - "format": "double" - }, - "supportsDineIn": { - "type": "boolean" - }, - "supportsPickup": { - "type": "boolean" - }, - "supportsDelivery": { - "type": "boolean" - }, - "supportsReservation": { - "type": "boolean" - }, - "supportsQueueing": { - "type": "boolean" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "StoreDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StoreDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "StoreDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreEmployeeShiftDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "staffId": { - "type": "integer", - "format": "int64" - }, - "shiftDate": { - "type": "string", - "format": "date-time" - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "roleType": { - "$ref": "#/components/schemas/StaffRoleType" - }, - "notes": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "StoreEmployeeShiftDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreEmployeeShiftDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreEmployeeShiftDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StoreEmployeeShiftDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreHolidayDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "date": { - "type": "string", - "format": "date-time" - }, - "isClosed": { - "type": "boolean" - }, - "reason": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "StoreHolidayDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreHolidayDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreHolidayDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StoreHolidayDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StorePickupSettingDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "allowToday": { - "type": "boolean" - }, - "allowDaysAhead": { - "type": "integer", - "format": "int32" - }, - "defaultCutoffMinutes": { - "type": "integer", - "format": "int32" - }, - "maxQuantityPerOrder": { - "type": "integer", - "format": "int32", - "nullable": true - } - }, - "additionalProperties": false - }, - "StorePickupSettingDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StorePickupSettingDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StorePickupSlotDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "cutoffMinutes": { - "type": "integer", - "format": "int32" - }, - "capacity": { - "type": "integer", - "format": "int32" - }, - "reservedCount": { - "type": "integer", - "format": "int32" - }, - "weekdays": { - "type": "string", - "nullable": true - }, - "isEnabled": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "StorePickupSlotDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StorePickupSlotDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StorePickupSlotDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StorePickupSlotDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreStaffDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "merchantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "phone": { - "type": "string", - "nullable": true - }, - "email": { - "type": "string", - "nullable": true - }, - "roleType": { - "$ref": "#/components/schemas/StaffRoleType" - }, - "status": { - "$ref": "#/components/schemas/StaffStatus" - } - }, - "additionalProperties": false - }, - "StoreStaffDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreStaffDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreStaffDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StoreStaffDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "门店运营状态。", - "format": "int32" - }, - "StoreTableAreaDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "StoreTableAreaDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreTableAreaDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreTableAreaDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StoreTableAreaDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreTableDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "areaId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "tableCode": { - "type": "string", - "nullable": true - }, - "capacity": { - "type": "integer", - "format": "int32" - }, - "tags": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/StoreTableStatus" - }, - "qrCodeUrl": { - "type": "string", - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "StoreTableDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/StoreTableDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreTableDtoIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StoreTableDto" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StoreTableStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "桌台占用状态。", - "format": "int32" - }, - "StringDictionaryItemDtoIReadOnlyListIReadOnlyDictionaryApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "object", - "additionalProperties": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DictionaryItemDto" - }, - "nullable": true - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "StringIReadOnlyListApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "type": "array", - "items": { - "type": "string" - }, - "description": "业务数据。", - "nullable": true - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "SubmitTenantVerificationCommand": { - "required": [ - "tenantId" - ], - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "businessLicenseNumber": { - "type": "string", - "nullable": true - }, - "businessLicenseUrl": { - "type": "string", - "nullable": true - }, - "legalPersonName": { - "type": "string", - "nullable": true - }, - "legalPersonIdNumber": { - "type": "string", - "nullable": true - }, - "legalPersonIdFrontUrl": { - "type": "string", - "nullable": true - }, - "legalPersonIdBackUrl": { - "type": "string", - "nullable": true - }, - "bankAccountName": { - "type": "string", - "nullable": true - }, - "bankAccountNumber": { - "type": "string", - "nullable": true - }, - "bankName": { - "type": "string", - "nullable": true - }, - "additionalDataJson": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "SubscriptionStatus": { - "enum": [ - 0, - 1, - 2, - 3, - 4 - ], - "type": "integer", - "description": "订阅状态。", - "format": "int32" - }, - "SystemParameterDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "key": { - "type": "string", - "nullable": true - }, - "value": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "isEnabled": { - "type": "boolean" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "SystemParameterDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/SystemParameterDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "SystemParameterDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SystemParameterDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "SystemParameterDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/SystemParameterDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantAnnouncementDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "title": { - "type": "string", - "nullable": true - }, - "content": { - "type": "string", - "nullable": true - }, - "announcementType": { - "$ref": "#/components/schemas/TenantAnnouncementType" - }, - "priority": { - "type": "integer", - "format": "int32" - }, - "effectiveFrom": { - "type": "string", - "format": "date-time" - }, - "effectiveTo": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "isActive": { - "type": "boolean" - }, - "isRead": { - "type": "boolean" - }, - "readAt": { - "type": "string", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "TenantAnnouncementDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantAnnouncementDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantAnnouncementDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TenantAnnouncementDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "TenantAnnouncementDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantAnnouncementDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantAnnouncementType": { - "enum": [ - 0, - 1, - 2 - ], - "type": "integer", - "description": "租户公告类型。", - "format": "int32" - }, - "TenantAuditAction": { - "enum": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7 - ], - "type": "integer", - "description": "租户运营审核动作。", - "format": "int32" - }, - "TenantAuditLogDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "action": { - "$ref": "#/components/schemas/TenantAuditAction" - }, - "title": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "operatorName": { - "type": "string", - "nullable": true - }, - "previousStatus": { - "$ref": "#/components/schemas/TenantStatus" - }, - "currentStatus": { - "$ref": "#/components/schemas/TenantStatus" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "TenantAuditLogDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TenantAuditLogDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "TenantAuditLogDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantAuditLogDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantBillingDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "statementNo": { - "type": "string", - "nullable": true - }, - "periodStart": { - "type": "string", - "format": "date-time" - }, - "periodEnd": { - "type": "string", - "format": "date-time" - }, - "amountDue": { - "type": "number", - "format": "double" - }, - "amountPaid": { - "type": "number", - "format": "double" - }, - "status": { - "$ref": "#/components/schemas/TenantBillingStatus" - }, - "dueDate": { - "type": "string", - "format": "date-time" - }, - "lineItemsJson": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "TenantBillingDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantBillingDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantBillingDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TenantBillingDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "TenantBillingDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantBillingDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantBillingStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "账单状态。", - "format": "int32" - }, - "TenantDetailDto": { - "type": "object", - "properties": { - "tenant": { - "$ref": "#/components/schemas/TenantDto" - }, - "verification": { - "$ref": "#/components/schemas/TenantVerificationDto" - }, - "subscription": { - "$ref": "#/components/schemas/TenantSubscriptionDto" - }, - "package": { - "$ref": "#/components/schemas/TenantPackageDto" - } - }, - "additionalProperties": false - }, - "TenantDetailDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantDetailDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "code": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "shortName": { - "type": "string", - "nullable": true - }, - "contactName": { - "type": "string", - "nullable": true - }, - "contactPhone": { - "type": "string", - "nullable": true - }, - "contactEmail": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/TenantStatus" - }, - "verificationStatus": { - "$ref": "#/components/schemas/TenantVerificationStatus" - }, - "currentPackageId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "effectiveFrom": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "effectiveTo": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "autoRenew": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "TenantDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TenantDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "TenantDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantNotificationChannel": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "通知推送渠道。", - "format": "int32" - }, - "TenantNotificationDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "title": { - "type": "string", - "nullable": true - }, - "message": { - "type": "string", - "nullable": true - }, - "channel": { - "$ref": "#/components/schemas/TenantNotificationChannel" - }, - "severity": { - "$ref": "#/components/schemas/TenantNotificationSeverity" - }, - "sentAt": { - "type": "string", - "format": "date-time" - }, - "readAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "metadataJson": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "TenantNotificationDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantNotificationDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantNotificationDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TenantNotificationDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "TenantNotificationDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantNotificationDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantNotificationSeverity": { - "enum": [ - 0, - 1, - 2 - ], - "type": "integer", - "description": "租户通知的重要程度。", - "format": "int32" - }, - "TenantPackageDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "packageType": { - "$ref": "#/components/schemas/TenantPackageType" - }, - "monthlyPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "yearlyPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "maxStoreCount": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxAccountCount": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxStorageGb": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxSmsCredits": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxDeliveryOrders": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "featurePoliciesJson": { - "type": "string", - "nullable": true - }, - "isActive": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "TenantPackageDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantPackageDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantPackageDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TenantPackageDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "TenantPackageDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantPackageDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantPackageType": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "套餐类型枚举。", - "format": "int32" - }, - "TenantProgressDto": { - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "code": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/TenantStatus" - }, - "verificationStatus": { - "$ref": "#/components/schemas/TenantVerificationStatus" - }, - "effectiveFrom": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "effectiveTo": { - "type": "string", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "TenantProgressDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantProgressDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantQuotaType": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5 - ], - "type": "integer", - "description": "配额类型,覆盖容量及调用次数。", - "format": "int32" - }, - "TenantStatus": { - "enum": [ - 0, - 1, - 2, - 3, - 4 - ], - "type": "integer", - "description": "租户服务状态。", - "format": "int32" - }, - "TenantSubscriptionDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "tenantPackageId": { - "type": "integer", - "format": "int64" - }, - "status": { - "$ref": "#/components/schemas/SubscriptionStatus" - }, - "effectiveFrom": { - "type": "string", - "format": "date-time" - }, - "effectiveTo": { - "type": "string", - "format": "date-time" - }, - "nextBillingDate": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "autoRenew": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "TenantSubscriptionDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantSubscriptionDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantVerificationDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "status": { - "$ref": "#/components/schemas/TenantVerificationStatus" - }, - "businessLicenseNumber": { - "type": "string", - "nullable": true - }, - "businessLicenseUrl": { - "type": "string", - "nullable": true - }, - "legalPersonName": { - "type": "string", - "nullable": true - }, - "legalPersonIdNumber": { - "type": "string", - "nullable": true - }, - "legalPersonIdFrontUrl": { - "type": "string", - "nullable": true - }, - "legalPersonIdBackUrl": { - "type": "string", - "nullable": true - }, - "bankAccountName": { - "type": "string", - "nullable": true - }, - "bankAccountNumber": { - "type": "string", - "nullable": true - }, - "bankName": { - "type": "string", - "nullable": true - }, - "additionalDataJson": { - "type": "string", - "nullable": true - }, - "submittedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "reviewedBy": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "reviewRemarks": { - "type": "string", - "nullable": true - }, - "reviewedByName": { - "type": "string", - "nullable": true - }, - "reviewedAt": { - "type": "string", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "TenantVerificationDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TenantVerificationDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "TenantVerificationStatus": { - "enum": [ - 0, - 1, - 2, - 3 - ], - "type": "integer", - "description": "租户实名认证状态。", - "format": "int32" - }, - "TokenResponse": { - "type": "object", - "properties": { - "accessToken": { - "type": "string", - "nullable": true - }, - "accessTokenExpiresAt": { - "type": "string", - "format": "date-time" - }, - "refreshToken": { - "type": "string", - "nullable": true - }, - "refreshTokenExpiresAt": { - "type": "string", - "format": "date-time" - }, - "user": { - "$ref": "#/components/schemas/CurrentUserProfile" - }, - "isNewUser": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "TokenResponseApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/TokenResponse" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "UnpublishProductCommand": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "reason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateDeliveryOrderCommand": { - "type": "object", - "properties": { - "deliveryOrderId": { - "type": "integer", - "format": "int64" - }, - "orderId": { - "type": "integer", - "format": "int64" - }, - "provider": { - "$ref": "#/components/schemas/DeliveryProvider" - }, - "providerOrderId": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/DeliveryStatus" - }, - "deliveryFee": { - "type": "number", - "format": "double", - "nullable": true - }, - "courierName": { - "type": "string", - "nullable": true - }, - "courierPhone": { - "type": "string", - "nullable": true - }, - "dispatchedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "pickedUpAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "deliveredAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "failureReason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateDictionaryGroupRequest": { - "required": [ - "name" - ], - "type": "object", - "properties": { - "name": { - "maxLength": 128, - "minLength": 1, - "type": "string" - }, - "description": { - "maxLength": 512, - "type": "string", - "nullable": true - }, - "isEnabled": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "UpdateDictionaryItemRequest": { - "required": [ - "value" - ], - "type": "object", - "properties": { - "value": { - "maxLength": 256, - "minLength": 1, - "type": "string" - }, - "isDefault": { - "type": "boolean" - }, - "isEnabled": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "description": { - "maxLength": 512, - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateMenuCommand": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "parentId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "path": { - "type": "string", - "nullable": true - }, - "component": { - "type": "string", - "nullable": true - }, - "title": { - "type": "string", - "nullable": true - }, - "icon": { - "type": "string", - "nullable": true - }, - "isIframe": { - "type": "boolean" - }, - "link": { - "type": "string", - "nullable": true - }, - "keepAlive": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "requiredPermissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "metaPermissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "metaRoles": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "authList": { - "type": "array", - "items": { - "$ref": "#/components/schemas/MenuAuthItemDto" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateMerchantCommand": { - "type": "object", - "properties": { - "merchantId": { - "type": "integer", - "format": "int64" - }, - "brandName": { - "type": "string", - "nullable": true - }, - "brandAlias": { - "type": "string", - "nullable": true - }, - "logoUrl": { - "type": "string", - "nullable": true - }, - "category": { - "type": "string", - "nullable": true - }, - "contactPhone": { - "type": "string", - "nullable": true - }, - "contactEmail": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/MerchantStatus" - } - }, - "additionalProperties": false - }, - "UpdateMerchantContractStatusCommand": { - "required": [ - "contractId", - "merchantId", - "status" - ], - "type": "object", - "properties": { - "merchantId": { - "type": "integer", - "format": "int64" - }, - "contractId": { - "type": "integer", - "format": "int64" - }, - "status": { - "$ref": "#/components/schemas/ContractStatus" - }, - "signedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "reason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateOrderCommand": { - "type": "object", - "properties": { - "orderId": { - "type": "integer", - "format": "int64" - }, - "orderNo": { - "type": "string", - "nullable": true - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "channel": { - "$ref": "#/components/schemas/OrderChannel" - }, - "deliveryType": { - "$ref": "#/components/schemas/DeliveryType" - }, - "status": { - "$ref": "#/components/schemas/OrderStatus" - }, - "paymentStatus": { - "$ref": "#/components/schemas/PaymentStatus" - }, - "customerName": { - "type": "string", - "nullable": true - }, - "customerPhone": { - "type": "string", - "nullable": true - }, - "tableNo": { - "type": "string", - "nullable": true - }, - "queueNumber": { - "type": "string", - "nullable": true - }, - "reservationId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "itemsAmount": { - "type": "number", - "format": "double" - }, - "discountAmount": { - "type": "number", - "format": "double" - }, - "payableAmount": { - "type": "number", - "format": "double" - }, - "paidAmount": { - "type": "number", - "format": "double" - }, - "paidAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "finishedAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "cancelledAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "cancelReason": { - "type": "string", - "nullable": true - }, - "remark": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdatePaymentCommand": { - "type": "object", - "properties": { - "paymentId": { - "type": "integer", - "format": "int64" - }, - "orderId": { - "type": "integer", - "format": "int64" - }, - "method": { - "$ref": "#/components/schemas/PaymentMethod" - }, - "status": { - "$ref": "#/components/schemas/PaymentStatus" - }, - "amount": { - "type": "number", - "format": "double" - }, - "tradeNo": { - "type": "string", - "nullable": true - }, - "channelTransactionId": { - "type": "string", - "nullable": true - }, - "paidAt": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "remark": { - "type": "string", - "nullable": true - }, - "payload": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdatePermissionCommand": { - "type": "object", - "properties": { - "permissionId": { - "type": "integer", - "format": "int64" - }, - "parentId": { - "type": "integer", - "format": "int64" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "type": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateProductCommand": { - "type": "object", - "properties": { - "productId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "categoryId": { - "type": "integer", - "format": "int64" - }, - "spuCode": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "subtitle": { - "type": "string", - "nullable": true - }, - "unit": { - "type": "string", - "nullable": true - }, - "price": { - "type": "number", - "format": "double" - }, - "originalPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "stockQuantity": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxQuantityPerOrder": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/ProductStatus" - }, - "coverImage": { - "type": "string", - "nullable": true - }, - "galleryImages": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "enableDineIn": { - "type": "boolean" - }, - "enablePickup": { - "type": "boolean" - }, - "enableDelivery": { - "type": "boolean" - }, - "isFeatured": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "UpdateRoleCommand": { - "type": "object", - "properties": { - "roleId": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateRoleTemplateCommand": { - "type": "object", - "properties": { - "templateCode": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "isActive": { - "type": "boolean" - }, - "permissionCodes": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateStoreBusinessHourCommand": { - "type": "object", - "properties": { - "businessHourId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "dayOfWeek": { - "$ref": "#/components/schemas/DayOfWeek" - }, - "hourType": { - "$ref": "#/components/schemas/BusinessHourType" - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "capacityLimit": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "notes": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateStoreCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "merchantId": { - "type": "integer", - "format": "int64" - }, - "code": { - "type": "string", - "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "phone": { - "type": "string", - "nullable": true - }, - "managerName": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/StoreStatus" - }, - "province": { - "type": "string", - "nullable": true - }, - "city": { - "type": "string", - "nullable": true - }, - "district": { - "type": "string", - "nullable": true - }, - "address": { - "type": "string", - "nullable": true - }, - "longitude": { - "type": "number", - "format": "double", - "nullable": true - }, - "latitude": { - "type": "number", - "format": "double", - "nullable": true - }, - "announcement": { - "type": "string", - "nullable": true - }, - "tags": { - "type": "string", - "nullable": true - }, - "deliveryRadiusKm": { - "type": "number", - "format": "double" - }, - "supportsDineIn": { - "type": "boolean" - }, - "supportsPickup": { - "type": "boolean" - }, - "supportsDelivery": { - "type": "boolean" - }, - "supportsReservation": { - "type": "boolean" - }, - "supportsQueueing": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "UpdateStoreDeliveryZoneCommand": { - "type": "object", - "properties": { - "deliveryZoneId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "zoneName": { - "type": "string", - "nullable": true - }, - "polygonGeoJson": { - "type": "string", - "nullable": true - }, - "minimumOrderAmount": { - "type": "number", - "format": "double", - "nullable": true - }, - "deliveryFee": { - "type": "number", - "format": "double", - "nullable": true - }, - "estimatedMinutes": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "UpdateStoreEmployeeShiftCommand": { - "type": "object", - "properties": { - "shiftId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "staffId": { - "type": "integer", - "format": "int64" - }, - "shiftDate": { - "type": "string", - "format": "date-time" - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "roleType": { - "$ref": "#/components/schemas/StaffRoleType" - }, - "notes": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateStoreHolidayCommand": { - "type": "object", - "properties": { - "holidayId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "date": { - "type": "string", - "format": "date-time" - }, - "isClosed": { - "type": "boolean" - }, - "reason": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "UpdateStorePickupSlotCommand": { - "type": "object", - "properties": { - "slotId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "startTime": { - "type": "string", - "format": "date-span" - }, - "endTime": { - "type": "string", - "format": "date-span" - }, - "cutoffMinutes": { - "type": "integer", - "format": "int32" - }, - "capacity": { - "type": "integer", - "format": "int32" - }, - "weekdays": { - "type": "string", - "nullable": true - }, - "isEnabled": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "UpdateStoreStaffCommand": { - "type": "object", - "properties": { - "staffId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "phone": { - "type": "string", - "nullable": true - }, - "email": { - "type": "string", - "nullable": true - }, - "roleType": { - "$ref": "#/components/schemas/StaffRoleType" - }, - "status": { - "$ref": "#/components/schemas/StaffStatus" - } - }, - "additionalProperties": false - }, - "UpdateStoreTableAreaCommand": { - "type": "object", - "properties": { - "areaId": { - "type": "integer", - "format": "int64" - }, - "storeId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "UpdateStoreTableCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "tableId": { - "type": "integer", - "format": "int64" - }, - "areaId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "tableCode": { - "type": "string", - "nullable": true - }, - "capacity": { - "type": "integer", - "format": "int32" - }, - "tags": { - "type": "string", - "nullable": true - }, - "status": { - "$ref": "#/components/schemas/StoreTableStatus" - } - }, - "additionalProperties": false - }, - "UpdateSystemParameterCommand": { - "type": "object", - "properties": { - "parameterId": { - "type": "integer", - "format": "int64" - }, - "key": { - "type": "string", - "nullable": true - }, - "value": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "isEnabled": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "UpdateTenantAnnouncementCommand": { - "type": "object", - "properties": { - "tenantId": { - "type": "integer", - "format": "int64" - }, - "announcementId": { - "type": "integer", - "format": "int64" - }, - "title": { - "type": "string", - "nullable": true - }, - "content": { - "type": "string", - "nullable": true - }, - "announcementType": { - "$ref": "#/components/schemas/TenantAnnouncementType" - }, - "priority": { - "type": "integer", - "format": "int32" - }, - "effectiveFrom": { - "type": "string", - "format": "date-time" - }, - "effectiveTo": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "isActive": { - "type": "boolean" - } - }, - "additionalProperties": false - }, - "UpdateTenantPackageCommand": { - "type": "object", - "properties": { - "tenantPackageId": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "packageType": { - "$ref": "#/components/schemas/TenantPackageType" - }, - "monthlyPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "yearlyPrice": { - "type": "number", - "format": "double", - "nullable": true - }, - "maxStoreCount": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxAccountCount": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxStorageGb": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxSmsCredits": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "maxDeliveryOrders": { - "type": "integer", - "format": "int32", - "nullable": true - }, - "featurePoliciesJson": { - "type": "string", - "nullable": true - }, - "isActive": { - "type": "boolean" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "UpsertInventoryBatchCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "productSkuId": { - "type": "integer", - "format": "int64" - }, - "batchNumber": { - "type": "string", - "nullable": true - }, - "productionDate": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "expireDate": { - "type": "string", - "format": "date-time", - "nullable": true - }, - "quantity": { - "type": "integer", - "format": "int32" - }, - "remainingQuantity": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false - }, - "UpsertStorePickupSettingCommand": { - "type": "object", - "properties": { - "storeId": { - "type": "integer", - "format": "int64" - }, - "allowToday": { - "type": "boolean" - }, - "allowDaysAhead": { - "type": "integer", - "format": "int32" - }, - "defaultCutoffMinutes": { - "type": "integer", - "format": "int32" - }, - "maxQuantityPerOrder": { - "type": "integer", - "format": "int32", - "nullable": true - } - }, - "additionalProperties": false - }, - "UserPermissionDto": { - "type": "object", - "properties": { - "userId": { - "type": "integer", - "format": "int64" - }, - "tenantId": { - "type": "integer", - "format": "int64" - }, - "merchantId": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "account": { - "type": "string", - "nullable": true - }, - "displayName": { - "type": "string", - "nullable": true - }, - "roles": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "permissions": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "UserPermissionDtoApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/UserPermissionDto" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - }, - "UserPermissionDtoPagedResult": { - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserPermissionDto" - }, - "description": "数据列表。", - "nullable": true - }, - "page": { - "type": "integer", - "description": "当前页码,从 1 开始。", - "format": "int32" - }, - "pageSize": { - "type": "integer", - "description": "每页条数。", - "format": "int32" - }, - "totalCount": { - "type": "integer", - "description": "总条数。", - "format": "int32" - }, - "totalPages": { - "type": "integer", - "description": "总页数。", - "format": "int32", - "readOnly": true - } - }, - "additionalProperties": false, - "description": "分页结果包装,携带列表与总条数等元数据。" - }, - "UserPermissionDtoPagedResultApiResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "是否成功。" - }, - "code": { - "type": "integer", - "description": "状态/错误码(默认 200)。", - "format": "int32" - }, - "message": { - "type": "string", - "description": "提示信息。", - "nullable": true - }, - "data": { - "$ref": "#/components/schemas/UserPermissionDtoPagedResult" - }, - "errors": { - "description": "错误详情(如字段验证错误)。", - "nullable": true - }, - "traceId": { - "type": "string", - "description": "TraceId,便于链路追踪。", - "nullable": true - }, - "timestamp": { - "type": "string", - "description": "时间戳(UTC)。", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "统一的 API 返回结果包装。" - } - }, - "securitySchemes": { - "Bearer": { - "type": "http", - "description": "在下方输入Bearer Token,格式:Bearer {token}", - "scheme": "bearer", - "bearerFormat": "JWT" - } - } - }, - "security": [ - { - "Bearer": [ ] - } - ], - "tags": [ - { - "name": "Auth", - "description": "管理后台认证接口" - }, - { - "name": "Deliveries", - "description": "配送单管理。" - }, - { - "name": "Dictionary", - "description": "参数字典管理。" - }, - { - "name": "Files", - "description": "管理后台文件上传。" - }, - { - "name": "Health", - "description": "管理后台 - 健康检查。" - }, - { - "name": "Inventory", - "description": "库存管理。" - }, - { - "name": "Menus", - "description": "菜单管理(可增删改查)。" - }, - { - "name": "MerchantCategories", - "description": "商户类目管理。" - }, - { - "name": "Merchants", - "description": "商户管理。" - }, - { - "name": "Orders", - "description": "订单管理。" - }, - { - "name": "Payments", - "description": "支付记录管理。" - }, - { - "name": "Permissions", - "description": "权限管理。" - }, - { - "name": "Products", - "description": "商品管理。" - }, - { - "name": "PublicTenantPackages", - "description": "公共租户套餐查询接口。" - }, - { - "name": "PublicTenants", - "description": "公域租户自助入住接口。" - }, - { - "name": "PublicTenantSubscriptions", - "description": "公域租户订阅自助接口(需登录,无权限校验)。" - }, - { - "name": "RoleTemplates", - "description": "角色模板管理(平台蓝本)。" - }, - { - "name": "StorePickup", - "description": "门店自提管理。" - }, - { - "name": "Stores", - "description": "门店管理。" - }, - { - "name": "StoreShifts", - "description": "门店排班管理。" - }, - { - "name": "StoreStaffs", - "description": "门店员工管理。" - }, - { - "name": "StoreTableAreas", - "description": "门店桌台区域管理。" - }, - { - "name": "StoreTables", - "description": "门店桌码管理。" - }, - { - "name": "SystemParameters", - "description": "系统参数管理。" - }, - { - "name": "TenantAnnouncements", - "description": "租户公告管理。" - }, - { - "name": "TenantBillings", - "description": "租户账单管理。" - }, - { - "name": "TenantNotifications", - "description": "租户通知接口。" - }, - { - "name": "TenantPackages", - "description": "租户套餐管理。" - }, - { - "name": "TenantRoles", - "description": "租户角色管理(实例层)。" - }, - { - "name": "Tenants", - "description": "租户管理。" - }, - { - "name": "UserPermissions", - "description": "用户权限洞察接口。" - } - ] -} \ No newline at end of file diff --git a/Document/xmind_小程序版模块规划.md b/Document/xmind_小程序版模块规划.md deleted file mode 100644 index 3af2007..0000000 --- a/Document/xmind_小程序版模块规划.md +++ /dev/null @@ -1,89 +0,0 @@ -# 外卖SaaS(小程序导向)模块脑图 - -## 1. 目标 -- 聚焦小程序用户体验:高效点单、扫码堂食、同城履约、实时状态 -- 平台/租户多租户隔离,支持商家快速入驻与运营 -- 门店同城即时配送为主,第三方配送对接兜底,统一回调验签 - -## 2. 端侧 -- 小程序用户端:扫码进店/堂食点餐、店铺浏览、菜品/套餐、购物车、下单支付、拼单、预购自提、同城配送、订单跟踪、优惠券/积分/会员、营销活动、评价、地址管理、搜索、签到、预约、社区、客服聊天、地图导航 -- 管理后台(商家/店员):门店配置、桌码管理、菜品与库存、订单/拼单/自提处理、配送调度与回调、营销配置、分销配置、客服工单/会话、数据看板 -- 平台运营后台:租户/商家审核、套餐与配额、全局配置、日志审计、监控看板、分销/返利策略、活动审核 - -## 3. 核心业务模块 -- 租户与平台 - - 租户生命周期:注册、实名认证/资质审核、套餐订阅、续费/升降配、停用/注销 - - 配额与权限:门店数/账号数/存储/短信/配送单量,RBAC 角色模板,租户级配置继承与覆盖 - - 平台运营:租户监控、账单/计费/催缴、公告/通知、合规与风控(黑名单/频率限制) -- 商家与门店 - - 入驻与资质审核:证照上传、合同、店铺类目、品牌与连锁 - - 门店配置:多店管理、营业时间、休息/打烊、门店状态、区域/配送范围、到店导航信息 - - 桌码/场景:桌码生成与绑定、桌台容量/区域、桌码标签(堂食/快餐/档口) - - 门店运营:员工账号与分工(前台/后厨/配送)、交班与收银、公告/售罄提示 -- 菜品与库存 - - 菜品建模:分类/标签/排序、规格与属性(辣度/份量)、套餐与组合、加料/做法/备注 - - 价格策略:会员价、门店价、时间段价、限时折扣、区域价 - - 库存与可售:总库存/门店库存/档期库存、售罄/预售、批量导入与同步、条码/编码 - - 媒资:图片/视频、SPU/SKU 编码、营养/过敏源/溯源信息 -- 扫码点餐/堂食 - - 桌码入口:扫码识别门店/桌台、桌台上下文、预加载菜单 - - 点餐流程:购物车并发锁、加菜/催单、口味备注、拆单/并单、多人同桌分付/代付 - - 账单与核销:桌台账单合并、结账/买单、电子小票、发票抬头、桌台释放 -- 预购自提 - - 档期配置:自提时间窗/容量、预售库存、截单时间 - - 下单与支付:自提地址确认、档期校验、预售与现制、库存锁定 - - 提货核销:提货码/手机号核销、自提柜/前台、超时/取消/退款、代取人 -- 下单与支付 - - 购物车与校验:库存/限购/门店状态/配送范围/桌台状态、券和积分叠加规则 - - 支付与结算:微信/支付宝/余额/优惠券/积分抵扣、回调幂等、预授权、分账/对账 - - 售后与状态机:退单/部分退款、异常单处理、状态机(待付→待接→制作→配送/自提→完成/取消) -- 同城即时配送(门店履约) - - 自配送:骑手管理、取/送件信息、路线估时、导航、取餐码、费用与补贴 - - 第三方配送:统一抽象(下单/取消/加价/查询)、多渠道择优、回调验签、异常重试与补偿 - - 配送体验:预计送达/计价、配送进度推送、无接触配送、收货码、投诉与赔付 -- 拼单 - - 团单规则:发起/加入、成团条件(人数/金额/时间)、拼主与参团人、支付/锁单策略 - - 失败与退款:超时/人数不足自动解散、自动退款/原路退、通知 - - 履约:同单配送至拼主地址、收件信息可见范围、团内消息/提醒 -- 优惠券与营销工具 - - 券种与发放:满减/折扣/新人券/裂变券/桌码专属券/会员券,渠道(领券中心/活动/分享/桌码) - - 核销规则:适用范围(门店/品类/菜品)、叠加/互斥、最低消费、有效期、库存与风控 - - 活动组件:抽奖、分享裂变、秒杀/限时抢购、满减活动、爆款/推荐位、裂变海报 -- 会员与积分/会员营销 - - 会员体系:付费会员/积分会员、等级/成长值、会员权益(专享价/券/运费/客服) - - 积分运营:获取(消费/签到/任务/活动)、消耗(抵扣/兑换)、有效期、黑名单 - - 会员运营:会员日、续费提醒、沉睡唤醒、专属活动、分层运营与 A/B -- 客服工具 - - 会话:实时聊天、机器人/人工切换、快捷回复、排队/转接、消息模板/通知 - - 质量与风控:会话记录与审计、敏感词、评价与回访、工单流转 -- 分销返利 - - 规则:商品/类目返利、佣金阶梯、结算周期、税务信息、违规处理 - - 链路:分享链接/小程序码、点击与下单跟踪、确认收货后结算、售后扣回 -- 地图导航 - - 门店/自提点定位、距离/路况、路线规划、附近门店/推荐、跳转原生导航 -- 签到打卡 - - 规则:每日/任务签到、连签奖励、补签、积分/券/成长值奖励、反作弊 -- 预约预订 - - 档期/资源:时间段、人员/座位/设备占用、容量校验 - - 流程:预约下单/支付、提醒/改期/取消、到店核销与履约记录 -- 搜索查询 - - 内容:门店/菜品/活动/优惠券搜索,过滤/排序,热门/历史搜索 - - 体验:纠错/联想、推荐、结果埋点与转化分析 -- 用户社区 - - 社区运营:动态发布/评论/点赞、话题/标签、图片/视频审核、举报与风控 - - 互动:店铺口碑、菜品晒图、官方/商家号发布、置顶与精选 -- 数据与分析 - - 交易分析:销售/订单/客单/转化漏斗、支付与退款、品类/单品分析 - - 营销分析:券发放与核销、活动效果(拼单/秒杀/抽奖/分销)、会员留存与复购 - - 履约分析:配送时效、超时/异常、堂食与自提拆分、投诉与赔付 - - 运营大盘:租户/商家健康度、活跃度、留存、GMV、成本与毛利 -- 系统与运维 - - 安全与合规:RBAC、租户隔离、限流与风控(设备/IP/账户/店铺)、敏感词与内容安全 - - 配置与网关:字典/参数、灰度/开关、网关限流/鉴权/租户透传 - - 可靠性:任务调度(订单/拼单超时、券过期、回调补偿)、幂等与重试、健康检查/告警、日志/链路追踪、备份恢复 - -## 4. 里程碑(建议) -- Phase 1:租户/商家入驻、门店与菜品、桌码扫码堂食、基础下单支付、预购自提、第三方配送骨架 -- Phase 2:拼单、优惠券与基础营销组件、会员积分/会员日、客服聊天、同城自配送调度、搜索 -- Phase 3:分销返利、签到打卡、预约预订、地图导航、社区、营销活动丰富(秒杀/抽奖等)、风控与审计、补偿与告警体系 -- Phase 4:性能优化与缓存、运营大盘与细分报表、测试与文档完善、上线与监控 diff --git a/Document/xmind_小程序版模块规划.xmind b/Document/xmind_小程序版模块规划.xmind deleted file mode 100644 index 9df8073..0000000 Binary files a/Document/xmind_小程序版模块规划.xmind and /dev/null differ diff --git a/README.md b/README.md index caaabce..341ceac 100644 --- a/README.md +++ b/README.md @@ -1,231 +1,19 @@ -# 外卖SaaS系统 (TakeoutSaaS) +# TakeoutSaaS.AdminApi -## 项目简介 +本仓库为 TakeoutSaaS 的 API 代码仓库(管理端为主,网关暂同仓库维护)。 -外卖SaaS系统是一个基于.NET 10的多租户外卖管理平台,为中小型餐饮企业提供完整的外卖业务解决方案。系统采用现代化的技术栈,支持商家管理、菜品管理、订单处理、配送管理、支付集成等核心功能。 +## 子模块 -### 核心特性 +- `TakeoutSaaS.BuildingBlocks/`:共享基础组件(Shared/Building Blocks) +- `TakeoutSaaS.Docs/`:全部文档 + 运维文件 + 脚本 -- **多租户架构**:支持多租户数据隔离,SaaS模式运营 -- **商家管理**:完善的商家入驻、门店管理、菜品管理功能 -- **订单管理**:订单全生命周期管理,实时状态跟踪 -- **配送管理**:配送任务、路线规划、第三方配送对接 -- **支付集成**:支持微信、支付宝等多种支付方式 -- **营销功能**:优惠券、满减活动、会员积分 -- **字典管理**:系统字典、租户覆盖、批量导入导出、缓存监控 -- **数据分析**:实时数据统计、经营报表、趋势分析 -- **安全可靠**:JWT认证、权限控制、数据加密 +## 初始化 -## 技术栈 - -### 后端技术 -- **.NET 10**:最新的.NET平台 -- **ASP.NET Core Web API**:RESTful API服务 -- **Entity Framework Core 10**:最新ORM框架 -- **Dapper 2.1+**:高性能数据访问 -- **PostgreSQL 16+**:主数据库 -- **Redis 7.0+**:分布式缓存 -- **RabbitMQ 3.12+**:消息队列 - -### 开发框架 -- **AutoMapper**:对象映射 -- **FluentValidation**:数据验证 -- **Serilog**:结构化日志 -- **MediatR**:CQRS模式 -- **Hangfire**:后台任务 -- **Swagger**:API文档 - -## 运行条件 - -### 开发环境要求 -* .NET SDK 10.0 或更高版本 -* PostgreSQL 16+ -* Redis 7.0+ -* RabbitMQ 3.12+(可选) -* Docker Desktop(推荐,用于容器化开发) - -### 推荐IDE -* Visual Studio 2022 -* JetBrains Rider -* Visual Studio Code - -## 快速开始 - -### 1. 克隆项目 ```bash -git clone https://github.com/your-org/takeout-saas.git -cd takeout-saas +git submodule update --init --recursive ``` -### 2. 使用Docker Compose启动依赖服务(推荐) -```bash -# 启动PostgreSQL、Redis、RabbitMQ等服务 -docker-compose up -d +## 文档入口 -# 查看服务状态 -docker-compose ps -``` - -### 3. 配置数据库连接 -编辑 `src/TakeoutSaaS.Api/appsettings.Development.json` - -### 4. 执行数据库迁移 -```bash -cd src/TakeoutSaaS.Api -dotnet ef database update -``` - -### 5. 运行项目 -```bash -dotnet run -``` - -访问 API 文档: -- 管理后台 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`:缓存预热字典编码列表 - -## 公告管理 - -> 最后更新日期:2025-12-20 - -### 功能概述 - -- 支持平台公告与租户公告统一管理(TenantId=0 代表平台公告) -- 状态机:草稿 → 已发布 → 已撤销(已发布不可编辑) -- 支持目标受众过滤与未读/已读能力 - -### 快速开始(示例流程) - -1. 创建公告(草稿) -2. 发布公告(进入 Published) -3. 应用端获取可见公告列表与未读公告 - -```mermaid -stateDiagram-v2 - [*] --> Draft - Draft --> Published: publish - Published --> Revoked: revoke - Revoked --> Published: republish -``` - -### 关键概念 - -- `Status`:Draft/Published/Revoked,已发布不可编辑 -- `RowVersion`:并发控制字段(Base64) -- `TargetType/TargetParameters`:目标受众过滤 - -### 相关文档 - -- `docs/api/announcements-api.md` -- `docs/permissions/announcement-permissions.md` -- `docs/adr/0001-announcement-status-state-machine.md` -- `docs/observability/announcement-events.md` -- `docs/migrations/announcement-status-migration.md` -- `docs/technical-debt.md` - -## 项目结构 - -``` -TakeoutSaaS/ -├── 0_Document/ # 项目文档 -│ ├── 01_项目概述.md -│ ├── 02_技术架构.md -│ ├── 03_数据库设计.md -│ ├── 04A_管理后台API.md -│ ├── 04B_小程序API.md -│ ├── 05_部署运维.md -│ └── 06_开发规范.md -├── src/ -│ ├── TakeoutSaaS.AdminApi/ # 管理后台 Web API -│ ├── TakeoutSaaS.MiniApi/ # 小程序/用户端 Web API -│ ├── TakeoutSaaS.Application/ # 应用层 -│ ├── TakeoutSaaS.Domain/ # 领域层 -│ ├── TakeoutSaaS.Infrastructure/ # 基础设施层 -│ └── TakeoutSaaS.Shared/ # 共享层 -├── tests/ -│ ├── TakeoutSaaS.UnitTests/ # 单元测试 -│ └── TakeoutSaaS.IntegrationTests/ # 集成测试 -├── docker-compose.yml # Docker编排文件 -└── README.md -``` - -## 测试说明 - -### 运行单元测试 -```bash -dotnet test tests/TakeoutSaaS.UnitTests -``` - -### 运行集成测试 -```bash -dotnet test tests/TakeoutSaaS.IntegrationTests -``` - -## 部署说明 - -### Docker部署 -```bash -# 构建镜像 -docker build -t takeout-saas-api:latest . - -# 运行容器 -docker run -d -p 8080:80 --name takeout-api takeout-saas-api:latest -``` - -详细部署文档请参考:[部署运维文档](0_Document/05_部署运维.md) - -## 文档 - -- [项目概述](0_Document/01_项目概述.md) - 系统介绍和业务说明 -- [技术架构](0_Document/02_技术架构.md) - 技术栈和架构设计 -- [数据库设计](0_Document/03_数据库设计.md) - 数据模型和表结构 -- [API接口设计](0_Document/04_API接口设计.md) - RESTful API规范 -- [部署运维](0_Document/05_部署运维.md) - 部署和运维指南 -- [开发规范](0_Document/06_开发规范.md) - 代码规范和最佳实践 - -## 开发规范 - -请遵循项目的[开发规范](0_Document/06_开发规范.md) - -## 贡献指南 - -1. Fork 本仓库 -2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) -3. 提交更改 (`git commit -m 'feat: Add some AmazingFeature'`) -4. 推送到分支 (`git push origin feature/AmazingFeature`) -5. 创建 Pull Request - -## 许可证 - -本项目采用 MIT 许可证 - -## 联系方式 - -- 项目地址:https://github.com/your-org/takeout-saas -- 问题反馈:https://github.com/your-org/takeout-saas/issues - -## 协作者 - -感谢所有为本项目做出贡献的开发者! - ---- - -⭐ 如果这个项目对你有帮助,请给我们一个星标! +- `TakeoutSaaS.Docs/README.md` +- `TakeoutSaaS.Docs/Document/README.md` diff --git a/TakeoutSaaS.BuildingBlocks b/TakeoutSaaS.BuildingBlocks new file mode 160000 index 0000000..bcf0a6b --- /dev/null +++ b/TakeoutSaaS.BuildingBlocks @@ -0,0 +1 @@ +Subproject commit bcf0a6bd7dbcbef19e630ca768ccb5d617373c7d diff --git a/TakeoutSaaS.Docs b/TakeoutSaaS.Docs new file mode 160000 index 0000000..88ad710 --- /dev/null +++ b/TakeoutSaaS.Docs @@ -0,0 +1 @@ +Subproject commit 88ad71041bcec59715274c9ca568b0ca434408a1 diff --git a/TakeoutSaaS.sln b/TakeoutSaaS.sln index e765339..593dd42 100644 --- a/TakeoutSaaS.sln +++ b/TakeoutSaaS.sln @@ -11,9 +11,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.AdminApi", "src EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{8D626EA8-CB54-BC41-363A-217881BEBA6E}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Shared.Web", "src\Core\TakeoutSaaS.Shared.Web\TakeoutSaaS.Shared.Web.csproj", "{022FCF39-EC48-46EA-AC08-FA2EAD1548B7}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Shared.Web", "TakeoutSaaS.BuildingBlocks\src\Core\TakeoutSaaS.Shared.Web\TakeoutSaaS.Shared.Web.csproj", "{022FCF39-EC48-46EA-AC08-FA2EAD1548B7}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Shared.Abstractions", "src\Core\TakeoutSaaS.Shared.Abstractions\TakeoutSaaS.Shared.Abstractions.csproj", "{0DA03B31-E718-4424-A1F0-9989E79FFE81}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Shared.Abstractions", "TakeoutSaaS.BuildingBlocks\src\Core\TakeoutSaaS.Shared.Abstractions\TakeoutSaaS.Shared.Abstractions.csproj", "{0DA03B31-E718-4424-A1F0-9989E79FFE81}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Application", "Application", "{22BAF98C-8415-17C4-B26A-D537657BC863}" EndProject @@ -41,7 +41,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gateway", "Gateway", "{6306 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.ApiGateway", "src\Gateway\TakeoutSaaS.ApiGateway\TakeoutSaaS.ApiGateway.csproj", "{A2620200-D487-49A7-ABAF-9B84951F81DD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Shared.Kernel", "src\Core\TakeoutSaaS.Shared.Kernel\TakeoutSaaS.Shared.Kernel.csproj", "{BBC99B58-ECA8-42C3-9070-9AA058D778D3}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Shared.Kernel", "TakeoutSaaS.BuildingBlocks\src\Core\TakeoutSaaS.Shared.Kernel\TakeoutSaaS.Shared.Kernel.csproj", "{BBC99B58-ECA8-42C3-9070-9AA058D778D3}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Module.Storage", "src\Modules\TakeoutSaaS.Module.Storage\TakeoutSaaS.Module.Storage.csproj", "{05058F44-6FB7-43AF-8648-8BF538E283EF}" EndProject diff --git a/deploy/dbhub/dbhub.toml b/deploy/dbhub/dbhub.toml deleted file mode 100644 index 814bcb7..0000000 --- a/deploy/dbhub/dbhub.toml +++ /dev/null @@ -1,15 +0,0 @@ -[[sources]] -id = "takeout_app" -dsn = "postgres://app_user:AppUser112233@120.53.222.17:5432/takeout_app_db" - -[[sources]] -id = "takeout_identity" -dsn = "postgres://identity_user:IdentityUser112233@120.53.222.17:5432/takeout_identity_db" - -[[sources]] -id = "takeout_dictionary" -dsn = "postgres://dictionary_user:DictionaryUser112233@120.53.222.17:5432/takeout_dictionary_db" - -[[sources]] -id = "takeout_hangfire" -dsn = "postgres://hangfire_user:HangFire112233@120.53.222.17:5432/takeout_hangfire_db" diff --git a/deploy/postgres/README.md b/deploy/postgres/README.md deleted file mode 100644 index 04e7222..0000000 --- a/deploy/postgres/README.md +++ /dev/null @@ -1,47 +0,0 @@ -# PostgreSQL 部署脚本 - -本目录提供在测试/预发布环境快速拉起 PostgreSQL 的脚本,复用线上同名数据库与账号,方便迁移/恢复。 - -## 目录结构 - -- `create_databases.sql`:创建四个业务库与对应角色(可多次执行,存在则跳过)。 -- `bootstrap.ps1`:PowerShell 包装脚本,调用 `psql` 执行 SQL。 - -## 前置条件 - -1. 已安装 PostgreSQL 12+,并能以管理员身份访问(默认使用 `postgres`)。 -2. 本地已配置 `psql` 可执行命令。 - -## 使用方法 - -```powershell -cd deploy/postgres -.\bootstrap.ps1 ` - -Host 120.53.222.17 ` - -Port 5432 ` - -AdminUser postgres ` - -AdminPassword "超级管理员密码" -``` - -脚本会: - -1. 创建/更新以下角色与库: - - `app_user` / `takeout_app_db` - - `identity_user` / `takeout_identity_db` - - `dictionary_user` / `takeout_dictionary_db` - - `hangfire_user` / `takeout_hangfire_db` -2. 为库设置 COMMENT,授予 Schema `public` 的 CRUD 权限。 -3. 输出执行日志,失败时终止。 - -## 自定义 - -- 如需修改密码或新增库,编辑 `create_databases.sql` 后重新运行脚本。 -- 若在本地拉起测试库,可把 `Host` 指向 `localhost`,其余参数保持一致。 - -## 常见问题 - -| 问题 | 处理方式 | -| --- | --- | -| `psql : command not found` | 确认 PostgreSQL bin 目录已加入 PATH。 | -| `permission denied to create database` | 改用具有 `CREATEDB` 权限的管理员执行脚本。 | -| 需要删除库 | 先 `DROP DATABASE xxx`,再运行脚本重新创建。 | diff --git a/deploy/postgres/bootstrap.ps1 b/deploy/postgres/bootstrap.ps1 deleted file mode 100644 index 3ea0bea..0000000 --- a/deploy/postgres/bootstrap.ps1 +++ /dev/null @@ -1,37 +0,0 @@ -param( - [string]$Host = "120.53.222.17", - [int]$Port = 5432, - [string]$AdminUser = "postgres", - [string]$AdminPassword = "" -) - -if (-not (Get-Command psql -ErrorAction SilentlyContinue)) { - throw "psql command not found. Add PostgreSQL bin directory to PATH." -} - -if ([string]::IsNullOrWhiteSpace($AdminPassword)) { - Write-Warning "AdminPassword not provided. You will be prompted by psql." -} - -$sqlPath = Join-Path $PSScriptRoot "create_databases.sql" -if (-not (Test-Path $sqlPath)) { - throw "Cannot find create_databases.sql under $PSScriptRoot." -} - -$env:PGPASSWORD = $AdminPassword - -$arguments = @( - "-h", $Host, - "-p", $Port, - "-U", $AdminUser, - "-f", $sqlPath -) - -Write-Host "Executing create_databases.sql on $Host:$Port as $AdminUser ..." -& psql @arguments - -if ($LASTEXITCODE -ne 0) { - throw "psql returned non-zero exit code ($LASTEXITCODE)." -} - -Write-Host "PostgreSQL databases and roles ensured successfully." diff --git a/deploy/postgres/create_databases.sql b/deploy/postgres/create_databases.sql deleted file mode 100644 index afc0817..0000000 --- a/deploy/postgres/create_databases.sql +++ /dev/null @@ -1,102 +0,0 @@ --- Reusable provisioning script for Takeout SaaS PostgreSQL databases. --- Execute with a superuser (e.g. postgres). Safe to re-run. - -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'app_user') THEN - CREATE ROLE app_user LOGIN PASSWORD 'AppUser112233'; - END IF; - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'identity_user') THEN - CREATE ROLE identity_user LOGIN PASSWORD 'IdentityUser112233'; - END IF; - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'dictionary_user') THEN - CREATE ROLE dictionary_user LOGIN PASSWORD 'DictionaryUser112233'; - END IF; - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'hangfire_user') THEN - CREATE ROLE hangfire_user LOGIN PASSWORD 'HangFire112233'; - END IF; - IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'logs_user') THEN - CREATE ROLE logs_user LOGIN PASSWORD 'Logs112233'; - END IF; -END $$; - -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'takeout_app_db') THEN - CREATE DATABASE takeout_app_db OWNER app_user ENCODING 'UTF8'; - END IF; -END $$; -COMMENT ON DATABASE takeout_app_db IS 'Takeout SaaS 业务域数据库'; - -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'takeout_identity_db') THEN - CREATE DATABASE takeout_identity_db OWNER identity_user ENCODING 'UTF8'; - END IF; -END $$; -COMMENT ON DATABASE takeout_identity_db IS 'Takeout SaaS 身份域数据库'; - -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'takeout_dictionary_db') THEN - CREATE DATABASE takeout_dictionary_db OWNER dictionary_user ENCODING 'UTF8'; - END IF; -END $$; -COMMENT ON DATABASE takeout_dictionary_db IS 'Takeout SaaS 字典域数据库'; - -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'takeout_hangfire_db') THEN - CREATE DATABASE takeout_hangfire_db OWNER hangfire_user ENCODING 'UTF8'; - END IF; -END $$; -COMMENT ON DATABASE takeout_hangfire_db IS 'Takeout SaaS 调度/Hangfire 数据库'; - -DO $$ -BEGIN - IF NOT EXISTS (SELECT 1 FROM pg_database WHERE datname = 'takeout_logs_db') THEN - CREATE DATABASE takeout_logs_db OWNER logs_user ENCODING 'UTF8'; - END IF; -END $$; -COMMENT ON DATABASE takeout_logs_db IS 'Takeout SaaS 审计/日志数据库'; - --- Ensure privileges and default schema permissions -\connect takeout_app_db -GRANT CONNECT, TEMP ON DATABASE takeout_app_db TO app_user; -GRANT USAGE ON SCHEMA public TO app_user; -GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO app_user; -GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO app_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO app_user; - -\connect takeout_identity_db -GRANT CONNECT, TEMP ON DATABASE takeout_identity_db TO identity_user; -GRANT USAGE ON SCHEMA public TO identity_user; -GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO identity_user; -GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO identity_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO identity_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO identity_user; - -\connect takeout_dictionary_db -GRANT CONNECT, TEMP ON DATABASE takeout_dictionary_db TO dictionary_user; -GRANT USAGE ON SCHEMA public TO dictionary_user; -GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO dictionary_user; -GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO dictionary_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO dictionary_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO dictionary_user; - -\connect takeout_hangfire_db -GRANT CONNECT, TEMP ON DATABASE takeout_hangfire_db TO hangfire_user; -GRANT USAGE ON SCHEMA public TO hangfire_user; -GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO hangfire_user; -GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO hangfire_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO hangfire_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO hangfire_user; - -\connect takeout_logs_db -GRANT CONNECT, TEMP ON DATABASE takeout_logs_db TO logs_user; -GRANT USAGE ON SCHEMA public TO logs_user; -GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO logs_user; -GRANT USAGE, SELECT, UPDATE ON ALL SEQUENCES IN SCHEMA public TO logs_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO logs_user; -ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO logs_user; diff --git a/deploy/postgres/migrate_logs_to_logs_db.sql b/deploy/postgres/migrate_logs_to_logs_db.sql deleted file mode 100644 index 95892c8..0000000 --- a/deploy/postgres/migrate_logs_to_logs_db.sql +++ /dev/null @@ -1,89 +0,0 @@ --- 日志库迁移脚本(请在 psql 中按步骤执行) - --- 1. 在日志库创建表结构(takeout_logs_db) -\connect takeout_logs_db - -CREATE TABLE IF NOT EXISTS tenant_audit_logs ( - "Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - "TenantId" bigint NOT NULL, - "Action" integer NOT NULL, - "Title" character varying(128) NOT NULL, - "Description" character varying(1024), - "OperatorId" bigint, - "OperatorName" character varying(64), - "PreviousStatus" integer, - "CurrentStatus" integer, - "CreatedAt" timestamp with time zone NOT NULL, - "UpdatedAt" timestamp with time zone, - "DeletedAt" timestamp with time zone, - "CreatedBy" bigint, - "UpdatedBy" bigint, - "DeletedBy" bigint -); -CREATE INDEX IF NOT EXISTS "IX_tenant_audit_logs_TenantId" ON tenant_audit_logs ("TenantId"); - -CREATE TABLE IF NOT EXISTS merchant_audit_logs ( - "Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - "MerchantId" bigint NOT NULL, - "Action" integer NOT NULL, - "Title" character varying(128) NOT NULL, - "Description" character varying(1024), - "OperatorId" bigint, - "OperatorName" character varying(64), - "CreatedAt" timestamp with time zone NOT NULL, - "UpdatedAt" timestamp with time zone, - "DeletedAt" timestamp with time zone, - "CreatedBy" bigint, - "UpdatedBy" bigint, - "DeletedBy" bigint, - "TenantId" bigint NOT NULL -); -CREATE INDEX IF NOT EXISTS "IX_merchant_audit_logs_TenantId_MerchantId" ON merchant_audit_logs ("TenantId", "MerchantId"); - -CREATE TABLE IF NOT EXISTS operation_logs ( - "Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - "OperationType" character varying(64) NOT NULL, - "TargetType" character varying(64) NOT NULL, - "TargetIds" text, - "OperatorId" character varying(64), - "OperatorName" character varying(128), - "Parameters" text, - "Result" text, - "Success" boolean NOT NULL, - "CreatedAt" timestamp with time zone NOT NULL, - "UpdatedAt" timestamp with time zone, - "DeletedAt" timestamp with time zone, - "CreatedBy" bigint, - "UpdatedBy" bigint, - "DeletedBy" bigint -); -CREATE INDEX IF NOT EXISTS "IX_operation_logs_CreatedAt" ON operation_logs ("CreatedAt"); -CREATE INDEX IF NOT EXISTS "IX_operation_logs_OperationType_CreatedAt" ON operation_logs ("OperationType", "CreatedAt"); - -CREATE TABLE IF NOT EXISTS member_growth_logs ( - "Id" bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, - "MemberId" bigint NOT NULL, - "ChangeValue" integer NOT NULL, - "CurrentValue" integer NOT NULL, - "Notes" character varying(256), - "OccurredAt" timestamp with time zone NOT NULL, - "CreatedAt" timestamp with time zone NOT NULL, - "UpdatedAt" timestamp with time zone, - "DeletedAt" timestamp with time zone, - "CreatedBy" bigint, - "UpdatedBy" bigint, - "DeletedBy" bigint, - "TenantId" bigint NOT NULL -); -CREATE INDEX IF NOT EXISTS "IX_member_growth_logs_TenantId_MemberId_OccurredAt" ON member_growth_logs ("TenantId", "MemberId", "OccurredAt"); - --- 2. 迁移数据(建议使用 pg_dump/pg_restore 或应用侧批量拷贝) --- 示例:pg_dump -t tenant_audit_logs -t merchant_audit_logs -t operation_logs -t member_growth_logs takeout_app_db > logs_dump.sql --- psql -d takeout_logs_db -f logs_dump.sql - --- 3. 在业务库删除旧日志表(takeout_app_db) -\connect takeout_app_db -DROP TABLE IF EXISTS tenant_audit_logs; -DROP TABLE IF EXISTS merchant_audit_logs; -DROP TABLE IF EXISTS operation_logs; -DROP TABLE IF EXISTS member_growth_logs; diff --git a/deploy/prometheus/alert.rules.yml b/deploy/prometheus/alert.rules.yml deleted file mode 100644 index a74f845..0000000 --- a/deploy/prometheus/alert.rules.yml +++ /dev/null @@ -1,34 +0,0 @@ -groups: - - name: takeoutsaas-app - interval: 30s - rules: - - alert: HighErrorRate - expr: | - sum(rate(http_server_request_duration_seconds_count{http_response_status_code=~"5.."}[5m])) - / sum(rate(http_server_request_duration_seconds_count[5m])) > 0.05 - for: 5m - labels: - severity: critical - annotations: - summary: "API 5xx 错误率过高" - description: "过去 5 分钟 5xx 占比超过 5%,请检查依赖或发布" - - - alert: HighP95Latency - expr: | - histogram_quantile(0.95, sum(rate(http_server_request_duration_seconds_bucket[5m])) by (le, service_name)) - > 1 - for: 5m - labels: - severity: warning - annotations: - summary: "API P95 延迟过高" - description: "过去 5 分钟 P95 超过 1s,请排查热点接口或依赖" - - - alert: InstanceDown - expr: up{job=~"admin-api|mini-api|user-api"} == 0 - for: 2m - labels: - severity: critical - annotations: - summary: "实例不可达" - description: "Prometheus 抓取失败,实例处于 down 状态" diff --git a/deploy/prometheus/prometheus.yml b/deploy/prometheus/prometheus.yml deleted file mode 100644 index 3385f12..0000000 --- a/deploy/prometheus/prometheus.yml +++ /dev/null @@ -1,28 +0,0 @@ -global: - scrape_interval: 15s - evaluation_interval: 30s - -rule_files: - - alert.rules.yml - -scrape_configs: - - job_name: admin-api - metrics_path: /metrics - static_configs: - - targets: ["admin-api:8080"] - labels: - service: admin-api - - - job_name: mini-api - metrics_path: /metrics - static_configs: - - targets: ["mini-api:8080"] - labels: - service: mini-api - - - job_name: user-api - metrics_path: /metrics - static_configs: - - targets: ["user-api:8080"] - labels: - service: user-api diff --git a/deploy/redis/README.md b/deploy/redis/README.md deleted file mode 100644 index c955032..0000000 --- a/deploy/redis/README.md +++ /dev/null @@ -1,34 +0,0 @@ -# Redis 部署脚本 - -本目录提供可复用的 Redis 配置,既可在本地通过 Docker Compose 启动,也可将 `redis.conf` 拷贝到现有服务器,确保与线上一致。 - -## 1. 部署步骤 (裸机)\n\n1. 将 \\ edis.conf\\ 拷贝到服务器(例如 /etc/redis/redis.conf)。\n2. 根据需要修改数据目录(\\dir\\)和绑定地址。\n3. 使用系统服务或 \\ edis-server redis.conf\\ 启动。\n4. 确认开放端口 6379,保证通过 \\ edis-cli -h -a ping\\ 可访问。\n\n## 2. 配置说明\n\n- \\ equirepass\\ 已设置为 MsuMshk112233。\n- 启用 appendonly(AOF),并每秒 fsync。\n- \\maxmemory-policy\\ 为 allkeys-lru,适合缓存场景。\n- \\protected-mode no\\ 允许远程连接,需结合安全组或防火墙限制来源 IP。\n\n## 3. 常用命令使用 `redis.conf` - -1. 把 `redis.conf` 拷贝到服务器 `/etc/redis/redis.conf`(或自定义目录)。 -2. 修改 `dir` 指向实际数据目录。 -3. 使用系统服务或 `redis-server redis.conf` 启动。 - -关键配置已包含: - -- `requirepass`(密码) -- `protected-mode no`(允许远程连接) -- `appendonly yes` + `appendfsync everysec` -- `maxmemory-policy allkeys-lru` - -## 3. 常用命令 - -在应用或 CLI 中使用: - -```bash -redis-cli -h 49.232.6.45 -p 6379 -a MsuMshk112233 ping -``` - -`appsettings.*.json` 的格式:`"Redis": "49.232.6.45:6379,password=MsuMshk112233,abortConnect=false"` - -## 4. 备份 - -- RDB 文件:`dump.rdb` -- AOF 文件:`appendonly.aof` - -通过 `redis-cli -a save` 或 `bgsave` 触发。确保备份目录已纳入快照/对象存储。 - diff --git a/deploy/redis/redis.conf b/deploy/redis/redis.conf deleted file mode 100644 index 5d20bb0..0000000 --- a/deploy/redis/redis.conf +++ /dev/null @@ -1,25 +0,0 @@ -bind 0.0.0.0 -port 6379 -protected-mode no - -requirepass MsuMshk112233 - -timeout 0 -tcp-keepalive 300 - -daemonize no - -loglevel notice -databases 16 - -save 900 1 -save 300 10 -save 60 10000 - -appendonly yes -appendfilename "appendonly.aof" -appendfsync everysec - -dir /data - -maxmemory-policy allkeys-lru diff --git a/scripts/build-adminapi-forlinux.sh b/scripts/build-adminapi-forlinux.sh deleted file mode 100755 index cfadd23..0000000 --- a/scripts/build-adminapi-forlinux.sh +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env bash -# 用法:在 Linux 终端执行本脚本,自动构建并重启 AdminApi 容器。 -# 前置:已安装并运行 Docker。 -set -euo pipefail -# 0. 遇到异常时输出错误信息,方便查看 -trap 'echo "发生错误:${BASH_COMMAND}" >&2' ERR -# 1. 基本变量(脚本位于 repo_root/scripts,下移一层再上跳到仓库根) -script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -repo_root="$(cd "${script_dir}/.." && pwd)" -image_name='takeout.api.admin:dev' -container_name='takeout.api.admin' -dockerfile_path="${repo_root}/src/Api/TakeoutSaaS.AdminApi/Dockerfile" -echo "工作目录:${repo_root}" -# 2. 停止并删除旧容器 -if docker ps -a --format '{{.Names}}' | grep -qx "${container_name}"; then - echo "发现旧容器,正在移除:${container_name}" - docker stop "${container_name}" >/dev/null - docker rm "${container_name}" >/dev/null -fi -# 3. 删除旧镜像 -if docker images --format '{{.Repository}}:{{.Tag}}' | grep -qx "${image_name}"; then - echo "发现旧镜像,正在移除:${image_name}" - docker rmi "${image_name}" >/dev/null -fi -# 4. 构建最新镜像(使用仓库根作为上下文) -echo "开始构建镜像:${image_name}" -docker build -f "${dockerfile_path}" -t "${image_name}" "${repo_root}" -# 5. 运行新容器并映射端口 -echo "运行新容器:${container_name} (端口映射 7801:7801,环境 Development)" -docker run -d --name "${container_name}" -e ASPNETCORE_ENVIRONMENT=Development -p 7801:7801 "${image_name}" -echo "完成。镜像:${image_name},容器:${container_name}。Swagger 访问:http://localhost:7801/swagger" -# 6. 交互式终端下暂停,方便查看输出 -if [ -t 0 ]; then - read -r -p "按回车关闭窗口" _ -fi diff --git a/scripts/build-adminapi.ps1 b/scripts/build-adminapi.ps1 deleted file mode 100644 index 29265bd..0000000 --- a/scripts/build-adminapi.ps1 +++ /dev/null @@ -1,46 +0,0 @@ -<# -用法:在 PowerShell 中执行本脚本,自动构建并重启 AdminApi 容器。 -如果要放到桌面双击运行,可将本文件复制到桌面后右键“使用 PowerShell 运行”。 -前置:已安装并运行 Docker Desktop。 -#> - -# 遇到异常时停住窗口,方便查看错误 -trap { - Write-Host "发生错误:" $_ -ForegroundColor Red - Read-Host "按回车关闭窗口" - exit 1 -} - -$ErrorActionPreference = 'Stop' - -# 1. 基本变量(脚本位于 repo_root/scripts,下移一层再上跳到仓库根) -$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$repoRoot = Split-Path -Parent $scriptDir -$imageName = 'takeout.api.admin:dev' -$containerName = 'takeout.api.admin' -$dockerfilePath = Join-Path $repoRoot 'src/Api/TakeoutSaaS.AdminApi/Dockerfile' - -Write-Host "工作目录:$repoRoot" - -# 2. 停止并删除旧容器 -if ((docker ps -a --format '{{.Names}}') -contains $containerName) { - Write-Host "发现旧容器,正在移除:$containerName" - docker stop $containerName | Out-Null - docker rm $containerName | Out-Null -} - -# 3. 删除旧镜像 -if ((docker images --format '{{.Repository}}:{{.Tag}}') -contains $imageName) { - Write-Host "发现旧镜像,正在移除:$imageName" - docker rmi $imageName | Out-Null -} - -# 4. 构建最新镜像(使用仓库根作为上下文) -Write-Host "开始构建镜像:$imageName" -docker build -f $dockerfilePath -t $imageName $repoRoot - -# 5. 运行新容器并映射端口 -Write-Host "运行新容器:$containerName (端口映射 7801:7801,环境 Development)" -docker run -d --name $containerName -e ASPNETCORE_ENVIRONMENT=Development -p 7801:7801 $imageName - -Write-Host "完成。镜像:$imageName,容器:$containerName。Swagger 访问:http://localhost:7801/swagger" diff --git a/src/Api/TakeoutSaaS.AdminApi/Dockerfile b/src/Api/TakeoutSaaS.AdminApi/Dockerfile index 27f5733..72754e9 100644 --- a/src/Api/TakeoutSaaS.AdminApi/Dockerfile +++ b/src/Api/TakeoutSaaS.AdminApi/Dockerfile @@ -1,8 +1,33 @@ FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src + +# Copy only what's needed for restore first, so `dotnet restore` can be cached. +COPY ["Directory.Build.props", "./"] +COPY ["TakeoutSaaS.sln", "./"] +COPY ["stylecop.json", "./"] +COPY ["src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj", "src/Api/TakeoutSaaS.AdminApi/"] +COPY ["src/Application/TakeoutSaaS.Application/TakeoutSaaS.Application.csproj", "src/Application/TakeoutSaaS.Application/"] +COPY ["TakeoutSaaS.BuildingBlocks/src/Core/TakeoutSaaS.Shared.Abstractions/TakeoutSaaS.Shared.Abstractions.csproj", "TakeoutSaaS.BuildingBlocks/src/Core/TakeoutSaaS.Shared.Abstractions/"] +COPY ["TakeoutSaaS.BuildingBlocks/src/Core/TakeoutSaaS.Shared.Kernel/TakeoutSaaS.Shared.Kernel.csproj", "TakeoutSaaS.BuildingBlocks/src/Core/TakeoutSaaS.Shared.Kernel/"] +COPY ["TakeoutSaaS.BuildingBlocks/src/Core/TakeoutSaaS.Shared.Web/TakeoutSaaS.Shared.Web.csproj", "TakeoutSaaS.BuildingBlocks/src/Core/TakeoutSaaS.Shared.Web/"] +COPY ["src/Domain/TakeoutSaaS.Domain/TakeoutSaaS.Domain.csproj", "src/Domain/TakeoutSaaS.Domain/"] +COPY ["src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj", "src/Infrastructure/TakeoutSaaS.Infrastructure/"] +COPY ["src/Modules/TakeoutSaaS.Module.Authorization/TakeoutSaaS.Module.Authorization.csproj", "src/Modules/TakeoutSaaS.Module.Authorization/"] +COPY ["src/Modules/TakeoutSaaS.Module.Delivery/TakeoutSaaS.Module.Delivery.csproj", "src/Modules/TakeoutSaaS.Module.Delivery/"] +COPY ["src/Modules/TakeoutSaaS.Module.Dictionary/TakeoutSaaS.Module.Dictionary.csproj", "src/Modules/TakeoutSaaS.Module.Dictionary/"] +COPY ["src/Modules/TakeoutSaaS.Module.Messaging/TakeoutSaaS.Module.Messaging.csproj", "src/Modules/TakeoutSaaS.Module.Messaging/"] +COPY ["src/Modules/TakeoutSaaS.Module.Scheduler/TakeoutSaaS.Module.Scheduler.csproj", "src/Modules/TakeoutSaaS.Module.Scheduler/"] +COPY ["src/Modules/TakeoutSaaS.Module.Sms/TakeoutSaaS.Module.Sms.csproj", "src/Modules/TakeoutSaaS.Module.Sms/"] +COPY ["src/Modules/TakeoutSaaS.Module.Storage/TakeoutSaaS.Module.Storage.csproj", "src/Modules/TakeoutSaaS.Module.Storage/"] +COPY ["src/Modules/TakeoutSaaS.Module.Tenancy/TakeoutSaaS.Module.Tenancy.csproj", "src/Modules/TakeoutSaaS.Module.Tenancy/"] + +RUN dotnet restore "src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj" + +# Copy the rest of the source after restore for best cache reuse. COPY . . -RUN dotnet restore src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj -RUN dotnet publish src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj -c Release -o /app/publish + +ARG BUILD_CONFIGURATION=Release +RUN dotnet publish "src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj" -c $BUILD_CONFIGURATION -o /app/publish --no-restore FROM mcr.microsoft.com/dotnet/aspnet:10.0 WORKDIR /app diff --git a/src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj b/src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj index 59d35a0..212123a 100644 --- a/src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj +++ b/src/Api/TakeoutSaaS.AdminApi/TakeoutSaaS.AdminApi.csproj @@ -26,7 +26,7 @@ - + diff --git a/src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj b/src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj index 22d0212..653f6a0 100644 Binary files a/src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj and b/src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj differ diff --git a/src/Api/TakeoutSaaS.UserApi/TakeoutSaaS.UserApi.csproj b/src/Api/TakeoutSaaS.UserApi/TakeoutSaaS.UserApi.csproj index e6d50e9..ed127bd 100644 Binary files a/src/Api/TakeoutSaaS.UserApi/TakeoutSaaS.UserApi.csproj and b/src/Api/TakeoutSaaS.UserApi/TakeoutSaaS.UserApi.csproj differ diff --git a/src/Application/TakeoutSaaS.Application/TakeoutSaaS.Application.csproj b/src/Application/TakeoutSaaS.Application/TakeoutSaaS.Application.csproj index 9d43afd..cf2034e 100644 Binary files a/src/Application/TakeoutSaaS.Application/TakeoutSaaS.Application.csproj and b/src/Application/TakeoutSaaS.Application/TakeoutSaaS.Application.csproj differ diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/DatabaseConstants.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/DatabaseConstants.cs deleted file mode 100644 index 4e9e458..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/DatabaseConstants.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Constants; - -/// -/// 数据源名称常量,统一配置键与使用说明。 -/// -public static class DatabaseConstants -{ - /// - /// 默认业务库(AppDatabase). - /// - public const string AppDataSource = "AppDatabase"; - - /// - /// 身份认证库(IdentityDatabase)。 - /// - public const string IdentityDataSource = "IdentityDatabase"; - - /// - /// 字典库(DictionaryDatabase)。 - /// - public const string DictionaryDataSource = "DictionaryDatabase"; - - /// - /// 日志库(LogsDatabase)。 - /// - public const string LogsDataSource = "LogsDatabase"; -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/ErrorCodes.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/ErrorCodes.cs deleted file mode 100644 index 3214155..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Constants/ErrorCodes.cs +++ /dev/null @@ -1,47 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Constants; - -/// -/// 统一错误码常量。 -/// -public static class ErrorCodes -{ - /// - /// 请求参数错误。 - /// - public const int BadRequest = 400; - - /// - /// 未授权访问。 - /// - public const int Unauthorized = 401; - - /// - /// 权限不足。 - /// - public const int Forbidden = 403; - - /// - /// 资源未找到。 - /// - public const int NotFound = 404; - - /// - /// 资源冲突。 - /// - public const int Conflict = 409; - - /// - /// 校验失败。 - /// - public const int ValidationFailed = 422; - - /// - /// 服务器内部错误。 - /// - public const int InternalServerError = 500; - - /// - /// 业务自定义错误(10000+)。 - /// - public const int BusinessError = 10001; -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Data/DatabaseConnectionRole.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Data/DatabaseConnectionRole.cs deleted file mode 100644 index 175f9f6..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Data/DatabaseConnectionRole.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Data; - -/// -/// 数据库连接角色,用于区分主写与从读连接。 -/// -public enum DatabaseConnectionRole -{ - /// - /// 主写连接,用于写入或强一致读。 - /// - Write = 1, - - /// - /// 从读连接,用于只读查询或报表。 - /// - Read = 2 -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Data/IDapperExecutor.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Data/IDapperExecutor.cs deleted file mode 100644 index 0423468..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Data/IDapperExecutor.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System.Data; - -namespace TakeoutSaaS.Shared.Abstractions.Data; - -/// -/// Dapper 查询/命令执行器抽象,封装连接获取与读写路由。 -/// -public interface IDapperExecutor -{ - /// - /// 使用指定数据源与读写角色执行异步查询,并返回结果。 - /// - /// 查询结果类型。 - /// 逻辑数据源名称。 - /// 连接角色(读/写)。 - /// 查询委托,提供已打开的连接和取消标记。 - /// 取消标记。 - /// 查询结果。 - Task QueryAsync( - string dataSourceName, - DatabaseConnectionRole role, - Func> query, - CancellationToken cancellationToken = default); - - /// - /// 使用指定数据源与读写角色执行异步命令。 - /// - /// 逻辑数据源名称。 - /// 连接角色(读/写)。 - /// 命令委托,提供已打开的连接和取消标记。 - /// 取消标记。 - /// 异步执行任务。 - Task ExecuteAsync( - string dataSourceName, - DatabaseConnectionRole role, - Func command, - CancellationToken cancellationToken = default); - - /// - /// 获取指定数据源及角色的默认命令超时时间(秒)。 - /// - /// 逻辑数据源名称。 - /// 连接角色,默认读取从库。 - /// 命令超时时间(秒)。 - int GetDefaultCommandTimeoutSeconds( - string dataSourceName, - DatabaseConnectionRole role = DatabaseConnectionRole.Read); -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Diagnostics/TraceContext.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Diagnostics/TraceContext.cs deleted file mode 100644 index ae8284b..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Diagnostics/TraceContext.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Diagnostics; - -/// -/// 轻量级 TraceId/SpanId 上下文,便于跨层访问当前请求的追踪标识。 -/// -public static class TraceContext -{ - private static readonly AsyncLocal TraceIdHolder = new(); - private static readonly AsyncLocal SpanIdHolder = new(); - - /// - /// 当前请求的 TraceId。 - /// - public static string? TraceId - { - get => TraceIdHolder.Value; - set => TraceIdHolder.Value = value; - } - - /// - /// 当前请求的 SpanId。 - /// - public static string? SpanId - { - get => SpanIdHolder.Value; - set => SpanIdHolder.Value = value; - } - - /// - /// 清理 TraceId,避免 AsyncLocal 污染其它请求。 - /// - public static void Clear() - { - TraceIdHolder.Value = null; - SpanIdHolder.Value = null; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/AuditableEntityBase.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/AuditableEntityBase.cs deleted file mode 100644 index 6dbcf9c..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/AuditableEntityBase.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Entities; - -/// -/// 审计实体基类:提供创建、更新时间以及软删除时间。 -/// -public abstract class AuditableEntityBase : EntityBase, IAuditableEntity -{ - /// - /// 创建时间(UTC)。 - /// - public DateTime CreatedAt { get; set; } - - /// - /// 最近一次更新时间(UTC),从未更新时为 null。 - /// - public DateTime? UpdatedAt { get; set; } - - /// - /// 软删除时间(UTC),未删除时为 null。 - /// - public DateTime? DeletedAt { get; set; } - - /// - /// 创建人用户标识,匿名或系统操作时为 null。 - /// - public long? CreatedBy { get; set; } - - /// - /// 最后更新人用户标识,匿名或系统操作时为 null。 - /// - public long? UpdatedBy { get; set; } - - /// - /// 删除人用户标识(软删除),未删除时为 null。 - /// - public long? DeletedBy { get; set; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/EntityBase.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/EntityBase.cs deleted file mode 100644 index e1e2aa4..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/EntityBase.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Entities; - -/// -/// 实体基类,统一提供主键标识。 -/// -public abstract class EntityBase -{ - /// - /// 实体唯一标识。 - /// - public long Id { get; set; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/IAuditableEntity.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/IAuditableEntity.cs deleted file mode 100644 index 844ad54..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/IAuditableEntity.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Entities; - -/// -/// 审计字段接口:提供创建、更新、删除时间与操作者标识。 -/// -public interface IAuditableEntity : ISoftDeleteEntity -{ - /// - /// 创建时间(UTC)。 - /// - DateTime CreatedAt { get; set; } - - /// - /// 更新时间(UTC),未更新时为 null。 - /// - DateTime? UpdatedAt { get; set; } - - /// - /// 删除时间(UTC),未删除时为 null。 - /// - new DateTime? DeletedAt { get; set; } - - /// - /// 创建人用户标识,匿名或系统操作时为 null。 - /// - long? CreatedBy { get; set; } - - /// - /// 最后更新人用户标识,匿名或系统操作时为 null。 - /// - long? UpdatedBy { get; set; } - - /// - /// 删除人用户标识(软删除),未删除时为 null。 - /// - long? DeletedBy { get; set; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/IMultiTenantEntity.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/IMultiTenantEntity.cs deleted file mode 100644 index 1a0fecd..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/IMultiTenantEntity.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Entities; - -/// -/// 多租户实体约定:所有持久化实体须包含租户标识字段。 -/// -public interface IMultiTenantEntity -{ - /// - /// 所属租户 ID。 - /// - long TenantId { get; set; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/ISoftDeleteEntity.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/ISoftDeleteEntity.cs deleted file mode 100644 index 4bc3fba..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/ISoftDeleteEntity.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Entities; - -/// -/// 软删除实体约定:提供可空的删除时间戳以支持全局过滤。 -/// -public interface ISoftDeleteEntity -{ - /// - /// 删除时间(UTC),未删除时为 null。 - /// - DateTime? DeletedAt { get; set; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/MultiTenantEntityBase.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/MultiTenantEntityBase.cs deleted file mode 100644 index df6417e..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Entities/MultiTenantEntityBase.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Entities; - -/// -/// 多租户审计实体基类:提供租户标识、审计字段与软删除标记。 -/// -public abstract class MultiTenantEntityBase : AuditableEntityBase, IMultiTenantEntity -{ - /// - /// 所属租户 ID。 - /// - public long TenantId { get; set; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Exceptions/BusinessException.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Exceptions/BusinessException.cs deleted file mode 100644 index b14dc4a..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Exceptions/BusinessException.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Exceptions; - -/// -/// 业务异常(用于可预期的业务校验错误)。 -/// -public class BusinessException(int errorCode, string message) : Exception(message) -{ - /// - /// 业务错误码。 - /// - public int ErrorCode { get; } = errorCode; -} - diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Exceptions/ValidationException.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Exceptions/ValidationException.cs deleted file mode 100644 index f95bf0b..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Exceptions/ValidationException.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Exceptions; - -/// -/// 验证异常(用于聚合验证错误信息)。 -/// -public class ValidationException(IDictionary errors) : Exception("一个或多个验证错误") -{ - /// - /// 字段/属性的错误集合。 - /// - public IDictionary Errors { get; } = errors; -} - diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Ids/IIdGenerator.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Ids/IIdGenerator.cs deleted file mode 100644 index ce8dff4..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Ids/IIdGenerator.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Ids; - -/// -/// 雪花 ID 生成器接口。 -/// -public interface IIdGenerator -{ - /// - /// 生成下一个唯一长整型 ID。 - /// - /// 雪花 ID。 - long NextId(); -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Ids/IdGeneratorOptions.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Ids/IdGeneratorOptions.cs deleted file mode 100644 index 6d9b40f..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Ids/IdGeneratorOptions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using System.ComponentModel.DataAnnotations; - -namespace TakeoutSaaS.Shared.Abstractions.Ids; - -/// -/// 雪花 ID 生成器配置。 -/// -public sealed class IdGeneratorOptions -{ - /// - /// 配置节名称。 - /// - public const string SectionName = "IdGenerator"; - - /// - /// 工作节点标识,0-31。 - /// - [Range(0, 31)] - public int WorkerId { get; set; } - - /// - /// 机房标识,0-31。 - /// - [Range(0, 31)] - public int DatacenterId { get; set; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Results/ApiResponse.NonGeneric.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Results/ApiResponse.NonGeneric.cs deleted file mode 100644 index 04f400c..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Results/ApiResponse.NonGeneric.cs +++ /dev/null @@ -1,43 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Results; - -/// -/// 非泛型便捷封装。 -/// -public static class ApiResponse -{ - /// - /// 仅返回成功消息(无数据)。 - /// - /// 提示信息。 - /// 封装后的成功响应。 - public static ApiResponse Success(string? message = "操作成功") - => ApiResponse.Ok(message: message); - - /// - /// 成功且携带数据。 - /// - /// 业务数据。 - /// 提示信息。 - /// 封装后的成功响应。 - public static ApiResponse Ok(object? data, string? message = "操作成功") - => data is null ? ApiResponse.Ok(message: message) : ApiResponse.Ok(data, message); - - /// - /// 错误返回。 - /// - /// 错误码。 - /// 错误提示。 - /// 封装后的失败响应。 - public static ApiResponse Failure(int code, string message) - => ApiResponse.Error(code, message); - - /// - /// 错误返回(附带详情)。 - /// - /// 错误码。 - /// 错误提示。 - /// 错误详情。 - /// 封装后的失败响应。 - public static ApiResponse Error(int code, string message, object? errors = null) - => ApiResponse.Error(code, message, errors); -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Results/ApiResponse.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Results/ApiResponse.cs deleted file mode 100644 index f89a1b7..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Results/ApiResponse.cs +++ /dev/null @@ -1,203 +0,0 @@ -using System.Diagnostics; -using TakeoutSaaS.Shared.Abstractions.Diagnostics; - -namespace TakeoutSaaS.Shared.Abstractions.Results; - -/// -/// 统一的 API 返回结果包装。 -/// -/// 数据载荷类型。 -public sealed record ApiResponse -{ - /// - /// 是否成功。 - /// - public bool Success { get; init; } - - /// - /// 状态/错误码(默认 200)。 - /// - public int Code { get; init; } = 200; - - /// - /// 提示信息。 - /// - public string? Message { get; init; } - - /// - /// 业务数据。 - /// - public T? Data { get; init; } - - /// - /// 错误详情(如字段验证错误)。 - /// - public object? Errors { get; init; } - - /// - /// TraceId,便于链路追踪。 - /// - public string TraceId { get; init; } = string.Empty; - - /// - /// 时间戳(UTC)。 - /// - public DateTime Timestamp { get; init; } = DateTime.UtcNow; - - /// - /// 成功返回。 - /// - /// 业务数据。 - /// 提示信息。 - /// 封装后的成功响应。 - public static ApiResponse Ok(T data, string? message = "操作成功") - => Create(true, 200, message, data); - - /// - /// 无数据的成功返回。 - /// - /// 提示信息。 - /// 封装后的成功响应。 - public static ApiResponse Ok(string? message = "操作成功") - => Create(true, 200, message, default); - - /// - /// 兼容旧名称:成功结果。 - /// - /// 业务数据。 - /// 提示信息。 - /// 封装后的成功响应。 - public static ApiResponse SuccessResult(T data, string? message = "操作成功") - => Ok(data, message); - - /// - /// 错误返回。 - /// - /// 错误码。 - /// 错误提示。 - /// 错误详情。 - /// 封装后的失败响应。 - public static ApiResponse Error(int code, string message, object? errors = null) - => Create(false, code, message, default, errors); - - /// - /// 兼容旧名称:失败结果。 - /// - /// 错误码。 - /// 错误提示。 - /// 封装后的失败响应。 - public static ApiResponse Failure(int code, string message) - => Error(code, message); - - /// - /// 附加错误详情。 - /// - /// 错误详情。 - /// 包含错误详情的新响应。 - public ApiResponse WithErrors(object? errors) - => this with { Errors = errors }; - - private static ApiResponse Create(bool success, int code, string? message, T? data, object? errors = null) - => new() - { - Success = success, - Code = code, - Message = message, - Data = data, - Errors = errors, - TraceId = ResolveTraceId(), - Timestamp = DateTime.UtcNow - }; - - /// - /// 解析当前 TraceId。 - /// - /// 当前有效的 TraceId。 - private static string ResolveTraceId() - { - if (!string.IsNullOrWhiteSpace(TraceContext.TraceId)) - { - return TraceContext.TraceId; - } - - if (!string.IsNullOrWhiteSpace(TraceContext.TraceId)) - { - return TraceContext.TraceId; - } - - if (Activity.Current?.Id is { } id && !string.IsNullOrWhiteSpace(id)) - { - return id; - } - - return IdFallbackGenerator.Instance.NextId().ToString(); - } -} - -/// -/// 作为 TraceId 缺失时的本地雪花 ID 备用生成器。 -/// -internal sealed class IdFallbackGenerator -{ - /// - /// 延迟初始化的单例实例承载。 - /// - private static readonly Lazy Lazy = new(() => new IdFallbackGenerator()); - - /// - /// 获取备用雪花生成器单例。 - /// - public static IdFallbackGenerator Instance => Lazy.Value; - - private readonly object _sync = new(); - private long _lastTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - private long _sequence; - - private IdFallbackGenerator() - { - } - - /// - /// 生成雪花风格的本地备用 ID。 - /// - /// 本地生成的雪花 ID。 - public long NextId() - { - lock (_sync) - { - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - if (timestamp == _lastTimestamp) - { - _sequence = (_sequence + 1) & 4095; - if (_sequence == 0) - { - timestamp = WaitNextMillis(_lastTimestamp); - } - } - else - { - _sequence = 0; - } - - _lastTimestamp = timestamp; - return ((timestamp - 1577836800000L) << 22) | _sequence; - } - } - - /// - /// 等待到下一个毫秒以避免序列冲突。 - /// - /// 上一毫秒的时间戳。 - /// 下一个时间戳(毫秒)。 - private static long WaitNextMillis(long lastTimestamp) - { - var timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - while (timestamp <= lastTimestamp) - { - Thread.SpinWait(100); - timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - } - - return timestamp; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Results/PagedResult.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Results/PagedResult.cs deleted file mode 100644 index 4bc4c7e..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Results/PagedResult.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Results; - -/// -/// 分页结果包装,携带列表与总条数等元数据。 -/// -/// 数据类型。 -/// -/// 初始化分页结果。 -/// -public sealed class PagedResult(IReadOnlyList items, int page, int pageSize, int totalCount) -{ - /// - /// 数据列表。 - /// - public IReadOnlyList Items { get; } = items; - - /// - /// 当前页码,从 1 开始。 - /// - public int Page { get; } = page; - - /// - /// 每页条数。 - /// - public int PageSize { get; } = pageSize; - - /// - /// 总条数。 - /// - public int TotalCount { get; } = totalCount; - - /// - /// 总页数。 - /// - public int TotalPages { get; } = pageSize == 0 ? 0 : (int)Math.Ceiling(totalCount / (double)pageSize); -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Security/ICurrentUserAccessor.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Security/ICurrentUserAccessor.cs deleted file mode 100644 index ba0d7e2..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Security/ICurrentUserAccessor.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Security; - -/// -/// 当前用户访问器:提供与当前请求相关的用户标识信息。 -/// -public interface ICurrentUserAccessor -{ - /// - /// 当前用户 ID,未登录时为 Guid.Empty。 - /// - long UserId { get; } - - /// - /// 是否已登录。 - /// - bool IsAuthenticated { get; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Serialization/SnowflakeIdJsonConverter.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Serialization/SnowflakeIdJsonConverter.cs deleted file mode 100644 index b7f82a0..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Serialization/SnowflakeIdJsonConverter.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace TakeoutSaaS.Shared.Abstractions.Serialization; - -/// -/// 将 long 类型的雪花 ID 以字符串形式序列化/反序列化,避免前端精度丢失。 -/// -public sealed class SnowflakeIdJsonConverter : JsonConverter -{ - /// - public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.TokenType switch - { - JsonTokenType.Number => reader.GetInt64(), - JsonTokenType.String when long.TryParse(reader.GetString(), out var value) => value, - JsonTokenType.Null => 0, - _ => throw new JsonException("无法解析雪花 ID") - }; - } - - /// - public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options) - { - writer.WriteStringValue(value == 0 ? "0" : value.ToString()); - } -} - -/// -/// 可空雪花 ID 转换器。 -/// -public sealed class NullableSnowflakeIdJsonConverter : JsonConverter -{ - /// - public override long? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - { - return reader.TokenType switch - { - JsonTokenType.Number => reader.GetInt64(), - JsonTokenType.String when long.TryParse(reader.GetString(), out var value) => value, - JsonTokenType.Null => null, - _ => throw new JsonException("无法解析雪花 ID") - }; - } - - /// - public override void Write(Utf8JsonWriter writer, long? value, JsonSerializerOptions options) - { - writer.WriteStringValue(value.HasValue ? value.Value.ToString() : null); - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/TakeoutSaaS.Shared.Abstractions.csproj b/src/Core/TakeoutSaaS.Shared.Abstractions/TakeoutSaaS.Shared.Abstractions.csproj deleted file mode 100644 index 43219c2..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/TakeoutSaaS.Shared.Abstractions.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - net10.0 - enable - enable - true - 1591 - - - - - - diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/ITenantContextAccessor.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/ITenantContextAccessor.cs deleted file mode 100644 index c05f027..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/ITenantContextAccessor.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Tenancy; - -/// -/// 租户上下文访问器:用于在请求生命周期内读写当前租户上下文。 -/// -public interface ITenantContextAccessor -{ - /// - /// 获取或设置当前租户上下文。 - /// - TenantContext? Current { get; set; } -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/ITenantProvider.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/ITenantProvider.cs deleted file mode 100644 index 76358db..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/ITenantProvider.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Tenancy; - -/// -/// 租户提供者:用于在各层读取当前请求绑定的租户 ID。 -/// -public interface ITenantProvider -{ - /// - /// 获取当前租户 ID,未解析时返回 0。 - /// - /// 当前请求绑定的租户 ID,未解析时为 0。 - long GetCurrentTenantId(); -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/TenantConstants.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/TenantConstants.cs deleted file mode 100644 index d5638fa..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/TenantConstants.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Tenancy; - -/// -/// 多租户相关通用常量。 -/// -public static class TenantConstants -{ - /// - /// HttpContext.Items 中租户上下文的键名。 - /// - public const string HttpContextItemKey = "__tenant_context"; -} diff --git a/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/TenantContext.cs b/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/TenantContext.cs deleted file mode 100644 index 8ba5da6..0000000 --- a/src/Core/TakeoutSaaS.Shared.Abstractions/Tenancy/TenantContext.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace TakeoutSaaS.Shared.Abstractions.Tenancy; - -/// -/// 租户上下文:封装当前请求解析得到的租户标识、编号及解析来源。 -/// -/// -/// 初始化租户上下文。 -/// -/// 租户 ID -/// 租户编码(可选) -/// 解析来源 -public sealed class TenantContext(long tenantId, string? tenantCode, string source) -{ - /// - /// 未解析到租户时的默认上下文。 - /// - public static TenantContext Empty { get; } = new(0, null, "unresolved"); - - /// - /// 当前租户 ID,未解析时为 Guid.Empty。 - /// - public long TenantId { get; } = tenantId; - - /// - /// 当前租户编码(例如子域名或业务编码),可为空。 - /// - public string? TenantCode { get; } = tenantCode; - - /// - /// 租户解析来源(Header、Host、Token 等)。 - /// - public string Source { get; } = source; - - /// - /// 是否已成功解析到租户。 - /// - public bool IsResolved => TenantId != 0; -} diff --git a/src/Core/TakeoutSaaS.Shared.Kernel/Ids/SnowflakeIdGenerator.cs b/src/Core/TakeoutSaaS.Shared.Kernel/Ids/SnowflakeIdGenerator.cs deleted file mode 100644 index 862edb9..0000000 --- a/src/Core/TakeoutSaaS.Shared.Kernel/Ids/SnowflakeIdGenerator.cs +++ /dev/null @@ -1,104 +0,0 @@ -using System.Diagnostics; -using System.Security.Cryptography; -using TakeoutSaaS.Shared.Abstractions.Ids; - -namespace TakeoutSaaS.Shared.Kernel.Ids; - -/// -/// 基于雪花算法的长整型 ID 生成器。 -/// -/// -/// 初始化生成器。 -/// -/// 工作节点 ID。 -/// 机房 ID。 -public sealed class SnowflakeIdGenerator(long workerId = 0, long datacenterId = 0) : IIdGenerator -{ - private const long Twepoch = 1577836800000L; // 2020-01-01 UTC - private const int WorkerIdBits = 5; - private const int DatacenterIdBits = 5; - private const int SequenceBits = 12; - - private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits); - private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits); - - private const int WorkerIdShift = SequenceBits; - private const int DatacenterIdShift = SequenceBits + WorkerIdBits; - private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits; - private const long SequenceMask = -1L ^ (-1L << SequenceBits); - - private readonly long _workerId = Normalize(workerId, MaxWorkerId, nameof(workerId)); - private readonly long _datacenterId = Normalize(datacenterId, MaxDatacenterId, nameof(datacenterId)); - private long _lastTimestamp = -1L; - private long _sequence = RandomNumberGenerator.GetInt32(0, (int)SequenceMask); - private readonly object _syncRoot = new(); - - - /// - public long NextId() - { - lock (_syncRoot) - { - var timestamp = CurrentTimeMillis(); - - if (timestamp < _lastTimestamp) - { - // 时钟回拨时等待到下一毫秒。 - var wait = _lastTimestamp - timestamp; - Thread.Sleep(TimeSpan.FromMilliseconds(wait)); - timestamp = CurrentTimeMillis(); - if (timestamp < _lastTimestamp) - { - throw new InvalidOperationException($"系统时钟回拨 {_lastTimestamp - timestamp} 毫秒,无法生成 ID。"); - } - } - - if (_lastTimestamp == timestamp) - { - _sequence = (_sequence + 1) & SequenceMask; - if (_sequence == 0) - { - timestamp = WaitNextMillis(_lastTimestamp); - } - } - else - { - _sequence = 0; - } - - _lastTimestamp = timestamp; - - var id = ((timestamp - Twepoch) << TimestampLeftShift) - | (_datacenterId << DatacenterIdShift) - | (_workerId << WorkerIdShift) - | _sequence; - - Debug.Assert(id > 0); - return id; - } - } - - private static long WaitNextMillis(long lastTimestamp) - { - var timestamp = CurrentTimeMillis(); - while (timestamp <= lastTimestamp) - { - Thread.SpinWait(50); - timestamp = CurrentTimeMillis(); - } - - return timestamp; - } - - private static long CurrentTimeMillis() => DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); - - private static long Normalize(long value, long max, string name) - { - if (value < 0 || value > max) - { - throw new ArgumentOutOfRangeException(name, value, $"取值范围 0~{max}"); - } - - return value; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Kernel/TakeoutSaaS.Shared.Kernel.csproj b/src/Core/TakeoutSaaS.Shared.Kernel/TakeoutSaaS.Shared.Kernel.csproj deleted file mode 100644 index db63687..0000000 --- a/src/Core/TakeoutSaaS.Shared.Kernel/TakeoutSaaS.Shared.Kernel.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - net10.0 - enable - enable - - - - - - - - - diff --git a/src/Core/TakeoutSaaS.Shared.Web/Api/BaseApiController.cs b/src/Core/TakeoutSaaS.Shared.Web/Api/BaseApiController.cs deleted file mode 100644 index af1240e..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Api/BaseApiController.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Microsoft.AspNetCore.Mvc; - -namespace TakeoutSaaS.Shared.Web.Api; - -/// -/// API 基类控制器: -/// - 统一应用 [ApiController] 和默认响应类型 -/// - 作为所有 API 控制器的基类,便于复用过滤器/中间件特性 -/// -[ApiController] -[Produces("application/json")] -public abstract class BaseApiController : ControllerBase -{ -} - diff --git a/src/Core/TakeoutSaaS.Shared.Web/Extensions/ApplicationBuilderExtensions.cs b/src/Core/TakeoutSaaS.Shared.Web/Extensions/ApplicationBuilderExtensions.cs deleted file mode 100644 index 2c25aaa..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Extensions/ApplicationBuilderExtensions.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.AspNetCore.Builder; -using TakeoutSaaS.Shared.Web.Middleware; - -namespace TakeoutSaaS.Shared.Web.Extensions; - -/// -/// Web 应用中间件扩展。 -/// -public static class ApplicationBuilderExtensions -{ - /// - /// 按规范启用 TraceId、请求日志、异常映射与安全响应头。 - /// - public static IApplicationBuilder UseSharedWebCore(this IApplicationBuilder app) - { - app.UseMiddleware(); - app.UseMiddleware(); - app.UseMiddleware(); - app.UseMiddleware(); - return app; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Extensions/ServiceCollectionExtensions.cs b/src/Core/TakeoutSaaS.Shared.Web/Extensions/ServiceCollectionExtensions.cs deleted file mode 100644 index 842728d..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Extensions/ServiceCollectionExtensions.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Asp.Versioning; -using Asp.Versioning.ApiExplorer; -using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.DependencyInjection; -using TakeoutSaaS.Shared.Abstractions.Security; -using TakeoutSaaS.Shared.Web.Filters; -using TakeoutSaaS.Shared.Web.Security; -namespace TakeoutSaaS.Shared.Web.Extensions; - -/// -/// Shared.Web 服务注册扩展。 -/// -public static class ServiceCollectionExtensions -{ - /// - /// 注册控制器、模型验证、API 版本化等基础能力。 - /// - public static IServiceCollection AddSharedWebCore(this IServiceCollection services) - { - // 1. 注册基础上下文与当前用户访问器 - services.AddHttpContextAccessor(); - services.AddEndpointsApiExplorer(); - services.AddScoped(); - // 2. 注册控制器与全局过滤器 - services - .AddControllers(options => - { - options.Filters.Add(); - options.Filters.Add(); - }) - .AddNewtonsoftJson(); - // 3. 配置模型验证行为 - services.Configure(options => - { - options.SuppressModelStateInvalidFilter = true; - }); - // 4. 配置 API 版本化 - var apiVersioningBuilder = services.AddApiVersioning(options => - { - options.AssumeDefaultVersionWhenUnspecified = true; - options.DefaultApiVersion = new ApiVersion(1, 0); - options.ReportApiVersions = true; - }); - // 5. 注册版本化 Api Explorer - apiVersioningBuilder.AddApiExplorer(setup => - { - setup.GroupNameFormat = "'v'VVV"; - setup.SubstituteApiVersionInUrl = true; - }); - // 6. 返回服务集合 - return services; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Filters/ApiResponseResultFilter.cs b/src/Core/TakeoutSaaS.Shared.Web/Filters/ApiResponseResultFilter.cs deleted file mode 100644 index 30c6c7c..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Filters/ApiResponseResultFilter.cs +++ /dev/null @@ -1,115 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using TakeoutSaaS.Shared.Abstractions.Constants; -using TakeoutSaaS.Shared.Abstractions.Results; - -namespace TakeoutSaaS.Shared.Web.Filters; - -/// -/// ApiResponse 结果过滤器:自动将 ApiResponse 转换为对应的 HTTP 状态码。 -/// 使用此过滤器后,控制器可以直接返回 ApiResponse<T>,无需再包一层 Ok() 或 Unauthorized()。 -/// -public sealed class ApiResponseResultFilter : IAsyncResultFilter -{ - /// - /// 执行结果过滤,将 ApiResponse 映射为对应 HTTP 状态码。 - /// - /// 结果执行上下文。 - /// 后续委托。 - /// 异步任务。 - public Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next) - { - // 1. 仅处理 ObjectResult - // 只处理 ObjectResult 类型的结果 - if (context.Result is not ObjectResult objectResult) - { - return next(); - } - - // 2. 结果为空直接跳过 - var value = objectResult.Value; - if (value == null) - { - return next(); - } - - // 3. 确认类型为 ApiResponse - // 检查是否是 ApiResponse 类型 - var valueType = value.GetType(); - if (!IsApiResponseType(valueType)) - { - return next(); - } - - // 4. 读取 Success 与 Code - // 使用反射获取 Success 和 Code 属性 - // 注意:由于已通过 IsApiResponseType 检查,属性名是固定的 - const string successPropertyName = "Success"; - const string codePropertyName = "Code"; - var successProperty = valueType.GetProperty(successPropertyName); - var codeProperty = valueType.GetProperty(codePropertyName); - - if (successProperty == null || codeProperty == null) - { - return next(); - } - - var success = (bool)(successProperty.GetValue(value) ?? false); - var code = (int)(codeProperty.GetValue(value) ?? 200); - - // 5. 映射 HTTP 状态码 - // 根据 Success 和 Code 设置 HTTP 状态码 - var statusCode = success ? MapSuccessCode(code) : MapErrorCode(code); - - // 6. 回写状态码 - // 更新 ObjectResult 的状态码 - objectResult.StatusCode = statusCode; - - return next(); - } - - private static bool IsApiResponseType(Type type) - { - // 检查是否是 ApiResponse 类型 - if (type.IsGenericType) - { - var genericTypeDefinition = type.GetGenericTypeDefinition(); - return genericTypeDefinition == typeof(ApiResponse<>); - } - - return false; - } - - private static int MapSuccessCode(int code) - { - // 成功情况下,通常返回 200 - // 但也可以根据业务码返回其他成功状态码(如 201 Created) - return code switch - { - 200 => StatusCodes.Status200OK, - 201 => StatusCodes.Status201Created, - 204 => StatusCodes.Status204NoContent, - _ => StatusCodes.Status200OK - }; - } - - private static int MapErrorCode(int code) - { - // 根据业务错误码映射到 HTTP 状态码 - return code switch - { - ErrorCodes.BadRequest => StatusCodes.Status400BadRequest, - ErrorCodes.Unauthorized => StatusCodes.Status401Unauthorized, - ErrorCodes.Forbidden => StatusCodes.Status403Forbidden, - ErrorCodes.NotFound => StatusCodes.Status404NotFound, - ErrorCodes.Conflict => StatusCodes.Status409Conflict, - ErrorCodes.ValidationFailed => StatusCodes.Status422UnprocessableEntity, - ErrorCodes.InternalServerError => StatusCodes.Status500InternalServerError, - // 业务错误码(10000+)统一返回 422 - >= 10000 => StatusCodes.Status422UnprocessableEntity, - // 默认返回 400 - _ => StatusCodes.Status400BadRequest - }; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Filters/ValidateModelAttribute.cs b/src/Core/TakeoutSaaS.Shared.Web/Filters/ValidateModelAttribute.cs deleted file mode 100644 index f128bea..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Filters/ValidateModelAttribute.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using Microsoft.AspNetCore.Mvc.Filters; -using TakeoutSaaS.Shared.Abstractions.Constants; -using TakeoutSaaS.Shared.Abstractions.Results; - -namespace TakeoutSaaS.Shared.Web.Filters; - -/// -/// 模型验证过滤器:将模型验证错误统一为ApiResponse输出 -/// -public sealed class ValidateModelAttribute : ActionFilterAttribute -{ - /// - /// 在 Action 执行前拦截模型验证错误。 - /// - /// 执行上下文。 - public override void OnActionExecuting(ActionExecutingContext context) - { - // 1. 模型验证未通过则返回 422 - if (!context.ModelState.IsValid) - { - var errors = context.ModelState - .Where(kv => kv.Value?.Errors.Count > 0) - .ToDictionary( - kv => kv.Key, - kv => kv.Value!.Errors.Select(e => string.IsNullOrWhiteSpace(e.ErrorMessage) ? "Invalid" : e.ErrorMessage).ToArray() - ); - - var response = ApiResponse.Error(ErrorCodes.ValidationFailed, "一个或多个验证错误", errors); - context.Result = new UnprocessableEntityObjectResult(response); - } - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Middleware/CorrelationIdMiddleware.cs b/src/Core/TakeoutSaaS.Shared.Web/Middleware/CorrelationIdMiddleware.cs deleted file mode 100644 index 3f545e3..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Middleware/CorrelationIdMiddleware.cs +++ /dev/null @@ -1,108 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using System.Diagnostics; -using TakeoutSaaS.Shared.Abstractions.Diagnostics; -using TakeoutSaaS.Shared.Abstractions.Ids; - -namespace TakeoutSaaS.Shared.Web.Middleware; - -/// -/// 统一 TraceId/CorrelationId,贯穿日志与响应。 -/// -public sealed class CorrelationIdMiddleware(RequestDelegate next, ILogger logger, IIdGenerator idGenerator) -{ - private const string TraceHeader = "X-Trace-Id"; - private const string SpanHeader = "X-Span-Id"; - private const string RequestHeader = "X-Request-Id"; - - /// - /// 管道入口,确保 TraceId/SpanId 贯穿请求。 - /// - /// HTTP 上下文。 - public async Task InvokeAsync(HttpContext context) - { - // 1. 确保活动存在并启动 - var ownsActivity = Activity.Current is null; - var activity = Activity.Current ?? new Activity("TakeoutSaaS.Request"); - - if (activity.Id is null) - { - activity.SetIdFormat(ActivityIdFormat.W3C); - activity.Start(); - } - - // 2. 生成/解析 TraceId、SpanId - var traceId = activity.TraceId.ToString(); - var spanId = activity.SpanId.ToString(); - - if (string.IsNullOrWhiteSpace(traceId)) - { - traceId = ResolveTraceId(context); - } - - // 3. 写入上下文与响应头 - context.TraceIdentifier = traceId; - TraceContext.TraceId = traceId; - TraceContext.SpanId = spanId; - - context.Response.OnStarting(() => - { - context.Response.Headers[TraceHeader] = traceId; - context.Response.Headers[SpanHeader] = spanId; - return Task.CompletedTask; - }); - - // 4. 带 Scope 调用后续中间件 - using (logger.BeginScope(new Dictionary - { - ["TraceId"] = traceId, - ["SpanId"] = spanId - })) - { - try - { - await next(context); - } - finally - { - // 5. 清理上下文与活动 - TraceContext.Clear(); - if (ownsActivity) - { - activity.Stop(); - } - } - } - } - - private string ResolveTraceId(HttpContext context) - { - if (TryGetHeader(context, TraceHeader, out var traceId)) - { - return traceId; - } - - if (TryGetHeader(context, RequestHeader, out var requestId)) - { - return requestId; - } - - return idGenerator.NextId().ToString(); - } - - private static bool TryGetHeader(HttpContext context, string headerName, out string value) - { - if (context.Request.Headers.TryGetValue(headerName, out var values)) - { - var headerValue = values.ToString(); - if (!string.IsNullOrWhiteSpace(headerValue)) - { - value = headerValue; - return true; - } - } - - value = string.Empty; - return false; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Middleware/ExceptionHandlingMiddleware.cs b/src/Core/TakeoutSaaS.Shared.Web/Middleware/ExceptionHandlingMiddleware.cs deleted file mode 100644 index 6af83c7..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Middleware/ExceptionHandlingMiddleware.cs +++ /dev/null @@ -1,139 +0,0 @@ -using FluentValidation.Results; -using Microsoft.AspNetCore.Http; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; -using System.Text.Json; -using System.Text.Json.Serialization; -using System.Collections.Generic; -using TakeoutSaaS.Shared.Abstractions.Constants; -using TakeoutSaaS.Shared.Abstractions.Exceptions; -using TakeoutSaaS.Shared.Abstractions.Results; -using FluentValidationException = FluentValidation.ValidationException; -using SharedValidationException = TakeoutSaaS.Shared.Abstractions.Exceptions.ValidationException; - -namespace TakeoutSaaS.Shared.Web.Middleware; - -/// -/// 全局异常处理中间件,将异常统一映射为 ApiResponse。 -/// -public sealed class ExceptionHandlingMiddleware(RequestDelegate next, ILogger logger, IHostEnvironment environment) -{ - private static readonly HashSet AllowedHttpErrorCodes = new() - { - ErrorCodes.BadRequest, - ErrorCodes.Unauthorized, - ErrorCodes.Forbidden, - ErrorCodes.NotFound, - ErrorCodes.Conflict, - ErrorCodes.ValidationFailed - }; - - private static readonly JsonSerializerOptions SerializerOptions = new() - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull - }; - - /// - /// 中间件入口,捕获并统一处理异常。 - /// - /// HTTP 上下文。 - public async Task InvokeAsync(HttpContext context) - { - try - { - await next(context); - } - catch (Exception ex) - { - // 1. 记录异常 - logger.LogError(ex, "未处理异常:{Message}", ex.Message); - // 2. 返回统一错误响应 - await HandleExceptionAsync(context, ex); - } - } - - private Task HandleExceptionAsync(HttpContext context, Exception exception) - { - // 1. 构建错误响应与状态码 - var (statusCode, response) = BuildErrorResponse(exception); - - if (environment.IsDevelopment()) - { - // 2. 开发环境附加细节 - response = response with - { - Message = exception.Message, - Errors = new - { - response.Errors, - detail = exception.ToString() - } - }; - } - - // 3. 写入响应 - context.Response.StatusCode = statusCode; - context.Response.ContentType = "application/json"; - return context.Response.WriteAsJsonAsync(response, SerializerOptions); - } - - private static (int StatusCode, ApiResponse Response) BuildErrorResponse(Exception exception) - { - return exception switch - { - DbUpdateConcurrencyException => ( - StatusCodes.Status409Conflict, - ApiResponse.Error( - ErrorCodes.Conflict, - "数据已被他人修改,请刷新后重试", - new Dictionary - { - ["RowVersion"] = ["数据已被他人修改,请刷新后重试"] - })), - UnauthorizedAccessException => ( - StatusCodes.Status403Forbidden, - ApiResponse.Error(ErrorCodes.Forbidden, "无权访问该资源")), - SharedValidationException validationException => ( - StatusCodes.Status422UnprocessableEntity, - ApiResponse.Error(ErrorCodes.ValidationFailed, "请求参数验证失败", validationException.Errors)), - FluentValidationException fluentValidationException => ( - StatusCodes.Status422UnprocessableEntity, - ApiResponse.Error( - ErrorCodes.ValidationFailed, - "请求参数验证失败", - NormalizeValidationErrors(fluentValidationException.Errors))), - BusinessException businessException => ( - // 1. 仅当业务错误码在白名单且位于 400-499 时透传,否则回退 400 - AllowedHttpErrorCodes.Contains(businessException.ErrorCode) && businessException.ErrorCode is >= 400 and < 500 - ? businessException.ErrorCode - : StatusCodes.Status400BadRequest, - ApiResponse.Error(businessException.ErrorCode, businessException.Message)), - _ => ( - StatusCodes.Status500InternalServerError, - ApiResponse.Error(ErrorCodes.InternalServerError, "服务器开小差啦,请稍后再试")) - }; - } - - private static IDictionary NormalizeValidationErrors(IEnumerable failures) - { - var result = new Dictionary>(StringComparer.OrdinalIgnoreCase); - foreach (var failure in failures) - { - var key = string.IsNullOrWhiteSpace(failure.PropertyName) ? "request" : failure.PropertyName; - if (!result.TryGetValue(key, out var list)) - { - list = new List(); - result[key] = list; - } - - if (!string.IsNullOrWhiteSpace(failure.ErrorMessage)) - { - list.Add(failure.ErrorMessage); - } - } - - return result.ToDictionary(pair => pair.Key, pair => pair.Value.Distinct().ToArray(), StringComparer.OrdinalIgnoreCase); - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Middleware/RequestLoggingMiddleware.cs b/src/Core/TakeoutSaaS.Shared.Web/Middleware/RequestLoggingMiddleware.cs deleted file mode 100644 index bd7a983..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Middleware/RequestLoggingMiddleware.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.Extensions.Logging; -using System.Diagnostics; -using TakeoutSaaS.Shared.Abstractions.Diagnostics; - -namespace TakeoutSaaS.Shared.Web.Middleware; - -/// -/// 基础请求日志(方法、路径、耗时、状态码、TraceId)。 -/// -public sealed class RequestLoggingMiddleware(RequestDelegate next, ILogger logger) -{ - /// - /// 记录请求日志并调用后续中间件。 - /// - /// HTTP 上下文。 - public async Task InvokeAsync(HttpContext context) - { - // 1. 启动计时 - var stopwatch = Stopwatch.StartNew(); - try - { - await next(context); - } - finally - { - // 2. 结束计时并输出日志 - stopwatch.Stop(); - var traceId = TraceContext.TraceId ?? context.TraceIdentifier; - var spanId = TraceContext.SpanId ?? Activity.Current?.SpanId.ToString() ?? string.Empty; - logger.LogInformation( - "HTTP {Method} {Path} => {StatusCode} ({Elapsed} ms) TraceId:{TraceId} SpanId:{SpanId}", - context.Request.Method, - context.Request.Path, - context.Response.StatusCode, - stopwatch.Elapsed.TotalMilliseconds, - traceId, - spanId); - } - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Middleware/SecurityHeadersMiddleware.cs b/src/Core/TakeoutSaaS.Shared.Web/Middleware/SecurityHeadersMiddleware.cs deleted file mode 100644 index dbc8773..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Middleware/SecurityHeadersMiddleware.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Microsoft.AspNetCore.Http; - -namespace TakeoutSaaS.Shared.Web.Middleware; - -/// -/// 安全响应头中间件 -/// -public sealed class SecurityHeadersMiddleware(RequestDelegate next) -{ - /// - /// 设置基础安全响应头。 - /// - /// HTTP 上下文。 - public async Task InvokeAsync(HttpContext context) - { - // 1. 写入安全响应头 - var headers = context.Response.Headers; - headers["X-Content-Type-Options"] = "nosniff"; - headers["X-Frame-Options"] = "DENY"; - headers["X-XSS-Protection"] = "1; mode=block"; - headers["Referrer-Policy"] = "no-referrer"; - // 2. 继续后续管道 - await next(context); - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Security/ClaimsPrincipalExtensions.cs b/src/Core/TakeoutSaaS.Shared.Web/Security/ClaimsPrincipalExtensions.cs deleted file mode 100644 index 630789b..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Security/ClaimsPrincipalExtensions.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Security.Claims; - -namespace TakeoutSaaS.Shared.Web.Security; - -/// -/// ClaimsPrincipal 便捷扩展 -/// -public static class ClaimsPrincipalExtensions -{ - /// - /// 获取当前用户 Id(不存在时返回 0)。 - /// - public static long GetUserId(this ClaimsPrincipal? principal) - { - if (principal == null) - { - return 0; - } - - var identifier = principal.FindFirstValue(ClaimTypes.NameIdentifier) - ?? principal.FindFirstValue("sub"); - - return long.TryParse(identifier, out var userId) - ? userId - : 0; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Security/HttpContextCurrentUserAccessor.cs b/src/Core/TakeoutSaaS.Shared.Web/Security/HttpContextCurrentUserAccessor.cs deleted file mode 100644 index bc43ea8..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Security/HttpContextCurrentUserAccessor.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Microsoft.AspNetCore.Http; -using System.Security.Claims; -using TakeoutSaaS.Shared.Abstractions.Security; - -namespace TakeoutSaaS.Shared.Web.Security; - -/// -/// 基于 HttpContext 的当前用户访问器。 -/// -/// -/// 初始化访问器。 -/// -public sealed class HttpContextCurrentUserAccessor(IHttpContextAccessor httpContextAccessor) : ICurrentUserAccessor -{ - /// - public long UserId - { - get - { - var principal = httpContextAccessor.HttpContext?.User; - if (principal == null || !principal.Identity?.IsAuthenticated == true) - { - return 0; - } - - var identifier = principal.FindFirstValue(ClaimTypes.NameIdentifier) - ?? principal.FindFirstValue("sub"); - - return long.TryParse(identifier, out var id) ? id : 0; - } - } - - /// - public bool IsAuthenticated => UserId != 0; -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Security/TenantHttpContextExtensions.cs b/src/Core/TakeoutSaaS.Shared.Web/Security/TenantHttpContextExtensions.cs deleted file mode 100644 index 12832c9..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Security/TenantHttpContextExtensions.cs +++ /dev/null @@ -1,31 +0,0 @@ -using Microsoft.AspNetCore.Http; -using TakeoutSaaS.Shared.Abstractions.Tenancy; - -namespace TakeoutSaaS.Shared.Web.Security; - -/// -/// HttpContext 租户扩展方法。 -/// -public static class TenantHttpContextExtensions -{ - /// - /// 获取 HttpContext.Items 中缓存的租户上下文。 - /// - /// 当前 HttpContext - /// 租户上下文,若不存在则返回 null - public static TenantContext? GetTenantContext(this HttpContext? context) - { - if (context == null) - { - return null; - } - - if (context.Items.TryGetValue(TenantConstants.HttpContextItemKey, out var value) && - value is TenantContext tenantContext) - { - return tenantContext; - } - - return null; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Swagger/ConfigureSwaggerOptions.cs b/src/Core/TakeoutSaaS.Shared.Web/Swagger/ConfigureSwaggerOptions.cs deleted file mode 100644 index cfa1753..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Swagger/ConfigureSwaggerOptions.cs +++ /dev/null @@ -1,60 +0,0 @@ -using Asp.Versioning.ApiExplorer; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Options; -using Microsoft.OpenApi; -using Swashbuckle.AspNetCore.SwaggerGen; -namespace TakeoutSaaS.Shared.Web.Swagger; - -/// -/// 根据 API 版本动态注册 Swagger 文档。 -/// -internal sealed class ConfigureSwaggerOptions( - IApiVersionDescriptionProvider provider, - IOptions settings) : IConfigureOptions -{ - private readonly SwaggerDocumentSettings _settings = settings.Value; - - /// - /// 根据 API 版本生成 Swagger 文档配置。 - /// - public void Configure(SwaggerGenOptions options) - { - // 1. 为每个 API 版本注册文档 - foreach (var description in provider.ApiVersionDescriptions) - { - var info = new OpenApiInfo - { - Title = $"{_settings.Title} {description.ApiVersion}", - Version = description.ApiVersion.ToString(), - Description = description.IsDeprecated - ? $"{_settings.Description}(该版本已弃用)" - : _settings.Description - }; - options.SwaggerGeneratorOptions.SwaggerDocs[description.GroupName] = info; - } - - // 2. 配置 JWT 授权信息 - if (_settings.EnableAuthorization) - { - const string bearerSchemeName = "Bearer"; - var scheme = new OpenApiSecurityScheme - { - Name = "Authorization", - Description = "在下方输入Bearer Token,格式:Bearer {token}", - In = ParameterLocation.Header, - Type = SecuritySchemeType.Http, - Scheme = "bearer", - BearerFormat = "JWT" - }; - options.AddSecurityDefinition(bearerSchemeName, scheme); - options.AddSecurityRequirement(document => - { - var requirement = new OpenApiSecurityRequirement - { - { new OpenApiSecuritySchemeReference(bearerSchemeName, document, null), new List() } - }; - return requirement; - }); - } - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Swagger/SwaggerDocumentSettings.cs b/src/Core/TakeoutSaaS.Shared.Web/Swagger/SwaggerDocumentSettings.cs deleted file mode 100644 index f0410e0..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Swagger/SwaggerDocumentSettings.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace TakeoutSaaS.Shared.Web.Swagger; - -/// -/// Swagger 文档配置。 -/// -public class SwaggerDocumentSettings -{ - /// - /// 文档标题。 - /// - public string Title { get; set; } = "TakeoutSaaS API"; - - /// - /// 描述信息。 - /// - public string? Description { get; set; } - - /// - /// 是否启用 JWT Authorize 按钮。 - /// - public bool EnableAuthorization { get; set; } = true; -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/Swagger/SwaggerExtensions.cs b/src/Core/TakeoutSaaS.Shared.Web/Swagger/SwaggerExtensions.cs deleted file mode 100644 index 0cfe43b..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/Swagger/SwaggerExtensions.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.IO; -using Asp.Versioning.ApiExplorer; -using Microsoft.AspNetCore.Builder; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using Swashbuckle.AspNetCore.Annotations; -using Swashbuckle.AspNetCore.SwaggerGen; - -namespace TakeoutSaaS.Shared.Web.Swagger; - -/// -/// Swagger 注册/启用扩展。 -/// -public static class SwaggerExtensions -{ - /// - /// 注入统一的 Swagger 服务。 - /// - public static IServiceCollection AddSharedSwagger(this IServiceCollection services, Action? configure = null) - { - // 1. 注册 Swagger 并加载 XML 注释以展示中文文档 - services.AddSwaggerGen(options => - { - var basePath = AppContext.BaseDirectory; - var xmlFiles = Directory.GetFiles(basePath, "*.xml"); - foreach (var xml in xmlFiles) - { - options.IncludeXmlComments(xml, true); - } - options.EnableAnnotations(); - }); - services.AddSingleton(_ => - { - var settings = new SwaggerDocumentSettings(); - configure?.Invoke(settings); - return settings; - }); - services.AddSingleton>(provider => - new ConfigureSwaggerOptions( - provider.GetRequiredService(), - Options.Create(provider.GetRequiredService()))); - return services; - } - - /// - /// 开发环境启用 Swagger UI(自动注册所有版本)。 - /// - public static IApplicationBuilder UseSharedSwagger(this IApplicationBuilder app) - { - var provider = app.ApplicationServices.GetRequiredService(); - var settings = app.ApplicationServices.GetRequiredService(); - const string routePrefix = "api/docs"; - const string legacyRoutePrefix = "swagger"; - // 1. 注册 Swagger 中间件(新旧入口同时支持) - app.UseSwagger(options => { options.RouteTemplate = $"{routePrefix}/{{documentName}}/swagger.json"; }); - app.UseSwagger(options => { options.RouteTemplate = $"{legacyRoutePrefix}/{{documentName}}/swagger.json"; }); - app.UseSwaggerUI(options => - { - options.RoutePrefix = routePrefix; - foreach (var description in provider.ApiVersionDescriptions) - { - // 3. 使用相对路径适配反向代理/网关前缀 - options.SwaggerEndpoint( - $"./{description.GroupName}/swagger.json", - $"{settings.Title} {description.ApiVersion}"); - } - // 2. 显示请求耗时 - options.DisplayRequestDuration(); - }); - app.UseSwaggerUI(options => - { - options.RoutePrefix = legacyRoutePrefix; - foreach (var description in provider.ApiVersionDescriptions) - { - // 3. 使用相对路径适配反向代理/网关前缀 - options.SwaggerEndpoint( - $"./{description.GroupName}/swagger.json", - $"{settings.Title} {description.ApiVersion}"); - } - // 2. 显示请求耗时 - options.DisplayRequestDuration(); - }); - return app; - } -} diff --git a/src/Core/TakeoutSaaS.Shared.Web/TakeoutSaaS.Shared.Web.csproj b/src/Core/TakeoutSaaS.Shared.Web/TakeoutSaaS.Shared.Web.csproj deleted file mode 100644 index ddb24c5..0000000 --- a/src/Core/TakeoutSaaS.Shared.Web/TakeoutSaaS.Shared.Web.csproj +++ /dev/null @@ -1,30 +0,0 @@ - - - net10.0 - enable - enable - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Domain/TakeoutSaaS.Domain/TakeoutSaaS.Domain.csproj b/src/Domain/TakeoutSaaS.Domain/TakeoutSaaS.Domain.csproj index fc99d63..9ef8b2e 100644 --- a/src/Domain/TakeoutSaaS.Domain/TakeoutSaaS.Domain.csproj +++ b/src/Domain/TakeoutSaaS.Domain/TakeoutSaaS.Domain.csproj @@ -7,7 +7,7 @@ 1591 - + diff --git a/src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj b/src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj index 931f2cc..a9fa7f1 100644 Binary files a/src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj and b/src/Infrastructure/TakeoutSaaS.Infrastructure/TakeoutSaaS.Infrastructure.csproj differ diff --git a/src/Modules/TakeoutSaaS.Module.Authorization/TakeoutSaaS.Module.Authorization.csproj b/src/Modules/TakeoutSaaS.Module.Authorization/TakeoutSaaS.Module.Authorization.csproj index 16cf38c..427c9a0 100644 Binary files a/src/Modules/TakeoutSaaS.Module.Authorization/TakeoutSaaS.Module.Authorization.csproj and b/src/Modules/TakeoutSaaS.Module.Authorization/TakeoutSaaS.Module.Authorization.csproj differ diff --git a/src/Modules/TakeoutSaaS.Module.Delivery/TakeoutSaaS.Module.Delivery.csproj b/src/Modules/TakeoutSaaS.Module.Delivery/TakeoutSaaS.Module.Delivery.csproj index 8001b38..def0807 100644 --- a/src/Modules/TakeoutSaaS.Module.Delivery/TakeoutSaaS.Module.Delivery.csproj +++ b/src/Modules/TakeoutSaaS.Module.Delivery/TakeoutSaaS.Module.Delivery.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/Modules/TakeoutSaaS.Module.Dictionary/TakeoutSaaS.Module.Dictionary.csproj b/src/Modules/TakeoutSaaS.Module.Dictionary/TakeoutSaaS.Module.Dictionary.csproj index 8cb6277..ec2e881 100644 --- a/src/Modules/TakeoutSaaS.Module.Dictionary/TakeoutSaaS.Module.Dictionary.csproj +++ b/src/Modules/TakeoutSaaS.Module.Dictionary/TakeoutSaaS.Module.Dictionary.csproj @@ -5,7 +5,7 @@ enable - + diff --git a/src/Modules/TakeoutSaaS.Module.Messaging/TakeoutSaaS.Module.Messaging.csproj b/src/Modules/TakeoutSaaS.Module.Messaging/TakeoutSaaS.Module.Messaging.csproj index 1350a29..1bc196e 100644 --- a/src/Modules/TakeoutSaaS.Module.Messaging/TakeoutSaaS.Module.Messaging.csproj +++ b/src/Modules/TakeoutSaaS.Module.Messaging/TakeoutSaaS.Module.Messaging.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/Modules/TakeoutSaaS.Module.Scheduler/TakeoutSaaS.Module.Scheduler.csproj b/src/Modules/TakeoutSaaS.Module.Scheduler/TakeoutSaaS.Module.Scheduler.csproj index ad73a3f..47e609a 100644 --- a/src/Modules/TakeoutSaaS.Module.Scheduler/TakeoutSaaS.Module.Scheduler.csproj +++ b/src/Modules/TakeoutSaaS.Module.Scheduler/TakeoutSaaS.Module.Scheduler.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Modules/TakeoutSaaS.Module.Sms/TakeoutSaaS.Module.Sms.csproj b/src/Modules/TakeoutSaaS.Module.Sms/TakeoutSaaS.Module.Sms.csproj index 7025f49..90460da 100644 --- a/src/Modules/TakeoutSaaS.Module.Sms/TakeoutSaaS.Module.Sms.csproj +++ b/src/Modules/TakeoutSaaS.Module.Sms/TakeoutSaaS.Module.Sms.csproj @@ -14,7 +14,7 @@ - + diff --git a/src/Modules/TakeoutSaaS.Module.Storage/TakeoutSaaS.Module.Storage.csproj b/src/Modules/TakeoutSaaS.Module.Storage/TakeoutSaaS.Module.Storage.csproj index e5ec475..16354c5 100644 Binary files a/src/Modules/TakeoutSaaS.Module.Storage/TakeoutSaaS.Module.Storage.csproj and b/src/Modules/TakeoutSaaS.Module.Storage/TakeoutSaaS.Module.Storage.csproj differ diff --git a/src/Modules/TakeoutSaaS.Module.Tenancy/TakeoutSaaS.Module.Tenancy.csproj b/src/Modules/TakeoutSaaS.Module.Tenancy/TakeoutSaaS.Module.Tenancy.csproj index db28803..fdb3727 100644 --- a/src/Modules/TakeoutSaaS.Module.Tenancy/TakeoutSaaS.Module.Tenancy.csproj +++ b/src/Modules/TakeoutSaaS.Module.Tenancy/TakeoutSaaS.Module.Tenancy.csproj @@ -5,7 +5,7 @@ enable - + diff --git a/商品模块_API设计_v1.md b/商品模块_API设计_v1.md deleted file mode 100644 index d6a1150..0000000 --- a/商品模块_API设计_v1.md +++ /dev/null @@ -1,426 +0,0 @@ -# 商品模块 API 设计(v1) -> 企业级/混合模式版 - -## 0. 目标与范围 -- 面向商业化外卖 SaaS,覆盖“总部主库 + 门店私库 + 多维度经营 + 可配置开关 + 可扩展集成”。 -- 本文仅讨论 API 设计与契约,不涉及实现细节。 -- 默认对齐项目现有约束:多租户、CQRS、统一响应、Snowflake ID、JWT/RBAC。 - -## 1. 通用规范 -### 1.1 路由与版本 -- AdminApi:`/api/admin/v1/...` -- MiniApi:`/api/mini/v1/...` -- UserApi:`/api/user/v1/...` - -### 1.2 鉴权与租户 -- Header:`Authorization: Bearer {token}` -- 租户:`X-Tenant-Id` 或 `X-Tenant-Code`(必填,除白名单路径) -- 角色权限:AdminApi 必须绑定 `PermissionAuthorize` 权限码 - -### 1.3 响应格式 -统一使用 `ApiResponse`,与现有 `Shared.Web` 约定一致。 - -### 1.4 ID 与并发 -- 所有 `long` 类型 ID 在 API 中 **序列化为 string**。 -- 更新类接口需携带 `rowVersion`(Base64)或 `If-Match` 以并发控制。 - -### 1.5 幂等与限流 -- 创建、批量变更、导入等写接口支持 `Idempotency-Key`。 -- 面向公网端启用限流策略,读接口优先缓存。 - -### 1.6 分页与排序 -统一参数:`page`、`pageSize`、`sortBy`、`sortOrder`(`asc|desc`)。 - -## 2. 产品原则(10 年外卖 SaaS 视角) -- 品牌一致性优先:总部主库保证品牌统一,门店仅允许“可控范围内的微调”。 -- 经营灵活性必备:门店私有商品与局部覆盖是应对“城市、商圈、人力”的关键。 -- C 端效率优先:类目不超过 2 级,菜单渲染优先走聚合与缓存。 -- 扩展优先:渠道/场景/时段/三方同步都必须可开关,避免“为少数租户拖累成本”。 - -## 3. 功能域拆分(可开关) -### 3.1 核心域 -- 公共商品库(Master Library,总部商品) -- 门店私有库(Store Library,本地特色) -- 引用/下发机制(Push & Pull) -- 类目管理(2 级以内 + 时段可见) -- 商品(Product/SPU)与规格 SKU -- 场景/渠道/时段维度可见性 -- 计价与打包费策略 -- 库存视图与沽清(含每日重置) - -### 3.2 可选域 -- 加料/口味(Addon/Modifier) -- 套餐/组合(Bundle/N 选 M) -- 称重计价与时价 -- 后厨生产(KDS/打印标签/台位) -- 三方平台同步(美团/饿了么/抖音) -- 审核流与定时上架 -- 多语言(I18n) -- 评分/销量统计视图(Stats) - -## 4. 核心架构:公共商品库 + 门店私有库 + Push/Pull -### 4.1 公共商品库(Tenant/Master Library) -- 定义:总部创建的标准化商品。 -- 作用:维护品牌统一形象(名称、图、描述、营养、后厨分类)。 -- 管控:总部可锁定核心字段,门店仅可引用,不可篡改。 - -### 4.2 门店私有库(Store Private Library) -- 定义:门店为本地市场创建的特色商品。 -- 作用:一店一策(开业活动、地域限定等)。 -- 权限:仅本门店可见,总部可审计但默认不干预。 - -### 4.3 引用与下发(Push & Pull) -- 总部推送(Push):支持“静默上架”或“待门店确认”。 -- 门店拉取(Pull):门店经理从公共库勾选引入到本店经营列表。 -- 门店引用后允许“局部覆盖”,但不破坏主库锁定字段。 - -### 4.4 混合视图标识 -- API 输出 `libraryType` + `masterProductId`,便于后台列表用标签区分来源。 -- `lockedFields` 返回总部锁定字段,避免门店误操作。 - -## 5. 维度管理:类目、场景、渠道与时段 -### 5.1 类目(2 级以内) -- 类目支持“生效时段”,如早餐类目 10:00 后隐藏。 -- 类目可绑定“场景”,如堂食专属类目。 - -### 5.2 场景(履约场景) -- 堂食(DineIn)、外卖(Delivery)、自提(Pickup)。 -- 外卖场景强制打包费规则;堂食可免打包费。 - -### 5.3 渠道(流量入口) -- 微信小程序、POS 点餐、美团、饿了么、抖音等。 -- 支持“渠道隔离”:显示顺序、价格、上下架状态可独立配置。 - -### 5.4 维度优先级(建议) -门店覆盖 > 渠道配置 > 时段配置 > 商品基础配置。 - -## 6. 核心业务规则 -### 6.1 覆盖机制(Override Rule) -- 门店可对价格、场景、上架/沽清做覆盖。 -- 被锁定字段不允许覆盖;如需调整须总部解锁或走审核。 - -### 6.2 计价与打包费 -- 计价模式:固定单价、按克计价(称重菜)、时价(随行就市)。 -- 打包费支持按 SKU 设置,且可按场景配置(堂食可为 0)。 -- 打包费支持单单封顶(不超过 X 元)。 - -### 6.3 库存与自动重置 -- 支持门店级“每日自动恢复初始库存”(默认凌晨执行)。 -- 沽清为临时状态,不影响主库与其他门店。 - -### 6.4 规格、加料与套餐 -- SKU 影响价格与库存。 -- 加料支持“收费加料 + 免费属性”,可配置选配上限/下限。 -- 动态套餐支持“N 选 M”,并要求库存穿透: - - 套餐内关键单品沽清时,套餐自动联动下架。 - -### 6.5 生产与后厨(KDS/打印) -- 商品可绑定“打印标签 + 后厨台位”。 -- 订单下发需标示场景,以区分堂食/外卖/自提出餐逻辑。 - -### 6.6 三方平台同步 -- 内置 Mapping 机制,支持“商品—平台商品”映射。 -- 价格/沽清变动触发事件总线,异步同步到平台接口。 - -## 7. 权限与审计 -- 总部运营:管理主库、类目、全局规则、价格上限、审核流。 -- 门店经理:门店私有商品、门店覆盖、今日沽清。 -- 字段级审计日志:记录“谁在何时修改了哪个门店商品的价格/状态”。 -- 推送审计:记录主库变更的下发范围与结果。 - -## 8. 功能开关(租户级) -用于“商业化套餐可选启用”。建议 AdminApi 提供读取能力,写入由套餐/配置管理模块控制。 - -示例结构: -```json -{ - "enableMasterLibrary": true, - "enableStoreLibrary": true, - "enablePushPull": true, - "enableVariant": true, - "enableAddon": true, - "enableBundle": true, - "enableSceneFilter": true, - "enableChannelIsolation": true, - "enableChannelPrice": true, - "enableTimePrice": true, - "enableStoreOverride": true, - "enablePricingWeight": true, - "enablePricingMarket": true, - "enablePackagingFee": true, - "enablePackagingFeeCap": true, - "enableDailyStockReset": true, - "enableInventory": true, - "enableApproval": false, - "enableScheduledPublish": true, - "enableKds": true, - "enableThirdPartySync": true, - "enableMultiLanguage": false, - "enableNutritionInfo": false -} -``` - -## 9. 关键 DTO(摘要) -> 字段命名遵循现有规范,布尔值使用 `Is/Has` 前缀。 - -### 9.1 CategoryDto -| 字段 | 说明 | -| --- | --- | -| id | 类目 ID(string) | -| parentId | 父级类目 ID | -| name | 类目名称 | -| sortOrder | 排序 | -| isEnabled | 是否启用 | -| availableScenes | 生效场景 | -| availableTimeRanges | 生效时段 | -| createdAt | 创建时间 | - -### 9.2 ProductDto(SPU) -| 字段 | 说明 | -| --- | --- | -| id | 商品 ID(string) | -| libraryType | Master/Store | -| masterProductId | 引用的主库商品 ID | -| storeId | 归属门店 | -| name | 商品名称 | -| categoryId | 类目 ID | -| unit | 单位 | -| tags | 标签 | -| coverImageUrl | 封面图 | -| imageUrls | 轮播图 | -| isEnabled | 是否启用 | -| isPublished | 是否上架 | -| hasSku | 是否包含 SKU | -| hasAddon | 是否包含加料 | -| pricingMode | Fixed/Weight/Market | -| basePrice | 基础价格 | -| packagingFee | 打包费(基础) | -| packagingFeeCap | 打包费封顶 | -| availableScenes | 生效场景 | -| availableChannels | 生效渠道 | -| lockedFields | 被总部锁定字段 | -| rowVersion | 并发字段 | - -### 9.3 SkuDto -| 字段 | 说明 | -| --- | --- | -| id | SKU ID(string) | -| productId | 商品 ID | -| specValues | 规格值列表 | -| price | 价格 | -| stock | 库存 | -| isEnabled | 是否启用 | -| rowVersion | 并发字段 | - -### 9.4 StoreProductOverrideDto -| 字段 | 说明 | -| --- | --- | -| storeId | 门店 ID | -| productId | 商品 ID | -| overridePrice | 覆盖价格 | -| overrideScenes | 覆盖场景 | -| isSoldOut | 是否沽清 | -| isApproved | 是否已审核 | -| overrideReason | 覆盖原因 | - -### 9.5 AddonGroupDto(可选) -| 字段 | 说明 | -| --- | --- | -| id | 组 ID | -| name | 组名 | -| minSelected | 最少选择 | -| maxSelected | 最多选择 | -| isRequired | 是否必选 | -| items | 加料项列表 | - -### 9.6 ChannelSettingDto(可选) -| 字段 | 说明 | -| --- | --- | -| channelCode | 渠道编码 | -| price | 渠道价格 | -| sortOrder | 渠道排序 | -| isEnabled | 是否启用 | - -### 9.7 ProductionProfileDto(可选) -| 字段 | 说明 | -| --- | --- | -| kitchenStationId | 后厨台位 | -| printTagId | 打印标签 | - -## 10. AdminApi(管理端)接口清单 -### 10.1 公共商品库(总部) -- `GET /api/admin/v1/master-products` -- `GET /api/admin/v1/master-products/{id}` -- `POST /api/admin/v1/master-products` -- `PUT /api/admin/v1/master-products/{id}` -- `PUT /api/admin/v1/master-products/{id}/lock-fields` -- `PUT /api/admin/v1/master-products/{id}/publish` -- `PUT /api/admin/v1/master-products/{id}/unpublish` - -### 10.2 门店私有库与经营商品 -- `GET /api/admin/v1/stores/{storeId}/products` -- `POST /api/admin/v1/stores/{storeId}/products`(创建门店私有商品) -- `POST /api/admin/v1/stores/{storeId}/products/pull`(从主库拉取) -- `PUT /api/admin/v1/stores/{storeId}/products/{id}` -- `PUT /api/admin/v1/stores/{storeId}/products/{id}/override` -- `PUT /api/admin/v1/stores/{storeId}/products/{id}/publish` -- `PUT /api/admin/v1/stores/{storeId}/products/{id}/unpublish` -- `PUT /api/admin/v1/stores/{storeId}/products/{id}/sold-out` - -### 10.3 总部推送(Push) -- `POST /api/admin/v1/master-products/{id}/push`(指定门店) -- `GET /api/admin/v1/master-products/{id}/push-tasks` -- `POST /api/admin/v1/push-tasks/{taskId}/retry` - -### 10.4 类目 -- `GET /api/admin/v1/categories` -- `POST /api/admin/v1/categories` -- `PUT /api/admin/v1/categories/{id}` -- `DELETE /api/admin/v1/categories/{id}` -- `PUT /api/admin/v1/categories/{id}/enable` -- `PUT /api/admin/v1/categories/{id}/disable` -- `PUT /api/admin/v1/categories/sort`(批量排序) -- `PUT /api/admin/v1/categories/{id}/schedule`(类目时段) -- `PUT /api/admin/v1/categories/{id}/scenes`(类目场景) - -### 10.5 规格与 SKU -- `GET /api/admin/v1/products/{id}/spec-groups` -- `PUT /api/admin/v1/products/{id}/spec-groups` -- `GET /api/admin/v1/products/{id}/skus` -- `POST /api/admin/v1/products/{id}/skus` -- `PUT /api/admin/v1/skus/{id}` -- `PUT /api/admin/v1/skus/{id}/enable` -- `PUT /api/admin/v1/skus/{id}/disable` -- `PUT /api/admin/v1/skus/{id}/price` -- `PUT /api/admin/v1/skus/{id}/stock` -- `PUT /api/admin/v1/skus/{id}/pricing-mode` -- `PUT /api/admin/v1/skus/{id}/packaging-fee` -- `PUT /api/admin/v1/skus/{id}/inventory-policy` - -### 10.6 场景/渠道/时段 -- `PUT /api/admin/v1/products/{id}/scenes` -- `PUT /api/admin/v1/products/{id}/channels` -- `PUT /api/admin/v1/products/{id}/time-slots` -- `PUT /api/admin/v1/products/{id}/channel-mappings` -- `POST /api/admin/v1/products/{id}/channel-sync` - -### 10.7 加料/口味(可选) -- `GET /api/admin/v1/products/{id}/addon-groups` -- `PUT /api/admin/v1/products/{id}/addon-groups` -- `PUT /api/admin/v1/addon-groups/{id}/items` -- `PUT /api/admin/v1/addon-groups/{id}/enable` -- `PUT /api/admin/v1/addon-groups/{id}/disable` - -### 10.8 套餐/组合(可选) -- `GET /api/admin/v1/bundles` -- `POST /api/admin/v1/bundles` -- `PUT /api/admin/v1/bundles/{id}` -- `PUT /api/admin/v1/bundles/{id}/publish` -- `PUT /api/admin/v1/bundles/{id}/unpublish` -- `PUT /api/admin/v1/bundles/{id}/items` -- `PUT /api/admin/v1/bundles/{id}/rules`(N 选 M) - -### 10.9 后厨生产(可选) -- `PUT /api/admin/v1/products/{id}/production-profile` -- `PUT /api/admin/v1/skus/{id}/production-profile` - -### 10.10 导入导出与索引 -- `POST /api/admin/v1/products/import` -- `GET /api/admin/v1/products/import/{taskId}` -- `GET /api/admin/v1/products/export` -- `POST /api/admin/v1/products/reindex` - -### 10.11 审计与日志 -- `GET /api/admin/v1/products/{id}/audit-logs` -- `GET /api/admin/v1/stores/{storeId}/products/{id}/override-logs` -- `GET /api/admin/v1/master-products/{id}/push-logs` - -### 10.12 功能开关读取 -- `GET /api/admin/v1/products/features` - -## 11. MiniApi(小程序端)接口清单 -- `GET /api/mini/v1/categories?scene=Delivery&channel=WeChatMiniProgram` -- `GET /api/mini/v1/menus/{storeId}?scene=Delivery&channel=WeChatMiniProgram` -- `GET /api/mini/v1/products?storeId=...&scene=Delivery&channel=WeChatMiniProgram` -- `GET /api/mini/v1/products/{id}?scene=Delivery&channel=WeChatMiniProgram` -- `GET /api/mini/v1/products/hot?storeId=...` -- `GET /api/mini/v1/products/recommended?storeId=...` -- `POST /api/mini/v1/products/price-estimate` -- `POST /api/mini/v1/products/checkout-validate` -- `POST /api/mini/v1/products/snapshots`(订单服务调用) - -## 12. UserApi(C 端用户)接口清单 -- `GET /api/user/v1/categories?scene=Delivery&channel=H5` -- `GET /api/user/v1/menus/{storeId}?scene=Delivery&channel=H5` -- `GET /api/user/v1/products?storeId=...&scene=Delivery&channel=H5` -- `GET /api/user/v1/products/{id}?scene=Delivery&channel=H5` -- `GET /api/user/v1/products/hot?storeId=...` -- `GET /api/user/v1/products/recommended?storeId=...` -- `POST /api/user/v1/products/price-estimate` -- `POST /api/user/v1/products/checkout-validate` - -## 13. 事件与扩展点 -采用 Outbox 模式输出领域事件,便于搜索索引、缓存失效、推荐计算与三方同步。 -- `MasterProductCreated` -- `MasterProductUpdated` -- `MasterProductPushed` -- `StoreProductPulled` -- `StoreProductOverridden` -- `ProductPriceChanged` -- `ProductAvailabilityChanged` -- `ProductSoldOutChanged` -- `SkuStockChanged` -- `ProductChannelSyncRequested` - -## 14. 示例(关键请求) -### 14.1 商品创建(总部主库) -```json -{ - "name": "黄金鸡排饭", - "categoryId": "1782328933492367360", - "unit": "份", - "coverImageUrl": "https://cdn/xxx.jpg", - "imageUrls": ["https://cdn/xxx1.jpg", "https://cdn/xxx2.jpg"], - "pricingMode": "Fixed", - "basePrice": 19.9, - "isEnabled": true -} -``` - -### 14.2 门店覆盖(价格 + 场景) -```json -{ - "overridePrice": 21.9, - "overrideScenes": ["Delivery", "Pickup"], - "isSoldOut": false, - "overrideReason": "外卖平台佣金调整" -} -``` - -### 14.3 结算校验(Mini/User) -```json -{ - "storeId": "1782328933492367000", - "scene": "Delivery", - "channel": "WeChatMiniProgram", - "items": [ - { - "productId": "1782328933492367360", - "skuId": "1782328933492367400", - "quantity": 2, - "addonItemIds": ["1782328933492367501", "1782328933492367502"] - } - ] -} -``` - -## 15. 依赖说明 -- 文件上传:复用 Storage 模块(FilesController)获取 URL。 -- 库存:优先对接 Inventory 模块,商品侧仅提供视图与校验。 -- 订单:下单时生成商品快照,避免历史价格漂移。 -- 后厨:KDS/打印由生产模块承接,商品仅配置绑定信息。 -- 三方同步:由集成服务监听事件并进行异步同步与重试。 -- 权限码:`product.read`、`product.write`、`product.publish`、`product.import` 等(待统一权限表配置)。 - ---- -**待确认**:渠道编码标准、称重计价精度与四舍五入规则、库存每日重置默认时间、Push 是否强制门店确认。