后端功能首次提交
This commit is contained in:
1 parent
5b38e1b567
commit
3405280224
1136 files changed
+96170
-1
No files matched your search
+43
@@ -0,0 +1,43 @@
|
||||
# Go
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
*.test
|
||||
*.out
|
||||
go.work
|
||||
|
||||
# Node.js
|
||||
node_modules/
|
||||
dist/
|
||||
build/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
|
||||
# Environment files with sensitive data
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs/
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
|
||||
# 外部文件
|
||||
new-api/
|
||||
sub2api/
|
||||
|
||||
# 配置文件(含敏感信息,使用 .example 模板代替)
|
||||
hack/config.yaml
|
||||
manifest/config/config.yaml
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
# Team-API — 项目开发规范
|
||||
|
||||
## 项目概述
|
||||
|
||||
多租户 AI API 网关 SaaS 平台。租户注册后获取 API Key,通过统一接口调用 OpenAI/Claude/Gemini 等大模型,平台负责计费、限流、监控。
|
||||
|
||||
双控制台架构:管理后台(平台运营)+ 租户控制台(组织使用),两套完全独立的用户体系。
|
||||
|
||||
## 技术栈
|
||||
|
||||
- **后端**:Go + GoFrame (v2) + goose(数据库迁移)
|
||||
- **数据库**:PostgreSQL(唯一,不用 MySQL/SQLite)
|
||||
- **缓存**:Redis + 内存缓存(双层缓存)
|
||||
- **前端**:Vue 3 + Vite + TailwindCSS + Naive UI(管理后台)
|
||||
- **包管理**:pnpm
|
||||
- **对象存储**:S3 / OSS / COS / MinIO(禁止纯本地磁盘作为生产存储)
|
||||
|
||||
## 项目结构
|
||||
|
||||
项目基于 GoFrame v2 标准项目结构(`gf init` 生成),在此基础上扩展业务模块。
|
||||
|
||||
```
|
||||
team-api/
|
||||
├── api/ # API 定义(请求/响应结构体 + 路由注解)
|
||||
│ ├── admin/v1/ # 管理后台 API(gf gen ctrl 源)
|
||||
│ ├── tenant/v1/ # 租户控制台 API(gf gen ctrl 源)
|
||||
│ ├── captcha/v1/ # 验证码 API(管理后台 + 租户控制台共用)
|
||||
│ ├── docs/v1/ # OpenAPI 文档 API
|
||||
│ ├── open/v1/ # 开放平台 API
|
||||
│ ├── payment/v1/ # 支付回调 API
|
||||
├── hack/
|
||||
│ └── config.yaml # gf CLI 脚手架配置(gen dao 等工具的数据库连接和生成规则)
|
||||
├── internal/
|
||||
│ ├── cmd/ # 入口命令、服务启动、路由注册
|
||||
│ │ ├── cmd.go # main 包注册,路由分组定义
|
||||
│ │ └── cmd_reset_pwd.go # 密码重置命令
|
||||
│ ├── consts/ # 常量定义(业务状态码、枚举等)
|
||||
│ ├── controller/ # 控制器(由 gf gen ctrl 从 api/ 自动生成,禁止手动修改)
|
||||
│ │ ├── admin/ # 管理后台控制器
|
||||
│ │ ├── tenant/ # 租户控制台控制器
|
||||
│ │ ├── captcha/ # 验证码控制器
|
||||
│ │ ├── docs/ # 文档控制器
|
||||
│ │ ├── open/ # 开放平台控制器
|
||||
│ ├── handler/ # 特殊端点处理器(不走 Controller 链路,见下方说明)
|
||||
│ │ ├── relay/ # AI 代理端点处理器
|
||||
│ │ ├── public/ # 支付回调端点处理器
|
||||
│ │ └── setup/ # 系统初始化向导处理器
|
||||
│ ├── logic/ # 业务逻辑实现(核心代码所在)
|
||||
│ │ ├── admin/ # 管理后台业务逻辑
|
||||
│ │ ├── tenant/ # 租户控制台业务逻辑
|
||||
│ │ ├── billing/ # 计费引擎
|
||||
│ │ ├── common/ # 公共逻辑(缓存、配置、安全、邮件、验证码、JWT 等)
|
||||
│ │ ├── docs/ # OpenAPI 文档生成
|
||||
│ │ ├── monitor/ # 监控告警引擎
|
||||
│ │ ├── notification/ # 通知服务
|
||||
│ │ ├── open/ # 开放平台业务逻辑
|
||||
│ │ ├── payment/ # 支付逻辑(回调处理、订单履约)
|
||||
│ │ ├── relay/ # Relay 业务逻辑(亲和性、健康检查、缓存)
|
||||
│ │ └── task/ # 异步任务框架
|
||||
│ ├── model/ # 数据模型(由 gf gen dao 自动生成,禁止手动修改)
|
||||
│ │ ├── do/ # Domain Objects(查询条件、输入结构体)
|
||||
│ │ └── entity/ # Entity(与数据库表 1:1 映射的数据实体)
|
||||
│ ├── packed/ # 打包资源(内嵌静态文件、编译时生成)
|
||||
│ ├── dao/ # 数据访问对象(由 gf gen dao 自动生成,禁止手动修改)
|
||||
│ ├── response/ # 统一响应工具包(Success/Error 封装)
|
||||
│ ├── service/ # 业务接口定义(由 gf gen service 从 logic/ 自动生成,禁止手动修改)
|
||||
│ ├── middleware/ # 中间件
|
||||
│ └── utility/ # 工具函数
|
||||
│ ├── crypto/ # 加密工具
|
||||
│ ├── export/ # 数据导出
|
||||
│ ├── totp/ # TOTP 两步验证
|
||||
│ └── turnstile/ # Cloudflare Turnstile 验证
|
||||
├── relay/ # AI 模型代理层(顶级模块,独立于 GoFrame 脚手架生成目录)
|
||||
│ ├── channel/ # 供应商适配器(registry.go + 24 个子目录,每个供应商一个)
|
||||
│ │ └── openai/ claude/ gemini/ ...
|
||||
│ ├── common/ # Relay 层共享类型和工具
|
||||
│ ├── constant/ # Relay 层常量(供应商类型、模式、错误码)
|
||||
│ ├── dto/ # 数据传输对象(OpenAI/Claude/Gemini/Realtime/Task 等格式定义)
|
||||
│ ├── handler/ # Relay 请求处理器(chat/claude/gemini/audio/rerank/task/realtime 等)
|
||||
│ ├── helper/ # Relay 辅助函数(流式处理、状态码映射、系统提示词、thinking 处理)
|
||||
│ ├── override/ # 请求/响应覆盖(Header 改写、参数覆盖)
|
||||
│ ├── scheduler/ # 渠道调度器(调度、亲和性、重试)
|
||||
│ └── taskchannel/ # 异步任务渠道适配器
|
||||
│ ├── registry.go # 任务渠道注册表
|
||||
│ ├── kling/ # 可灵视频生成
|
||||
│ ├── midjourney/ # Midjourney 图像生成
|
||||
│ ├── sora/ # Sora 视频生成
|
||||
│ └── suno/ # Suno 音乐生成
|
||||
├── manifest/
|
||||
│ ├── config/ # 应用运行时配置(GoFrame 标准路径)
|
||||
│ ├── deploy/ # 部署配置(K8s/Compose 等)
|
||||
│ ├── docker/ # Docker 构建配置
|
||||
│ ├── i18n/ # 国际化资源文件
|
||||
│ └── protobuf/ # Protobuf 定义文件
|
||||
├── migrations/ # goose 数据库迁移脚本(六位序号编号:000001_xxx.sql)
|
||||
├── web/ # 前端
|
||||
│ ├── admin/ # 管理后台
|
||||
│ └── tenant/ # 租户控制台
|
||||
├── docs/ # 项目文档
|
||||
│ ├── 开发计划-v2/ # 分周期开发计划(周期一~六)
|
||||
│ └── 协议文档/ # 协议相关文档
|
||||
├── new-api/ # 参考项目(只读,不修改)
|
||||
├── sub2api/ # 参考项目(只读,不修改)
|
||||
├── main.go # 应用入口
|
||||
├── go.mod
|
||||
└── Makefile
|
||||
```
|
||||
|
||||
### Relay 层设计说明
|
||||
|
||||
Relay 层作为顶级 `relay/` 模块独立于 GoFrame 脚手架生成目录(`internal/` 下的 `controller/service/dao/model`),原因:
|
||||
- **文件量大**:24 个供应商适配器 + 4 个异步任务适配器 + 共享模块,放在 `internal/logic/` 下层级过深
|
||||
- **职责独立**:Relay 是纯粹的代理转发层,不依赖 GoFrame ORM/DAO,与 `internal/` 下的业务逻辑解耦
|
||||
- **参考对齐**:目录结构与 new-api 的 `relay/` 保持一致,降低移植和理解成本
|
||||
|
||||
`internal/logic/` 中的业务逻辑(如计费、渠道调度)通过 Go import 调用 `relay/` 包,而非将 relay 嵌入 logic 内部。
|
||||
|
||||
### GoFrame 代码生成与手动编写分界
|
||||
|
||||
| 目录 | 生成方式 | 能否手动修改 |
|
||||
|------|---------|------------|
|
||||
| `api/` | 手动编写 | 是(结构体定义和路由注解) |
|
||||
| `hack/config.yaml` | 手动编写 | 是(CLI 工具配置) |
|
||||
| `internal/controller/` | `gf gen ctrl` | 否(自动生成) |
|
||||
| `internal/service/` | `gf gen service` | 否(自动生成接口) |
|
||||
| `internal/model/do/` | `gf gen dao` | 否(自动生成) |
|
||||
| `internal/model/entity/` | `gf gen dao` | 否(自动生成) |
|
||||
| `internal/dao/` | `gf gen dao` | 否(自动生成) |
|
||||
| `internal/logic/` | 手动编写 | 是(核心业务逻辑) |
|
||||
| `internal/cmd/` | 手动编写 | 是(路由注册、服务启动) |
|
||||
| `internal/consts/` | 手动编写 | 是(常量定义) |
|
||||
| `internal/handler/` | 手动编写 | 是(特殊端点处理器,见下方说明) |
|
||||
| `internal/response/` | 手动编写 | 是(统一响应工具包) |
|
||||
| `internal/middleware/` | 手动编写 | 是(中间件) |
|
||||
| `internal/utility/` | 手动编写 | 是(工具函数:加密、导出、TOTP、Turnstile) |
|
||||
| `manifest/config/` | 手动编写 | 是(运行时配置) |
|
||||
| `relay/` | 手动编写 | 是(AI 模型代理层,独立于 GoFrame 脚手架) |
|
||||
|
||||
### internal/handler/ 目录说明
|
||||
|
||||
`internal/handler/` 目录包含**特殊端点的处理器**,这些端点不适合走 GoFrame 的标准 Controller 链路:
|
||||
|
||||
| 子目录 | 用途 |
|
||||
|--------|------|
|
||||
| `handler/relay/` | `/v1/*` AI 代理端点(OpenAI/Claude/Gemini 兼容格式)- 需要直接操作 `http.ResponseWriter` 进行流式转发 |
|
||||
| `handler/public/` | `/api/payment/*` 支付回调端点 - 需要返回非 JSON 格式的响应(如支付宝的表单重定向) |
|
||||
| `handler/setup/` | `/api/setup/*` 系统初始化向导端点 - 首次部署时的系统配置页面和初始化接口 |
|
||||
|
||||
**为什么不用 Controller**:
|
||||
- **流式响应**:AI 代理端点需要实时转发上游的 SSE 流,Controller 的响应包装会破坏流式传输
|
||||
- **原生格式透传**:必须保持与 OpenAI/Claude/Gemini API 完全兼容的请求/响应格式
|
||||
- **自定义响应**:支付回调需要返回 HTML 表单或文本响应,而非统一的 JSON 格式
|
||||
|
||||
**与 Controller 的区别**:
|
||||
- Controller:走 GoFrame 标准链路(`api → controller → service → logic → dao`),返回统一 JSON 响应
|
||||
- Handler:直接处理 HTTP 请求/响应,不走 GoFrame 的 `ghttp.Request` 包装,用于特殊场景
|
||||
|
||||
### GoFrame 脚手架生成顺序(重要)
|
||||
|
||||
项目 `hack/config.yaml` 中 `gfcli.gen.ctrl` 已配置 `withService: true`,意味着 `gf gen ctrl` 会尝试自动将控制器连接到 service 方法。但前提是 **service 接口中已存在对应方法**,否则生成 `CodeNotImplemented` 桩代码。
|
||||
|
||||
**新增接口时必须按以下顺序执行,不可颠倒:**
|
||||
|
||||
1. **编写 API 定义**(`api/xxx/v1/xxx.go`)— 添加 Req/Res 结构体
|
||||
2. **编写 Logic 实现**(`internal/logic/xxx/xxx.go`)— 实现业务逻辑
|
||||
3. **`gf gen service`** — 从 Logic 方法签名自动生成 Service 接口
|
||||
4. **`gf gen ctrl`** — 从 API 定义生成 Controller,此时 `withService: true` 会自动生成 `return service.Xxx().Method(ctx, req)` 调用
|
||||
|
||||
如果先执行 `gf gen ctrl` 再执行 `gf gen service`,控制器会是桩代码(返回 501 Not Implemented),需要手动修改。始终遵循 "logic → gen service → gen ctrl" 的顺序可避免此问题。
|
||||
|
||||
### GoFrame 请求处理链路
|
||||
|
||||
```
|
||||
cmd(路由注册)
|
||||
→ api(请求/响应结构体定义)
|
||||
→ controller(解析请求、校验参数、调用 service)
|
||||
→ service(接口定义,自动生成)
|
||||
→ logic(业务逻辑实现,使用 DO 构造查询)
|
||||
→ dao(ORM 操作,返回 Entity)
|
||||
← 返回 Entity
|
||||
← controller 格式化响应(Res 结构体)
|
||||
```
|
||||
|
||||
## 参考项目(只读,禁止修改)
|
||||
|
||||
项目根目录下有 `new-api/` 和 `sub2api/` 两个参考项目,它们是大模型网关领域的成熟实现。
|
||||
大多数情况下不需要查看这2个目录下的代码,除非我主动提及或者涉及到大模型相关的实现逻辑。
|
||||
|
||||
### new-api 重点参考
|
||||
|
||||
- **Relay 代理层架构**:`controller/relay/`,适配器模式、请求转发、响应解析
|
||||
- **供应商适配器**:`relay/channel/` 下 40+ 供应商的适配器实现,优先复用
|
||||
- **协议转换**:OpenAI ↔ Claude ↔ Gemini 消息格式互转
|
||||
- **渠道调度**:优先级/权重选择、自动重试、Key 轮询
|
||||
- **计费模型**:预扣/结算/退款、梯度定价、Token 计量
|
||||
|
||||
### sub2api 重点参考
|
||||
|
||||
- **渠道亲和性**:用户+模型→渠道映射缓存策略
|
||||
- **运维监控**:仪表盘设计、健康监控页面
|
||||
- **用户体系**:前端布局和组件设计
|
||||
|
||||
### 参考原则
|
||||
|
||||
参考不等于照搬。new-api 使用 Gin + GORM,我们需要适配到 GoFrame 框架。接口设计和核心算法可以参考,但代码需要重新组织以符合 GoFrame 标准结构(`api → controller → service → logic → dao` 分层)和项目的多租户架构。注意 GoFrame 的 `model/do/`、`model/entity/`、`dao/`、`service/`、`controller/` 均由脚手架自动生成,业务代码只写在 `api/`、`logic/`、`cmd/`、`handler/`、`middleware/`、`response/`、`utility/`、`consts/` 和顶级 `relay/` 中。
|
||||
|
||||
## 核心架构决策
|
||||
|
||||
### 多租户隔离
|
||||
|
||||
行级隔离:所有业务表包含 `tenant_id` 字段,GoFrame ORM 中间件全局注入 `WHERE tenant_id = ?`。请求链路通过 Context 传递 tenant_id。
|
||||
|
||||
### 路由前缀
|
||||
|
||||
```
|
||||
/api/admin/ 管理后台(JWT 认证,admin_users 表)
|
||||
/api/tenant/ 租户控制台(JWT 认证,tenant_users 表,RAM 格式 用户名@租户代码)
|
||||
/api/payment/ 支付回调(签名验证,无用户认证)
|
||||
/api/captcha/ 验证码服务(无需认证,管理后台 + 租户控制台共用)
|
||||
/api/docs/ OpenAPI 文档(无需认证)
|
||||
/api/open/ 开放平台 API(HMAC-SHA256 认证)
|
||||
/api/setup/ 系统初始化向导(首次部署,完成后禁用)
|
||||
/v1/ AI 代理端点 — OpenAI 兼容格式(API Key 认证,Bearer Token)
|
||||
/v1beta/ AI 代理端点 — Gemini 兼容格式(API Key 认证,Bearer Token)
|
||||
/suno/ Suno 音乐生成端点(API Key 认证)
|
||||
```
|
||||
|
||||
### RBAC 权限模型
|
||||
|
||||
三层:角色 + 权限点 + 数据范围。公式:`is_allowed = has_permission_point AND within_data_scope AND resource_state_allows`。
|
||||
|
||||
管理后台角色:`super_admin`(全权限)、`admin`(可配置权限集)。
|
||||
租户控制台角色:`owner`(全权限)、`admin`(管理权限)、`member`(个人数据)。
|
||||
|
||||
### 五层额度模型
|
||||
|
||||
```
|
||||
租户钱包(货币池)→ 套餐额度(资源池)→ 成员额度(控制线)→ 项目预算(控制线)→ Key 额度(控制线)
|
||||
```
|
||||
|
||||
扣费优先级:先扣套餐资源量,不足部分扣钱包余额。免费版额度耗尽停止服务,钱包余额不兜底。
|
||||
|
||||
### 计费流程
|
||||
|
||||
```
|
||||
预扣(Redis 原子操作)→ 转发请求 → 结算(实际用量)→ 退款/补扣差额
|
||||
```
|
||||
|
||||
价格查询优先级:租户独立价 > 套餐价 > 模型基础价 > 硬编码默认。
|
||||
|
||||
最终价格公式:`最终价格 = 基础价格 × 模型乘数 × 租户乘数`。模型乘数根据模型稀有度/成本动态调整;租户乘数根据租户等级/用量等级设置(VIP 折扣等)。双层乘数替代单纯的"租户独立定价",提供更灵活的定价能力。
|
||||
|
||||
### 钱包冻结余额
|
||||
|
||||
wallets 表包含 `frozen_balance` 字段,用于支付中/退款中的金额冻结,防止并发超扣。可用余额 = `balance - frozen_balance`。预扣和支付操作需检查可用余额而非总余额。
|
||||
|
||||
### 系统货币规则
|
||||
|
||||
平台采用**内部统一 USD + 充值入口 CNY**策略,系统内除充值/支付外的所有金额均为 USD:
|
||||
|
||||
| 业务场景 | 货币 | 说明 |
|
||||
|----------|------|------|
|
||||
| 大模型价格展示和计费 | **USD(美元)** | 模型定价、Token 单价、计费扣费统一使用美元,与上游供应商(OpenAI/Anthropic/Google)报价币种一致 |
|
||||
| 用户钱包余额 | **USD(美元)** | 钱包存储 USD 余额,充值时 CNY 按汇率转换为 USD 入账 |
|
||||
| 计费记录 / 交易流水 | **USD(美元)** | 所有 bil_records、bil_transactions 金额均为 USD |
|
||||
| 套餐价格 | **CNY(人民币)** | 管理后台创建套餐时设置的价格为人民币,用户购买套餐使用人民币支付 |
|
||||
| 充值/支付 | **CNY(人民币)** | 用户通过支付渠道(支付宝/微信/Stripe)充值为人民币,履约时转换为 USD 入账钱包 |
|
||||
|
||||
**换算规则**:
|
||||
- 管理后台支付设置中配置 CNY → USD 兑换比例(`payment_exchange_rate_cny_to_usd`,默认 0.14)
|
||||
- 充值履约时调用 `billing.ConvertCNYToUSD(ctx, cnyAmount)` 将 CNY 金额转换为 USD 入账钱包
|
||||
- 计费引擎全程使用 USD,无需换算
|
||||
- 前端展示规则:钱包余额/交易记录/计费用 `$`(USD),套餐价格/充值金额/订单金额用 `¥`(CNY)
|
||||
|
||||
## 数据库表前缀定义
|
||||
|
||||
按功能域划分,新建表时必须归入对应前缀,除非加入了新的功能模型,否则不得自行新增前缀。
|
||||
|
||||
| 前缀 | 功能域 | 周期 | 涉及表(示例) |
|
||||
|------|--------|------|--------------|
|
||||
| `sys_` | 平台系统 + 系统配置 | 一 | `sys_admin_users` `sys_admin_role_perms` `sys_admin_data_scopes` `sys_sessions` `sys_email_verify_codes` `sys_idempotency_records` `sys_options` |
|
||||
| `tnt_` | 租户核心 + 项目管理 | 一 | `tnt_tenants` `tnt_users` `tnt_invitations` `tnt_member_imports` `tnt_member_model_scopes` `tnt_projects` |
|
||||
| `mdl_` | AI 模型 | 一 | `mdl_models` `mdl_pricing_tiers` `mdl_tenant_models` |
|
||||
| `chn_` | 渠道管理 | 一 | `chn_channels` `chn_abilities` `chn_health_scores` `chn_channel_keys` `chn_channel_affinities` |
|
||||
| `api_` | API 密钥 | 一 | `api_keys` `api_key_model_scopes` |
|
||||
| `bil_` | 计费账单 | 一 | `bil_records` `bil_wallets` `bil_transactions` `bil_usage_logs` `bil_daily_usage_summary` `bil_daily_revenue_summary` `bil_monthly_usage_summary` `bil_monthly_revenue_summary` |
|
||||
| `ord_` | 订单支付 + 优惠券 | 二 | `ord_orders` `ord_refunds` `ord_payment_channels` `ord_promo_codes` `ord_promo_code_usages` `ord_redemptions` `ord_redemption_usages` |
|
||||
| `pln_` | 套餐订阅 | 二 | `pln_plans` `pln_tenant_plans` `pln_feature_flags` |
|
||||
| `ntf_` | 通知消息 | 三 | `ntf_templates` `ntf_send_log` `ntf_messages` `ntf_read_status` `ntf_preferences` `ntf_announcements` |
|
||||
| `aud_` | 审计日志 | 三 | `aud_request_logs` `aud_operation_logs` `aud_sensitive_access_logs` `aud_login_history` |
|
||||
| `spt_` | 客户支持(工单+帮助+反馈) | 三/六 | `spt_tickets` `spt_replies` `spt_attachments` `spt_categories` `spt_articles` `spt_feedbacks` |
|
||||
| `ops_` | 运维监控 | 四 | `ops_alert_rules` `ops_alert_events` `ops_system_metrics` |
|
||||
| `tsk_` | 异步任务 | 四 | `tsk_tasks` `tsk_task_logs` `tsk_async_tasks` |
|
||||
| `fil_` | 文件存储 | 四 | `fil_files` |
|
||||
| `opn_` | 开放平台 + Webhook | 五 | `opn_apps` `opn_webhook_configs` `opn_webhook_events` `opn_webhook_delivery_logs` |
|
||||
| `clg_` | 更新日志 | 六 | `clg_changelogs` |
|
||||
|
||||
### 前缀使用规则
|
||||
|
||||
- 新建表必须从上表选择前缀,不允许自行新增前缀
|
||||
- 如果一个表明显属于两个域,选择核心归属域的前缀
|
||||
- 通用/跨域表(如 `sys_options` 系统配置)放在最相关的域下
|
||||
- 迁移脚本文件名按现有文件顺序递增编号,格式:`{序号}_{变更内容描述}.sql`,例如 `000002_alter_mdl_pricing_cache_fields.sql`
|
||||
|
||||
## 开发规范
|
||||
|
||||
### Go 后端
|
||||
|
||||
- **缩进统一使用 tab**:所有 Go 代码的缩进必须使用 tab,与 `go fmt` 自动格式化保持一致,禁止混用空格和 tab 缩进
|
||||
- GoFrame 标准项目结构,不要偏离。框架使用规范(时间处理、错误处理、ORM 模式、日志等)详见 [`docs/reference/goframe-conventions.md`](docs/reference/goframe-conventions.md),遇到不确定的 GoFrame 用法时善用 `/goframe-v2` skill 查询框架规范
|
||||
- **修复 GoFrame 框架使用 bug 时**,必须在 `docs/reference/goframe-conventions.md` 末尾的「已修复的框架使用错误记录」章节追加记录(问题描述、原因、修复方式),防止同类问题重现
|
||||
- 数据库迁移用 goose,脚本按六位序号递增编号(`migrations/000001_xxx.sql`)
|
||||
- 所有业务表必须有 `id`, `created_at`, `updated_at` 字段
|
||||
- 审计相关表按月分区(audit_logs)
|
||||
- 使用量大的写入操作(usage_logs)异步批量写入
|
||||
- 错误响应统一格式:`{"error": {"type": "...", "message": "...", "code": "...", "request_id": "..."}}`
|
||||
- 每个 API 请求生成唯一 Request ID,贯穿全链路
|
||||
- 敏感字段(密码、API Key 原值)AES-256 加密存储
|
||||
- 缓存策略:API Key 60s、用户信息 300s、模型定价 600s、渠道信息 300s
|
||||
|
||||
### 前端
|
||||
|
||||
- Vue 3 Composition API + `<script setup>` 语法
|
||||
- **管理后台**:使用 **Naive UI** 组件库,快速构建数据密集型页面(表格、表单、图表等),可参考 [Soybean Admin](https://github.com/soybeanjs/soybean-admin) 的架构设计(路由、权限、布局)
|
||||
- **租户控制台**:TailwindCSS 原子类 + 自建组件,面向客户,注重品牌调性和视觉差异化
|
||||
- TailwindCSS 作为基础样式层,两个控制台共用(Naive UI 的 CSS-in-JS 方案与 TailwindCSS 无冲突)
|
||||
- 状态管理用 Pinia
|
||||
- HTTP 请求封装 Axios,JWT 自动刷新,统一错误处理
|
||||
- 按钮级权限控制:无权限的按钮不渲染(`v-if="hasPermission('xxx')"`)
|
||||
- 前端不用 React,不用 JSX
|
||||
|
||||
### 数据库
|
||||
|
||||
- 只用 PostgreSQL,写 SQL 迁移脚本时使用 PostgreSQL 语法
|
||||
- **数据库是远程连接**,本地没有 psql 等命令可用,数据库操作只能通过 goose 迁移脚本执行
|
||||
- **表名带模块前缀**:同一模块/功能/域的表使用统一前缀(见下方《数据库表前缀定义》),提升可维护性
|
||||
- **全部小写蛇形命名**:表名和字段名一律 `snake_case`,禁止驼峰或大写
|
||||
- **禁止数据库级外键**:所有关联都是逻辑关联,不使用 `REFERENCES`/`FOREIGN KEY`,在代码层面处理关联关系和级联操作
|
||||
- **所有字段必须带注释**:建表时每个字段都加 `COMMENT '说明'`,便于后续维护
|
||||
- JSONB 字段用于灵活配置(功能权限、通知偏好等)
|
||||
- 字符串字段注意长度限制,不要用 `VARCHAR(255)` 一刀切
|
||||
- 金额字段统一用 `NUMERIC(20,10)`(PostgreSQL 中 NUMERIC 与 DECIMAL 等价),避免累计计算精度丢失,不用 FLOAT
|
||||
- 索引按实际查询场景创建,不过度索引
|
||||
- **追加写表使用 BRIN 索引**:`usage_logs`、`audit_logs`、`billing_records` 等按时间追加写入的表,在 `created_at` 字段上使用 BRIN 索引(而非 B-tree),大幅节省存储空间
|
||||
|
||||
### API 接口
|
||||
|
||||
- **URL 路径统一小写蛇形**:`/api/admin/tenant-plans` 而非 `/api/admin/tenantPlans`
|
||||
- GoFrame 有脚手架命令(`gf gen`),能使用脚手架生成的代码(model/dao/api)就用脚手架生成,不要手写
|
||||
- 完整的 JSON 示例、SSE 流式格式、各供应商响应格式、错误类型映射、中间件差异等详见 [`docs/reference/api-format-reference.md`](docs/reference/api-format-reference.md)
|
||||
|
||||
#### 统一响应格式(`/api/*` 管理类接口)
|
||||
|
||||
所有管理类接口(`/api/admin/*`、`/api/tenant/*`、`/api/payment/*`、`/api/open/*`)使用统一 JSON 结构:`{"code": 0, "message": "ok", "data": ..., "request_id": "..."}`。`code=0` 成功,非 0 错误。HTTP 状态码照常设置,前端以 `code` 为主。
|
||||
|
||||
**data 字段规范**:分页列表 `{list, total, page, page_size}`,不分页 `{list}`,创建 `{id}`,详情直接返回对象,更新/删除 `null`。数组字段名统一用 `list`,list 内部可为空但不能有 null。
|
||||
|
||||
**后端**:统一使用 `internal/response` 包(`response.Success` / `response.Error`),禁止直接拼 `g.Map`。业务错误码 >= 10000 定义在 `internal/consts/consts.go`,映射为 HTTP 422。`message` 必须中文,禁止暴露技术细节。
|
||||
|
||||
**前端**:Axios 拦截器以 `code === 0` 为唯一成功判据,统一处理错误提示。所有 API 调用 `try/catch` 包裹。
|
||||
|
||||
#### 大模型代理接口(`/v1/*`、`/v1beta/*`、`/suno/*`)
|
||||
|
||||
代理端点是 OpenAI/Claude/Gemini 等 AI 服务的反向代理,必须与上游 API 格式完全兼容。核心规则:
|
||||
|
||||
- **禁止使用统一响应格式和 `internal/response` 包**,直接操作 `http.ResponseWriter`
|
||||
- **原生透传**:上游响应原样转发,错误也用供应商原生格式
|
||||
- 错误处理:`WriteRelayError`(OpenAI 格式)、`WriteClaudeRelayError`(Claude 格式)
|
||||
|
||||
### Definition of Done(功能完成标准)
|
||||
|
||||
每个功能模块交付时需满足以下标准:
|
||||
|
||||
| # | 标准 | 说明 |
|
||||
|---|------|------|
|
||||
| 1 | 功能通过手动测试 | 核心业务流程端到端可跑通 |
|
||||
| 2 | 单元测试覆盖率 ≥ 80% | 核心计费/调度/权限逻辑必须有单元测试 |
|
||||
| 3 | 接口文档同步更新 | API 端点变更时同步更新 OpenAPI 文档 |
|
||||
| 4 | 数据库迁移可重复执行 | goose up/down 幂等,不破坏已有数据 |
|
||||
| 5 | 错误码与提示文案完整 | 所有错误场景有明确错误码和用户可读消息 |
|
||||
| 6 | 日志记录完整(含 trace_id) | 关键业务操作日志贯穿 request_id |
|
||||
| 7 | 权限校验覆盖所有端点 | 新增端点必须配置权限点,无权限返回 403 |
|
||||
| 8 | 代码审查通过 | 核心模块需 Code Review 后合入 |
|
||||
|
||||
|
||||
## 文档索引
|
||||
|
||||
关键文档在 `docs/` 下,需要时直接阅读:
|
||||
|
||||
| 文档 | 路径 | 用途 |
|
||||
|------|------|------|
|
||||
| 产品需求文档 | `docs/team-api产品需求文档.md` | 功能需求的最终依据 |
|
||||
| 原始开发计划 | `docs/team-api开发计划.md` | S01-S26 迭代拆分 |
|
||||
| new-api 调研 | `docs/new-api调研报告.md` | 参考项目能力盘点 |
|
||||
| sub2api 调研 | `docs/sub2api调研报告.md` | 参考项目能力盘点 |
|
||||
| 对比分析 | `docs/new-api-vs-sub2api对比分析报告.md` | 两者差异 |
|
||||
| 大模型实施方案 | `docs/大模型完整实施方案-v2.1.md` | 大模型代理层设计 |
|
||||
| API 格式参考 | `docs/reference/api-format-reference.md` | JSON 示例、SSE 格式、错误映射、中间件差异 |
|
||||
| GoFrame 使用规范 | `docs/reference/goframe-conventions.md` | 框架使用规范 + 已修复的框架 bug 记录 |
|
||||
|
||||
|
||||
## 开发环境
|
||||
|
||||
- **操作系统**:Windows
|
||||
- **GoFrame CLI**:已安装 `gf` 脚手架,优先使用 CLI 完成以下工作:
|
||||
|
||||
| 命令 | 用途 | 何时使用 |
|
||||
|------|------|---------|
|
||||
| `gf init` | 初始化项目骨架 | 项目创建时 |
|
||||
| `gf gen dao` | 从数据库生成 DAO/DO/Entity 代码 | 表结构变更后 |
|
||||
| `gf gen service` | 从 Logic 层生成 Service 接口 | 业务接口变更后 |
|
||||
| `gf gen ctrl` | 从 API 定义生成 Controller | API 定义变更后 |
|
||||
| `gf gen pb` | 生成 protobuf 文件 | 需要时 |
|
||||
| `gf run` | 热编译运行开发服务器 | 开发调试 |
|
||||
| `gf build` | 编译生产二进制 | 构建部署 |
|
||||
@@ -0,0 +1,41 @@
|
||||
ROOT_DIR = $(shell pwd)
|
||||
DEPLOY_NAME = "team-api"
|
||||
DOCKER_NAME = "team-api"
|
||||
|
||||
# DB_URL 设置方式(三选一):
|
||||
# 1. 创建 .env 文件(推荐): DB_URL = "host=... port=... user=... password=... dbname=... sslmode=disable"
|
||||
# 2. 设置环境变量: export DB_URL="host=..."
|
||||
# 3. 直接写在下方: DB_URL = "host=..."
|
||||
ifneq (,$(wildcard .env))
|
||||
include .env
|
||||
endif
|
||||
|
||||
.PHONY: run build tidy migrate-up migrate-down migrate-status migrate-reset
|
||||
|
||||
include ./hack/hack-cli.mk
|
||||
include ./hack/hack.mk
|
||||
|
||||
# GoFrame hot-reload dev server
|
||||
run:
|
||||
gf run main.go
|
||||
|
||||
# Build production binary
|
||||
build:
|
||||
gf build
|
||||
|
||||
# Tidy go modules
|
||||
tidy:
|
||||
go mod tidy
|
||||
|
||||
# Goose migration commands
|
||||
migrate-up:
|
||||
goose -dir migrations postgres $(DB_URL) up
|
||||
|
||||
migrate-down:
|
||||
goose -dir migrations postgres $(DB_URL) down
|
||||
|
||||
migrate-status:
|
||||
goose -dir migrations postgres $(DB_URL) status
|
||||
|
||||
migrate-reset:
|
||||
goose -dir migrations postgres $(DB_URL) reset
|
||||
@@ -20,7 +20,7 @@
|
||||
## 功能特性
|
||||
|
||||
- **多租户架构** — 行级租户隔离,管理后台与租户控制台双独立用户体系
|
||||
- **25+ 大模型供应商** — OpenAI、Claude、Gemini、DeepSeek、通义千问、智谱、Moonshot、Mistral、xAI、AWS Bedrock、Azure OpenAI、Vertex AI、Cloudflare Workers AI、Ollama 等
|
||||
- **25+ 大模型供应商** — OpenAI、Claude、Gemini、DeepSeek、通义千问、智谱、Ollama 等
|
||||
- **OpenAI 兼容 API** — 无缝替换 OpenAI API,支持对话补全、向量嵌入、图像生成、语音、实时通信等
|
||||
- **智能渠道调度** — 优先级/权重路由、自动故障转移、健康监控、渠道亲和性
|
||||
- **五层额度模型** — 租户钱包 → 套餐额度 → 成员额度 → 项目预算 → Key 额度
|
||||
@@ -358,10 +358,14 @@ Team-API 实现了五层额度体系:
|
||||
| OAuth/SSO | ✅ | OAuth 集成、SSO 自动建户 |
|
||||
| API Playground | ✅ | 在线调试(真实调用、计费) |
|
||||
| OpenAPI 文档 | ✅ | 3.0 规范自动生成 |
|
||||
| 图片模型适配验证 | 🚧 | 系统已有部分代码,但未进行验证 |
|
||||
| 视频模型适配验证 | 🚧 | 系统已有部分代码,但未进行验证 |
|
||||
| 嵌入模型适配验证 | 🚧 | 系统已有部分代码,但未进行验证 |
|
||||
| 新手引导流程 | ⬜ | 5 步引导、空状态提示 |
|
||||
| 在线审计 | ⬜ | 在线升级 |
|
||||
| 演示站点 | ⬜ | 在线演示 |
|
||||
| 审计日志分库存储 | ⬜ | 审计日志存入独立库中维护 |
|
||||
| 插件功能 | ⬜ | 计划参考GVA或者Hotgo的实现 |
|
||||
|
||||
## 参与贡献
|
||||
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
)
|
||||
|
||||
type IAdminV1 interface {
|
||||
AdminUserList(ctx context.Context, req *v1.AdminUserListReq) (res *v1.AdminUserListRes, err error)
|
||||
AdminUserCreate(ctx context.Context, req *v1.AdminUserCreateReq) (res *v1.AdminUserCreateRes, err error)
|
||||
AdminUserUpdate(ctx context.Context, req *v1.AdminUserUpdateReq) (res *v1.AdminUserUpdateRes, err error)
|
||||
AdminUserDelete(ctx context.Context, req *v1.AdminUserDeleteReq) (res *v1.AdminUserDeleteRes, err error)
|
||||
AdminUserUpdateStatus(ctx context.Context, req *v1.AdminUserUpdateStatusReq) (res *v1.AdminUserUpdateStatusRes, err error)
|
||||
AdminUserResetPassword(ctx context.Context, req *v1.AdminUserResetPasswordReq) (res *v1.AdminUserResetPasswordRes, err error)
|
||||
AdminUserExport(ctx context.Context, req *v1.AdminUserExportReq) (res *v1.AdminUserExportRes, err error)
|
||||
AuditConfigGet(ctx context.Context, req *v1.AuditConfigGetReq) (res *v1.AuditConfigGetRes, err error)
|
||||
AuditConfigUpdate(ctx context.Context, req *v1.AuditConfigUpdateReq) (res *v1.AuditConfigUpdateRes, err error)
|
||||
OperationLogList(ctx context.Context, req *v1.OperationLogListReq) (res *v1.OperationLogListRes, err error)
|
||||
SensitiveLogList(ctx context.Context, req *v1.SensitiveLogListReq) (res *v1.SensitiveLogListRes, err error)
|
||||
RequestAuditLogList(ctx context.Context, req *v1.RequestAuditLogListReq) (res *v1.RequestAuditLogListRes, err error)
|
||||
RequestAuditLogDetail(ctx context.Context, req *v1.RequestAuditLogDetailReq) (res *v1.RequestAuditLogDetailRes, err error)
|
||||
OperationLogExport(ctx context.Context, req *v1.OperationLogExportReq) (res *v1.OperationLogExportRes, err error)
|
||||
AdminLogin(ctx context.Context, req *v1.AdminLoginReq) (res *v1.AdminLoginRes, err error)
|
||||
AdminLogout(ctx context.Context, req *v1.AdminLogoutReq) (res *v1.AdminLogoutRes, err error)
|
||||
AdminRefresh(ctx context.Context, req *v1.AdminRefreshReq) (res *v1.AdminRefreshRes, err error)
|
||||
AdminSessionList(ctx context.Context, req *v1.AdminSessionListReq) (res *v1.AdminSessionListRes, err error)
|
||||
AdminRevokeSession(ctx context.Context, req *v1.AdminRevokeSessionReq) (res *v1.AdminRevokeSessionRes, err error)
|
||||
AdminForceLogout(ctx context.Context, req *v1.AdminForceLogoutReq) (res *v1.AdminForceLogoutRes, err error)
|
||||
AdminChangePassword(ctx context.Context, req *v1.AdminChangePasswordReq) (res *v1.AdminChangePasswordRes, err error)
|
||||
ChangelogCreate(ctx context.Context, req *v1.ChangelogCreateReq) (res *v1.ChangelogCreateRes, err error)
|
||||
ChangelogList(ctx context.Context, req *v1.ChangelogListReq) (res *v1.ChangelogListRes, err error)
|
||||
ChangelogUpdate(ctx context.Context, req *v1.ChangelogUpdateReq) (res *v1.ChangelogUpdateRes, err error)
|
||||
ChangelogDelete(ctx context.Context, req *v1.ChangelogDeleteReq) (res *v1.ChangelogDeleteRes, err error)
|
||||
ChangelogPublish(ctx context.Context, req *v1.ChangelogPublishReq) (res *v1.ChangelogPublishRes, err error)
|
||||
ChannelList(ctx context.Context, req *v1.ChannelListReq) (res *v1.ChannelListRes, err error)
|
||||
ChannelCreate(ctx context.Context, req *v1.ChannelCreateReq) (res *v1.ChannelCreateRes, err error)
|
||||
ChannelUpdate(ctx context.Context, req *v1.ChannelUpdateReq) (res *v1.ChannelUpdateRes, err error)
|
||||
ChannelDelete(ctx context.Context, req *v1.ChannelDeleteReq) (res *v1.ChannelDeleteRes, err error)
|
||||
ChannelDetail(ctx context.Context, req *v1.ChannelDetailReq) (res *v1.ChannelDetailRes, err error)
|
||||
ChannelKeyCreate(ctx context.Context, req *v1.ChannelKeyCreateReq) (res *v1.ChannelKeyCreateRes, err error)
|
||||
ChannelKeyDelete(ctx context.Context, req *v1.ChannelKeyDeleteReq) (res *v1.ChannelKeyDeleteRes, err error)
|
||||
ChannelAbilityBatch(ctx context.Context, req *v1.ChannelAbilityBatchReq) (res *v1.ChannelAbilityBatchRes, err error)
|
||||
ProviderDefaultURL(ctx context.Context, req *v1.ProviderDefaultURLReq) (res *v1.ProviderDefaultURLRes, err error)
|
||||
ChannelKeyList(ctx context.Context, req *v1.ChannelKeyListReq) (res *v1.ChannelKeyListRes, err error)
|
||||
ChannelAbilitiesGet(ctx context.Context, req *v1.ChannelAbilitiesGetReq) (res *v1.ChannelAbilitiesGetRes, err error)
|
||||
ChannelHealthTrend(ctx context.Context, req *v1.ChannelHealthTrendReq) (res *v1.ChannelHealthTrendRes, err error)
|
||||
ChannelExport(ctx context.Context, req *v1.ChannelExportReq) (res *v1.ChannelExportRes, err error)
|
||||
ChannelClone(ctx context.Context, req *v1.ChannelCloneReq) (res *v1.ChannelCloneRes, err error)
|
||||
ChannelOAuthAuthURL(ctx context.Context, req *v1.ChannelOAuthAuthURLReq) (res *v1.ChannelOAuthAuthURLRes, err error)
|
||||
ChannelOAuthExchange(ctx context.Context, req *v1.ChannelOAuthExchangeReq) (res *v1.ChannelOAuthExchangeRes, err error)
|
||||
ChannelOAuthRefresh(ctx context.Context, req *v1.ChannelOAuthRefreshReq) (res *v1.ChannelOAuthRefreshRes, err error)
|
||||
ChannelTest(ctx context.Context, req *v1.ChannelTestReq) (res *v1.ChannelTestRes, err error)
|
||||
CronJobList(ctx context.Context, req *v1.CronJobListReq) (res *v1.CronJobListRes, err error)
|
||||
CronJobExecutions(ctx context.Context, req *v1.CronJobExecutionsReq) (res *v1.CronJobExecutionsRes, err error)
|
||||
CronJobTrigger(ctx context.Context, req *v1.CronJobTriggerReq) (res *v1.CronJobTriggerRes, err error)
|
||||
AdminDashboard(ctx context.Context, req *v1.AdminDashboardReq) (res *v1.AdminDashboardRes, err error)
|
||||
AdminDashboardTrends(ctx context.Context, req *v1.AdminDashboardTrendsReq) (res *v1.AdminDashboardTrendsRes, err error)
|
||||
AdminDashboardTopTenants(ctx context.Context, req *v1.AdminDashboardTopTenantsReq) (res *v1.AdminDashboardTopTenantsRes, err error)
|
||||
AdminDashboardModelDistribution(ctx context.Context, req *v1.AdminDashboardModelDistributionReq) (res *v1.AdminDashboardModelDistributionRes, err error)
|
||||
AdminDashboardChannelHealth(ctx context.Context, req *v1.AdminDashboardChannelHealthReq) (res *v1.AdminDashboardChannelHealthRes, err error)
|
||||
AdminDashboardRecentAlerts(ctx context.Context, req *v1.AdminDashboardRecentAlertsReq) (res *v1.AdminDashboardRecentAlertsRes, err error)
|
||||
AdminUsageLogList(ctx context.Context, req *v1.AdminUsageLogListReq) (res *v1.AdminUsageLogListRes, err error)
|
||||
AdminBillingRecordList(ctx context.Context, req *v1.AdminBillingRecordListReq) (res *v1.AdminBillingRecordListRes, err error)
|
||||
AdminWalletList(ctx context.Context, req *v1.AdminWalletListReq) (res *v1.AdminWalletListRes, err error)
|
||||
AdminWalletInfo(ctx context.Context, req *v1.AdminWalletInfoReq) (res *v1.AdminWalletInfoRes, err error)
|
||||
AdminWalletAdjust(ctx context.Context, req *v1.AdminWalletAdjustReq) (res *v1.AdminWalletAdjustRes, err error)
|
||||
AdminWalletTransactionList(ctx context.Context, req *v1.AdminWalletTransactionListReq) (res *v1.AdminWalletTransactionListRes, err error)
|
||||
AdminWalletSetWarningThreshold(ctx context.Context, req *v1.AdminWalletSetWarningThresholdReq) (res *v1.AdminWalletSetWarningThresholdRes, err error)
|
||||
AdminUsageLogExport(ctx context.Context, req *v1.AdminUsageLogExportReq) (res *v1.AdminUsageLogExportRes, err error)
|
||||
AdminBillingRecordExport(ctx context.Context, req *v1.AdminBillingRecordExportReq) (res *v1.AdminBillingRecordExportRes, err error)
|
||||
DataGovernanceSettingsGet(ctx context.Context, req *v1.DataGovernanceSettingsGetReq) (res *v1.DataGovernanceSettingsGetRes, err error)
|
||||
DataGovernanceSettingsUpdate(ctx context.Context, req *v1.DataGovernanceSettingsUpdateReq) (res *v1.DataGovernanceSettingsUpdateRes, err error)
|
||||
DataGovernanceExport(ctx context.Context, req *v1.DataGovernanceExportReq) (res *v1.DataGovernanceExportRes, err error)
|
||||
DataGovernanceDeletion(ctx context.Context, req *v1.DataGovernanceDeletionReq) (res *v1.DataGovernanceDeletionRes, err error)
|
||||
DataGovernanceCleanup(ctx context.Context, req *v1.DataGovernanceCleanupReq) (res *v1.DataGovernanceCleanupRes, err error)
|
||||
ErrorLogList(ctx context.Context, req *v1.ErrorLogListReq) (res *v1.ErrorLogListRes, err error)
|
||||
ErrorLogDetail(ctx context.Context, req *v1.ErrorLogDetailReq) (res *v1.ErrorLogDetailRes, err error)
|
||||
ErrorLogResolve(ctx context.Context, req *v1.ErrorLogResolveReq) (res *v1.ErrorLogResolveRes, err error)
|
||||
ErrorLogBatchResolve(ctx context.Context, req *v1.ErrorLogBatchResolveReq) (res *v1.ErrorLogBatchResolveRes, err error)
|
||||
ErrorLogStats(ctx context.Context, req *v1.ErrorLogStatsReq) (res *v1.ErrorLogStatsRes, err error)
|
||||
FeedbackListAll(ctx context.Context, req *v1.FeedbackListAllReq) (res *v1.FeedbackListAllRes, err error)
|
||||
FeedbackReply(ctx context.Context, req *v1.FeedbackReplyReq) (res *v1.FeedbackReplyRes, err error)
|
||||
FeedbackUpdateStatus(ctx context.Context, req *v1.FeedbackUpdateStatusReq) (res *v1.FeedbackUpdateStatusRes, err error)
|
||||
FeedbackStats(ctx context.Context, req *v1.FeedbackStatsReq) (res *v1.FeedbackStatsRes, err error)
|
||||
HelpCategoryCreate(ctx context.Context, req *v1.HelpCategoryCreateReq) (res *v1.HelpCategoryCreateRes, err error)
|
||||
HelpCategoryUpdate(ctx context.Context, req *v1.HelpCategoryUpdateReq) (res *v1.HelpCategoryUpdateRes, err error)
|
||||
HelpCategoryDelete(ctx context.Context, req *v1.HelpCategoryDeleteReq) (res *v1.HelpCategoryDeleteRes, err error)
|
||||
HelpCategoryList(ctx context.Context, req *v1.HelpCategoryListReq) (res *v1.HelpCategoryListRes, err error)
|
||||
HelpArticleCreate(ctx context.Context, req *v1.HelpArticleCreateReq) (res *v1.HelpArticleCreateRes, err error)
|
||||
HelpArticleUpdate(ctx context.Context, req *v1.HelpArticleUpdateReq) (res *v1.HelpArticleUpdateRes, err error)
|
||||
HelpArticleDelete(ctx context.Context, req *v1.HelpArticleDeleteReq) (res *v1.HelpArticleDeleteRes, err error)
|
||||
HelpArticleList(ctx context.Context, req *v1.HelpArticleListReq) (res *v1.HelpArticleListRes, err error)
|
||||
HelpArticleGet(ctx context.Context, req *v1.HelpArticleGetReq) (res *v1.HelpArticleGetRes, err error)
|
||||
ModelList(ctx context.Context, req *v1.ModelListReq) (res *v1.ModelListRes, err error)
|
||||
ModelCreate(ctx context.Context, req *v1.ModelCreateReq) (res *v1.ModelCreateRes, err error)
|
||||
ModelUpdate(ctx context.Context, req *v1.ModelUpdateReq) (res *v1.ModelUpdateRes, err error)
|
||||
ModelDelete(ctx context.Context, req *v1.ModelDeleteReq) (res *v1.ModelDeleteRes, err error)
|
||||
PricingList(ctx context.Context, req *v1.PricingListReq) (res *v1.PricingListRes, err error)
|
||||
PricingGet(ctx context.Context, req *v1.PricingGetReq) (res *v1.PricingGetRes, err error)
|
||||
PricingSet(ctx context.Context, req *v1.PricingSetReq) (res *v1.PricingSetRes, err error)
|
||||
ModelExport(ctx context.Context, req *v1.ModelExportReq) (res *v1.ModelExportRes, err error)
|
||||
PricingFetchOfficial(ctx context.Context, req *v1.PricingFetchOfficialReq) (res *v1.PricingFetchOfficialRes, err error)
|
||||
ModelFetchOfficialInfo(ctx context.Context, req *v1.ModelFetchOfficialInfoReq) (res *v1.ModelFetchOfficialInfoRes, err error)
|
||||
MonitorDashboard(ctx context.Context, req *v1.MonitorDashboardReq) (res *v1.MonitorDashboardRes, err error)
|
||||
MonitorTraffic(ctx context.Context, req *v1.MonitorTrafficReq) (res *v1.MonitorTrafficRes, err error)
|
||||
MonitorLatency(ctx context.Context, req *v1.MonitorLatencyReq) (res *v1.MonitorLatencyRes, err error)
|
||||
MonitorSystem(ctx context.Context, req *v1.MonitorSystemReq) (res *v1.MonitorSystemRes, err error)
|
||||
MonitorDBPool(ctx context.Context, req *v1.MonitorDBPoolReq) (res *v1.MonitorDBPoolRes, err error)
|
||||
MonitorRedisPool(ctx context.Context, req *v1.MonitorRedisPoolReq) (res *v1.MonitorRedisPoolRes, err error)
|
||||
MonitorRealtime(ctx context.Context, req *v1.MonitorRealtimeReq) (res *v1.MonitorRealtimeRes, err error)
|
||||
AlertRuleList(ctx context.Context, req *v1.AlertRuleListReq) (res *v1.AlertRuleListRes, err error)
|
||||
AlertOptions(ctx context.Context, req *v1.AlertOptionsReq) (res *v1.AlertOptionsRes, err error)
|
||||
AlertRuleCreate(ctx context.Context, req *v1.AlertRuleCreateReq) (res *v1.AlertRuleCreateRes, err error)
|
||||
AlertRuleUpdate(ctx context.Context, req *v1.AlertRuleUpdateReq) (res *v1.AlertRuleUpdateRes, err error)
|
||||
AlertRuleDelete(ctx context.Context, req *v1.AlertRuleDeleteReq) (res *v1.AlertRuleDeleteRes, err error)
|
||||
AlertRuleToggle(ctx context.Context, req *v1.AlertRuleToggleReq) (res *v1.AlertRuleToggleRes, err error)
|
||||
AlertTest(ctx context.Context, req *v1.AlertTestReq) (res *v1.AlertTestRes, err error)
|
||||
AlertEventList(ctx context.Context, req *v1.AlertEventListReq) (res *v1.AlertEventListRes, err error)
|
||||
AlertEventAcknowledge(ctx context.Context, req *v1.AlertEventAcknowledgeReq) (res *v1.AlertEventAcknowledgeRes, err error)
|
||||
AlertEventResolve(ctx context.Context, req *v1.AlertEventResolveReq) (res *v1.AlertEventResolveRes, err error)
|
||||
TemplateList(ctx context.Context, req *v1.TemplateListReq) (res *v1.TemplateListRes, err error)
|
||||
TemplateGet(ctx context.Context, req *v1.TemplateGetReq) (res *v1.TemplateGetRes, err error)
|
||||
TemplateUpdate(ctx context.Context, req *v1.TemplateUpdateReq) (res *v1.TemplateUpdateRes, err error)
|
||||
TemplateTest(ctx context.Context, req *v1.TemplateTestReq) (res *v1.TemplateTestRes, err error)
|
||||
MessageList(ctx context.Context, req *v1.MessageListReq) (res *v1.MessageListRes, err error)
|
||||
MessageSend(ctx context.Context, req *v1.MessageSendReq) (res *v1.MessageSendRes, err error)
|
||||
MessageBroadcast(ctx context.Context, req *v1.MessageBroadcastReq) (res *v1.MessageBroadcastRes, err error)
|
||||
AnnouncementList(ctx context.Context, req *v1.AnnouncementListReq) (res *v1.AnnouncementListRes, err error)
|
||||
AnnouncementCreate(ctx context.Context, req *v1.AnnouncementCreateReq) (res *v1.AnnouncementCreateRes, err error)
|
||||
AnnouncementUpdate(ctx context.Context, req *v1.AnnouncementUpdateReq) (res *v1.AnnouncementUpdateRes, err error)
|
||||
AnnouncementPublish(ctx context.Context, req *v1.AnnouncementPublishReq) (res *v1.AnnouncementPublishRes, err error)
|
||||
AnnouncementArchive(ctx context.Context, req *v1.AnnouncementArchiveReq) (res *v1.AnnouncementArchiveRes, err error)
|
||||
OrderList(ctx context.Context, req *v1.OrderListReq) (res *v1.OrderListRes, err error)
|
||||
OrderDetail(ctx context.Context, req *v1.OrderDetailReq) (res *v1.OrderDetailRes, err error)
|
||||
OrderRefund(ctx context.Context, req *v1.OrderRefundReq) (res *v1.OrderRefundRes, err error)
|
||||
OrderComplete(ctx context.Context, req *v1.OrderCompleteReq) (res *v1.OrderCompleteRes, err error)
|
||||
OrderExport(ctx context.Context, req *v1.OrderExportReq) (res *v1.OrderExportRes, err error)
|
||||
AdminMemberCreate(ctx context.Context, req *v1.AdminMemberCreateReq) (res *v1.AdminMemberCreateRes, err error)
|
||||
AdminMemberDisable(ctx context.Context, req *v1.AdminMemberDisableReq) (res *v1.AdminMemberDisableRes, err error)
|
||||
AdminMemberEnable(ctx context.Context, req *v1.AdminMemberEnableReq) (res *v1.AdminMemberEnableRes, err error)
|
||||
AdminMemberResetPassword(ctx context.Context, req *v1.AdminMemberResetPasswordReq) (res *v1.AdminMemberResetPasswordRes, err error)
|
||||
PaymentChannelList(ctx context.Context, req *v1.PaymentChannelListReq) (res *v1.PaymentChannelListRes, err error)
|
||||
PaymentChannelCreate(ctx context.Context, req *v1.PaymentChannelCreateReq) (res *v1.PaymentChannelCreateRes, err error)
|
||||
PaymentChannelDetail(ctx context.Context, req *v1.PaymentChannelDetailReq) (res *v1.PaymentChannelDetailRes, err error)
|
||||
PaymentChannelUpdate(ctx context.Context, req *v1.PaymentChannelUpdateReq) (res *v1.PaymentChannelUpdateRes, err error)
|
||||
PaymentChannelDelete(ctx context.Context, req *v1.PaymentChannelDeleteReq) (res *v1.PaymentChannelDeleteRes, err error)
|
||||
PaymentChannelToggle(ctx context.Context, req *v1.PaymentChannelToggleReq) (res *v1.PaymentChannelToggleRes, err error)
|
||||
PaymentSettingsGet(ctx context.Context, req *v1.PaymentSettingsGetReq) (res *v1.PaymentSettingsGetRes, err error)
|
||||
PaymentSettingsUpdate(ctx context.Context, req *v1.PaymentSettingsUpdateReq) (res *v1.PaymentSettingsUpdateRes, err error)
|
||||
AdminPermissionList(ctx context.Context, req *v1.AdminPermissionListReq) (res *v1.AdminPermissionListRes, err error)
|
||||
AdminPermissionUpdate(ctx context.Context, req *v1.AdminPermissionUpdateReq) (res *v1.AdminPermissionUpdateRes, err error)
|
||||
AdminDataScopeUpdate(ctx context.Context, req *v1.AdminDataScopeUpdateReq) (res *v1.AdminDataScopeUpdateRes, err error)
|
||||
AdminAllPermissions(ctx context.Context, req *v1.AdminAllPermissionsReq) (res *v1.AdminAllPermissionsRes, err error)
|
||||
PlanList(ctx context.Context, req *v1.PlanListReq) (res *v1.PlanListRes, err error)
|
||||
PlanCreate(ctx context.Context, req *v1.PlanCreateReq) (res *v1.PlanCreateRes, err error)
|
||||
PlanDetail(ctx context.Context, req *v1.PlanDetailReq) (res *v1.PlanDetailRes, err error)
|
||||
PlanUpdate(ctx context.Context, req *v1.PlanUpdateReq) (res *v1.PlanUpdateRes, err error)
|
||||
PlanArchive(ctx context.Context, req *v1.PlanArchiveReq) (res *v1.PlanArchiveRes, err error)
|
||||
PlanToggleRecommend(ctx context.Context, req *v1.PlanToggleRecommendReq) (res *v1.PlanToggleRecommendRes, err error)
|
||||
PlanExport(ctx context.Context, req *v1.PlanExportReq) (res *v1.PlanExportRes, err error)
|
||||
PluginList(ctx context.Context, req *v1.PluginListReq) (res *v1.PluginListRes, err error)
|
||||
PluginDetail(ctx context.Context, req *v1.PluginDetailReq) (res *v1.PluginDetailRes, err error)
|
||||
PluginInstall(ctx context.Context, req *v1.PluginInstallReq) (res *v1.PluginInstallRes, err error)
|
||||
PluginEnable(ctx context.Context, req *v1.PluginEnableReq) (res *v1.PluginEnableRes, err error)
|
||||
PluginDisable(ctx context.Context, req *v1.PluginDisableReq) (res *v1.PluginDisableRes, err error)
|
||||
PluginUninstall(ctx context.Context, req *v1.PluginUninstallReq) (res *v1.PluginUninstallRes, err error)
|
||||
PluginUpgrade(ctx context.Context, req *v1.PluginUpgradeReq) (res *v1.PluginUpgradeRes, err error)
|
||||
PluginConfigUpdate(ctx context.Context, req *v1.PluginConfigUpdateReq) (res *v1.PluginConfigUpdateRes, err error)
|
||||
PluginConfigSchema(ctx context.Context, req *v1.PluginConfigSchemaReq) (res *v1.PluginConfigSchemaRes, err error)
|
||||
PromoCodeList(ctx context.Context, req *v1.PromoCodeListReq) (res *v1.PromoCodeListRes, err error)
|
||||
PromoCodeCreate(ctx context.Context, req *v1.PromoCodeCreateReq) (res *v1.PromoCodeCreateRes, err error)
|
||||
PromoCodeUpdate(ctx context.Context, req *v1.PromoCodeUpdateReq) (res *v1.PromoCodeUpdateRes, err error)
|
||||
PromoCodeUsages(ctx context.Context, req *v1.PromoCodeUsagesReq) (res *v1.PromoCodeUsagesRes, err error)
|
||||
PromoCodeExport(ctx context.Context, req *v1.PromoCodeExportReq) (res *v1.PromoCodeExportRes, err error)
|
||||
RedemptionList(ctx context.Context, req *v1.RedemptionListReq) (res *v1.RedemptionListRes, err error)
|
||||
RedemptionCreate(ctx context.Context, req *v1.RedemptionCreateReq) (res *v1.RedemptionCreateRes, err error)
|
||||
RedemptionDisable(ctx context.Context, req *v1.RedemptionDisableReq) (res *v1.RedemptionDisableRes, err error)
|
||||
RedemptionUsages(ctx context.Context, req *v1.RedemptionUsagesReq) (res *v1.RedemptionUsagesRes, err error)
|
||||
RedemptionExport(ctx context.Context, req *v1.RedemptionExportReq) (res *v1.RedemptionExportRes, err error)
|
||||
Admin2FASetup(ctx context.Context, req *v1.Admin2FASetupReq) (res *v1.Admin2FASetupRes, err error)
|
||||
Admin2FAEnable(ctx context.Context, req *v1.Admin2FAEnableReq) (res *v1.Admin2FAEnableRes, err error)
|
||||
Admin2FADisable(ctx context.Context, req *v1.Admin2FADisableReq) (res *v1.Admin2FADisableRes, err error)
|
||||
Admin2FARegenerateBackupCodes(ctx context.Context, req *v1.Admin2FARegenerateBackupCodesReq) (res *v1.Admin2FARegenerateBackupCodesRes, err error)
|
||||
Admin2FAVerify(ctx context.Context, req *v1.Admin2FAVerifyReq) (res *v1.Admin2FAVerifyRes, err error)
|
||||
Admin2FAConfirm(ctx context.Context, req *v1.Admin2FAConfirmReq) (res *v1.Admin2FAConfirmRes, err error)
|
||||
AdminLoginHistory(ctx context.Context, req *v1.AdminLoginHistoryReq) (res *v1.AdminLoginHistoryRes, err error)
|
||||
AdminSettingsCategories(ctx context.Context, req *v1.AdminSettingsCategoriesReq) (res *v1.AdminSettingsCategoriesRes, err error)
|
||||
AdminSettingsGet(ctx context.Context, req *v1.AdminSettingsGetReq) (res *v1.AdminSettingsGetRes, err error)
|
||||
AdminSettingsUpdate(ctx context.Context, req *v1.AdminSettingsUpdateReq) (res *v1.AdminSettingsUpdateRes, err error)
|
||||
TaskList(ctx context.Context, req *v1.TaskListReq) (res *v1.TaskListRes, err error)
|
||||
TaskDetail(ctx context.Context, req *v1.TaskDetailReq) (res *v1.TaskDetailRes, err error)
|
||||
TaskCancel(ctx context.Context, req *v1.TaskCancelReq) (res *v1.TaskCancelRes, err error)
|
||||
TaskRetry(ctx context.Context, req *v1.TaskRetryReq) (res *v1.TaskRetryRes, err error)
|
||||
TenantCreate(ctx context.Context, req *v1.TenantCreateReq) (res *v1.TenantCreateRes, err error)
|
||||
TenantList(ctx context.Context, req *v1.TenantListReq) (res *v1.TenantListRes, err error)
|
||||
TenantGet(ctx context.Context, req *v1.TenantGetReq) (res *v1.TenantGetRes, err error)
|
||||
TenantChannelScopeUpdate(ctx context.Context, req *v1.TenantChannelScopeUpdateReq) (res *v1.TenantChannelScopeUpdateRes, err error)
|
||||
TenantUpdateStatus(ctx context.Context, req *v1.TenantUpdateStatusReq) (res *v1.TenantUpdateStatusRes, err error)
|
||||
TenantUpdate(ctx context.Context, req *v1.TenantUpdateReq) (res *v1.TenantUpdateRes, err error)
|
||||
AdminMemberList(ctx context.Context, req *v1.AdminMemberListReq) (res *v1.AdminMemberListRes, err error)
|
||||
TenantExport(ctx context.Context, req *v1.TenantExportReq) (res *v1.TenantExportRes, err error)
|
||||
AdminMemberExport(ctx context.Context, req *v1.AdminMemberExportReq) (res *v1.AdminMemberExportRes, err error)
|
||||
TenantSelect(ctx context.Context, req *v1.TenantSelectReq) (res *v1.TenantSelectRes, err error)
|
||||
TenantModelList(ctx context.Context, req *v1.TenantModelListReq) (res *v1.TenantModelListRes, err error)
|
||||
TenantModelBatchAssign(ctx context.Context, req *v1.TenantModelBatchAssignReq) (res *v1.TenantModelBatchAssignRes, err error)
|
||||
TenantModelUpdate(ctx context.Context, req *v1.TenantModelUpdateReq) (res *v1.TenantModelUpdateRes, err error)
|
||||
TenantModelDelete(ctx context.Context, req *v1.TenantModelDeleteReq) (res *v1.TenantModelDeleteRes, err error)
|
||||
TicketList(ctx context.Context, req *v1.TicketListReq) (res *v1.TicketListRes, err error)
|
||||
TicketGet(ctx context.Context, req *v1.TicketGetReq) (res *v1.TicketGetRes, err error)
|
||||
TicketAssign(ctx context.Context, req *v1.TicketAssignReq) (res *v1.TicketAssignRes, err error)
|
||||
TicketReply(ctx context.Context, req *v1.TicketReplyReq) (res *v1.TicketReplyRes, err error)
|
||||
TicketStatusUpdate(ctx context.Context, req *v1.TicketStatusUpdateReq) (res *v1.TicketStatusUpdateRes, err error)
|
||||
UsageLogCleanupCreate(ctx context.Context, req *v1.UsageLogCleanupCreateReq) (res *v1.UsageLogCleanupCreateRes, err error)
|
||||
UsageLogCleanupList(ctx context.Context, req *v1.UsageLogCleanupListReq) (res *v1.UsageLogCleanupListRes, err error)
|
||||
UsageLogCleanupCancel(ctx context.Context, req *v1.UsageLogCleanupCancelReq) (res *v1.UsageLogCleanupCancelRes, err error)
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// AdminUserListReq 管理员列表请求
|
||||
type AdminUserListReq struct {
|
||||
g.Meta `path:"/users" method:"get" mime:"json" tags:"管理后台-用户管理" summary:"管理员列表"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" dc:"每页数量"`
|
||||
Keyword string `json:"keyword" dc:"搜索关键词(用户名/邮箱)"`
|
||||
Role string `json:"role" dc:"角色筛选"`
|
||||
Status string `json:"status" dc:"状态筛选"`
|
||||
}
|
||||
|
||||
type AdminUserListRes struct {
|
||||
List []AdminUserItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type AdminUserItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
LastLoginAt string `json:"last_login_at"`
|
||||
LastLoginIp string `json:"last_login_ip"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// AdminUserCreateReq 创建管理员请求
|
||||
type AdminUserCreateReq struct {
|
||||
g.Meta `path:"/users" method:"post" mime:"json" tags:"管理后台-用户管理" summary:"创建管理员"`
|
||||
Username string `json:"username" v:"required|length:3,50#请输入用户名|用户名长度为3-50位" dc:"用户名"`
|
||||
Password string `json:"password" v:"required|length:8,64#请输入密码|密码长度为8-64位" dc:"密码"`
|
||||
Email string `json:"email" v:"email#邮箱格式不正确" dc:"邮箱"`
|
||||
Role string `json:"role" d:"admin" dc:"角色:super_admin / admin"`
|
||||
}
|
||||
|
||||
type AdminUserCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// AdminUserUpdateReq 更新管理员请求
|
||||
type AdminUserUpdateReq struct {
|
||||
g.Meta `path:"/users/{id}" method:"put" mime:"json" tags:"管理后台-用户管理" summary:"更新管理员"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"管理员ID"`
|
||||
DisplayName *string `json:"display_name" dc:"显示名称"`
|
||||
Email *string `json:"email" dc:"邮箱"`
|
||||
Role *string `json:"role" dc:"角色"`
|
||||
}
|
||||
|
||||
type AdminUserUpdateRes struct{}
|
||||
|
||||
// AdminUserDeleteReq 删除管理员请求
|
||||
type AdminUserDeleteReq struct {
|
||||
g.Meta `path:"/users/{id}" method:"delete" mime:"json" tags:"管理后台-用户管理" summary:"删除管理员"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"管理员ID"`
|
||||
}
|
||||
|
||||
type AdminUserDeleteRes struct{}
|
||||
|
||||
// AdminUserUpdateStatusReq 启用/禁用管理员请求
|
||||
type AdminUserUpdateStatusReq struct {
|
||||
g.Meta `path:"/users/{id}/status" method:"put" mime:"json" tags:"管理后台-用户管理" summary:"启用/禁用管理员"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"管理员ID"`
|
||||
Status string `json:"status" v:"required|in:active,disabled#请选择状态|状态值无效" dc:"状态:active / disabled"`
|
||||
}
|
||||
|
||||
type AdminUserUpdateStatusRes struct{}
|
||||
|
||||
// AdminUserResetPasswordReq 重置管理员密码请求
|
||||
type AdminUserResetPasswordReq struct {
|
||||
g.Meta `path:"/users/{id}/reset-password" method:"put" mime:"json" tags:"管理后台-用户管理" summary:"重置管理员密码"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"管理员ID"`
|
||||
NewPassword string `json:"new_password" v:"required|length:8,64#请输入新密码|密码长度为8-64位" dc:"新密码"`
|
||||
}
|
||||
|
||||
type AdminUserResetPasswordRes struct{}
|
||||
|
||||
// AdminUserExportReq 导出用户列表请求
|
||||
type AdminUserExportReq struct {
|
||||
g.Meta `path:"/users/export" method:"get" mime:"json" tags:"管理后台-用户管理" summary:"导出用户列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Keyword string `json:"keyword" in:"query" dc:"搜索关键词(用户名/邮箱)"`
|
||||
Role string `json:"role" in:"query" dc:"角色筛选"`
|
||||
Status string `json:"status" in:"query" dc:"状态筛选"`
|
||||
}
|
||||
|
||||
type AdminUserExportRes struct{}
|
||||
@@ -0,0 +1,97 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 审计管理 ===
|
||||
|
||||
type AuditConfigGetReq struct {
|
||||
g.Meta `path:"/audit/config" method:"get" mime:"json" tags:"管理后台-审计" summary:"获取审计配置"`
|
||||
}
|
||||
|
||||
type AuditConfigGetRes struct {
|
||||
AuditLevel string `json:"audit_level"`
|
||||
}
|
||||
|
||||
type AuditConfigUpdateReq struct {
|
||||
g.Meta `path:"/audit/config" method:"put" mime:"json" tags:"管理后台-审计" summary:"更新审计配置"`
|
||||
AuditLevel string `json:"audit_level" v:"required|in:full,full_text,masked,question_only,none"`
|
||||
}
|
||||
|
||||
type AuditConfigUpdateRes struct{}
|
||||
|
||||
type OperationLogListReq struct {
|
||||
g.Meta `path:"/audit/operation-logs" method:"get" mime:"json" tags:"管理后台-审计" summary:"操作日志列表"`
|
||||
Page int `json:"page" d:"1"`
|
||||
PageSize int `json:"page_size" d:"20"`
|
||||
UserID int `json:"user_id" dc:"用户ID"`
|
||||
UserType string `json:"user_type" dc:"用户类型"`
|
||||
Action string `json:"action" dc:"操作类型"`
|
||||
StartDate string `json:"start_date" dc:"开始日期"`
|
||||
EndDate string `json:"end_date" dc:"结束日期"`
|
||||
}
|
||||
|
||||
type OperationLogListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type SensitiveLogListReq struct {
|
||||
g.Meta `path:"/audit/sensitive-logs" method:"get" mime:"json" tags:"管理后台-审计" summary:"敏感访问日志"`
|
||||
Page int `json:"page" d:"1"`
|
||||
PageSize int `json:"page_size" d:"20"`
|
||||
UserID int `json:"user_id" dc:"用户ID"`
|
||||
ResourceType string `json:"resource_type" dc:"资源类型"`
|
||||
}
|
||||
|
||||
type SensitiveLogListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type RequestAuditLogListReq struct {
|
||||
g.Meta `path:"/audit/request-logs" method:"get" mime:"json" tags:"管理后台-审计" summary:"请求审计日志"`
|
||||
Page int `json:"page" d:"1"`
|
||||
PageSize int `json:"page_size" d:"20"`
|
||||
TenantID int `json:"tenant_id" dc:"租户ID"`
|
||||
ApiKeyID int `json:"api_key_id" dc:"API Key ID"`
|
||||
Username string `json:"username" dc:"用户名(模糊匹配)"`
|
||||
RequestId string `json:"request_id" dc:"Request ID(精确匹配)"`
|
||||
Method string `json:"method" dc:"HTTP 方法"`
|
||||
Path string `json:"path" dc:"请求路径"`
|
||||
StatusCode int `json:"status_code" dc:"状态码"`
|
||||
StartDate string `json:"start_date" dc:"开始日期"`
|
||||
EndDate string `json:"end_date" dc:"结束日期"`
|
||||
}
|
||||
|
||||
type RequestAuditLogListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type RequestAuditLogDetailReq struct {
|
||||
g.Meta `path:"/audit/request-logs/{id}" method:"get" mime:"json" tags:"管理后台-审计" summary:"请求审计日志详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type RequestAuditLogDetailRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
// OperationLogExportReq 导出操作日志请求
|
||||
type OperationLogExportReq struct {
|
||||
g.Meta `path:"/audit/operation-logs/export" method:"get" mime:"json" tags:"管理后台-审计" summary:"导出操作日志"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
UserID int `json:"user_id" in:"query" dc:"用户ID"`
|
||||
UserType string `json:"user_type" in:"query" dc:"用户类型"`
|
||||
Action string `json:"action" in:"query" dc:"操作类型"`
|
||||
StartDate string `json:"start_date" in:"query" dc:"开始日期"`
|
||||
EndDate string `json:"end_date" in:"query" dc:"结束日期"`
|
||||
}
|
||||
|
||||
type OperationLogExportRes struct{}
|
||||
@@ -0,0 +1,98 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// AdminLoginReq 管理后台登录请求
|
||||
type AdminLoginReq struct {
|
||||
g.Meta `path:"/auth/login" method:"post" mime:"json" tags:"管理后台-认证" summary:"管理员登录" group:"public" middleware:"-"`
|
||||
Username string `json:"username" v:"required#请输入用户名" dc:"用户名"`
|
||||
Password string `json:"password" v:"required#请输入密码" dc:"密码"`
|
||||
CaptchaKey string `json:"captcha_key" dc:"验证码key(验证码启用时必填)"`
|
||||
CaptchaX int `json:"captcha_x" dc:"滑块X坐标(验证码启用时必填)"`
|
||||
}
|
||||
|
||||
type AdminLoginRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
TotpRequired bool `json:"totp_required"` // 是否需要 2FA 验证
|
||||
ProvisionalToken string `json:"provisional_token,omitempty"` // 2FA 临时令牌(totp_required=true 时返回)
|
||||
User struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
} `json:"user"`
|
||||
}
|
||||
|
||||
// AdminLogoutReq 管理后台登出请求
|
||||
type AdminLogoutReq struct {
|
||||
g.Meta `path:"/auth/logout" method:"post" mime:"json" tags:"管理后台-认证" summary:"管理员登出"`
|
||||
}
|
||||
|
||||
type AdminLogoutRes struct{}
|
||||
|
||||
// AdminRefreshReq 刷新 Token 请求
|
||||
type AdminRefreshReq struct {
|
||||
g.Meta `path:"/auth/refresh" method:"post" mime:"json" tags:"管理后台-认证" summary:"刷新 Token" group:"public" middleware:"-"`
|
||||
RefreshToken string `json:"refresh_token" v:"required#请提供刷新令牌" dc:"刷新令牌"`
|
||||
}
|
||||
|
||||
type AdminRefreshRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
}
|
||||
|
||||
// AdminSessionListReq 活跃会话列表请求(查看所有管理员)
|
||||
type AdminSessionListReq struct {
|
||||
g.Meta `path:"/auth/sessions" method:"get" mime:"json" tags:"管理后台-认证" summary:"活跃会话列表"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
Username string `json:"username" in:"query" dc:"用户名(模糊搜索)"`
|
||||
IpAddress string `json:"ip_address" in:"query" dc:"IP地址(模糊搜索)"`
|
||||
}
|
||||
|
||||
type AdminSessionListRes struct {
|
||||
List []AdminSessionItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type AdminSessionItem struct {
|
||||
ID int64 `json:"id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"display_name"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
DeviceInfo string `json:"device_info"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
IsCurrent bool `json:"is_current"`
|
||||
}
|
||||
|
||||
// AdminRevokeSessionReq 踢出指定会话请求
|
||||
type AdminRevokeSessionReq struct {
|
||||
g.Meta `path:"/auth/sessions/{id}" method:"delete" mime:"json" tags:"管理后台-认证" summary:"踢出指定会话"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定会话ID"`
|
||||
}
|
||||
|
||||
type AdminRevokeSessionRes struct{}
|
||||
|
||||
// AdminForceLogoutReq 强制下线指定用户请求
|
||||
type AdminForceLogoutReq struct {
|
||||
g.Meta `path:"/auth/sessions/user/{id}" method:"delete" mime:"json" tags:"管理后台-认证" summary:"强制用户下线"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定用户ID"`
|
||||
}
|
||||
|
||||
type AdminForceLogoutRes struct{}
|
||||
|
||||
// AdminChangePasswordReq 修改密码请求
|
||||
type AdminChangePasswordReq struct {
|
||||
g.Meta `path:"/auth/change-password" method:"put" mime:"json" tags:"管理后台-认证" summary:"修改密码"`
|
||||
OldPassword string `json:"old_password" v:"required#请输入原密码" dc:"原密码"`
|
||||
NewPassword string `json:"new_password" v:"required|length:8,64#请输入新密码|密码长度为8-64位" dc:"新密码"`
|
||||
}
|
||||
|
||||
type AdminChangePasswordRes struct{}
|
||||
@@ -0,0 +1,73 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 更新日志(管理后台) ===
|
||||
|
||||
type ChangelogCreateReq struct {
|
||||
g.Meta `path:"/changelogs" method:"post" mime:"json" tags:"管理后台-更新日志" summary:"创建更新日志"`
|
||||
Version string `json:"version" v:"required|length:1,50" dc:"版本号"`
|
||||
Title string `json:"title" v:"required|length:1,200" dc:"标题"`
|
||||
Content string `json:"content" v:"required" dc:"Markdown 内容"`
|
||||
Type string `json:"type" d:"feature" v:"in:feature,fix,improvement,breaking" dc:"类型"`
|
||||
}
|
||||
|
||||
type ChangelogCreateRes struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
type ChangelogListReq struct {
|
||||
g.Meta `path:"/changelogs" method:"get" mime:"json" tags:"管理后台-更新日志" summary:"更新日志列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
Type string `json:"type" in:"query"`
|
||||
}
|
||||
|
||||
type ChangelogItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Version string `json:"version"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
PublishedAt *gtime.Time `json:"published_at,omitempty"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type ChangelogListRes struct {
|
||||
List []*ChangelogItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type ChangelogUpdateReq struct {
|
||||
g.Meta `path:"/changelogs/{id}" method:"put" mime:"json" tags:"管理后台-更新日志" summary:"更新更新日志"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Version string `json:"version" v:"required|length:1,50" dc:"版本号"`
|
||||
Title string `json:"title" v:"required|length:1,200" dc:"标题"`
|
||||
Content string `json:"content" v:"required" dc:"Markdown 内容"`
|
||||
Type string `json:"type" v:"in:feature,fix,improvement,breaking" dc:"类型"`
|
||||
Status string `json:"status" v:"in:draft,published" dc:"状态"`
|
||||
}
|
||||
|
||||
type ChangelogUpdateRes struct{}
|
||||
|
||||
type ChangelogDeleteReq struct {
|
||||
g.Meta `path:"/changelogs/{id}" method:"delete" mime:"json" tags:"管理后台-更新日志" summary:"删除更新日志"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type ChangelogDeleteRes struct{}
|
||||
|
||||
type ChangelogPublishReq struct {
|
||||
g.Meta `path:"/changelogs/{id}/publish" method:"post" mime:"json" tags:"管理后台-更新日志" summary:"发布更新日志"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type ChangelogPublishRes struct{}
|
||||
@@ -0,0 +1,255 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ChannelListReq 渠道列表请求
|
||||
type ChannelListReq struct {
|
||||
g.Meta `path:"/channels" method:"get" mime:"json" tags:"管理后台-渠道" summary:"渠道列表"`
|
||||
Page int `json:"page" d:"1" v:"min:1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" v:"min:1|max:100" dc:"每页数量"`
|
||||
Type int `json:"type" dc:"供应商类型筛选"`
|
||||
Status string `json:"status" dc:"状态筛选:active/disabled/testing"`
|
||||
Search string `json:"search" dc:"搜索关键词"`
|
||||
}
|
||||
|
||||
// ChannelListRes 渠道列表响应
|
||||
type ChannelListRes struct {
|
||||
List []ChannelItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// ChannelItem 渠道信息
|
||||
type ChannelItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
TypeName string `json:"type_name"`
|
||||
BaseURL string `json:"base_url"`
|
||||
Status string `json:"status"`
|
||||
Priority int `json:"priority"`
|
||||
Weight int `json:"weight"`
|
||||
TestModel string `json:"test_model"`
|
||||
Remark string `json:"remark"`
|
||||
IsVIP bool `json:"is_vip"`
|
||||
UseProxy bool `json:"use_proxy"`
|
||||
SharingThreshold *float64 `json:"sharing_threshold"`
|
||||
PreemptionThreshold *float64 `json:"preemption_threshold"`
|
||||
BorrowingCooldownSeconds *int `json:"borrowing_cooldown_seconds"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
HealthScore *float64 `json:"health_score"`
|
||||
}
|
||||
|
||||
// ChannelCreateReq 创建渠道请求
|
||||
type ChannelCreateReq struct {
|
||||
g.Meta `path:"/channels" method:"post" mime:"json" tags:"管理后台-渠道" summary:"创建渠道"`
|
||||
Name string `json:"name" v:"required|length:1,100#请输入渠道名|渠道名长度1-100" dc:"渠道名称"`
|
||||
Type int `json:"type" v:"required|min:1#请选择供应商类型" dc:"供应商类型"`
|
||||
BaseURL string `json:"base_url" dc:"API 基础地址(留空使用供应商默认地址)"`
|
||||
ApiKey string `json:"api_key" v:"required#请输入 API Key" dc:"API Key"`
|
||||
Priority int `json:"priority" d:"0" dc:"优先级"`
|
||||
Weight int `json:"weight" d:"100" v:"between:1,100" dc:"权重"`
|
||||
TestModel string `json:"test_model" dc:"测试模型名"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
IsVIP bool `json:"is_vip" d:"false" dc:"是否VIP专属渠道"`
|
||||
UseProxy bool `json:"use_proxy" d:"false" dc:"启用代理"`
|
||||
SharingThreshold float64 `json:"sharing_threshold" d:"0.6" dc:"普通租户借用阈值"`
|
||||
PreemptionThreshold float64 `json:"preemption_threshold" d:"0.8" dc:"VIP抢占阈值"`
|
||||
BorrowingCooldownSeconds int `json:"borrowing_cooldown_seconds" d:"30" dc:"被抢占后冷却时间(秒)"`
|
||||
}
|
||||
|
||||
// ChannelCreateRes 创建渠道响应
|
||||
type ChannelCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// ChannelUpdateReq 更新渠道请求
|
||||
type ChannelUpdateReq struct {
|
||||
g.Meta `path:"/channels/{id}" method:"put" mime:"json" tags:"管理后台-渠道" summary:"更新渠道"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"渠道ID"`
|
||||
Name string `json:"name" dc:"渠道名称"`
|
||||
BaseURL string `json:"base_url" dc:"API 基础地址"`
|
||||
ApiKey *string `json:"api_key" dc:"更新 API Key(留空不更新)"`
|
||||
Priority int `json:"priority" dc:"优先级"`
|
||||
Weight int `json:"weight" dc:"权重"`
|
||||
TestModel string `json:"test_model" dc:"测试模型名"`
|
||||
Remark string `json:"remark" dc:"备注"`
|
||||
Status string `json:"status" v:"in:active,disabled,testing" dc:"状态"`
|
||||
IsVIP *bool `json:"is_vip" dc:"是否VIP专属渠道"`
|
||||
UseProxy *bool `json:"use_proxy" dc:"启用代理"`
|
||||
SharingThreshold *float64 `json:"sharing_threshold" dc:"普通租户借用阈值"`
|
||||
PreemptionThreshold *float64 `json:"preemption_threshold" dc:"VIP抢占阈值"`
|
||||
BorrowingCooldownSeconds *int `json:"borrowing_cooldown_seconds" dc:"被抢占后冷却时间(秒)"`
|
||||
}
|
||||
|
||||
// ChannelDeleteReq 删除渠道请求
|
||||
type ChannelDeleteReq struct {
|
||||
g.Meta `path:"/channels/{id}" method:"delete" mime:"json" tags:"管理后台-渠道" summary:"删除渠道"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"渠道ID"`
|
||||
}
|
||||
|
||||
// ChannelDetailReq 渠道详情请求
|
||||
type ChannelDetailReq struct {
|
||||
g.Meta `path:"/channels/{id}" method:"get" mime:"json" tags:"管理后台-渠道" summary:"渠道详情"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"渠道ID"`
|
||||
}
|
||||
|
||||
// ChannelDetailRes 渠道详情响应
|
||||
type ChannelDetailRes struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type int `json:"type"`
|
||||
TypeName string `json:"type_name"`
|
||||
BaseURL string `json:"base_url"`
|
||||
Status string `json:"status"`
|
||||
Priority int `json:"priority"`
|
||||
Weight int `json:"weight"`
|
||||
TestModel string `json:"test_model"`
|
||||
Remark string `json:"remark"`
|
||||
IsVIP bool `json:"is_vip"`
|
||||
UseProxy bool `json:"use_proxy"`
|
||||
SharingThreshold *float64 `json:"sharing_threshold"`
|
||||
PreemptionThreshold *float64 `json:"preemption_threshold"`
|
||||
BorrowingCooldownSeconds *int `json:"borrowing_cooldown_seconds"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
HealthScore *float64 `json:"health_score"`
|
||||
KeyType string `json:"key_type"`
|
||||
KeyStatus string `json:"key_status"`
|
||||
KeyName string `json:"key_name"`
|
||||
TokenExpiresAt string `json:"token_expires_at"`
|
||||
}
|
||||
|
||||
// ChannelKeyCreateReq 添加渠道 Key 请求
|
||||
type ChannelKeyCreateReq struct {
|
||||
g.Meta `path:"/channels/{channel_id}/keys" method:"post" mime:"json" tags:"管理后台-渠道" summary:"添加渠道 Key"`
|
||||
ChannelID int64 `json:"channel_id" in:"path" v:"required" dc:"渠道ID"`
|
||||
Name string `json:"name" dc:"Key 别名"`
|
||||
ApiKey string `json:"api_key" v:"required" dc:"API Key 原值"`
|
||||
}
|
||||
|
||||
// ChannelKeyDeleteReq 删除渠道 Key 请求
|
||||
type ChannelKeyDeleteReq struct {
|
||||
g.Meta `path:"/channels/{channel_id}/keys/{key_id}" method:"delete" mime:"json" tags:"管理后台-渠道" summary:"删除渠道 Key"`
|
||||
ChannelID int64 `json:"channel_id" in:"path" v:"required" dc:"渠道ID"`
|
||||
KeyID int64 `json:"key_id" in:"path" v:"required" dc:"Key ID"`
|
||||
}
|
||||
|
||||
// ChannelKeyDeleteRes 删除渠道 Key 响应
|
||||
type ChannelKeyDeleteRes struct{}
|
||||
|
||||
// ChannelKeyCreateRes 添加渠道 Key 响应
|
||||
type ChannelKeyCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// ChannelAbilityBatchReq 批量设置渠道模型能力
|
||||
type ChannelAbilityBatchReq struct {
|
||||
g.Meta `path:"/channels/{channel_id}/abilities" method:"put" mime:"json" tags:"管理后台-渠道" summary:"设置渠道模型能力"`
|
||||
ChannelID int64 `json:"channel_id" in:"path" v:"required" dc:"渠道ID"`
|
||||
Abilities []AbilityItem `json:"abilities" dc:"能力列表"`
|
||||
}
|
||||
|
||||
// AbilityItem 模型能力项
|
||||
type AbilityItem struct {
|
||||
ID int64 `json:"id"`
|
||||
ModelName string `json:"model_name" v:"required" dc:"平台标准模型名"`
|
||||
UpstreamModel string `json:"upstream_model" dc:"上游实际模型名"`
|
||||
Enabled bool `json:"enabled" d:"true" dc:"是否启用"`
|
||||
}
|
||||
|
||||
// ProviderDefaultURLReq 获取供应商默认 URL
|
||||
type ProviderDefaultURLReq struct {
|
||||
g.Meta `path:"/channels/provider-default-urls" method:"get" mime:"json" tags:"管理后台-渠道" summary:"供应商默认地址"`
|
||||
}
|
||||
|
||||
type ProviderDefaultURLRes struct {
|
||||
URLs map[int]string `json:"urls"`
|
||||
}
|
||||
|
||||
// ChannelUpdateRes 更新渠道响应
|
||||
type ChannelUpdateRes struct{}
|
||||
|
||||
// ChannelDeleteRes 删除渠道响应
|
||||
type ChannelDeleteRes struct{}
|
||||
|
||||
// ChannelAbilityBatchRes 批量设置渠道模型能力响应
|
||||
type ChannelAbilityBatchRes struct{}
|
||||
|
||||
// ChannelKeyListReq 渠道 Key 列表请求
|
||||
type ChannelKeyListReq struct {
|
||||
g.Meta `path:"/channels/{channel_id}/keys" method:"get" mime:"json" tags:"管理后台-渠道" summary:"渠道Key列表"`
|
||||
ChannelID int64 `json:"channel_id" in:"path" v:"required" dc:"渠道ID"`
|
||||
}
|
||||
|
||||
type ChannelKeyListRes struct {
|
||||
List []ChannelKeyItem `json:"list"`
|
||||
}
|
||||
|
||||
// ChannelKeyItem 渠道 Key 信息
|
||||
type ChannelKeyItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ApiKey string `json:"api_key"`
|
||||
Status string `json:"status"`
|
||||
KeyType string `json:"key_type"`
|
||||
TokenExpiresAt string `json:"token_expires_at"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// ChannelAbilitiesGetReq 获取渠道模型能力请求
|
||||
type ChannelAbilitiesGetReq struct {
|
||||
g.Meta `path:"/channels/{channel_id}/abilities" method:"get" mime:"json" tags:"管理后台-渠道" summary:"获取渠道模型能力"`
|
||||
ChannelID int64 `json:"channel_id" in:"path" v:"required" dc:"渠道ID"`
|
||||
}
|
||||
|
||||
type ChannelAbilitiesGetRes struct {
|
||||
List []AbilityItem `json:"list"`
|
||||
}
|
||||
|
||||
// ChannelHealthTrendReq 渠道健康趋势请求
|
||||
type ChannelHealthTrendReq struct {
|
||||
g.Meta `path:"/channels/{id}/health_trend" method:"get" mime:"json" tags:"管理后台-渠道" summary:"渠道健康趋势"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"渠道ID"`
|
||||
Hours int `json:"hours" d:"24" v:"between:1,168" dc:"查询时长(小时)"`
|
||||
}
|
||||
|
||||
// ChannelHealthTrendRes 渠道健康趋势响应
|
||||
type ChannelHealthTrendRes struct {
|
||||
Points []HealthTrendPoint `json:"points"`
|
||||
}
|
||||
|
||||
// HealthTrendPoint 健康趋势数据点
|
||||
type HealthTrendPoint struct {
|
||||
SnapshotAt string `json:"snapshot_at"`
|
||||
HealthScore float64 `json:"health_score"`
|
||||
SuccessRate float64 `json:"success_rate"`
|
||||
LatencyMs float64 `json:"latency_ms"`
|
||||
StabilityScore float64 `json:"stability_score"`
|
||||
ConsecutiveFailures int `json:"consecutive_failures"`
|
||||
}
|
||||
|
||||
// ChannelExportReq 导出渠道列表请求
|
||||
type ChannelExportReq struct {
|
||||
g.Meta `path:"/channels/export" method:"get" mime:"json" tags:"管理后台-渠道" summary:"导出渠道列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Type int `json:"type" in:"query" dc:"供应商类型筛选"`
|
||||
Status string `json:"status" in:"query" dc:"状态筛选:active/disabled/testing"`
|
||||
Search string `json:"search" in:"query" dc:"搜索关键词"`
|
||||
}
|
||||
|
||||
type ChannelExportRes struct{}
|
||||
|
||||
// ChannelCloneReq 克隆渠道请求
|
||||
type ChannelCloneReq struct {
|
||||
g.Meta `path:"/channels/{id}/clone" method:"post" mime:"json" tags:"管理后台-渠道" summary:"克隆渠道"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"源渠道ID"`
|
||||
Name string `json:"name" dc:"新渠道名称(留空使用默认)"`
|
||||
ApiKey string `json:"api_key" v:"required#请输入新渠道的 API Key" dc:"新渠道的 API Key"`
|
||||
}
|
||||
|
||||
// ChannelCloneRes 克隆渠道响应
|
||||
type ChannelCloneRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ChannelOAuthAuthURLReq 生成 OAuth 授权链接请求
|
||||
type ChannelOAuthAuthURLReq struct {
|
||||
g.Meta `path:"/channels/oauth/auth-url" method:"post" mime:"json" tags:"管理后台-渠道" summary:"生成 OAuth 授权链接"`
|
||||
Platform string `json:"platform" v:"required|in:claude,openai,gemini" dc:"平台:claude/openai/gemini"`
|
||||
AuthMode string `json:"auth_mode" d:"browser" v:"in:browser,cookie" dc:"授权模式:browser=浏览器跳转,cookie=Cookie自动授权(仅Claude)"`
|
||||
Scope string `json:"scope" d:"full" v:"in:full,inference" dc:"授权范围(仅Claude)"`
|
||||
OAuthType string `json:"oauth_type" d:"code_assist" v:"in:code_assist" dc:"OAuth 类型(仅Gemini)"`
|
||||
SessionKey string `json:"session_key" dc:"Claude sessionKey cookie(仅 cookie 模式)"`
|
||||
}
|
||||
|
||||
type ChannelOAuthAuthURLRes struct {
|
||||
AuthURL string `json:"auth_url"`
|
||||
SessionID string `json:"session_id"`
|
||||
KeyID int64 `json:"key_id,omitempty"` // cookie 模式完成后的 key_id
|
||||
ChannelID int64 `json:"channel_id,omitempty"` // cookie 模式完成后的 channel_id
|
||||
}
|
||||
|
||||
// ChannelOAuthExchangeReq OAuth 授权码换取令牌请求
|
||||
type ChannelOAuthExchangeReq struct {
|
||||
g.Meta `path:"/channels/oauth/exchange" method:"post" mime:"json" tags:"管理后台-渠道" summary:"OAuth 授权码换取令牌"`
|
||||
SessionID string `json:"session_id" v:"required" dc:"授权会话ID"`
|
||||
Code string `json:"code" dc:"授权码(浏览器模式必填)"`
|
||||
State string `json:"state" dc:"state 参数"`
|
||||
KeyName string `json:"key_name" d:"OAuth 官方账号" dc:"存储的 Key 名称"`
|
||||
}
|
||||
|
||||
type ChannelOAuthExchangeRes struct {
|
||||
ChannelID int64 `json:"channel_id"`
|
||||
KeyID int64 `json:"key_id"`
|
||||
}
|
||||
|
||||
// ChannelOAuthRefreshReq 手动刷新 OAuth 令牌请求
|
||||
type ChannelOAuthRefreshReq struct {
|
||||
g.Meta `path:"/channels/oauth/refresh" method:"post" mime:"json" tags:"管理后台-渠道" summary:"手动刷新 OAuth 令牌"`
|
||||
KeyID int64 `json:"key_id" v:"required" dc:"渠道 Key ID"`
|
||||
}
|
||||
|
||||
type ChannelOAuthRefreshRes struct {
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ChannelTestReq 渠道测试请求
|
||||
type ChannelTestReq struct {
|
||||
g.Meta `path:"/channels/{id}/test" method:"post" mime:"json" tags:"管理后台-渠道" summary:"测试渠道可用性"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"渠道ID"`
|
||||
ModelName string `json:"model_name" dc:"测试模型名(可选,默认使用渠道的 test_model)"`
|
||||
}
|
||||
|
||||
// ChannelTestRes 渠道测试响应
|
||||
type ChannelTestRes struct {
|
||||
Success bool `json:"success"`
|
||||
Latency int64 `json:"latency_ms"`
|
||||
ModelName string `json:"model_name"`
|
||||
Error string `json:"error,omitempty"`
|
||||
Request *ChannelTestReqDetail `json:"request,omitempty"`
|
||||
Response string `json:"response,omitempty"`
|
||||
}
|
||||
|
||||
// ChannelTestReqDetail 测试请求详情
|
||||
type ChannelTestReqDetail struct {
|
||||
Method string `json:"method"`
|
||||
URL string `json:"url"`
|
||||
Headers map[string]string `json:"headers"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 定时任务 ===
|
||||
|
||||
type CronJobListReq struct {
|
||||
g.Meta `path:"/cron-jobs" method:"get" mime:"json" tags:"管理后台-定时任务" summary:"定时任务列表"`
|
||||
}
|
||||
|
||||
type CronJobItem struct {
|
||||
Name string `json:"name"`
|
||||
Schedule string `json:"schedule"`
|
||||
IsRunning bool `json:"is_running"`
|
||||
LastStatus string `json:"last_status"`
|
||||
LastStartedAt string `json:"last_started_at"`
|
||||
LastDurationMs int `json:"last_duration_ms"`
|
||||
LastErrorMsg string `json:"last_error_message"`
|
||||
TotalExecs int `json:"total_executions"`
|
||||
TotalFailures int `json:"total_failures"`
|
||||
}
|
||||
|
||||
type CronJobListRes struct {
|
||||
List []CronJobItem `json:"list"`
|
||||
}
|
||||
|
||||
type CronJobExecutionsReq struct {
|
||||
g.Meta `path:"/cron-jobs/{name}/executions" method:"get" mime:"json" tags:"管理后台-定时任务" summary:"任务执行历史"`
|
||||
Name string `json:"name" in:"path" v:"required"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query" dc:"过滤状态:succeeded/failed"`
|
||||
}
|
||||
|
||||
type CronJobExecutionsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type CronJobTriggerReq struct {
|
||||
g.Meta `path:"/cron-jobs/{name}/trigger" method:"post" mime:"json" tags:"管理后台-定时任务" summary:"手动触发任务"`
|
||||
Name string `json:"name" in:"path" v:"required"`
|
||||
}
|
||||
|
||||
type CronJobTriggerRes struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
@@ -0,0 +1,319 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 仪表盘 ===
|
||||
|
||||
type AdminDashboardReq struct {
|
||||
g.Meta `path:"/dashboard" method:"get" mime:"json" tags:"管理后台-仪表盘" summary:"仪表盘统计"`
|
||||
}
|
||||
|
||||
type AdminDashboardRes struct {
|
||||
Tenants int `json:"tenants"`
|
||||
Members int `json:"members"`
|
||||
ActiveChannels int `json:"active_channels"`
|
||||
Today *DayStats `json:"today"`
|
||||
Yesterday *DayStats `json:"yesterday"`
|
||||
Month *MonthStats `json:"month"`
|
||||
}
|
||||
|
||||
type DayStats struct {
|
||||
Requests int `json:"requests"`
|
||||
ActiveTenants int `json:"active_tenants"`
|
||||
InputTokens int `json:"input_tokens"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
SuccessRate float64 `json:"success_rate"`
|
||||
}
|
||||
|
||||
type MonthStats struct {
|
||||
Requests int `json:"requests"`
|
||||
InputTokens int `json:"input_tokens"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
Revenue float64 `json:"revenue"`
|
||||
}
|
||||
|
||||
type AdminDashboardTrendsReq struct {
|
||||
g.Meta `path:"/dashboard/trends" method:"get" mime:"json" tags:"管理后台-仪表盘" summary:"趋势数据"`
|
||||
Days int `json:"days" d:"30" v:"between:1,90" dc:"天数"`
|
||||
}
|
||||
|
||||
type AdminDashboardTrendsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
}
|
||||
|
||||
type AdminDashboardTopTenantsReq struct {
|
||||
g.Meta `path:"/dashboard/top-tenants" method:"get" mime:"json" tags:"管理后台-仪表盘" summary:"TOP租户"`
|
||||
Days int `json:"days" d:"30" v:"between:1,90" dc:"天数"`
|
||||
}
|
||||
|
||||
type AdminDashboardTopTenantsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
}
|
||||
|
||||
type AdminDashboardModelDistributionReq struct {
|
||||
g.Meta `path:"/dashboard/model-distribution" method:"get" mime:"json" tags:"管理后台-仪表盘" summary:"模型分布"`
|
||||
Days int `json:"days" d:"30" v:"between:1,90" dc:"天数"`
|
||||
}
|
||||
|
||||
type AdminDashboardModelDistributionRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
}
|
||||
|
||||
type AdminDashboardChannelHealthReq struct {
|
||||
g.Meta `path:"/dashboard/channel-health" method:"get" mime:"json" tags:"管理后台-仪表盘" summary:"渠道健康概览"`
|
||||
}
|
||||
|
||||
type ChannelHealthItem struct {
|
||||
ChannelId int64 `json:"channel_id"`
|
||||
ChannelName string `json:"channel_name"`
|
||||
Status string `json:"status"`
|
||||
HealthScore float64 `json:"health_score"`
|
||||
SuccessRate float64 `json:"success_rate"`
|
||||
LatencyMs int `json:"latency_ms"`
|
||||
}
|
||||
|
||||
type AdminDashboardChannelHealthRes struct {
|
||||
List []ChannelHealthItem `json:"list"`
|
||||
}
|
||||
|
||||
type AdminDashboardRecentAlertsReq struct {
|
||||
g.Meta `path:"/dashboard/recent-alerts" method:"get" mime:"json" tags:"管理后台-仪表盘" summary:"最近告警"`
|
||||
}
|
||||
|
||||
type RecentAlertItem struct {
|
||||
Id int64 `json:"id"`
|
||||
RuleName string `json:"rule_name"`
|
||||
Level string `json:"level"`
|
||||
Status string `json:"status"`
|
||||
TriggerMessage string `json:"trigger_message"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type AdminDashboardRecentAlertsRes struct {
|
||||
List []RecentAlertItem `json:"list"`
|
||||
}
|
||||
|
||||
// === 用量日志 ===
|
||||
|
||||
type AdminUsageLogListReq struct {
|
||||
g.Meta `path:"/usage-logs" method:"get" mime:"json" tags:"管理后台-用量" summary:"用量日志列表"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" v:"between:1,100" dc:"每页数量"`
|
||||
TenantID int64 `json:"tenant_id" dc:"租户ID"`
|
||||
Username string `json:"username" dc:"用户名(模糊匹配)"`
|
||||
Model string `json:"model" dc:"模型名称"`
|
||||
Status string `json:"status" dc:"状态"`
|
||||
StartDate string `json:"start_date" dc:"开始日期"`
|
||||
EndDate string `json:"end_date" dc:"结束日期"`
|
||||
}
|
||||
|
||||
type AdminUsageLogItem struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
UserId int64 `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
ProjectId int64 `json:"project_id"`
|
||||
ProjectName string `json:"project_name"`
|
||||
ApiKeyId int64 `json:"api_key_id"`
|
||||
ApiKeyName string `json:"api_key_name"`
|
||||
ChannelId int64 `json:"channel_id"`
|
||||
ChannelName string `json:"channel_name"`
|
||||
ChannelType int `json:"channel_type"`
|
||||
ModelName string `json:"model_name"`
|
||||
RequestedModel string `json:"requested_model"`
|
||||
UpstreamModel string `json:"upstream_model"`
|
||||
RelayMode string `json:"relay_mode"`
|
||||
RequestType int `json:"request_type"`
|
||||
InputTokens int `json:"input_tokens"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
CacheCreationTokens int `json:"cache_creation_tokens"`
|
||||
CacheReadTokens int `json:"cache_read_tokens"`
|
||||
CacheCreation5mTokens int `json:"cache_creation_5m_tokens"`
|
||||
CacheCreation1hTokens int `json:"cache_creation_1h_tokens"`
|
||||
ReasoningTokens int `json:"reasoning_tokens"`
|
||||
AudioInputTokens int `json:"audio_input_tokens"`
|
||||
AudioOutputTokens int `json:"audio_output_tokens"`
|
||||
ImageOutputTokens int `json:"image_output_tokens"`
|
||||
InputCost float64 `json:"input_cost"`
|
||||
OutputCost float64 `json:"output_cost"`
|
||||
CacheCreationCost float64 `json:"cache_creation_cost"`
|
||||
CacheReadCost float64 `json:"cache_read_cost"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
ActualCost float64 `json:"actual_cost"`
|
||||
Currency string `json:"currency"`
|
||||
BillingMode string `json:"billing_mode"`
|
||||
BillingSource string `json:"billing_source"`
|
||||
RateMultiplier float64 `json:"rate_multiplier"`
|
||||
LatencyMs int `json:"latency_ms"`
|
||||
FirstTokenMs int `json:"first_token_ms"`
|
||||
Status string `json:"status"`
|
||||
ErrorMessage string `json:"error_message"`
|
||||
RetryIndex int `json:"retry_index"`
|
||||
ClientIp string `json:"client_ip"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
ServiceTier string `json:"service_tier"`
|
||||
ReasoningEffort string `json:"reasoning_effort"`
|
||||
StreamEndReason string `json:"stream_end_reason"`
|
||||
ImageCount int `json:"image_count"`
|
||||
ImageSize string `json:"image_size"`
|
||||
PreDeductAmount float64 `json:"pre_deduct_amount"`
|
||||
RefundAmount float64 `json:"refund_amount"`
|
||||
SupplementAmount float64 `json:"supplement_amount"`
|
||||
BillingSummary string `json:"billing_summary"`
|
||||
BillingSnapshot string `json:"billing_snapshot"`
|
||||
InboundEndpoint string `json:"inbound_endpoint"`
|
||||
RequestId string `json:"request_id"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type AdminUsageLogListRes struct {
|
||||
List []*AdminUsageLogItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// === 计费记录 ===
|
||||
|
||||
type AdminBillingRecordListReq struct {
|
||||
g.Meta `path:"/billing-records" method:"get" mime:"json" tags:"管理后台-用量" summary:"计费记录列表"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" v:"between:1,100" dc:"每页数量"`
|
||||
TenantID int64 `json:"tenant_id" dc:"租户ID"`
|
||||
}
|
||||
|
||||
type AdminBillingRecordItem struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
UserId int64 `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
ChannelId int64 `json:"channel_id"`
|
||||
ChannelName string `json:"channel_name"`
|
||||
ModelName string `json:"model_name"`
|
||||
RelayMode string `json:"relay_mode"`
|
||||
InputTokens int `json:"input_tokens"`
|
||||
OutputTokens int `json:"output_tokens"`
|
||||
InputPrice float64 `json:"input_price"`
|
||||
OutputPrice float64 `json:"output_price"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
Currency string `json:"currency"`
|
||||
Status string `json:"status"`
|
||||
SettledAt *gtime.Time `json:"settled_at"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type AdminBillingRecordListRes struct {
|
||||
List []*AdminBillingRecordItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// === 钱包管理 ===
|
||||
|
||||
type AdminWalletListReq struct {
|
||||
g.Meta `path:"/wallets" method:"get" mime:"json" tags:"管理后台-钱包" summary:"钱包列表"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" v:"between:1,100" dc:"每页数量"`
|
||||
}
|
||||
|
||||
type AdminWalletItem struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
Balance float64 `json:"balance"`
|
||||
FrozenBalance float64 `json:"frozen_balance"`
|
||||
WarningThreshold float64 `json:"warning_threshold"`
|
||||
Currency string `json:"currency"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type AdminWalletListRes struct {
|
||||
List []*AdminWalletItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type AdminWalletInfoReq struct {
|
||||
g.Meta `path:"/wallets/{tenant_id}" method:"get" mime:"json" tags:"管理后台-钱包" summary:"钱包详情"`
|
||||
TenantID int64 `json:"tenant_id" in:"path" v:"required|min:1" dc:"租户ID"`
|
||||
}
|
||||
|
||||
type AdminWalletInfoRes struct {
|
||||
Balance float64 `json:"balance"`
|
||||
FrozenBalance float64 `json:"frozen_balance"`
|
||||
WarningThreshold *float64 `json:"warning_threshold"`
|
||||
}
|
||||
|
||||
type AdminWalletAdjustReq struct {
|
||||
g.Meta `path:"/wallets/{tenant_id}/adjust" method:"post" mime:"json" tags:"管理后台-钱包" summary:"调整余额"`
|
||||
TenantID int64 `json:"tenant_id" in:"path" v:"required|min:1" dc:"租户ID"`
|
||||
Amount float64 `json:"amount" v:"required" dc:"调整金额(正数充值,负数扣减)"`
|
||||
Description string `json:"description" dc:"调整说明"`
|
||||
}
|
||||
|
||||
type AdminWalletAdjustRes struct{}
|
||||
|
||||
type AdminWalletTransactionListReq struct {
|
||||
g.Meta `path:"/wallets/{tenant_id}/transactions" method:"get" mime:"json" tags:"管理后台-钱包" summary:"交易流水"`
|
||||
TenantID int64 `json:"tenant_id" in:"path" v:"required|min:1" dc:"租户ID"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" v:"between:1,100" dc:"每页数量"`
|
||||
Type string `json:"type" dc:"交易类型"`
|
||||
}
|
||||
|
||||
type AdminWalletTransactionItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Amount float64 `json:"amount"`
|
||||
BalanceAfter float64 `json:"balance_after"`
|
||||
FrozenAfter float64 `json:"frozen_after"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type AdminWalletTransactionListRes struct {
|
||||
List []*AdminWalletTransactionItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type AdminWalletSetWarningThresholdReq struct {
|
||||
g.Meta `path:"/wallets/{tenant_id}/warning-threshold" method:"put" mime:"json" tags:"管理后台-钱包" summary:"设置预警阈值"`
|
||||
TenantID int64 `json:"tenant_id" in:"path" v:"required|min:1" dc:"租户ID"`
|
||||
Threshold float64 `json:"threshold" v:"min:0" dc:"预警阈值"`
|
||||
}
|
||||
|
||||
type AdminWalletSetWarningThresholdRes struct{}
|
||||
|
||||
// AdminUsageLogExportReq 导出用量日志请求
|
||||
type AdminUsageLogExportReq struct {
|
||||
g.Meta `path:"/usage-logs/export" method:"get" mime:"json" tags:"管理后台-用量" summary:"导出用量日志"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
TenantID int64 `json:"tenant_id" in:"query" dc:"租户ID"`
|
||||
Username string `json:"username" in:"query" dc:"用户名(模糊匹配)"`
|
||||
Model string `json:"model" in:"query" dc:"模型名称"`
|
||||
Status string `json:"status" in:"query" dc:"状态"`
|
||||
StartDate string `json:"start_date" in:"query" dc:"开始日期"`
|
||||
EndDate string `json:"end_date" in:"query" dc:"结束日期"`
|
||||
}
|
||||
|
||||
type AdminUsageLogExportRes struct{}
|
||||
|
||||
// AdminBillingRecordExportReq 导出计费记录请求
|
||||
type AdminBillingRecordExportReq struct {
|
||||
g.Meta `path:"/billing-records/export" method:"get" mime:"json" tags:"管理后台-用量" summary:"导出计费记录"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
TenantID int64 `json:"tenant_id" in:"query" dc:"租户ID"`
|
||||
}
|
||||
|
||||
type AdminBillingRecordExportRes struct{}
|
||||
@@ -0,0 +1,54 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 数据治理设置 ===
|
||||
|
||||
type DataGovernanceSettingsGetReq struct {
|
||||
g.Meta `path:"/data-governance/settings" method:"get" mime:"json" tags:"管理后台-数据治理" summary:"获取数据治理设置"`
|
||||
}
|
||||
|
||||
type DataGovernanceSettingsGetRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type DataGovernanceSettingsUpdateReq struct {
|
||||
g.Meta `path:"/data-governance/settings" method:"put" mime:"json" tags:"管理后台-数据治理" summary:"更新数据治理设置"`
|
||||
Settings map[string]string `json:"settings" v:"required" dc:"设置键值对"`
|
||||
}
|
||||
|
||||
type DataGovernanceSettingsUpdateRes struct{}
|
||||
|
||||
// === 数据导出 ===
|
||||
|
||||
type DataGovernanceExportReq struct {
|
||||
g.Meta `path:"/data-governance/export" method:"post" mime:"json" tags:"管理后台-数据治理" summary:"请求数据导出"`
|
||||
TenantID int64 `json:"tenant_id" v:"required" dc:"租户ID"`
|
||||
Scopes []string `json:"scopes" v:"required" dc:"导出范围: members,usage,billing,logs"`
|
||||
}
|
||||
|
||||
type DataGovernanceExportRes struct {
|
||||
TaskID int64 `json:"task_id"`
|
||||
}
|
||||
|
||||
// === 数据删除 ===
|
||||
|
||||
type DataGovernanceDeletionReq struct {
|
||||
g.Meta `path:"/data-governance/deletion" method:"post" mime:"json" tags:"管理后台-数据治理" summary:"请求数据删除"`
|
||||
TenantID int64 `json:"tenant_id" v:"required" dc:"租户ID"`
|
||||
Reason string `json:"reason" v:"required" dc:"删除原因"`
|
||||
}
|
||||
|
||||
type DataGovernanceDeletionRes struct {
|
||||
TaskID int64 `json:"task_id"`
|
||||
}
|
||||
|
||||
// === 手动清理 ===
|
||||
|
||||
type DataGovernanceCleanupReq struct {
|
||||
g.Meta `path:"/data-governance/cleanup" method:"post" mime:"json" tags:"管理后台-数据治理" summary:"手动触发数据清理"`
|
||||
}
|
||||
|
||||
type DataGovernanceCleanupRes struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 系统错误日志 ===
|
||||
|
||||
type ErrorLogListReq struct {
|
||||
g.Meta `path:"/error-logs" method:"get" mime:"json" tags:"管理后台-系统错误" summary:"错误日志列表"`
|
||||
Page int `json:"page" d:"1"`
|
||||
PageSize int `json:"page_size" d:"20"`
|
||||
Source string `json:"source" in:"query" dc:"错误来源:api/panic/cron/background"`
|
||||
ErrorCode int `json:"error_code" in:"query" dc:"错误码"`
|
||||
Resolved string `json:"resolved" in:"query" dc:"处理状态:true/false"`
|
||||
StartDate string `json:"start_date" in:"query" dc:"开始日期"`
|
||||
EndDate string `json:"end_date" in:"query" dc:"结束日期"`
|
||||
Keyword string `json:"keyword" in:"query" dc:"关键词搜索(错误消息/请求路径)"`
|
||||
}
|
||||
|
||||
type ErrorLogListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type ErrorLogDetailReq struct {
|
||||
g.Meta `path:"/error-logs/{id}" method:"get" mime:"json" tags:"管理后台-系统错误" summary:"错误日志详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type ErrorLogDetailRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type ErrorLogResolveReq struct {
|
||||
g.Meta `path:"/error-logs/{id}/resolve" method:"put" mime:"json" tags:"管理后台-系统错误" summary:"标记错误已处理"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type ErrorLogResolveRes struct{}
|
||||
|
||||
type ErrorLogBatchResolveReq struct {
|
||||
g.Meta `path:"/error-logs/batch-resolve" method:"put" mime:"json" tags:"管理后台-系统错误" summary:"批量标记已处理"`
|
||||
Ids []int64 `json:"ids" v:"required"`
|
||||
}
|
||||
|
||||
type ErrorLogBatchResolveRes struct{}
|
||||
|
||||
type ErrorLogStatsReq struct {
|
||||
g.Meta `path:"/error-logs/stats" method:"get" mime:"json" tags:"管理后台-系统错误" summary:"错误统计"`
|
||||
}
|
||||
|
||||
type ErrorLogStatsRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 用户反馈(管理后台) ===
|
||||
|
||||
type FeedbackListAllReq struct {
|
||||
g.Meta `path:"/feedbacks" method:"get" mime:"json" tags:"管理后台-反馈" summary:"反馈列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
Category string `json:"category" in:"query"`
|
||||
TenantID int64 `json:"tenant_id" in:"query"`
|
||||
Priority string `json:"priority" in:"query"`
|
||||
}
|
||||
|
||||
type FeedbackAdminItem struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
UserId int64 `json:"user_id"`
|
||||
UserDisplayName string `json:"user_display_name"`
|
||||
Category string `json:"category"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Priority string `json:"priority"`
|
||||
AdminReply string `json:"admin_reply,omitempty"`
|
||||
Resolution string `json:"resolution,omitempty"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type FeedbackListAllRes struct {
|
||||
List []*FeedbackAdminItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type FeedbackReplyReq struct {
|
||||
g.Meta `path:"/feedbacks/{id}/reply" method:"post" mime:"json" tags:"管理后台-反馈" summary:"回复反馈"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Reply string `json:"reply" v:"required|length:1,5000" dc:"回复内容"`
|
||||
Status string `json:"status" v:"in:acknowledged,in_progress,resolved,closed" dc:"更新状态"`
|
||||
Resolution string `json:"resolution" dc:"解决方案摘要"`
|
||||
}
|
||||
|
||||
type FeedbackReplyRes struct{}
|
||||
|
||||
type FeedbackUpdateStatusReq struct {
|
||||
g.Meta `path:"/feedbacks/{id}/status" method:"put" mime:"json" tags:"管理后台-反馈" summary:"更新反馈状态"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Status string `json:"status" v:"required|in:pending,acknowledged,in_progress,resolved,closed" dc:"状态"`
|
||||
Priority string `json:"priority" v:"in:low,normal,high,critical" dc:"优先级"`
|
||||
}
|
||||
|
||||
type FeedbackUpdateStatusRes struct{}
|
||||
|
||||
type FeedbackStatsReq struct {
|
||||
g.Meta `path:"/feedbacks/stats" method:"get" mime:"json" tags:"管理后台-反馈" summary:"反馈统计"`
|
||||
}
|
||||
|
||||
type FeedbackStatsRes struct {
|
||||
Total int `json:"total"`
|
||||
Pending int `json:"pending"`
|
||||
Acknowledged int `json:"acknowledged"`
|
||||
InProgress int `json:"in_progress"`
|
||||
Resolved int `json:"resolved"`
|
||||
Closed int `json:"closed"`
|
||||
ByCategory map[string]int `json:"by_category"`
|
||||
RecentTrend []TrendItem `json:"recent_trend"`
|
||||
}
|
||||
|
||||
type TrendItem struct {
|
||||
Date string `json:"date"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 帮助中心 - 分类(管理后台) ===
|
||||
|
||||
type HelpCategoryCreateReq struct {
|
||||
g.Meta `path:"/help-categories" method:"post" mime:"json" tags:"管理后台-帮助中心" summary:"创建帮助分类"`
|
||||
ParentId int64 `json:"parent_id" d:"0" dc:"父分类ID,0为顶级"`
|
||||
Name string `json:"name" v:"required|length:1,100" dc:"分类名称"`
|
||||
Slug string `json:"slug" v:"required|length:1,100" dc:"URL友好标识"`
|
||||
Description string `json:"description" dc:"分类描述"`
|
||||
SortOrder int `json:"sort_order" d:"0" dc:"排序序号"`
|
||||
Icon string `json:"icon" dc:"图标名称"`
|
||||
IsVisible *bool `json:"is_visible" d:"true" dc:"是否对外可见"`
|
||||
}
|
||||
|
||||
type HelpCategoryCreateRes struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
type HelpCategoryUpdateReq struct {
|
||||
g.Meta `path:"/help-categories/{id}" method:"put" mime:"json" tags:"管理后台-帮助中心" summary:"更新帮助分类"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
ParentId int64 `json:"parent_id" d:"0" dc:"父分类ID,0为顶级"`
|
||||
Name string `json:"name" v:"required|length:1,100" dc:"分类名称"`
|
||||
Slug string `json:"slug" v:"required|length:1,100" dc:"URL友好标识"`
|
||||
Description string `json:"description" dc:"分类描述"`
|
||||
SortOrder int `json:"sort_order" d:"0" dc:"排序序号"`
|
||||
Icon string `json:"icon" dc:"图标名称"`
|
||||
IsVisible *bool `json:"is_visible" dc:"是否对外可见"`
|
||||
}
|
||||
|
||||
type HelpCategoryUpdateRes struct{}
|
||||
|
||||
type HelpCategoryDeleteReq struct {
|
||||
g.Meta `path:"/help-categories/{id}" method:"delete" mime:"json" tags:"管理后台-帮助中心" summary:"删除帮助分类"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type HelpCategoryDeleteRes struct{}
|
||||
|
||||
type HelpCategoryListReq struct {
|
||||
g.Meta `path:"/help-categories" method:"get" mime:"json" tags:"管理后台-帮助中心" summary:"帮助分类列表"`
|
||||
ParentId int64 `json:"parent_id" in:"query" d:"-1" dc:"父分类ID,-1表示全部"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type HelpCategoryItem struct {
|
||||
Id int64 `json:"id"`
|
||||
ParentId int64 `json:"parent_id"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
Description string `json:"description"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Icon string `json:"icon"`
|
||||
IsVisible bool `json:"is_visible"`
|
||||
ArticleCount int `json:"article_count"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type HelpCategoryListRes struct {
|
||||
List []*HelpCategoryItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// === 帮助中心 - 文章(管理后台) ===
|
||||
|
||||
type HelpArticleCreateReq struct {
|
||||
g.Meta `path:"/help-articles" method:"post" mime:"json" tags:"管理后台-帮助中心" summary:"创建帮助文章"`
|
||||
CategoryId int64 `json:"category_id" v:"required|min:1" dc:"所属分类ID"`
|
||||
Title string `json:"title" v:"required|length:1,200" dc:"文章标题"`
|
||||
Slug string `json:"slug" v:"required|length:1,200" dc:"URL友好标识"`
|
||||
Content string `json:"content" v:"required" dc:"文章内容(Markdown)"`
|
||||
Summary string `json:"summary" dc:"文章摘要"`
|
||||
Status string `json:"status" d:"draft" v:"in:draft,published" dc:"状态"`
|
||||
SortOrder int `json:"sort_order" d:"0" dc:"排序序号"`
|
||||
Keywords []string `json:"keywords" dc:"关键词列表"`
|
||||
}
|
||||
|
||||
type HelpArticleCreateRes struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
type HelpArticleUpdateReq struct {
|
||||
g.Meta `path:"/help-articles/{id}" method:"put" mime:"json" tags:"管理后台-帮助中心" summary:"更新帮助文章"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
CategoryId int64 `json:"category_id" v:"required|min:1" dc:"所属分类ID"`
|
||||
Title string `json:"title" v:"required|length:1,200" dc:"文章标题"`
|
||||
Slug string `json:"slug" v:"required|length:1,200" dc:"URL友好标识"`
|
||||
Content string `json:"content" dc:"文章内容(Markdown),不传则不更新"`
|
||||
Summary string `json:"summary" dc:"文章摘要"`
|
||||
Status string `json:"status" v:"in:draft,published" dc:"状态"`
|
||||
SortOrder int `json:"sort_order" d:"0" dc:"排序序号"`
|
||||
Keywords []string `json:"keywords" dc:"关键词列表"`
|
||||
}
|
||||
|
||||
type HelpArticleUpdateRes struct{}
|
||||
|
||||
type HelpArticleDeleteReq struct {
|
||||
g.Meta `path:"/help-articles/{id}" method:"delete" mime:"json" tags:"管理后台-帮助中心" summary:"删除帮助文章"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type HelpArticleDeleteRes struct{}
|
||||
|
||||
type HelpArticleListReq struct {
|
||||
g.Meta `path:"/help-articles" method:"get" mime:"json" tags:"管理后台-帮助中心" summary:"帮助文章列表"`
|
||||
CategoryId int64 `json:"category_id" in:"query" dc:"按分类过滤"`
|
||||
Status string `json:"status" in:"query" dc:"按状态过滤"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type HelpArticleItem struct {
|
||||
Id int64 `json:"id"`
|
||||
CategoryId int64 `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Slug string `json:"slug"`
|
||||
Summary string `json:"summary"`
|
||||
Status string `json:"status"`
|
||||
AuthorId int64 `json:"author_id"`
|
||||
ViewCount int `json:"view_count"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Keywords []string `json:"keywords"`
|
||||
PublishedAt *gtime.Time `json:"published_at,omitempty"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type HelpArticleListRes struct {
|
||||
List []*HelpArticleItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type HelpArticleGetReq struct {
|
||||
g.Meta `path:"/help-articles/{id}" method:"get" mime:"json" tags:"管理后台-帮助中心" summary:"帮助文章详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type HelpArticleGetRes struct {
|
||||
Id int64 `json:"id"`
|
||||
CategoryId int64 `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Slug string `json:"slug"`
|
||||
Content string `json:"content"`
|
||||
Summary string `json:"summary"`
|
||||
Status string `json:"status"`
|
||||
AuthorId int64 `json:"author_id"`
|
||||
ViewCount int `json:"view_count"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
Keywords []string `json:"keywords"`
|
||||
PublishedAt *gtime.Time `json:"published_at,omitempty"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -0,0 +1,204 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ModelListReq 模型列表请求
|
||||
type ModelListReq struct {
|
||||
g.Meta `path:"/models" method:"get" mime:"json" tags:"管理后台-模型" summary:"模型列表"`
|
||||
Page int `json:"page" d:"1" v:"min:1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" v:"min:1|max:100" dc:"每页数量"`
|
||||
Category string `json:"category" dc:"模型分类筛选:chat/embedding/image/audio/rerank"`
|
||||
Status string `json:"status" dc:"状态筛选:active/deprecated/offline"`
|
||||
Search string `json:"search" dc:"搜索关键词(模型名或显示名)"`
|
||||
}
|
||||
|
||||
// ModelListRes 模型列表响应
|
||||
type ModelListRes struct {
|
||||
List []ModelItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// ModelItem 模型信息
|
||||
type ModelItem struct {
|
||||
ID int64 `json:"id"`
|
||||
ModelId string `json:"model_id"`
|
||||
ModelName string `json:"model_name"`
|
||||
Category string `json:"category"`
|
||||
Status string `json:"status"`
|
||||
MaxContext int `json:"max_context_tokens"`
|
||||
MaxOutput int `json:"max_output_tokens"`
|
||||
Capabilities map[string]bool `json:"capabilities"`
|
||||
Description string `json:"description"`
|
||||
Tags []string `json:"tags"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
DeprecatedAt *string `json:"deprecated_at"`
|
||||
SunsetDate *string `json:"sunset_date"`
|
||||
ReplacementModel string `json:"replacement_model"`
|
||||
}
|
||||
|
||||
// ModelCreateReq 创建模型请求
|
||||
type ModelCreateReq struct {
|
||||
g.Meta `path:"/models" method:"post" mime:"json" tags:"管理后台-模型" summary:"创建模型"`
|
||||
ModelId string `json:"model_id" v:"required|length:1,100#请输入模型标识|模型标识长度1-100" dc:"模型唯一标识"`
|
||||
ModelName string `json:"model_name" dc:"模型显示名称"`
|
||||
Category string `json:"category" v:"required|in:chat,embedding,image,audio,rerank#请选择分类|分类必须是 chat/embedding/image/audio/rerank" dc:"模型分类"`
|
||||
MaxContext int `json:"max_context_tokens" dc:"最大上下文 token 数"`
|
||||
MaxOutput int `json:"max_output_tokens" dc:"最大输出 token 数"`
|
||||
Capabilities map[string]bool `json:"capabilities" dc:"模型能力特性"`
|
||||
Description string `json:"description" dc:"模型描述"`
|
||||
Tags []string `json:"tags" dc:"标签列表"`
|
||||
}
|
||||
|
||||
// ModelCreateRes 创建模型响应
|
||||
type ModelCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// ModelUpdateReq 更新模型请求
|
||||
type ModelUpdateReq struct {
|
||||
g.Meta `path:"/models/{id}" method:"put" mime:"json" tags:"管理后台-模型" summary:"更新模型"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"模型ID"`
|
||||
ModelName string `json:"model_name" dc:"模型显示名称"`
|
||||
Category string `json:"category" v:"in:chat,embedding,image,audio,rerank" dc:"模型分类"`
|
||||
MaxContext int `json:"max_context_tokens" dc:"最大上下文 token 数"`
|
||||
MaxOutput int `json:"max_output_tokens" dc:"最大输出 token 数"`
|
||||
Capabilities map[string]bool `json:"capabilities" dc:"模型能力特性"`
|
||||
Description string `json:"description" dc:"模型描述"`
|
||||
Tags []string `json:"tags" dc:"标签列表"`
|
||||
Status string `json:"status" v:"in:active,deprecated,offline" dc:"状态"`
|
||||
SunsetDate *string `json:"sunset_date" dc:"下线日期(格式:YYYY-MM-DD,仅 deprecated 状态有效)"`
|
||||
ReplacementModel string `json:"replacement_model" dc:"推荐替代模型名"`
|
||||
}
|
||||
|
||||
// ModelDeleteReq 删除模型请求
|
||||
type ModelDeleteReq struct {
|
||||
g.Meta `path:"/models/{id}" method:"delete" mime:"json" tags:"管理后台-模型" summary:"删除模型"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"模型ID"`
|
||||
}
|
||||
|
||||
// PricingItem 定价项(支持按次/按量/阶梯)
|
||||
type PricingItem struct {
|
||||
BillingMode string `json:"billing_mode" v:"required|in:token,per_request,tiered" dc:"计费模式"`
|
||||
MinTokens int64 `json:"min_tokens" dc:"阶梯起始 token 数"`
|
||||
MaxTokens *int64 `json:"max_tokens" dc:"阶梯结束 token 数(NULL=无上限)"`
|
||||
InputPrice float64 `json:"input_price" dc:"每 1M input token 价格"`
|
||||
OutputPrice float64 `json:"output_price" dc:"每 1M output token 价格"`
|
||||
PerRequestPrice *float64 `json:"per_request_price" dc:"按次单价(仅 per_request)"`
|
||||
CacheReadPrice float64 `json:"cache_read_price" dc:"缓存读取每 1M token 价格"`
|
||||
CacheCreationPrice float64 `json:"cache_creation_price" dc:"缓存创建每 1M token 价格"`
|
||||
}
|
||||
|
||||
// PricingListReq 定价列表请求(模型定价页面专用)
|
||||
type PricingListReq struct {
|
||||
g.Meta `path:"/models/pricing" method:"get" mime:"json" tags:"管理后台-模型" summary:"模型定价列表"`
|
||||
Page int `json:"page" d:"1" v:"min:1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" v:"min:1|max:100" dc:"每页数量"`
|
||||
Category string `json:"category" dc:"模型分类筛选"`
|
||||
Search string `json:"search" dc:"搜索关键词(模型名或显示名)"`
|
||||
}
|
||||
|
||||
// PricingListRes 定价列表响应
|
||||
type PricingListRes struct {
|
||||
List []PricingListItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// PricingListItem 定价列表项(模型基础信息 + 定价摘要)
|
||||
type PricingListItem struct {
|
||||
ID int64 `json:"id"`
|
||||
ModelId string `json:"model_id"`
|
||||
ModelName string `json:"model_name"`
|
||||
Category string `json:"category"`
|
||||
PricingMode string `json:"pricing_mode"`
|
||||
InputPrice float64 `json:"input_price"`
|
||||
OutputPrice float64 `json:"output_price"`
|
||||
PerRequestPrice float64 `json:"per_request_price"`
|
||||
}
|
||||
|
||||
// PricingGetReq 获取模型定价
|
||||
type PricingGetReq struct {
|
||||
g.Meta `path:"/models/{model_id}/pricing" method:"get" mime:"json" tags:"管理后台-模型" summary:"获取模型定价"`
|
||||
ModelID int64 `json:"model_id" in:"path" v:"required" dc:"模型ID"`
|
||||
}
|
||||
|
||||
type PricingGetRes struct {
|
||||
List []PricingItem `json:"list"`
|
||||
}
|
||||
|
||||
// PricingSetReq 设置模型定价(全量替换)
|
||||
type PricingSetReq struct {
|
||||
g.Meta `path:"/models/{model_id}/pricing" method:"put" mime:"json" tags:"管理后台-模型" summary:"设置模型定价"`
|
||||
ModelID int64 `json:"model_id" in:"path" v:"required" dc:"模型ID"`
|
||||
Items []PricingItem `json:"items" v:"required" dc:"定价列表"`
|
||||
}
|
||||
|
||||
type PricingSetRes struct{}
|
||||
|
||||
// ModelUpdateRes 更新模型响应
|
||||
type ModelUpdateRes struct{}
|
||||
|
||||
// ModelDeleteRes 删除模型响应
|
||||
type ModelDeleteRes struct{}
|
||||
|
||||
// ModelExportReq 导出模型列表请求
|
||||
type ModelExportReq struct {
|
||||
g.Meta `path:"/models/export" method:"get" mime:"json" tags:"管理后台-模型" summary:"导出模型列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Category string `json:"category" in:"query" dc:"模型分类筛选:chat/embedding/image/audio/rerank"`
|
||||
Status string `json:"status" in:"query" dc:"状态筛选:active/deprecated/offline"`
|
||||
Search string `json:"search" in:"query" dc:"搜索关键词(模型名或显示名)"`
|
||||
}
|
||||
|
||||
type ModelExportRes struct{}
|
||||
|
||||
// PricingFetchOfficialReq 拉取模型官方定价
|
||||
type PricingFetchOfficialReq struct {
|
||||
g.Meta `path:"/models/{model_id}/official-pricing" method:"get" mime:"json" tags:"管理后台-模型" summary:"拉取模型官方定价"`
|
||||
ModelID int64 `json:"model_id" in:"path" v:"required" dc:"模型ID"`
|
||||
}
|
||||
|
||||
// PricingFetchOfficialRes 拉取官方定价响应
|
||||
type PricingFetchOfficialRes struct {
|
||||
ModelName string `json:"model_name"` // 数据库中的模型名
|
||||
Sources []*OfficialPricingSource `json:"sources"` // 多来源定价数据
|
||||
}
|
||||
|
||||
// OfficialPricingSource 单个来源的官方定价数据
|
||||
type OfficialPricingSource struct {
|
||||
Source string `json:"source"` // 数据来源("litellm" / "models.dev")
|
||||
Found bool `json:"found"` // 是否找到
|
||||
Provider string `json:"provider,omitempty"` // 供应商(anthropic/openai/...)
|
||||
Mode string `json:"mode,omitempty"` // 模型类型(chat/embedding/...)
|
||||
MaxContext int `json:"max_context_tokens,omitempty"` // 最大上下文
|
||||
MaxOutput int `json:"max_output_tokens,omitempty"` // 最大输出
|
||||
Pricing *OfficialPricingItem `json:"pricing,omitempty"` // 定价信息
|
||||
}
|
||||
|
||||
// OfficialPricingItem 官方定价项
|
||||
type OfficialPricingItem struct {
|
||||
InputPrice float64 `json:"input_price"` // $/1M tokens
|
||||
OutputPrice float64 `json:"output_price"` // $/1M tokens
|
||||
CacheReadPrice float64 `json:"cache_read_price"` // $/1M tokens
|
||||
CacheCreationPrice float64 `json:"cache_creation_price"` // $/1M tokens
|
||||
BillingMode string `json:"billing_mode"` // 建议计费模式
|
||||
}
|
||||
|
||||
// ModelFetchOfficialInfoReq 按名称拉取官方模型信息(上下文长度+能力特性)
|
||||
type ModelFetchOfficialInfoReq struct {
|
||||
g.Meta `path:"/models/official-info" method:"get" mime:"json" tags:"管理后台-模型" summary:"拉取官方模型信息"`
|
||||
ModelName string `json:"model_name" in:"query" v:"required" dc:"模型名称"`
|
||||
}
|
||||
|
||||
// ModelFetchOfficialInfoRes 官方模型信息响应
|
||||
type ModelFetchOfficialInfoRes struct {
|
||||
Found bool `json:"found"`
|
||||
Provider string `json:"provider,omitempty"`
|
||||
MaxContextTokens int `json:"max_context_tokens,omitempty"`
|
||||
MaxOutputTokens int `json:"max_output_tokens,omitempty"`
|
||||
Capabilities map[string]bool `json:"capabilities,omitempty"`
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 监控仪表盘 ===
|
||||
|
||||
type MonitorDashboardReq struct {
|
||||
g.Meta `path:"/monitor/dashboard" method:"get" mime:"json" tags:"管理后台-监控" summary:"监控仪表盘"`
|
||||
Minutes int `json:"minutes" in:"query" d:"5"`
|
||||
}
|
||||
|
||||
type MonitorDashboardRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type MonitorTrafficReq struct {
|
||||
g.Meta `path:"/monitor/traffic" method:"get" mime:"json" tags:"管理后台-监控" summary:"流量曲线"`
|
||||
Minutes int `json:"minutes" in:"query" d:"30"`
|
||||
}
|
||||
|
||||
type MonitorTrafficRes struct {
|
||||
Data any `json:"data"`
|
||||
}
|
||||
|
||||
type MonitorLatencyReq struct {
|
||||
g.Meta `path:"/monitor/latency" method:"get" mime:"json" tags:"管理后台-监控" summary:"延迟直方图"`
|
||||
Minutes int `json:"minutes" in:"query" d:"5"`
|
||||
}
|
||||
|
||||
type MonitorLatencyRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type MonitorSystemReq struct {
|
||||
g.Meta `path:"/monitor/system" method:"get" mime:"json" tags:"管理后台-监控" summary:"系统指标"`
|
||||
Minutes int `json:"minutes" in:"query" d:"60"`
|
||||
}
|
||||
|
||||
type MonitorSystemRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type MonitorDBPoolReq struct {
|
||||
g.Meta `path:"/monitor/db-pool" method:"get" mime:"json" tags:"管理后台-监控" summary:"数据库连接池"`
|
||||
}
|
||||
|
||||
type MonitorDBPoolRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type MonitorRedisPoolReq struct {
|
||||
g.Meta `path:"/monitor/redis-pool" method:"get" mime:"json" tags:"管理后台-监控" summary:"Redis连接池"`
|
||||
}
|
||||
|
||||
type MonitorRedisPoolRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
// === 实时监控 ===
|
||||
|
||||
type MonitorRealtimeReq struct {
|
||||
g.Meta `path:"/monitor/realtime" method:"get" mime:"json" tags:"管理后台-监控" summary:"实时监控数据"`
|
||||
}
|
||||
|
||||
type MonitorRealtimeRes struct {
|
||||
Data any `json:"data"`
|
||||
}
|
||||
|
||||
// === 告警规则 ===
|
||||
|
||||
type AlertRuleListReq struct {
|
||||
g.Meta `path:"/alert/rules" method:"get" mime:"json" tags:"管理后台-告警" summary:"告警规则列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
MetricType string `json:"metric_type" in:"query"`
|
||||
Level string `json:"level" in:"query"`
|
||||
Enabled string `json:"enabled" in:"query"`
|
||||
}
|
||||
|
||||
type AlertRuleListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type AlertOptionsReq struct {
|
||||
g.Meta `path:"/alert/options" method:"get" mime:"json" tags:"管理后台-告警" summary:"告警选项"`
|
||||
}
|
||||
|
||||
type AlertOptionsRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type AlertRuleCreateReq struct {
|
||||
g.Meta `path:"/alert/rules" method:"post" mime:"json" tags:"管理后台-告警" summary:"创建告警规则"`
|
||||
Name string `json:"name" v:"required"`
|
||||
MetricType string `json:"metric_type" v:"required"`
|
||||
Condition string `json:"condition" v:"required"`
|
||||
Threshold float64 `json:"threshold" v:"required"`
|
||||
DurationSeconds int `json:"duration_seconds"`
|
||||
NotificationMethods []string `json:"notification_methods"`
|
||||
WebhookURL string `json:"webhook_url"`
|
||||
Level string `json:"level"`
|
||||
CooldownSeconds int `json:"cooldown_seconds"`
|
||||
NotifyUserIDs []int64 `json:"notify_user_ids"`
|
||||
}
|
||||
|
||||
type AlertRuleCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type AlertRuleUpdateReq struct {
|
||||
g.Meta `path:"/alert/rules/{id}" method:"put" mime:"json" tags:"管理后台-告警" summary:"更新告警规则"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Name string `json:"name"`
|
||||
MetricType string `json:"metric_type"`
|
||||
Condition string `json:"condition"`
|
||||
Threshold *float64 `json:"threshold"`
|
||||
DurationSeconds *int `json:"duration_seconds"`
|
||||
NotificationMethods []string `json:"notification_methods"`
|
||||
WebhookURL string `json:"webhook_url"`
|
||||
Level string `json:"level"`
|
||||
CooldownSeconds *int `json:"cooldown_seconds"`
|
||||
NotifyUserIDs []int64 `json:"notify_user_ids"`
|
||||
}
|
||||
|
||||
type AlertRuleUpdateRes struct{}
|
||||
|
||||
type AlertRuleDeleteReq struct {
|
||||
g.Meta `path:"/alert/rules/{id}" method:"delete" mime:"json" tags:"管理后台-告警" summary:"删除告警规则"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type AlertRuleDeleteRes struct{}
|
||||
|
||||
type AlertRuleToggleReq struct {
|
||||
g.Meta `path:"/alert/rules/{id}/toggle" method:"put" mime:"json" tags:"管理后台-告警" summary:"切换告警规则"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type AlertRuleToggleRes struct{}
|
||||
|
||||
type AlertTestReq struct {
|
||||
g.Meta `path:"/alert/rules/{id}/test" method:"post" mime:"json" tags:"管理后台-告警" summary:"测试告警"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type AlertTestRes struct {
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// === 告警事件 ===
|
||||
|
||||
type AlertEventListReq struct {
|
||||
g.Meta `path:"/alert/events" method:"get" mime:"json" tags:"管理后台-告警" summary:"告警事件列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
Level string `json:"level" in:"query"`
|
||||
RuleID int64 `json:"rule_id" in:"query"`
|
||||
}
|
||||
|
||||
type AlertEventListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type AlertEventAcknowledgeReq struct {
|
||||
g.Meta `path:"/alert/events/{id}/acknowledge" method:"put" mime:"json" tags:"管理后台-告警" summary:"确认告警"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type AlertEventAcknowledgeRes struct{}
|
||||
|
||||
type AlertEventResolveReq struct {
|
||||
g.Meta `path:"/alert/events/{id}/resolve" method:"put" mime:"json" tags:"管理后台-告警" summary:"解决告警"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Notes string `json:"notes"`
|
||||
}
|
||||
|
||||
type AlertEventResolveRes struct{}
|
||||
@@ -0,0 +1,192 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 通知模板管理 ===
|
||||
|
||||
type TemplateListReq struct {
|
||||
g.Meta `path:"/notification/templates" method:"get" mime:"json" tags:"管理后台-通知" summary:"模板列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TemplateItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Channel string `json:"channel"`
|
||||
Subject string `json:"subject"`
|
||||
BodyTemplate string `json:"body_template"`
|
||||
Variables string `json:"variables"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type TemplateListRes struct {
|
||||
List []*TemplateItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TemplateGetReq struct {
|
||||
g.Meta `path:"/notification/templates/{code}" method:"get" mime:"json" tags:"管理后台-通知" summary:"模板详情"`
|
||||
Code string `json:"code" in:"path" v:"required"`
|
||||
}
|
||||
|
||||
type TemplateGetRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TemplateUpdateReq struct {
|
||||
g.Meta `path:"/notification/templates/{code}" method:"put" mime:"json" tags:"管理后台-通知" summary:"更新模板"`
|
||||
Code string `json:"code" in:"path" v:"required"`
|
||||
Subject string `json:"subject"`
|
||||
BodyTemplate string `json:"body_template"`
|
||||
Channel string `json:"channel"`
|
||||
}
|
||||
|
||||
type TemplateUpdateRes struct{}
|
||||
|
||||
type TemplateTestReq struct {
|
||||
g.Meta `path:"/notification/templates/{code}/test" method:"post" mime:"json" tags:"管理后台-通知" summary:"测试模板"`
|
||||
Code string `json:"code" in:"path" v:"required"`
|
||||
Variables map[string]any `json:"variables"`
|
||||
}
|
||||
|
||||
type TemplateTestRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
// === 站内消息管理 ===
|
||||
|
||||
type MessageListReq struct {
|
||||
g.Meta `path:"/notification/messages" method:"get" mime:"json" tags:"管理后台-通知" summary:"消息列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
TenantID int64 `json:"tenant_id" in:"query"`
|
||||
Type string `json:"type" in:"query"`
|
||||
}
|
||||
|
||||
type MessageItem struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
UserId int64 `json:"user_id"`
|
||||
UserName string `json:"user_name"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Channel string `json:"channel"`
|
||||
IsRead int `json:"is_read"`
|
||||
IsBroadcast int `json:"is_broadcast"`
|
||||
Metadata string `json:"metadata"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type MessageListRes struct {
|
||||
List []*MessageItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type MessageSendReq struct {
|
||||
g.Meta `path:"/notification/messages/send" method:"post" mime:"json" tags:"管理后台-通知" summary:"发送消息"`
|
||||
TenantID int64 `json:"tenant_id" v:"required|min:1"`
|
||||
UserID int64 `json:"user_id" dc:"目标用户ID,留空则发送给租户所有人"`
|
||||
Title string `json:"title" v:"required"`
|
||||
Content string `json:"content" v:"required"`
|
||||
Channel string `json:"channel"`
|
||||
}
|
||||
|
||||
type MessageSendRes struct{}
|
||||
|
||||
type MessageBroadcastReq struct {
|
||||
g.Meta `path:"/notification/messages/broadcast" method:"post" mime:"json" tags:"管理后台-通知" summary:"广播消息"`
|
||||
TenantID int64 `json:"tenant_id" v:"required|min:1"`
|
||||
Title string `json:"title" v:"required"`
|
||||
Content string `json:"content" v:"required"`
|
||||
TargetRoles string `json:"target_roles" d:"" dc:"目标角色,逗号分隔如 owner,admin;留空表示全部角色"`
|
||||
}
|
||||
|
||||
type MessageBroadcastRes struct{}
|
||||
|
||||
// === 公告管理 ===
|
||||
|
||||
type AnnouncementListReq struct {
|
||||
g.Meta `path:"/announcements" method:"get" mime:"json" tags:"管理后台-公告" summary:"公告列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
}
|
||||
|
||||
type AnnouncementItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
Status string `json:"status"`
|
||||
IsPinned int `json:"is_pinned"`
|
||||
DisplayPosition string `json:"display_position"`
|
||||
EffectiveAt *gtime.Time `json:"effective_at"`
|
||||
ExpiresAt *gtime.Time `json:"expires_at"`
|
||||
CreatedBy int64 `json:"created_by"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type AnnouncementListRes struct {
|
||||
List []*AnnouncementItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type AnnouncementCreateReq struct {
|
||||
g.Meta `path:"/announcements" method:"post" mime:"json" tags:"管理后台-公告" summary:"创建公告"`
|
||||
Title string `json:"title" v:"required"`
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content" v:"required"`
|
||||
Status string `json:"status"`
|
||||
IsPinned int `json:"is_pinned"`
|
||||
DisplayPosition string `json:"display_position"`
|
||||
EffectiveAt string `json:"effective_at"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
}
|
||||
|
||||
type AnnouncementCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type AnnouncementUpdateReq struct {
|
||||
g.Meta `path:"/announcements/{id}" method:"put" mime:"json" tags:"管理后台-公告" summary:"更新公告"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Title string `json:"title" dc:"标题"`
|
||||
Type string `json:"type" dc:"类型:info/warning/important"`
|
||||
Content string `json:"content" dc:"内容"`
|
||||
Status string `json:"status" dc:"状态:draft/published/archived"`
|
||||
IsPinned *int `json:"is_pinned" dc:"是否置顶"`
|
||||
DisplayPosition string `json:"display_position" dc:"展示位置:login/console/both"`
|
||||
EffectiveAt string `json:"effective_at" dc:"生效时间"`
|
||||
ExpiresAt string `json:"expires_at" dc:"过期时间"`
|
||||
}
|
||||
|
||||
type AnnouncementUpdateRes struct{}
|
||||
|
||||
type AnnouncementPublishReq struct {
|
||||
g.Meta `path:"/announcements/{id}/publish" method:"put" mime:"json" tags:"管理后台-公告" summary:"发布公告"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type AnnouncementPublishRes struct{}
|
||||
|
||||
type AnnouncementArchiveReq struct {
|
||||
g.Meta `path:"/announcements/{id}/archive" method:"put" mime:"json" tags:"管理后台-公告" summary:"归档公告"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type AnnouncementArchiveRes struct{}
|
||||
@@ -0,0 +1,82 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 订单管理(管理后台) ===
|
||||
|
||||
type OrderListReq struct {
|
||||
g.Meta `path:"/orders" method:"get" mime:"json" tags:"管理后台-订单" summary:"订单列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
TenantID string `json:"tenant_id" in:"query"`
|
||||
}
|
||||
|
||||
type OrderItem struct {
|
||||
Id int64 `json:"id"`
|
||||
OrderNo string `json:"order_no"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
OrderType string `json:"order_type"`
|
||||
PlanId int64 `json:"plan_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
DiscountAmount float64 `json:"discount_amount"`
|
||||
FinalAmount float64 `json:"final_amount"`
|
||||
Currency string `json:"currency"`
|
||||
PaymentChannel string `json:"payment_channel"`
|
||||
PaymentMethod string `json:"payment_method"`
|
||||
PaymentNo string `json:"payment_no"`
|
||||
Status string `json:"status"`
|
||||
PaidAt *gtime.Time `json:"paid_at"`
|
||||
FulfilledAt *gtime.Time `json:"fulfilled_at"`
|
||||
ExpiredAt *gtime.Time `json:"expired_at"`
|
||||
CancelledAt *gtime.Time `json:"cancelled_at"`
|
||||
RelatedOrderId int64 `json:"related_order_id"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type OrderListRes struct {
|
||||
List []*OrderItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type OrderDetailReq struct {
|
||||
g.Meta `path:"/orders/{id}" method:"get" mime:"json" tags:"管理后台-订单" summary:"订单详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type OrderDetailRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type OrderRefundReq struct {
|
||||
g.Meta `path:"/orders/{id}/refund" method:"post" mime:"json" tags:"管理后台-订单" summary:"发起退款"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
type OrderRefundRes struct{}
|
||||
|
||||
type OrderCompleteReq struct {
|
||||
g.Meta `path:"/orders/{id}/complete" method:"post" mime:"json" tags:"管理后台-订单" summary:"手动完成订单"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type OrderCompleteRes struct{}
|
||||
|
||||
// OrderExportReq 导出订单列表请求
|
||||
type OrderExportReq struct {
|
||||
g.Meta `path:"/orders/export" method:"get" mime:"json" tags:"管理后台-订单" summary:"导出订单列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Status string `json:"status" in:"query" dc:"状态筛选"`
|
||||
TenantID string `json:"tenant_id" in:"query" dc:"租户ID筛选"`
|
||||
}
|
||||
|
||||
type OrderExportRes struct{}
|
||||
@@ -0,0 +1,123 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 成员管理(管理后台)===
|
||||
|
||||
type AdminMemberCreateReq struct {
|
||||
g.Meta `path:"/members" method:"post" mime:"json" tags:"管理后台-成员" summary:"添加成员"`
|
||||
TenantID int64 `json:"tenant_id" v:"required|min:1#请选择租户|租户ID无效" dc:"租户ID"`
|
||||
Username string `json:"username" v:"required|length:3,50#请输入用户名|用户名长度为3-50位" dc:"用户名"`
|
||||
Email string `json:"email" v:"required|email#请输入邮箱|邮箱格式不正确" dc:"邮箱"`
|
||||
Password string `json:"password" v:"required|length:8,64#请输入密码|密码长度为8-64位" dc:"密码"`
|
||||
DisplayName string `json:"display_name" dc:"显示名称"`
|
||||
Role string `json:"role" v:"required|in:admin,member#请选择角色|角色无效" dc:"角色:admin/member"`
|
||||
}
|
||||
|
||||
type AdminMemberCreateRes struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
type AdminMemberDisableReq struct {
|
||||
g.Meta `path:"/members/{id}/disable" method:"put" mime:"json" tags:"管理后台-成员" summary:"禁用成员"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type AdminMemberDisableRes struct{}
|
||||
|
||||
type AdminMemberEnableReq struct {
|
||||
g.Meta `path:"/members/{id}/enable" method:"put" mime:"json" tags:"管理后台-成员" summary:"启用成员"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type AdminMemberEnableRes struct{}
|
||||
|
||||
type AdminMemberResetPasswordReq struct {
|
||||
g.Meta `path:"/members/{id}/reset-password" method:"put" mime:"json" tags:"管理后台-成员" summary:"重置成员密码"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type AdminMemberResetPasswordRes struct {
|
||||
NewPassword string `json:"new_password"`
|
||||
}
|
||||
|
||||
// === 支付渠道管理 ===
|
||||
|
||||
type PaymentChannelListReq struct {
|
||||
g.Meta `path:"/payment-channels" method:"get" mime:"json" tags:"管理后台-支付" summary:"支付渠道列表"`
|
||||
}
|
||||
|
||||
type PaymentChannelListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
}
|
||||
|
||||
type PaymentChannelCreateReq struct {
|
||||
g.Meta `path:"/payment-channels" method:"post" mime:"json" tags:"管理后台-支付" summary:"创建支付渠道"`
|
||||
Channel string `json:"channel" v:"required#请输入渠道类型" dc:"渠道类型"`
|
||||
Name string `json:"name" v:"required#请输入渠道名称" dc:"渠道名称"`
|
||||
PaymentType string `json:"payment_type" dc:"支付类型"`
|
||||
Config string `json:"config" dc:"配置(JSON)"`
|
||||
SortOrder int `json:"sort_order" dc:"排序"`
|
||||
}
|
||||
|
||||
type PaymentChannelCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type PaymentChannelDetailReq struct {
|
||||
g.Meta `path:"/payment-channels/{id}" method:"get" mime:"json" tags:"管理后台-支付" summary:"支付渠道详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1" dc:"渠道ID"`
|
||||
}
|
||||
|
||||
type PaymentChannelDetailRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type PaymentChannelUpdateReq struct {
|
||||
g.Meta `path:"/payment-channels/{id}" method:"put" mime:"json" tags:"管理后台-支付" summary:"更新支付渠道"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1" dc:"渠道ID"`
|
||||
Update map[string]interface{} `json:"update" dc:"更新字段"`
|
||||
}
|
||||
|
||||
type PaymentChannelUpdateRes struct{}
|
||||
|
||||
type PaymentChannelDeleteReq struct {
|
||||
g.Meta `path:"/payment-channels/{id}" method:"delete" mime:"json" tags:"管理后台-支付" summary:"删除支付渠道"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1" dc:"渠道ID"`
|
||||
}
|
||||
|
||||
type PaymentChannelDeleteRes struct{}
|
||||
|
||||
type PaymentChannelToggleReq struct {
|
||||
g.Meta `path:"/payment-channels/{id}/toggle" method:"put" mime:"json" tags:"管理后台-支付" summary:"切换支付渠道状态"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1" dc:"渠道ID"`
|
||||
}
|
||||
|
||||
type PaymentChannelToggleRes struct {
|
||||
IsEnabled bool `json:"is_enabled"`
|
||||
}
|
||||
|
||||
// === 支付设置 ===
|
||||
|
||||
type PaymentSettingsGetReq struct {
|
||||
g.Meta `path:"/payment-settings" method:"get" mime:"json" tags:"管理后台-支付" summary:"获取支付设置"`
|
||||
}
|
||||
|
||||
type PaymentSettingsGetRes struct {
|
||||
AmountOptions []int `json:"amount_options"`
|
||||
AmountDiscount map[int]float64 `json:"amount_discount"`
|
||||
MinTopUp int `json:"min_topup"`
|
||||
Currency string `json:"currency"`
|
||||
CallbackBaseURL string `json:"callback_base_url"`
|
||||
}
|
||||
|
||||
type PaymentSettingsUpdateReq struct {
|
||||
g.Meta `path:"/payment-settings" method:"put" mime:"json" tags:"管理后台-支付" summary:"更新支付设置"`
|
||||
AmountOptions []int `json:"amount_options" dc:"充值金额选项"`
|
||||
AmountDiscount map[int]float64 `json:"amount_discount" dc:"充值折扣"`
|
||||
MinTopUp int `json:"min_topup" dc:"最低充值金额"`
|
||||
Currency string `json:"currency" dc:"货币"`
|
||||
CallbackBaseURL string `json:"callback_base_url" dc:"回调基础URL"`
|
||||
}
|
||||
|
||||
type PaymentSettingsUpdateRes struct{}
|
||||
@@ -0,0 +1,58 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// AdminPermissionListReq 获取管理员权限点请求
|
||||
type AdminPermissionListReq struct {
|
||||
g.Meta `path:"/users/{id}/permissions" method:"get" mime:"json" tags:"管理后台-权限管理" summary:"获取管理员权限点"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"管理员ID"`
|
||||
}
|
||||
|
||||
type AdminPermissionListRes struct {
|
||||
Permissions []string `json:"permissions"`
|
||||
DataScopes []DataScopeItem `json:"data_scopes"`
|
||||
}
|
||||
|
||||
type DataScopeItem struct {
|
||||
ID int64 `json:"id"`
|
||||
ScopeType string `json:"scope_type"`
|
||||
ScopeValue string `json:"scope_value"`
|
||||
}
|
||||
|
||||
// AdminPermissionUpdateReq 更新管理员权限点请求
|
||||
type AdminPermissionUpdateReq struct {
|
||||
g.Meta `path:"/users/{id}/permissions" method:"put" mime:"json" tags:"管理后台-权限管理" summary:"更新管理员权限点"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"管理员ID"`
|
||||
Permissions []string `json:"permissions" dc:"权限点列表"`
|
||||
}
|
||||
|
||||
type AdminPermissionUpdateRes struct{}
|
||||
|
||||
// AdminDataScopeUpdateReq 更新管理员数据范围请求
|
||||
type AdminDataScopeUpdateReq struct {
|
||||
g.Meta `path:"/users/{id}/data-scopes" method:"put" mime:"json" tags:"管理后台-权限管理" summary:"更新管理员数据范围"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"管理员ID"`
|
||||
DataScopes []DataScopeInput `json:"data_scopes" dc:"数据范围列表"`
|
||||
}
|
||||
|
||||
type DataScopeInput struct {
|
||||
ScopeType string `json:"scope_type" v:"required|in:all,tenant_group,tenant#请选择范围类型|范围类型无效" dc:"范围类型"`
|
||||
ScopeValue string `json:"scope_value" dc:"范围值"`
|
||||
}
|
||||
|
||||
type AdminDataScopeUpdateRes struct{}
|
||||
|
||||
// AdminAllPermissionsReq 获取所有可用权限点请求
|
||||
type AdminAllPermissionsReq struct {
|
||||
g.Meta `path:"/permissions" method:"get" mime:"json" tags:"管理后台-权限管理" summary:"获取所有可用权限点"`
|
||||
}
|
||||
|
||||
type AdminAllPermissionsRes struct {
|
||||
Groups []PermissionGroup `json:"groups"`
|
||||
}
|
||||
|
||||
type PermissionGroup struct {
|
||||
Name string `json:"name"`
|
||||
Label string `json:"label"`
|
||||
Permissions []string `json:"permissions"`
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 套餐管理 ===
|
||||
|
||||
type PlanListReq struct {
|
||||
g.Meta `path:"/plans" method:"get" mime:"json" tags:"管理后台-套餐" summary:"套餐列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
}
|
||||
|
||||
type PlanItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Identifier string `json:"identifier"`
|
||||
Description string `json:"description"`
|
||||
MonthlyPrice float64 `json:"monthly_price"`
|
||||
YearlyPrice float64 `json:"yearly_price"`
|
||||
Status string `json:"status"`
|
||||
MonthlyQuotaTokens int64 `json:"monthly_quota_tokens"`
|
||||
AllowedModels []string `json:"allowed_models"`
|
||||
IsRecommended bool `json:"is_recommended"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type PlanListRes struct {
|
||||
List []*PlanItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type PlanCreateReq struct {
|
||||
g.Meta `path:"/plans" method:"post" mime:"json" tags:"管理后台-套餐" summary:"创建套餐"`
|
||||
Name string `json:"name" v:"required#请输入名称"`
|
||||
Identifier string `json:"identifier" v:"required#请输入标识符"`
|
||||
Description string `json:"description"`
|
||||
MonthlyPrice float64 `json:"monthly_price"`
|
||||
YearlyPrice float64 `json:"yearly_price"`
|
||||
MonthlyQuotaTokens int64 `json:"monthly_quota_tokens"`
|
||||
AllowedModels []string `json:"allowed_models"`
|
||||
IsRecommended bool `json:"is_recommended"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
type PlanCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type PlanDetailReq struct {
|
||||
g.Meta `path:"/plans/{id}" method:"get" mime:"json" tags:"管理后台-套餐" summary:"套餐详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type PlanDetailRes struct {
|
||||
Data *PlanItem `json:"data"`
|
||||
}
|
||||
|
||||
type PlanUpdateReq struct {
|
||||
g.Meta `path:"/plans/{id}" method:"put" mime:"json" tags:"管理后台-套餐" summary:"更新套餐"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Update map[string]interface{} `json:"update" v:"required"`
|
||||
}
|
||||
|
||||
type PlanUpdateRes struct{}
|
||||
|
||||
type PlanArchiveReq struct {
|
||||
g.Meta `path:"/plans/{id}" method:"delete" mime:"json" tags:"管理后台-套餐" summary:"下架套餐"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type PlanArchiveRes struct{}
|
||||
|
||||
type PlanToggleRecommendReq struct {
|
||||
g.Meta `path:"/plans/{id}/toggle-recommend" method:"put" mime:"json" tags:"管理后台-套餐" summary:"切换推荐"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type PlanToggleRecommendRes struct{}
|
||||
|
||||
// PlanExportReq 导出套餐列表请求
|
||||
type PlanExportReq struct {
|
||||
g.Meta `path:"/plans/export" method:"get" mime:"json" tags:"管理后台-套餐" summary:"导出套餐列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Status string `json:"status" in:"query" dc:"状态筛选"`
|
||||
}
|
||||
|
||||
type PlanExportRes struct{}
|
||||
@@ -0,0 +1,115 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// PluginListReq 插件列表
|
||||
type PluginListReq struct {
|
||||
g.Meta `path:"/plugins" method:"get" mime:"json" tags:"管理后台-插件管理" summary:"插件列表"`
|
||||
Category string `json:"category" in:"query" dc:"按分类筛选"`
|
||||
Status string `json:"status" in:"query" dc:"按状态筛选"`
|
||||
}
|
||||
|
||||
type PluginItem struct {
|
||||
Name string `json:"name"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
Category string `json:"category"`
|
||||
Author string `json:"author"`
|
||||
Status string `json:"status"`
|
||||
Installed bool `json:"installed"`
|
||||
Config g.Map `json:"config"`
|
||||
}
|
||||
|
||||
type PluginListRes struct {
|
||||
List []PluginItem `json:"list"`
|
||||
}
|
||||
|
||||
// PluginDetailReq 插件详情
|
||||
type PluginDetailReq struct {
|
||||
g.Meta `path:"/plugins/{name}" method:"get" mime:"json" tags:"管理后台-插件管理" summary:"插件详情"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type PluginDetailRes struct {
|
||||
Name string `json:"name"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
Category string `json:"category"`
|
||||
Author string `json:"author"`
|
||||
Status string `json:"status"`
|
||||
Dependencies []string `json:"dependencies"`
|
||||
Config g.Map `json:"config"`
|
||||
ErrorMsg string `json:"error_msg,omitempty"`
|
||||
}
|
||||
|
||||
// PluginInstallReq 安装插件
|
||||
type PluginInstallReq struct {
|
||||
g.Meta `path:"/plugins/{name}/install" method:"post" mime:"json" tags:"管理后台-插件管理" summary:"安装插件"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type PluginInstallRes struct{}
|
||||
|
||||
// PluginEnableReq 启用插件
|
||||
type PluginEnableReq struct {
|
||||
g.Meta `path:"/plugins/{name}/enable" method:"post" mime:"json" tags:"管理后台-插件管理" summary:"启用插件"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type PluginEnableRes struct{}
|
||||
|
||||
// PluginDisableReq 禁用插件
|
||||
type PluginDisableReq struct {
|
||||
g.Meta `path:"/plugins/{name}/disable" method:"post" mime:"json" tags:"管理后台-插件管理" summary:"禁用插件"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type PluginDisableRes struct{}
|
||||
|
||||
// PluginUninstallReq 卸载插件
|
||||
type PluginUninstallReq struct {
|
||||
g.Meta `path:"/plugins/{name}/uninstall" method:"post" mime:"json" tags:"管理后台-插件管理" summary:"卸载插件"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
KeepData bool `json:"keep_data" in:"query" dc:"是否保留数据"`
|
||||
}
|
||||
|
||||
type PluginUninstallRes struct{}
|
||||
|
||||
// PluginUpgradeReq 升级插件
|
||||
type PluginUpgradeReq struct {
|
||||
g.Meta `path:"/plugins/{name}/upgrade" method:"post" mime:"json" tags:"管理后台-插件管理" summary:"升级插件"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type PluginUpgradeRes struct{}
|
||||
|
||||
// PluginConfigUpdateReq 更新插件配置
|
||||
type PluginConfigUpdateReq struct {
|
||||
g.Meta `path:"/plugins/{name}/config" method:"put" mime:"json" tags:"管理后台-插件管理" summary:"更新插件配置"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
Config g.Map `json:"config" v:"required" dc:"插件配置"`
|
||||
}
|
||||
|
||||
type PluginConfigUpdateRes struct{}
|
||||
|
||||
// PluginConfigSchemaReq 获取插件配置 schema
|
||||
type PluginConfigSchemaReq struct {
|
||||
g.Meta `path:"/plugins/{name}/config-schema" method:"get" mime:"json" tags:"管理后台-插件管理" summary:"获取插件配置 schema"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type PluginConfigFieldItem struct {
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
Type string `json:"type"`
|
||||
Default any `json:"default"`
|
||||
Options []string `json:"options,omitempty"`
|
||||
Required bool `json:"required"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type PluginConfigSchemaRes struct {
|
||||
List []PluginConfigFieldItem `json:"list"`
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 优惠码管理 ===
|
||||
|
||||
type PromoCodeListReq struct {
|
||||
g.Meta `path:"/promo-codes" method:"get" mime:"json" tags:"管理后台-优惠码" summary:"优惠码列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type PromoCodeItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
DiscountValue float64 `json:"discount_value"`
|
||||
MinAmount float64 `json:"min_amount"`
|
||||
MaxDiscount float64 `json:"max_discount"`
|
||||
TotalCount int `json:"total_count"`
|
||||
UsedCount int `json:"used_count"`
|
||||
PerUserLimit int `json:"per_user_limit"`
|
||||
ValidFrom *gtime.Time `json:"valid_from"`
|
||||
ValidTo *gtime.Time `json:"valid_to"`
|
||||
PlanIds []int64 `json:"plan_ids"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type PromoCodeListRes struct {
|
||||
List []*PromoCodeItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type PromoCodeCreateReq struct {
|
||||
g.Meta `path:"/promo-codes" method:"post" mime:"json" tags:"管理后台-优惠码" summary:"创建优惠码"`
|
||||
Data map[string]interface{} `json:"data" v:"required"`
|
||||
}
|
||||
|
||||
type PromoCodeCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type PromoCodeUpdateReq struct {
|
||||
g.Meta `path:"/promo-codes/{id}" method:"put" mime:"json" tags:"管理后台-优惠码" summary:"更新优惠码"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Update map[string]interface{} `json:"update" v:"required"`
|
||||
}
|
||||
|
||||
type PromoCodeUpdateRes struct{}
|
||||
|
||||
type PromoCodeUsagesReq struct {
|
||||
g.Meta `path:"/promo-codes/{id}/usages" method:"get" mime:"json" tags:"管理后台-优惠码" summary:"优惠码使用记录"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type PromoCodeUsageItem struct {
|
||||
Id int64 `json:"id"`
|
||||
PromoCodeId int64 `json:"promo_code_id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
OrderId int64 `json:"order_id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
DiscountAmount float64 `json:"discount_amount"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type PromoCodeUsagesRes struct {
|
||||
List []*PromoCodeUsageItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// PromoCodeExportReq 导出优惠码列表请求
|
||||
type PromoCodeExportReq struct {
|
||||
g.Meta `path:"/promo-codes/export" method:"get" mime:"json" tags:"管理后台-优惠码" summary:"导出优惠码列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
}
|
||||
|
||||
type PromoCodeExportRes struct{}
|
||||
@@ -0,0 +1,98 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 兑换码管理 ===
|
||||
|
||||
type RedemptionListReq struct {
|
||||
g.Meta `path:"/redemptions" method:"get" mime:"json" tags:"管理后台-兑换码" summary:"兑换码列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
}
|
||||
|
||||
type RedemptionItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Type string `json:"type"`
|
||||
Value float64 `json:"value"`
|
||||
PlanId int64 `json:"plan_id"`
|
||||
DurationDays int `json:"duration_days"`
|
||||
MaxUses int `json:"max_uses"`
|
||||
UsedCount int `json:"used_count"`
|
||||
RedeemedBy int64 `json:"redeemed_by"`
|
||||
RedeemedAt *gtime.Time `json:"redeemed_at"`
|
||||
ExpiresAt *gtime.Time `json:"expires_at"`
|
||||
Status string `json:"status"`
|
||||
BatchNo string `json:"batch_no"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type RedemptionListRes struct {
|
||||
List []*RedemptionItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type RedemptionCreateReq struct {
|
||||
g.Meta `path:"/redemptions" method:"post" mime:"json" tags:"管理后台-兑换码" summary:"批量创建兑换码"`
|
||||
Count int `json:"count" v:"required|min:1|max:1000"`
|
||||
Type string `json:"type" v:"required|in:quota,plan,duration"`
|
||||
Value float64 `json:"value"`
|
||||
PlanID int64 `json:"plan_id"`
|
||||
DurationDays int `json:"duration_days"`
|
||||
}
|
||||
|
||||
type RedemptionCreateRes struct {
|
||||
Created int `json:"created"`
|
||||
}
|
||||
|
||||
type RedemptionDisableReq struct {
|
||||
g.Meta `path:"/redemptions/{id}/disable" method:"put" mime:"json" tags:"管理后台-兑换码" summary:"禁用兑换码"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type RedemptionDisableRes struct{}
|
||||
|
||||
type RedemptionUsagesReq struct {
|
||||
g.Meta `path:"/redemptions/usages" method:"get" mime:"json" tags:"管理后台-兑换码" summary:"兑换码使用记录"`
|
||||
RedemptionId int64 `json:"redemption_id" in:"query" d:"0"`
|
||||
TenantId int64 `json:"tenant_id" in:"query" d:"0"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type RedemptionUsageItem struct {
|
||||
Id int64 `json:"id"`
|
||||
RedemptionId int64 `json:"redemption_id"`
|
||||
Code string `json:"code"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
UserId int64 `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
Type string `json:"type"`
|
||||
Value float64 `json:"value"`
|
||||
TransactionId int64 `json:"transaction_id"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type RedemptionUsagesRes struct {
|
||||
List []*RedemptionUsageItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// RedemptionExportReq 导出兑换码列表请求
|
||||
type RedemptionExportReq struct {
|
||||
g.Meta `path:"/redemptions/export" method:"get" mime:"json" tags:"管理后台-兑换码" summary:"导出兑换码列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Status string `json:"status" in:"query" dc:"状态筛选"`
|
||||
}
|
||||
|
||||
type RedemptionExportRes struct{}
|
||||
@@ -0,0 +1,122 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ============================================================
|
||||
// 2FA 启用流程
|
||||
// ============================================================
|
||||
|
||||
// Admin2FASetupReq 开启 2FA 设置(生成密钥和 QR Code)
|
||||
type Admin2FASetupReq struct {
|
||||
g.Meta `path:"/security/2fa/setup" method:"post" mime:"json" tags:"管理后台-安全" summary:"开启2FA设置"`
|
||||
}
|
||||
|
||||
type Admin2FASetupRes struct {
|
||||
Secret string `json:"secret"` // TOTP 密钥(用于手动输入)
|
||||
URI string `json:"uri"` // otpauth:// URI
|
||||
}
|
||||
|
||||
// Admin2FAEnableReq 确认启用 2FA(验证 TOTP 码)
|
||||
type Admin2FAEnableReq struct {
|
||||
g.Meta `path:"/security/2fa/enable" method:"post" mime:"json" tags:"管理后台-安全" summary:"确认启用2FA"`
|
||||
Code string `json:"code" v:"required|length:6,6#请输入验证码|验证码为6位" dc:"TOTP 验证码"`
|
||||
Password string `json:"password" v:"required#请输入密码" dc:"当前密码(安全确认)"`
|
||||
}
|
||||
|
||||
type Admin2FAEnableRes struct {
|
||||
BackupCodes []string `json:"backup_codes"` // 备用恢复码(仅展示一次)
|
||||
}
|
||||
|
||||
// Admin2FADisableReq 禁用 2FA
|
||||
type Admin2FADisableReq struct {
|
||||
g.Meta `path:"/security/2fa/disable" method:"post" mime:"json" tags:"管理后台-安全" summary:"禁用2FA"`
|
||||
Code string `json:"code" v:"required#请输入验证码或恢复码" dc:"TOTP 验证码或恢复码"`
|
||||
}
|
||||
|
||||
type Admin2FADisableRes struct{}
|
||||
|
||||
// Admin2FARegenerateBackupCodesReq 重新生成备用恢复码
|
||||
type Admin2FARegenerateBackupCodesReq struct {
|
||||
g.Meta `path:"/security/2fa/backup-codes" method:"post" mime:"json" tags:"管理后台-安全" summary:"重新生成备用恢复码"`
|
||||
Code string `json:"code" v:"required#请输入验证码" dc:"TOTP 验证码"`
|
||||
}
|
||||
|
||||
type Admin2FARegenerateBackupCodesRes struct {
|
||||
BackupCodes []string `json:"backup_codes"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 2FA 登录验证
|
||||
// ============================================================
|
||||
|
||||
// Admin2FAVerifyReq 登录时 2FA 验证
|
||||
type Admin2FAVerifyReq struct {
|
||||
g.Meta `path:"/auth/2fa/verify" method:"post" mime:"json" tags:"管理后台-认证" summary:"2FA登录验证" group:"public" middleware:"-"`
|
||||
Provisional string `json:"provisional_token" v:"required#缺少临时令牌" dc:"登录时返回的临时令牌"`
|
||||
Code string `json:"code" v:"required#请输入验证码" dc:"TOTP 验证码或恢复码"`
|
||||
}
|
||||
|
||||
type Admin2FAVerifyRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
User struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
} `json:"user"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 高风险操作二次验证
|
||||
// ============================================================
|
||||
|
||||
// Admin2FAConfirmReq 高风险操作二次验证
|
||||
type Admin2FAConfirmReq struct {
|
||||
g.Meta `path:"/security/2fa/confirm" method:"post" mime:"json" tags:"管理后台-安全" summary:"高风险操作二次验证"`
|
||||
Code string `json:"code" v:"required#请输入验证码" dc:"TOTP 验证码"`
|
||||
}
|
||||
|
||||
type Admin2FAConfirmRes struct {
|
||||
ConfirmToken string `json:"confirm_token"` // 确认令牌(5分钟有效,用于高风险操作请求头)
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 登录历史
|
||||
// ============================================================
|
||||
|
||||
// AdminLoginHistoryReq 登录历史列表(查看所有管理员)
|
||||
type AdminLoginHistoryReq struct {
|
||||
g.Meta `path:"/security/login-history" method:"get" tags:"管理后台-安全" summary:"登录历史"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
Username string `json:"username" in:"query" dc:"用户名(模糊搜索)"`
|
||||
IpAddress string `json:"ip_address" in:"query" dc:"IP地址(模糊搜索)"`
|
||||
Success *bool `json:"success" in:"query" dc:"登录状态:true成功/false失败"`
|
||||
LoginMethod string `json:"login_method" in:"query" dc:"登录方式:password/totp/sso/backup_code"`
|
||||
StartTime string `json:"start_time" in:"query" dc:"开始时间(格式:2006-01-02)"`
|
||||
EndTime string `json:"end_time" in:"query" dc:"结束时间(格式:2006-01-02)"`
|
||||
}
|
||||
|
||||
type AdminLoginHistoryRes struct {
|
||||
List []LoginHistoryItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type LoginHistoryItem struct {
|
||||
ID int64 `json:"id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
Username string `json:"username"`
|
||||
DisplayName string `json:"display_name"`
|
||||
LoginMethod string `json:"login_method"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Location string `json:"location"`
|
||||
IsNewDevice bool `json:"is_new_device"`
|
||||
Success bool `json:"success"`
|
||||
FailReason string `json:"fail_reason"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// AdminSettingsCategoriesReq 获取所有设置分类
|
||||
type AdminSettingsCategoriesReq struct {
|
||||
g.Meta `path:"/settings/categories" method:"get" mime:"json" tags:"管理后台-系统设置" summary:"获取设置分类列表"`
|
||||
}
|
||||
|
||||
type SettingCategoryItem struct {
|
||||
Key string `json:"key"`
|
||||
Label string `json:"label"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
Order int `json:"order"`
|
||||
}
|
||||
|
||||
type AdminSettingsCategoriesRes struct {
|
||||
List []SettingCategoryItem `json:"list"`
|
||||
}
|
||||
|
||||
// AdminSettingsGetReq 获取指定分类的设置(含 schema + 当前值)
|
||||
type AdminSettingsGetReq struct {
|
||||
g.Meta `path:"/settings/{category}" method:"get" mime:"json" tags:"管理后台-系统设置" summary:"获取分类设置"`
|
||||
Category string `json:"category" in:"path" v:"required" dc:"设置分类"`
|
||||
}
|
||||
|
||||
type AdminSettingItem struct {
|
||||
Key string `json:"key"`
|
||||
Value interface{} `json:"value"`
|
||||
Type string `json:"type"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Sensitive bool `json:"sensitive,omitempty"`
|
||||
Validation string `json:"validation,omitempty"`
|
||||
Default interface{} `json:"default"`
|
||||
}
|
||||
|
||||
type AdminSettingsGetRes struct {
|
||||
List []AdminSettingItem `json:"list"`
|
||||
}
|
||||
|
||||
// AdminSettingsUpdateReq 更新指定分类的设置
|
||||
type AdminSettingsUpdateReq struct {
|
||||
g.Meta `path:"/settings/{category}" method:"put" mime:"json" tags:"管理后台-系统设置" summary:"更新分类设置"`
|
||||
Category string `json:"category" in:"path" v:"required" dc:"设置分类"`
|
||||
Settings map[string]interface{} `json:"settings" v:"required" dc:"设置键值对"`
|
||||
}
|
||||
|
||||
type AdminSettingsUpdateRes struct{}
|
||||
@@ -0,0 +1,66 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 任务管理 ===
|
||||
|
||||
type TaskListReq struct {
|
||||
g.Meta `path:"/tasks" method:"get" mime:"json" tags:"管理后台-任务管理" summary:"任务列表"`
|
||||
Page int `json:"page" in:"query" d:"1" v:"min:1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" v:"min:1|max:100" dc:"每页数量"`
|
||||
Status string `json:"status" in:"query" dc:"筛选状态"`
|
||||
Handler string `json:"handler" in:"query" dc:"筛选handler"`
|
||||
}
|
||||
|
||||
type TaskItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Handler string `json:"handler"`
|
||||
Status string `json:"status"`
|
||||
MaxRetries int `json:"max_retries"`
|
||||
RetryCount int `json:"retry_count"`
|
||||
ErrorMessage string `json:"error_message,omitempty"`
|
||||
StartedAt string `json:"started_at,omitempty"`
|
||||
FinishedAt string `json:"finished_at,omitempty"`
|
||||
ScheduledAt string `json:"scheduled_at,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type TaskListRes struct {
|
||||
List []TaskItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TaskDetailReq struct {
|
||||
g.Meta `path:"/tasks/{id}" method:"get" mime:"json" tags:"管理后台-任务管理" summary:"任务详情"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"任务ID"`
|
||||
}
|
||||
|
||||
type TaskLogItem struct {
|
||||
Level string `json:"level"`
|
||||
Message string `json:"message"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type TaskDetailRes struct {
|
||||
Task TaskItem `json:"task"`
|
||||
RecentLogs []TaskLogItem `json:"recent_logs"`
|
||||
}
|
||||
|
||||
type TaskCancelReq struct {
|
||||
g.Meta `path:"/tasks/{id}/cancel" method:"post" mime:"json" tags:"管理后台-任务管理" summary:"取消任务"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"任务ID"`
|
||||
}
|
||||
|
||||
type TaskCancelRes struct{}
|
||||
|
||||
type TaskRetryReq struct {
|
||||
g.Meta `path:"/tasks/{id}/retry" method:"post" mime:"json" tags:"管理后台-任务管理" summary:"重试任务"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"任务ID"`
|
||||
}
|
||||
|
||||
type TaskRetryRes struct {
|
||||
TaskID int64 `json:"task_id"`
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// TenantCreateReq 创建租户请求
|
||||
type TenantCreateReq struct {
|
||||
g.Meta `path:"/tenants" method:"post" mime:"json" tags:"管理后台-租户管理" summary:"创建租户"`
|
||||
TenantName string `json:"tenant_name" v:"required|length:2,100#请输入租户名称|租户名称长度为2-100位" dc:"租户名称"`
|
||||
TenantCode string `json:"tenant_code" v:"required|length:3,30|regex:^[a-z0-9][a-z0-9-]*[a-z0-9]$#请输入租户代码|租户代码为3-30位|租户代码仅允许小写字母、数字、中划线" dc:"租户代码"`
|
||||
Username string `json:"username" v:"required|length:3,50#请输入管理员用户名|用户名长度为3-50位" dc:"管理员用户名"`
|
||||
Email string `json:"email" v:"required|email#请输入邮箱|邮箱格式不正确" dc:"管理员邮箱"`
|
||||
Password string `json:"password" v:"required|length:8,64#请输入密码|密码长度为8-64位" dc:"管理员密码"`
|
||||
MaxMembers *int `json:"max_members" dc:"最大成员数(默认10)"`
|
||||
MaxConcurrency *int `json:"max_concurrency" dc:"并发上限,0不限(默认0)"`
|
||||
}
|
||||
|
||||
type TenantCreateRes struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
// TenantListReq 租户列表请求
|
||||
type TenantListReq struct {
|
||||
g.Meta `path:"/tenants" method:"get" mime:"json" tags:"管理后台-租户管理" summary:"租户列表"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" dc:"每页数量"`
|
||||
Keyword string `json:"keyword" dc:"搜索关键词(名称/代码)"`
|
||||
Status string `json:"status" dc:"状态筛选:active/suspended/closed"`
|
||||
}
|
||||
|
||||
type TenantListRes struct {
|
||||
List []TenantItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
LogoURL string `json:"logo_url"`
|
||||
OwnerUserID int64 `json:"owner_user_id"`
|
||||
OwnerName string `json:"owner_name"`
|
||||
Status string `json:"status"`
|
||||
MaxMembers int `json:"max_members"`
|
||||
MaxConcurrency int `json:"max_concurrency"`
|
||||
DefaultChannelScope string `json:"default_channel_scope"`
|
||||
MemberCount int `json:"member_count"`
|
||||
WalletBalance string `json:"wallet_balance"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TenantGetReq 获取租户详情
|
||||
type TenantGetReq struct {
|
||||
g.Meta `path:"/tenants/{id}" method:"get" mime:"json" tags:"管理后台-租户管理" summary:"租户详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"租户ID"`
|
||||
}
|
||||
|
||||
type TenantGetRes struct {
|
||||
TenantItem
|
||||
Settings string `json:"settings"`
|
||||
}
|
||||
|
||||
// TenantChannelScopeUpdateReq 更新租户默认渠道范围
|
||||
type TenantChannelScopeUpdateReq struct {
|
||||
g.Meta `path:"/tenants/{id}/channel-scope" method:"put" mime:"json" tags:"管理后台-租户管理" summary:"更新租户渠道范围"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"租户ID"`
|
||||
DefaultChannelScope *string `json:"default_channel_scope" dc:"默认渠道范围JSON数组,如[1,5,12],null或[]表示全部"`
|
||||
}
|
||||
|
||||
// TenantUpdateStatusReq 更新租户状态
|
||||
type TenantUpdateStatusReq struct {
|
||||
g.Meta `path:"/tenants/{id}/status" method:"put" mime:"json" tags:"管理后台-租户管理" summary:"更新租户状态"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"租户ID"`
|
||||
Status string `json:"status" v:"required|in:active,suspended,closed#请选择状态|状态值无效" dc:"状态:active / suspended / closed"`
|
||||
}
|
||||
|
||||
type TenantUpdateStatusRes struct{}
|
||||
|
||||
// TenantUpdateReq 更新租户信息
|
||||
type TenantUpdateReq struct {
|
||||
g.Meta `path:"/tenants/{id}" method:"put" mime:"json" tags:"管理后台-租户管理" summary:"更新租户"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"租户ID"`
|
||||
Name string `json:"name" dc:"租户名称"`
|
||||
MaxMembers *int `json:"max_members" dc:"最大成员数"`
|
||||
MaxConcurrency *int `json:"max_concurrency" dc:"租户总并发上限(0表示不限制)"`
|
||||
}
|
||||
|
||||
type TenantUpdateRes struct{}
|
||||
|
||||
// AdminMemberListReq 成员列表请求(管理后台查看所有租户成员)
|
||||
type AdminMemberListReq struct {
|
||||
g.Meta `path:"/members" method:"get" mime:"json" tags:"管理后台-租户管理" summary:"成员列表"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" dc:"每页数量"`
|
||||
Keyword string `json:"keyword" dc:"搜索关键词(用户名/邮箱)"`
|
||||
Status string `json:"status" dc:"状态筛选"`
|
||||
Role string `json:"role" dc:"角色筛选"`
|
||||
TenantID int64 `json:"tenant_id" dc:"租户ID筛选"`
|
||||
}
|
||||
|
||||
type AdminMemberListRes struct {
|
||||
List []AdminMemberItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// TenantChannelScopeUpdateRes 更新租户渠道范围响应
|
||||
type TenantChannelScopeUpdateRes struct{}
|
||||
|
||||
type AdminMemberItem struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
TenantCode string `json:"tenant_code"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
LastLoginAt string `json:"last_login_at"`
|
||||
LastLoginIP string `json:"last_login_ip"`
|
||||
FailedAttempts int `json:"failed_attempts"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// TenantExportReq 导出租户列表请求
|
||||
type TenantExportReq struct {
|
||||
g.Meta `path:"/tenants/export" method:"get" mime:"json" tags:"管理后台-租户" summary:"导出租户列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Keyword string `json:"keyword" in:"query" dc:"搜索关键词(名称/代码)"`
|
||||
Status string `json:"status" in:"query" dc:"状态筛选:active/suspended/closed"`
|
||||
}
|
||||
|
||||
type TenantExportRes struct{}
|
||||
|
||||
// AdminMemberExportReq 导出成员列表请求
|
||||
type AdminMemberExportReq struct {
|
||||
g.Meta `path:"/tenants/members/export" method:"get" mime:"json" tags:"管理后台-成员" summary:"导出成员列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Keyword string `json:"keyword" in:"query" dc:"搜索关键词(用户名/邮箱)"`
|
||||
Status string `json:"status" in:"query" dc:"状态筛选"`
|
||||
Role string `json:"role" in:"query" dc:"角色筛选"`
|
||||
TenantID int64 `json:"tenant_id" in:"query" dc:"租户ID筛选"`
|
||||
}
|
||||
|
||||
type AdminMemberExportRes struct{}
|
||||
|
||||
// TenantSelectReq 租户下拉选择列表(轻量,用于选择器组件)
|
||||
type TenantSelectReq struct {
|
||||
g.Meta `path:"/tenants/select" method:"get" mime:"json" tags:"管理后台-租户管理" summary:"租户下拉选择列表"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
Keyword string `json:"keyword" in:"query" dc:"搜索关键词(名称/代码)"`
|
||||
}
|
||||
|
||||
type TenantSelectRes struct {
|
||||
List []TenantSelectItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantSelectItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// TenantModelListReq 租户模型分配列表
|
||||
type TenantModelListReq struct {
|
||||
g.Meta `path:"/tenants/{tenant_id}/models" method:"get" mime:"json" tags:"管理后台-租户模型" summary:"租户模型分配列表"`
|
||||
TenantID int64 `json:"tenant_id" in:"path" v:"required" dc:"租户ID"`
|
||||
}
|
||||
|
||||
type TenantModelListRes struct {
|
||||
List []TenantModelItem `json:"list"`
|
||||
}
|
||||
|
||||
type TenantModelItem struct {
|
||||
ID int64 `json:"id"`
|
||||
TenantID int64 `json:"tenant_id"`
|
||||
ModelID int64 `json:"model_id"`
|
||||
ModelCode string `json:"model_code"`
|
||||
ModelName string `json:"model_name"`
|
||||
Category string `json:"category"`
|
||||
Enabled bool `json:"enabled"`
|
||||
BillingMode *string `json:"billing_mode"`
|
||||
PerRequestPrice *float64 `json:"per_request_price"`
|
||||
DiscountRatio *float64 `json:"discount_ratio"`
|
||||
MaxConcurrency *int `json:"max_concurrency"`
|
||||
ChannelScope string `json:"channel_scope"`
|
||||
CustomInputPrice *float64 `json:"custom_input_price"`
|
||||
CustomOutputPrice *float64 `json:"custom_output_price"`
|
||||
Multiplier float64 `json:"multiplier"`
|
||||
}
|
||||
|
||||
// TenantModelBatchAssignReq 批量分配模型给租户
|
||||
type TenantModelBatchAssignReq struct {
|
||||
g.Meta `path:"/tenants/{tenant_id}/models" method:"post" mime:"json" tags:"管理后台-租户模型" summary:"批量分配模型"`
|
||||
TenantID int64 `json:"tenant_id" in:"path" v:"required" dc:"租户ID"`
|
||||
Assignments []ModelAssignment `json:"assignments" v:"required" dc:"模型分配列表"`
|
||||
}
|
||||
|
||||
type ModelAssignment struct {
|
||||
ModelID int64 `json:"model_id" v:"required" dc:"模型ID"`
|
||||
Enabled bool `json:"enabled" d:"true" dc:"是否启用"`
|
||||
BillingMode *string `json:"billing_mode" dc:"覆盖计费模式"`
|
||||
PerRequestPrice *float64 `json:"per_request_price" dc:"按次单价"`
|
||||
DiscountRatio *float64 `json:"discount_ratio" dc:"折扣比例(0-1)"`
|
||||
MaxConcurrency *int `json:"max_concurrency" dc:"单模型并发上限"`
|
||||
ChannelScope *string `json:"channel_scope" dc:"渠道范围JSON数组"`
|
||||
CustomInputPrice *float64 `json:"custom_input_price" dc:"自定义输入价格"`
|
||||
CustomOutputPrice *float64 `json:"custom_output_price" dc:"自定义输出价格"`
|
||||
}
|
||||
|
||||
type TenantModelBatchAssignRes struct {
|
||||
Assigned int `json:"assigned"`
|
||||
}
|
||||
|
||||
// TenantModelUpdateReq 更新租户模型分配配置
|
||||
type TenantModelUpdateReq struct {
|
||||
g.Meta `path:"/tenants/{tenant_id}/models/{model_id}" method:"put" mime:"json" tags:"管理后台-租户模型" summary:"更新租户模型配置"`
|
||||
TenantID int64 `json:"tenant_id" in:"path" v:"required" dc:"租户ID"`
|
||||
ModelID int64 `json:"model_id" in:"path" v:"required" dc:"模型ID"`
|
||||
Enabled *bool `json:"enabled" dc:"是否启用"`
|
||||
BillingMode *string `json:"billing_mode" v:"in:token,per_request" dc:"计费模式"`
|
||||
PerRequestPrice **float64 `json:"per_request_price" dc:"按次单价"`
|
||||
DiscountRatio **float64 `json:"discount_ratio" dc:"折扣比例"`
|
||||
MaxConcurrency **int `json:"max_concurrency" dc:"单模型并发上限"`
|
||||
ChannelScope **string `json:"channel_scope" dc:"渠道范围JSON数组"`
|
||||
CustomInputPrice **float64 `json:"custom_input_price" dc:"自定义输入价格"`
|
||||
CustomOutputPrice **float64 `json:"custom_output_price" dc:"自定义输出价格"`
|
||||
}
|
||||
|
||||
type TenantModelUpdateRes struct{}
|
||||
|
||||
// TenantModelDeleteReq 移除租户模型分配
|
||||
type TenantModelDeleteReq struct {
|
||||
g.Meta `path:"/tenants/{tenant_id}/models/{model_id}" method:"delete" mime:"json" tags:"管理后台-租户模型" summary:"移除租户模型"`
|
||||
TenantID int64 `json:"tenant_id" in:"path" v:"required" dc:"租户ID"`
|
||||
ModelID int64 `json:"model_id" in:"path" v:"required" dc:"模型ID"`
|
||||
}
|
||||
|
||||
type TenantModelDeleteRes struct{}
|
||||
@@ -0,0 +1,75 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 工单管理(管理后台) ===
|
||||
|
||||
type TicketListReq struct {
|
||||
g.Meta `path:"/tickets" method:"get" mime:"json" tags:"管理后台-工单" summary:"工单列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
Category string `json:"category" in:"query"`
|
||||
TenantID int64 `json:"tenant_id" in:"query"`
|
||||
AssignedAdminID int64 `json:"assigned_admin_id" in:"query"`
|
||||
}
|
||||
|
||||
type TicketItem struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
Category string `json:"category"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Urgency string `json:"urgency"`
|
||||
Status string `json:"status"`
|
||||
AssignedAdminId int64 `json:"assigned_admin_id"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
UserDisplayName string `json:"user_display_name"`
|
||||
AssignedAdminName string `json:"assigned_admin_name"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type TicketListRes struct {
|
||||
List []*TicketItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TicketGetReq struct {
|
||||
g.Meta `path:"/tickets/{id}" method:"get" mime:"json" tags:"管理后台-工单" summary:"工单详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TicketGetRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TicketAssignReq struct {
|
||||
g.Meta `path:"/tickets/{id}/assign" method:"put" mime:"json" tags:"管理后台-工单" summary:"分配工单"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
AdminID int64 `json:"admin_id" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TicketAssignRes struct{}
|
||||
|
||||
type TicketReplyReq struct {
|
||||
g.Meta `path:"/tickets/{id}/reply" method:"post" mime:"json" tags:"管理后台-工单" summary:"回复工单"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Content string `json:"content" v:"required"`
|
||||
}
|
||||
|
||||
type TicketReplyRes struct{}
|
||||
|
||||
type TicketStatusUpdateReq struct {
|
||||
g.Meta `path:"/tickets/{id}/status" method:"put" mime:"json" tags:"管理后台-工单" summary:"更新工单状态"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Status string `json:"status" v:"required|in:pending,processing,replied,closed,reopened"`
|
||||
}
|
||||
|
||||
type TicketStatusUpdateRes struct{}
|
||||
@@ -0,0 +1,51 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 用量日志清理 ===
|
||||
|
||||
type UsageLogCleanupCreateReq struct {
|
||||
g.Meta `path:"/usage-logs/cleanup" method:"post" mime:"json" tags:"管理后台-日志清理" summary:"创建清理任务"`
|
||||
StartTime string `json:"start_time" v:"required|datetime" dc:"起始时间(RFC3339)"`
|
||||
EndTime string `json:"end_time" v:"required|datetime" dc:"截止时间(RFC3339)"`
|
||||
TenantID *int64 `json:"tenant_id,omitempty" dc:"指定租户(可选)"`
|
||||
ModelName string `json:"model_name,omitempty" dc:"指定模型(可选)"`
|
||||
Status string `json:"status,omitempty" dc:"指定状态(可选)"`
|
||||
BatchSize int `json:"batch_size,omitempty" d:"5000" v:"min:100|max:50000" dc:"每批删除行数"`
|
||||
DryRun bool `json:"dry_run,omitempty" dc:"预演模式(不实际删除)"`
|
||||
}
|
||||
|
||||
type UsageLogCleanupCreateRes struct {
|
||||
TaskID int64 `json:"task_id"`
|
||||
}
|
||||
|
||||
type UsageLogCleanupListReq struct {
|
||||
g.Meta `path:"/usage-logs/cleanup/tasks" method:"get" mime:"json" tags:"管理后台-日志清理" summary:"清理任务列表"`
|
||||
Page int `json:"page" in:"query" d:"1" v:"min:1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" v:"min:1|max:100" dc:"每页数量"`
|
||||
}
|
||||
|
||||
type UsageLogCleanupTaskItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
ErrorMessage string `json:"error_message,omitempty"`
|
||||
Result string `json:"result,omitempty"`
|
||||
StartedAt string `json:"started_at,omitempty"`
|
||||
FinishedAt string `json:"finished_at,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type UsageLogCleanupListRes struct {
|
||||
List []UsageLogCleanupTaskItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type UsageLogCleanupCancelReq struct {
|
||||
g.Meta `path:"/usage-logs/cleanup/tasks/{id}/cancel" method:"post" mime:"json" tags:"管理后台-日志清理" summary:"取消清理任务"`
|
||||
ID int64 `json:"id" in:"path" v:"required" dc:"任务ID"`
|
||||
}
|
||||
|
||||
type UsageLogCleanupCancelRes struct{}
|
||||
@@ -0,0 +1,16 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/captcha/v1"
|
||||
)
|
||||
|
||||
type ICaptchaV1 interface {
|
||||
CaptchaGenerate(ctx context.Context, req *v1.CaptchaGenerateReq) (res *v1.CaptchaGenerateRes, err error)
|
||||
CaptchaVerify(ctx context.Context, req *v1.CaptchaVerifyReq) (res *v1.CaptchaVerifyRes, err error)
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// CaptchaGenerateReq 生成滑块验证码请求
|
||||
type CaptchaGenerateReq struct {
|
||||
g.Meta `path:"/" method:"get" mime:"json" tags:"公共-验证码" summary:"生成滑块验证码" group:"public" middleware:"-"`
|
||||
}
|
||||
|
||||
type CaptchaGenerateRes struct {
|
||||
CaptchaKey string `json:"captcha_key"`
|
||||
MasterImage string `json:"master_image"`
|
||||
TileImage string `json:"tile_image"`
|
||||
TileY int `json:"tile_y"`
|
||||
}
|
||||
|
||||
// CaptchaVerifyReq 验证滑块验证码请求
|
||||
type CaptchaVerifyReq struct {
|
||||
g.Meta `path:"/verify" method:"post" mime:"json" tags:"公共-验证码" summary:"验证滑块验证码" group:"public" middleware:"-"`
|
||||
CaptchaKey string `json:"captcha_key" v:"required#请提供验证码key" dc:"验证码key"`
|
||||
CaptchaX int `json:"captcha_x" v:"required|min:0#请提供滑块X坐标|X坐标不能为负数" dc:"滑块X坐标"`
|
||||
}
|
||||
|
||||
type CaptchaVerifyRes struct {
|
||||
Verified bool `json:"verified"`
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package docs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/docs/v1"
|
||||
)
|
||||
|
||||
type IDocsV1 interface {
|
||||
OpenAPISpec(ctx context.Context, req *v1.OpenAPISpecReq) (res *v1.OpenAPISpecRes, err error)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// OpenAPISpecReq returns the OpenAPI 3.0 specification for /v1/* endpoints.
|
||||
type OpenAPISpecReq struct {
|
||||
g.Meta `path:"/docs/api/openapi.json" method:"get" tags:"Docs" summary:"Get OpenAPI 3.0 spec"`
|
||||
}
|
||||
|
||||
type OpenAPISpecRes struct {
|
||||
// Spec is returned as raw JSON; controller writes it directly.
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package open
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/open/v1"
|
||||
)
|
||||
|
||||
type IOpenV1 interface {
|
||||
OpenMemberList(ctx context.Context, req *v1.OpenMemberListReq) (res *v1.OpenMemberListRes, err error)
|
||||
OpenMemberCreate(ctx context.Context, req *v1.OpenMemberCreateReq) (res *v1.OpenMemberCreateRes, err error)
|
||||
OpenMemberUpdate(ctx context.Context, req *v1.OpenMemberUpdateReq) (res *v1.OpenMemberUpdateRes, err error)
|
||||
OpenMemberDelete(ctx context.Context, req *v1.OpenMemberDeleteReq) (res *v1.OpenMemberDeleteRes, err error)
|
||||
OpenMemberQuota(ctx context.Context, req *v1.OpenMemberQuotaReq) (res *v1.OpenMemberQuotaRes, err error)
|
||||
OpenMemberQuotaUpdate(ctx context.Context, req *v1.OpenMemberQuotaUpdateReq) (res *v1.OpenMemberQuotaUpdateRes, err error)
|
||||
OpenMemberModels(ctx context.Context, req *v1.OpenMemberModelsReq) (res *v1.OpenMemberModelsRes, err error)
|
||||
OpenMemberModelsUpdate(ctx context.Context, req *v1.OpenMemberModelsUpdateReq) (res *v1.OpenMemberModelsUpdateRes, err error)
|
||||
OpenKeyList(ctx context.Context, req *v1.OpenKeyListReq) (res *v1.OpenKeyListRes, err error)
|
||||
OpenKeyCreate(ctx context.Context, req *v1.OpenKeyCreateReq) (res *v1.OpenKeyCreateRes, err error)
|
||||
OpenKeyDelete(ctx context.Context, req *v1.OpenKeyDeleteReq) (res *v1.OpenKeyDeleteRes, err error)
|
||||
OpenUsageQuery(ctx context.Context, req *v1.OpenUsageQueryReq) (res *v1.OpenUsageQueryRes, err error)
|
||||
OpenBillingQuery(ctx context.Context, req *v1.OpenBillingQueryReq) (res *v1.OpenBillingQueryRes, err error)
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ============================================================
|
||||
// 开放平台业务 API(第三方应用调用)
|
||||
// ============================================================
|
||||
|
||||
// OpenMemberList 成员列表
|
||||
type OpenMemberListReq struct {
|
||||
g.Meta `path:"/v1/members" method:"get" tags:"开放平台API" summary:"成员列表"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
Keyword string `json:"keyword" in:"query" dc:"搜索关键词"`
|
||||
Role string `json:"role" in:"query" dc:"按角色筛选"`
|
||||
Status string `json:"status" in:"query" dc:"按状态筛选"`
|
||||
}
|
||||
|
||||
type OpenMemberListRes struct {
|
||||
List []OpenMemberItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type OpenMemberItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// OpenMemberCreate 创建成员
|
||||
type OpenMemberCreateReq struct {
|
||||
g.Meta `path:"/v1/members" method:"post" mime:"json" tags:"开放平台API" summary:"创建成员"`
|
||||
Username string `json:"username" v:"required|length:2,50#请输入用户名|用户名长度2-50" dc:"用户名"`
|
||||
Email string `json:"email" v:"required|email#请输入邮箱|邮箱格式不正确" dc:"邮箱"`
|
||||
Password string `json:"password" v:"required|length:6,50#请输入密码|密码长度6-50" dc:"密码"`
|
||||
Role string `json:"role" v:"required|in:admin,member#请选择角色|角色无效" dc:"角色"`
|
||||
DisplayName string `json:"display_name" dc:"显示名称"`
|
||||
}
|
||||
|
||||
type OpenMemberCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// OpenMemberUpdate 更新成员
|
||||
type OpenMemberUpdateReq struct {
|
||||
g.Meta `path:"/v1/members/{id}" method:"put" mime:"json" tags:"开放平台API" summary:"更新成员"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定成员ID" dc:"成员ID"`
|
||||
Role *string `json:"role" v:"in:admin,member#角色无效" dc:"角色"`
|
||||
DisplayName *string `json:"display_name" dc:"显示名称"`
|
||||
Status *string `json:"status" v:"in:active,disabled#状态无效" dc:"状态"`
|
||||
}
|
||||
|
||||
type OpenMemberUpdateRes struct{}
|
||||
|
||||
// OpenMemberDelete 删除成员
|
||||
type OpenMemberDeleteReq struct {
|
||||
g.Meta `path:"/v1/members/{id}" method:"delete" tags:"开放平台API" summary:"删除成员"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定成员ID" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type OpenMemberDeleteRes struct{}
|
||||
|
||||
// OpenMemberQuota 成员额度查询
|
||||
type OpenMemberQuotaReq struct {
|
||||
g.Meta `path:"/v1/members/{id}/quota" method:"get" tags:"开放平台API" summary:"成员额度查询"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定成员ID" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type OpenMemberQuotaRes struct {
|
||||
QuotaType string `json:"quota_type"`
|
||||
QuotaLimit float64 `json:"quota_limit"`
|
||||
QuotaUsed float64 `json:"quota_used"`
|
||||
Period string `json:"period"`
|
||||
}
|
||||
|
||||
// OpenMemberQuotaUpdate 更新成员额度
|
||||
type OpenMemberQuotaUpdateReq struct {
|
||||
g.Meta `path:"/v1/members/{id}/quota" method:"put" mime:"json" tags:"开放平台API" summary:"更新成员额度"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定成员ID" dc:"成员ID"`
|
||||
QuotaType string `json:"quota_type" v:"required|in:none,total,periodic#请选择额度类型|额度类型无效" dc:"额度类型"`
|
||||
QuotaLimit float64 `json:"quota_limit" v:"min:0" dc:"额度上限(USD)"`
|
||||
Period string `json:"period" v:"in:day,week,month" dc:"周期类型"`
|
||||
}
|
||||
|
||||
type OpenMemberQuotaUpdateRes struct{}
|
||||
|
||||
// OpenMemberModels 成员可用模型
|
||||
type OpenMemberModelsReq struct {
|
||||
g.Meta `path:"/v1/members/{id}/models" method:"get" tags:"开放平台API" summary:"成员可用模型列表"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定成员ID" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type OpenMemberModelsRes struct {
|
||||
List []string `json:"list"`
|
||||
}
|
||||
|
||||
// OpenMemberModelsUpdate 更新成员可用模型
|
||||
type OpenMemberModelsUpdateReq struct {
|
||||
g.Meta `path:"/v1/members/{id}/models" method:"put" mime:"json" tags:"开放平台API" summary:"更新成员可用模型"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定成员ID" dc:"成员ID"`
|
||||
ModelIDs []int64 `json:"model_ids" v:"required#请选择模型列表" dc:"模型ID列表"`
|
||||
}
|
||||
|
||||
type OpenMemberModelsUpdateRes struct{}
|
||||
|
||||
// ============================================================
|
||||
// API Key 管理
|
||||
// ============================================================
|
||||
|
||||
// OpenKeyList API Key 列表
|
||||
type OpenKeyListReq struct {
|
||||
g.Meta `path:"/v1/keys" method:"get" tags:"开放平台API" summary:"API Key列表"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
Status string `json:"status" in:"query" dc:"按状态筛选"`
|
||||
}
|
||||
|
||||
type OpenKeyListRes struct {
|
||||
List []OpenKeyItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type OpenKeyItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"` // 脱敏显示 sk-***xxx
|
||||
Status string `json:"status"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// OpenKeyCreate 创建 API Key
|
||||
type OpenKeyCreateReq struct {
|
||||
g.Meta `path:"/v1/keys" method:"post" mime:"json" tags:"开放平台API" summary:"创建API Key"`
|
||||
Name string `json:"name" v:"required|length:2,100#请输入Key名称|名称长度2-100" dc:"Key名称"`
|
||||
ModelScopes []string `json:"model_scopes" dc:"可用模型列表(为空则不限)"`
|
||||
QuotaLimit string `json:"quota_limit" d:"0" dc:"额度上限(0=不限)"`
|
||||
}
|
||||
|
||||
type OpenKeyCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
Key string `json:"key"` // 完整 Key,仅创建时返回
|
||||
}
|
||||
|
||||
// OpenKeyDelete 删除 API Key
|
||||
type OpenKeyDeleteReq struct {
|
||||
g.Meta `path:"/v1/keys/{id}" method:"delete" tags:"开放平台API" summary:"删除API Key"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定Key ID" dc:"Key ID"`
|
||||
}
|
||||
|
||||
type OpenKeyDeleteRes struct{}
|
||||
|
||||
// ============================================================
|
||||
// 用量查询
|
||||
// ============================================================
|
||||
|
||||
// OpenUsageQuery 用量查询
|
||||
type OpenUsageQueryReq struct {
|
||||
g.Meta `path:"/v1/usage" method:"get" tags:"开放平台API" summary:"用量查询"`
|
||||
StartDate string `json:"start_date" in:"query" v:"required#请输入开始日期" dc:"开始日期 (YYYY-MM-DD)"`
|
||||
EndDate string `json:"end_date" in:"query" v:"required#请输入结束日期" dc:"结束日期 (YYYY-MM-DD)"`
|
||||
GroupBy string `json:"group_by" in:"query" d:"day" v:"in:day,model,key#分组方式无效" dc:"分组方式: day/model/key"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
}
|
||||
|
||||
type OpenUsageQueryRes struct {
|
||||
List []OpenUsageItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type OpenUsageItem struct {
|
||||
Date string `json:"date"`
|
||||
Model string `json:"model,omitempty"`
|
||||
KeyName string `json:"key_name,omitempty"`
|
||||
RequestCount int64 `json:"request_count"`
|
||||
PromptTokens int64 `json:"prompt_tokens"`
|
||||
CompletionTokens int64 `json:"completion_tokens"`
|
||||
TotalTokens int64 `json:"total_tokens"`
|
||||
Cost string `json:"cost"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 费用查询
|
||||
// ============================================================
|
||||
|
||||
// OpenBillingQuery 费用查询
|
||||
type OpenBillingQueryReq struct {
|
||||
g.Meta `path:"/v1/billing" method:"get" tags:"开放平台API" summary:"费用查询"`
|
||||
StartDate string `json:"start_date" in:"query" v:"required#请输入开始日期" dc:"开始日期 (YYYY-MM-DD)"`
|
||||
EndDate string `json:"end_date" in:"query" v:"required#请输入结束日期" dc:"结束日期 (YYYY-MM-DD)"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
}
|
||||
|
||||
type OpenBillingQueryRes struct {
|
||||
List []OpenBillingItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type OpenBillingItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Amount string `json:"amount"`
|
||||
Balance string `json:"balance,omitempty"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
Whitespace-only changes.
@@ -0,0 +1 @@
|
||||
package settings
|
||||
@@ -0,0 +1,16 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package settings
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/settings/v1"
|
||||
)
|
||||
|
||||
type ISettingsV1 interface {
|
||||
PublicSettingsGet(ctx context.Context, req *v1.PublicSettingsGetReq) (res *v1.PublicSettingsGetRes, err error)
|
||||
PublicAnnouncements(ctx context.Context, req *v1.PublicAnnouncementsReq) (res *v1.PublicAnnouncementsRes, err error)
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// PublicSettingsGetReq 获取公开设置项
|
||||
type PublicSettingsGetReq struct {
|
||||
g.Meta `path:"/public" method:"get" mime:"json" tags:"公开-系统设置" summary:"获取公开设置项" middleware:"-"`
|
||||
}
|
||||
|
||||
// PublicSettingsGetRes 返回所有 IsPublic=true 的设置项(key → typed value)
|
||||
type PublicSettingsGetRes struct {
|
||||
Settings map[string]any `json:"settings"`
|
||||
}
|
||||
|
||||
// PublicAnnouncementsReq 获取公开公告(无需认证,用于登录页等)
|
||||
type PublicAnnouncementsReq struct {
|
||||
g.Meta `path:"/announcements" method:"get" mime:"json" tags:"公开-公告" summary:"获取公开公告" middleware:"-"`
|
||||
Position string `json:"position" in:"query" dc:"展示位置过滤:login/console/both"`
|
||||
}
|
||||
|
||||
type PublicAnnouncementsRes struct {
|
||||
List []PublicAnnouncementItem `json:"list"`
|
||||
}
|
||||
|
||||
type PublicAnnouncementItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
IsPinned int `json:"is_pinned"`
|
||||
DisplayPosition string `json:"display_position"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
// =================================================================================
|
||||
// Code generated and maintained by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package tenant
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/tenant/v1"
|
||||
)
|
||||
|
||||
type ITenantV1 interface {
|
||||
TenantApiKeyList(ctx context.Context, req *v1.TenantApiKeyListReq) (res *v1.TenantApiKeyListRes, err error)
|
||||
TenantApiKeyCreate(ctx context.Context, req *v1.TenantApiKeyCreateReq) (res *v1.TenantApiKeyCreateRes, err error)
|
||||
TenantApiKeyDelete(ctx context.Context, req *v1.TenantApiKeyDeleteReq) (res *v1.TenantApiKeyDeleteRes, err error)
|
||||
TenantApiKeyUpdateScopes(ctx context.Context, req *v1.TenantApiKeyUpdateScopesReq) (res *v1.TenantApiKeyUpdateScopesRes, err error)
|
||||
TenantApiKeyExport(ctx context.Context, req *v1.TenantApiKeyExportReq) (res *v1.TenantApiKeyExportRes, err error)
|
||||
TenantAuditConfigGet(ctx context.Context, req *v1.TenantAuditConfigGetReq) (res *v1.TenantAuditConfigGetRes, err error)
|
||||
TenantAuditConfigUpdate(ctx context.Context, req *v1.TenantAuditConfigUpdateReq) (res *v1.TenantAuditConfigUpdateRes, err error)
|
||||
TenantAuditLogs(ctx context.Context, req *v1.TenantAuditLogsReq) (res *v1.TenantAuditLogsRes, err error)
|
||||
TenantRequestAuditLogs(ctx context.Context, req *v1.TenantRequestAuditLogsReq) (res *v1.TenantRequestAuditLogsRes, err error)
|
||||
TenantRequestAuditLogDetail(ctx context.Context, req *v1.TenantRequestAuditLogDetailReq) (res *v1.TenantRequestAuditLogDetailRes, err error)
|
||||
TenantRegister(ctx context.Context, req *v1.TenantRegisterReq) (res *v1.TenantRegisterRes, err error)
|
||||
TenantLogin(ctx context.Context, req *v1.TenantLoginReq) (res *v1.TenantLoginRes, err error)
|
||||
TenantLogout(ctx context.Context, req *v1.TenantLogoutReq) (res *v1.TenantLogoutRes, err error)
|
||||
TenantRefresh(ctx context.Context, req *v1.TenantRefreshReq) (res *v1.TenantRefreshRes, err error)
|
||||
TenantChangePassword(ctx context.Context, req *v1.TenantChangePasswordReq) (res *v1.TenantChangePasswordRes, err error)
|
||||
TenantSessionList(ctx context.Context, req *v1.TenantSessionListReq) (res *v1.TenantSessionListRes, err error)
|
||||
TenantRevokeSession(ctx context.Context, req *v1.TenantRevokeSessionReq) (res *v1.TenantRevokeSessionRes, err error)
|
||||
TenantUsageLogs(ctx context.Context, req *v1.TenantUsageLogsReq) (res *v1.TenantUsageLogsRes, err error)
|
||||
TenantBillingRecords(ctx context.Context, req *v1.TenantBillingRecordsReq) (res *v1.TenantBillingRecordsRes, err error)
|
||||
TenantUsageLogsExport(ctx context.Context, req *v1.TenantUsageLogsExportReq) (res *v1.TenantUsageLogsExportRes, err error)
|
||||
TenantRequestClosure(ctx context.Context, req *v1.TenantRequestClosureReq) (res *v1.TenantRequestClosureRes, err error)
|
||||
TenantCancelClosure(ctx context.Context, req *v1.TenantCancelClosureReq) (res *v1.TenantCancelClosureRes, err error)
|
||||
TenantDashboard(ctx context.Context, req *v1.TenantDashboardReq) (res *v1.TenantDashboardRes, err error)
|
||||
TenantTokenTrends(ctx context.Context, req *v1.TenantTokenTrendsReq) (res *v1.TenantTokenTrendsRes, err error)
|
||||
TenantModelDistribution(ctx context.Context, req *v1.TenantModelDistributionReq) (res *v1.TenantModelDistributionRes, err error)
|
||||
TenantBalancePrediction(ctx context.Context, req *v1.TenantBalancePredictionReq) (res *v1.TenantBalancePredictionRes, err error)
|
||||
TenantBudgetAlerts(ctx context.Context, req *v1.TenantBudgetAlertsReq) (res *v1.TenantBudgetAlertsRes, err error)
|
||||
TenantMemberUsageRanking(ctx context.Context, req *v1.TenantMemberUsageRankingReq) (res *v1.TenantMemberUsageRankingRes, err error)
|
||||
TenantSendCode(ctx context.Context, req *v1.TenantSendCodeReq) (res *v1.TenantSendCodeRes, err error)
|
||||
TenantResetPassword(ctx context.Context, req *v1.TenantResetPasswordReq) (res *v1.TenantResetPasswordRes, err error)
|
||||
TenantChangeEmail(ctx context.Context, req *v1.TenantChangeEmailReq) (res *v1.TenantChangeEmailRes, err error)
|
||||
FeedbackCreate(ctx context.Context, req *v1.FeedbackCreateReq) (res *v1.FeedbackCreateRes, err error)
|
||||
FeedbackList(ctx context.Context, req *v1.FeedbackListReq) (res *v1.FeedbackListRes, err error)
|
||||
FeedbackGet(ctx context.Context, req *v1.FeedbackGetReq) (res *v1.FeedbackGetRes, err error)
|
||||
HelpPublicCategoryList(ctx context.Context, req *v1.HelpPublicCategoryListReq) (res *v1.HelpPublicCategoryListRes, err error)
|
||||
HelpPublicArticleList(ctx context.Context, req *v1.HelpPublicArticleListReq) (res *v1.HelpPublicArticleListRes, err error)
|
||||
HelpPublicArticleGet(ctx context.Context, req *v1.HelpPublicArticleGetReq) (res *v1.HelpPublicArticleGetRes, err error)
|
||||
HelpPublicSearch(ctx context.Context, req *v1.HelpPublicSearchReq) (res *v1.HelpPublicSearchRes, err error)
|
||||
TenantMemberList(ctx context.Context, req *v1.TenantMemberListReq) (res *v1.TenantMemberListRes, err error)
|
||||
TenantMemberInvite(ctx context.Context, req *v1.TenantMemberInviteReq) (res *v1.TenantMemberInviteRes, err error)
|
||||
TenantInvitationList(ctx context.Context, req *v1.TenantInvitationListReq) (res *v1.TenantInvitationListRes, err error)
|
||||
TenantInvitationRevoke(ctx context.Context, req *v1.TenantInvitationRevokeReq) (res *v1.TenantInvitationRevokeRes, err error)
|
||||
TenantInviteInfo(ctx context.Context, req *v1.TenantInviteInfoReq) (res *v1.TenantInviteInfoRes, err error)
|
||||
TenantMemberJoin(ctx context.Context, req *v1.TenantMemberJoinReq) (res *v1.TenantMemberJoinRes, err error)
|
||||
TenantMemberCreate(ctx context.Context, req *v1.TenantMemberCreateReq) (res *v1.TenantMemberCreateRes, err error)
|
||||
TenantMemberResetPassword(ctx context.Context, req *v1.TenantMemberResetPasswordReq) (res *v1.TenantMemberResetPasswordRes, err error)
|
||||
TenantMemberRemove(ctx context.Context, req *v1.TenantMemberRemoveReq) (res *v1.TenantMemberRemoveRes, err error)
|
||||
TenantMemberUpdateRole(ctx context.Context, req *v1.TenantMemberUpdateRoleReq) (res *v1.TenantMemberUpdateRoleRes, err error)
|
||||
TenantMemberGet(ctx context.Context, req *v1.TenantMemberGetReq) (res *v1.TenantMemberGetRes, err error)
|
||||
TenantMemberUsage(ctx context.Context, req *v1.TenantMemberUsageReq) (res *v1.TenantMemberUsageRes, err error)
|
||||
TenantMemberApiKeys(ctx context.Context, req *v1.TenantMemberApiKeysReq) (res *v1.TenantMemberApiKeysRes, err error)
|
||||
TenantMemberExport(ctx context.Context, req *v1.TenantMemberExportReq) (res *v1.TenantMemberExportRes, err error)
|
||||
TenantImportRecords(ctx context.Context, req *v1.TenantImportRecordsReq) (res *v1.TenantImportRecordsRes, err error)
|
||||
TenantImportRecordGet(ctx context.Context, req *v1.TenantImportRecordGetReq) (res *v1.TenantImportRecordGetRes, err error)
|
||||
TenantMemberImport(ctx context.Context, req *v1.TenantMemberImportReq) (res *v1.TenantMemberImportRes, err error)
|
||||
TenantMemberQuota(ctx context.Context, req *v1.TenantMemberQuotaReq) (res *v1.TenantMemberQuotaRes, err error)
|
||||
TenantMemberQuotaSet(ctx context.Context, req *v1.TenantMemberQuotaSetReq) (res *v1.TenantMemberQuotaSetRes, err error)
|
||||
TenantMemberModelScopes(ctx context.Context, req *v1.TenantMemberModelScopesReq) (res *v1.TenantMemberModelScopesRes, err error)
|
||||
TenantMemberModelScopesSet(ctx context.Context, req *v1.TenantMemberModelScopesSetReq) (res *v1.TenantMemberModelScopesSetRes, err error)
|
||||
ModelComparison(ctx context.Context, req *v1.ModelComparisonReq) (res *v1.ModelComparisonRes, err error)
|
||||
TenantAvailableModels(ctx context.Context, req *v1.TenantAvailableModelsReq) (res *v1.TenantAvailableModelsRes, err error)
|
||||
TenantNotifications(ctx context.Context, req *v1.TenantNotificationsReq) (res *v1.TenantNotificationsRes, err error)
|
||||
TenantUnreadCount(ctx context.Context, req *v1.TenantUnreadCountReq) (res *v1.TenantUnreadCountRes, err error)
|
||||
TenantMarkRead(ctx context.Context, req *v1.TenantMarkReadReq) (res *v1.TenantMarkReadRes, err error)
|
||||
TenantMarkAllRead(ctx context.Context, req *v1.TenantMarkAllReadReq) (res *v1.TenantMarkAllReadRes, err error)
|
||||
TenantNotificationPreferencesGet(ctx context.Context, req *v1.TenantNotificationPreferencesGetReq) (res *v1.TenantNotificationPreferencesGetRes, err error)
|
||||
TenantNotificationPreferencesUpdate(ctx context.Context, req *v1.TenantNotificationPreferencesUpdateReq) (res *v1.TenantNotificationPreferencesUpdateRes, err error)
|
||||
TenantAnnouncements(ctx context.Context, req *v1.TenantAnnouncementsReq) (res *v1.TenantAnnouncementsRes, err error)
|
||||
TenantNotificationsExport(ctx context.Context, req *v1.TenantNotificationsExportReq) (res *v1.TenantNotificationsExportRes, err error)
|
||||
OAuthAuthorize(ctx context.Context, req *v1.OAuthAuthorizeReq) (res *v1.OAuthAuthorizeRes, err error)
|
||||
OAuthCallback(ctx context.Context, req *v1.OAuthCallbackReq) (res *v1.OAuthCallbackRes, err error)
|
||||
OAuthLink(ctx context.Context, req *v1.OAuthLinkReq) (res *v1.OAuthLinkRes, err error)
|
||||
OAuthUnlink(ctx context.Context, req *v1.OAuthUnlinkReq) (res *v1.OAuthUnlinkRes, err error)
|
||||
OAuthListProviders(ctx context.Context, req *v1.OAuthListProvidersReq) (res *v1.OAuthListProvidersRes, err error)
|
||||
OpenAppList(ctx context.Context, req *v1.OpenAppListReq) (res *v1.OpenAppListRes, err error)
|
||||
OpenAppCreate(ctx context.Context, req *v1.OpenAppCreateReq) (res *v1.OpenAppCreateRes, err error)
|
||||
OpenAppUpdate(ctx context.Context, req *v1.OpenAppUpdateReq) (res *v1.OpenAppUpdateRes, err error)
|
||||
OpenAppDelete(ctx context.Context, req *v1.OpenAppDeleteReq) (res *v1.OpenAppDeleteRes, err error)
|
||||
OpenAppResetSecret(ctx context.Context, req *v1.OpenAppResetSecretReq) (res *v1.OpenAppResetSecretRes, err error)
|
||||
OpenAppToggleStatus(ctx context.Context, req *v1.OpenAppToggleStatusReq) (res *v1.OpenAppToggleStatusRes, err error)
|
||||
WebhookConfigList(ctx context.Context, req *v1.WebhookConfigListReq) (res *v1.WebhookConfigListRes, err error)
|
||||
WebhookConfigCreate(ctx context.Context, req *v1.WebhookConfigCreateReq) (res *v1.WebhookConfigCreateRes, err error)
|
||||
WebhookConfigUpdate(ctx context.Context, req *v1.WebhookConfigUpdateReq) (res *v1.WebhookConfigUpdateRes, err error)
|
||||
WebhookConfigDelete(ctx context.Context, req *v1.WebhookConfigDeleteReq) (res *v1.WebhookConfigDeleteRes, err error)
|
||||
WebhookDeliveryLogs(ctx context.Context, req *v1.WebhookDeliveryLogsReq) (res *v1.WebhookDeliveryLogsRes, err error)
|
||||
WebhookRetry(ctx context.Context, req *v1.WebhookRetryReq) (res *v1.WebhookRetryRes, err error)
|
||||
TenantOrderCreate(ctx context.Context, req *v1.TenantOrderCreateReq) (res *v1.TenantOrderCreateRes, err error)
|
||||
TenantOrderPay(ctx context.Context, req *v1.TenantOrderPayReq) (res *v1.TenantOrderPayRes, err error)
|
||||
TenantOrderList(ctx context.Context, req *v1.TenantOrderListReq) (res *v1.TenantOrderListRes, err error)
|
||||
TenantOrderDetail(ctx context.Context, req *v1.TenantOrderDetailReq) (res *v1.TenantOrderDetailRes, err error)
|
||||
TenantOrderCancel(ctx context.Context, req *v1.TenantOrderCancelReq) (res *v1.TenantOrderCancelRes, err error)
|
||||
TenantPaymentInfo(ctx context.Context, req *v1.TenantPaymentInfoReq) (res *v1.TenantPaymentInfoRes, err error)
|
||||
TenantOrderExport(ctx context.Context, req *v1.TenantOrderExportReq) (res *v1.TenantOrderExportRes, err error)
|
||||
TenantOrgInfo(ctx context.Context, req *v1.TenantOrgInfoReq) (res *v1.TenantOrgInfoRes, err error)
|
||||
TenantOrgUpdate(ctx context.Context, req *v1.TenantOrgUpdateReq) (res *v1.TenantOrgUpdateRes, err error)
|
||||
TenantOrgTransfer(ctx context.Context, req *v1.TenantOrgTransferReq) (res *v1.TenantOrgTransferRes, err error)
|
||||
TenantProfile(ctx context.Context, req *v1.TenantProfileReq) (res *v1.TenantProfileRes, err error)
|
||||
TenantProfileUpdate(ctx context.Context, req *v1.TenantProfileUpdateReq) (res *v1.TenantProfileUpdateRes, err error)
|
||||
TenantIPWhitelistGet(ctx context.Context, req *v1.TenantIPWhitelistGetReq) (res *v1.TenantIPWhitelistGetRes, err error)
|
||||
TenantIPWhitelistUpdate(ctx context.Context, req *v1.TenantIPWhitelistUpdateReq) (res *v1.TenantIPWhitelistUpdateRes, err error)
|
||||
PersonalDashboard(ctx context.Context, req *v1.PersonalDashboardReq) (res *v1.PersonalDashboardRes, err error)
|
||||
PersonalTokenTrends(ctx context.Context, req *v1.PersonalTokenTrendsReq) (res *v1.PersonalTokenTrendsRes, err error)
|
||||
PersonalModelDist(ctx context.Context, req *v1.PersonalModelDistReq) (res *v1.PersonalModelDistRes, err error)
|
||||
PersonalApiKeyUsage(ctx context.Context, req *v1.PersonalApiKeyUsageReq) (res *v1.PersonalApiKeyUsageRes, err error)
|
||||
TenantPlanList(ctx context.Context, req *v1.TenantPlanListReq) (res *v1.TenantPlanListRes, err error)
|
||||
TenantPlanCurrent(ctx context.Context, req *v1.TenantPlanCurrentReq) (res *v1.TenantPlanCurrentRes, err error)
|
||||
TenantPlanCancelAutoRenew(ctx context.Context, req *v1.TenantPlanCancelAutoRenewReq) (res *v1.TenantPlanCancelAutoRenewRes, err error)
|
||||
PlaygroundChat(ctx context.Context, req *v1.PlaygroundChatReq) (res *v1.PlaygroundChatRes, err error)
|
||||
PlaygroundImage(ctx context.Context, req *v1.PlaygroundImageReq) (res *v1.PlaygroundImageRes, err error)
|
||||
PlaygroundAudioTTS(ctx context.Context, req *v1.PlaygroundAudioTTSReq) (res *v1.PlaygroundAudioTTSRes, err error)
|
||||
PlaygroundEmbedding(ctx context.Context, req *v1.PlaygroundEmbeddingReq) (res *v1.PlaygroundEmbeddingRes, err error)
|
||||
PlaygroundRerank(ctx context.Context, req *v1.PlaygroundRerankReq) (res *v1.PlaygroundRerankRes, err error)
|
||||
SandboxChat(ctx context.Context, req *v1.SandboxChatReq) (res *v1.SandboxChatRes, err error)
|
||||
SandboxQuota(ctx context.Context, req *v1.SandboxQuotaReq) (res *v1.SandboxQuotaRes, err error)
|
||||
TenantPluginList(ctx context.Context, req *v1.TenantPluginListReq) (res *v1.TenantPluginListRes, err error)
|
||||
TenantPluginDetail(ctx context.Context, req *v1.TenantPluginDetailReq) (res *v1.TenantPluginDetailRes, err error)
|
||||
TenantPluginConfigUpdate(ctx context.Context, req *v1.TenantPluginConfigUpdateReq) (res *v1.TenantPluginConfigUpdateRes, err error)
|
||||
TenantPluginEnable(ctx context.Context, req *v1.TenantPluginEnableReq) (res *v1.TenantPluginEnableRes, err error)
|
||||
TenantPluginDisable(ctx context.Context, req *v1.TenantPluginDisableReq) (res *v1.TenantPluginDisableRes, err error)
|
||||
TenantProjectList(ctx context.Context, req *v1.TenantProjectListReq) (res *v1.TenantProjectListRes, err error)
|
||||
TenantProjectCreate(ctx context.Context, req *v1.TenantProjectCreateReq) (res *v1.TenantProjectCreateRes, err error)
|
||||
TenantProjectUpdate(ctx context.Context, req *v1.TenantProjectUpdateReq) (res *v1.TenantProjectUpdateRes, err error)
|
||||
TenantProjectArchive(ctx context.Context, req *v1.TenantProjectArchiveReq) (res *v1.TenantProjectArchiveRes, err error)
|
||||
TenantProjectUnarchive(ctx context.Context, req *v1.TenantProjectUnarchiveReq) (res *v1.TenantProjectUnarchiveRes, err error)
|
||||
TenantProjectGet(ctx context.Context, req *v1.TenantProjectGetReq) (res *v1.TenantProjectGetRes, err error)
|
||||
TenantProjectApiKeyList(ctx context.Context, req *v1.TenantProjectApiKeyListReq) (res *v1.TenantProjectApiKeyListRes, err error)
|
||||
TenantProjectApiKeyCreate(ctx context.Context, req *v1.TenantProjectApiKeyCreateReq) (res *v1.TenantProjectApiKeyCreateRes, err error)
|
||||
TenantProjectApiKeyDelete(ctx context.Context, req *v1.TenantProjectApiKeyDeleteReq) (res *v1.TenantProjectApiKeyDeleteRes, err error)
|
||||
TenantProjectUsageStats(ctx context.Context, req *v1.TenantProjectUsageStatsReq) (res *v1.TenantProjectUsageStatsRes, err error)
|
||||
TenantProjectUsageLogs(ctx context.Context, req *v1.TenantProjectUsageLogsReq) (res *v1.TenantProjectUsageLogsRes, err error)
|
||||
TenantRedeemCode(ctx context.Context, req *v1.TenantRedeemCodeReq) (res *v1.TenantRedeemCodeRes, err error)
|
||||
TenantValidatePromoCode(ctx context.Context, req *v1.TenantValidatePromoCodeReq) (res *v1.TenantValidatePromoCodeRes, err error)
|
||||
TenantRedemptionUsages(ctx context.Context, req *v1.TenantRedemptionUsagesReq) (res *v1.TenantRedemptionUsagesRes, err error)
|
||||
Tenant2FASetup(ctx context.Context, req *v1.Tenant2FASetupReq) (res *v1.Tenant2FASetupRes, err error)
|
||||
Tenant2FAEnable(ctx context.Context, req *v1.Tenant2FAEnableReq) (res *v1.Tenant2FAEnableRes, err error)
|
||||
Tenant2FADisable(ctx context.Context, req *v1.Tenant2FADisableReq) (res *v1.Tenant2FADisableRes, err error)
|
||||
Tenant2FARegenerateBackupCodes(ctx context.Context, req *v1.Tenant2FARegenerateBackupCodesReq) (res *v1.Tenant2FARegenerateBackupCodesRes, err error)
|
||||
Tenant2FAVerify(ctx context.Context, req *v1.Tenant2FAVerifyReq) (res *v1.Tenant2FAVerifyRes, err error)
|
||||
Tenant2FAConfirm(ctx context.Context, req *v1.Tenant2FAConfirmReq) (res *v1.Tenant2FAConfirmRes, err error)
|
||||
TenantLoginHistory(ctx context.Context, req *v1.TenantLoginHistoryReq) (res *v1.TenantLoginHistoryRes, err error)
|
||||
TenantTicketCreate(ctx context.Context, req *v1.TenantTicketCreateReq) (res *v1.TenantTicketCreateRes, err error)
|
||||
TenantTicketList(ctx context.Context, req *v1.TenantTicketListReq) (res *v1.TenantTicketListRes, err error)
|
||||
TenantTicketGet(ctx context.Context, req *v1.TenantTicketGetReq) (res *v1.TenantTicketGetRes, err error)
|
||||
TenantTicketReply(ctx context.Context, req *v1.TenantTicketReplyReq) (res *v1.TenantTicketReplyRes, err error)
|
||||
TenantTicketClose(ctx context.Context, req *v1.TenantTicketCloseReq) (res *v1.TenantTicketCloseRes, err error)
|
||||
TenantTicketReopen(ctx context.Context, req *v1.TenantTicketReopenReq) (res *v1.TenantTicketReopenRes, err error)
|
||||
TenantTicketExport(ctx context.Context, req *v1.TenantTicketExportReq) (res *v1.TenantTicketExportRes, err error)
|
||||
TenantWallet(ctx context.Context, req *v1.TenantWalletReq) (res *v1.TenantWalletRes, err error)
|
||||
TenantWalletTransactions(ctx context.Context, req *v1.TenantWalletTransactionsReq) (res *v1.TenantWalletTransactionsRes, err error)
|
||||
TenantWalletTransactionsExport(ctx context.Context, req *v1.TenantWalletTransactionsExportReq) (res *v1.TenantWalletTransactionsExportRes, err error)
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户 API Key 管理 ===
|
||||
|
||||
type TenantApiKeyListReq struct {
|
||||
g.Meta `path:"/api-keys" method:"get" mime:"json" tags:"租户控制台-API Key" summary:"API Key列表"`
|
||||
KeyType string `json:"key_type" in:"query"`
|
||||
ProjectID int64 `json:"project_id" in:"query"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantApiKeyListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantApiKeyCreateReq struct {
|
||||
g.Meta `path:"/api-keys" method:"post" mime:"json" tags:"租户控制台-API Key" summary:"创建API Key"`
|
||||
Name string `json:"name" v:"required"`
|
||||
Scope string `json:"scope"`
|
||||
KeyType string `json:"key_type"`
|
||||
ProjectID int64 `json:"project_id"`
|
||||
ExpiresInDays int `json:"expires_in_days"`
|
||||
ModelNames []string `json:"model_names"`
|
||||
}
|
||||
|
||||
type TenantApiKeyCreateRes struct {
|
||||
Id int64 `json:"id"`
|
||||
Key string `json:"key"`
|
||||
KeyPrefix string `json:"key_prefix"`
|
||||
KeyType string `json:"key_type"`
|
||||
Name string `json:"name"`
|
||||
Scope string `json:"scope"`
|
||||
}
|
||||
|
||||
type TenantApiKeyDeleteReq struct {
|
||||
g.Meta `path:"/api-keys/{id}" method:"delete" mime:"json" tags:"租户控制台-API Key" summary:"删除API Key"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantApiKeyDeleteRes struct{}
|
||||
|
||||
type TenantApiKeyUpdateScopesReq struct {
|
||||
g.Meta `path:"/api-keys/{id}/scopes" method:"put" mime:"json" tags:"租户控制台-API Key" summary:"更新API Key模型范围"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
ModelNames []string `json:"model_names" v:"required"`
|
||||
}
|
||||
|
||||
type TenantApiKeyUpdateScopesRes struct{}
|
||||
|
||||
// TenantApiKeyExportReq 导出API Key列表请求
|
||||
type TenantApiKeyExportReq struct {
|
||||
g.Meta `path:"/api-keys/export" method:"get" mime:"json" tags:"租户控制台-API Key" summary:"导出API Key列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
KeyType string `json:"key_type" in:"query"`
|
||||
ProjectID int64 `json:"project_id" in:"query"`
|
||||
}
|
||||
|
||||
type TenantApiKeyExportRes struct{}
|
||||
@@ -0,0 +1,63 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户审计 ===
|
||||
|
||||
type TenantAuditConfigGetReq struct {
|
||||
g.Meta `path:"/audit/config" method:"get" mime:"json" tags:"租户控制台-审计" summary:"审计配置"`
|
||||
}
|
||||
|
||||
type TenantAuditConfigGetRes struct {
|
||||
AuditLevel string `json:"audit_level"`
|
||||
}
|
||||
|
||||
type TenantAuditConfigUpdateReq struct {
|
||||
g.Meta `path:"/audit/config" method:"put" mime:"json" tags:"租户控制台-审计" summary:"更新审计配置"`
|
||||
AuditLevel string `json:"audit_level" v:"required"`
|
||||
}
|
||||
|
||||
type TenantAuditConfigUpdateRes struct{}
|
||||
|
||||
type TenantAuditLogsReq struct {
|
||||
g.Meta `path:"/audit/logs" method:"get" mime:"json" tags:"租户控制台-审计" summary:"审计日志"`
|
||||
Page int `json:"page" d:"1"`
|
||||
PageSize int `json:"page_size" d:"20"`
|
||||
}
|
||||
|
||||
type TenantAuditLogsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// === 租户请求审计日志(API 调用的输入输出) ===
|
||||
|
||||
type TenantRequestAuditLogsReq struct {
|
||||
g.Meta `path:"/audit/request-logs" method:"get" mime:"json" tags:"租户控制台-审计" summary:"请求审计日志"`
|
||||
Page int `json:"page" in:"query" d:"1" v:"min:1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" v:"min:1|max:100"`
|
||||
Username string `json:"username" in:"query" dc:"用户名(模糊匹配)"`
|
||||
RequestId string `json:"request_id" in:"query" dc:"Request ID(精确匹配)"`
|
||||
Path string `json:"path" in:"query" dc:"请求路径(模糊匹配)"`
|
||||
StatusCode int `json:"status_code" in:"query" dc:"HTTP 状态码"`
|
||||
StartDate string `json:"start_date" in:"query" dc:"开始日期"`
|
||||
EndDate string `json:"end_date" in:"query" dc:"结束日期"`
|
||||
}
|
||||
|
||||
type TenantRequestAuditLogsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantRequestAuditLogDetailReq struct {
|
||||
g.Meta `path:"/audit/request-logs/{id}" method:"get" mime:"json" tags:"租户控制台-审计" summary:"请求审计日志详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantRequestAuditLogDetailRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// TenantRegisterReq 租户注册请求
|
||||
type TenantRegisterReq struct {
|
||||
g.Meta `path:"/auth/register" method:"post" mime:"json" tags:"租户控制台-认证" summary:"租户注册" group:"public" middleware:"-"`
|
||||
Email string `json:"email" v:"required|email#请输入邮箱|邮箱格式不正确" dc:"邮箱"`
|
||||
Code string `json:"code" dc:"邮箱验证码(邮箱验证开启时必填)"`
|
||||
Password string `json:"password" v:"required|length:8,64#请输入密码|密码长度为8-64位" dc:"密码"`
|
||||
TenantName string `json:"tenant_name" v:"required|length:2,100#请输入组织名称|组织名称长度为2-100位" dc:"组织名称"`
|
||||
TenantCode string `json:"tenant_code" v:"required|length:3,30|regex:^[a-z0-9][a-z0-9-]*[a-z0-9]$#请输入组织代码|组织代码为3-30位小写字母数字|组织代码格式不正确" dc:"组织代码"`
|
||||
Username string `json:"username" v:"required|length:3,50#请输入用户名|用户名长度为3-50位" dc:"用户名"`
|
||||
CaptchaKey string `json:"captcha_key" dc:"滑块验证码key(邮箱验证关闭时必填)"`
|
||||
CaptchaX int `json:"captcha_x" dc:"滑块X坐标(邮箱验证关闭时必填)"`
|
||||
}
|
||||
|
||||
type TenantRegisterRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
Tenant struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"tenant"`
|
||||
User struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role"`
|
||||
} `json:"user"`
|
||||
}
|
||||
|
||||
// TenantLoginReq 租户登录请求
|
||||
type TenantLoginReq struct {
|
||||
g.Meta `path:"/auth/login" method:"post" mime:"json" tags:"租户控制台-认证" summary:"租户登录" group:"public" middleware:"-"`
|
||||
Account string `json:"account" v:"required#请输入账号" dc:"账号(username@tenant_code 或邮箱)"`
|
||||
Password string `json:"password" v:"required#请输入密码" dc:"密码"`
|
||||
Type string `json:"type" v:"required|in:ram,admin#请选择登录方式|登录方式无效" dc:"登录方式:ram(RAM账号)/ admin(管理员邮箱)"`
|
||||
CaptchaKey string `json:"captcha_key" dc:"验证码key(验证码启用时必填)"`
|
||||
CaptchaX int `json:"captcha_x" dc:"滑块X坐标(验证码启用时必填)"`
|
||||
}
|
||||
|
||||
type TenantLoginRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
TotpRequired bool `json:"totp_required"` // 是否需要 2FA 验证
|
||||
ProvisionalToken string `json:"provisional_token,omitempty"` // 2FA 临时令牌
|
||||
Tenant struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"tenant"`
|
||||
User struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role"`
|
||||
} `json:"user"`
|
||||
MaintenanceInfo *LoginMaintenanceInfo `json:"maintenance_info,omitempty"`
|
||||
}
|
||||
|
||||
// LoginMaintenanceInfo 维护模式信息
|
||||
type LoginMaintenanceInfo struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Message string `json:"message"`
|
||||
Duration string `json:"duration"`
|
||||
}
|
||||
|
||||
// TenantLogoutReq 租户登出请求
|
||||
type TenantLogoutReq struct {
|
||||
g.Meta `path:"/auth/logout" method:"post" mime:"json" tags:"租户控制台-认证" summary:"租户登出"`
|
||||
}
|
||||
|
||||
type TenantLogoutRes struct{}
|
||||
|
||||
// TenantRefreshReq 刷新 Token 请求
|
||||
type TenantRefreshReq struct {
|
||||
g.Meta `path:"/auth/refresh" method:"post" mime:"json" tags:"租户控制台-认证" summary:"刷新 Token" group:"public" middleware:"-"`
|
||||
RefreshToken string `json:"refresh_token" v:"required#请提供刷新令牌" dc:"刷新令牌"`
|
||||
}
|
||||
|
||||
type TenantRefreshRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
}
|
||||
|
||||
// TenantChangePasswordReq 修改密码请求
|
||||
type TenantChangePasswordReq struct {
|
||||
g.Meta `path:"/auth/change-password" method:"put" mime:"json" tags:"租户控制台-认证" summary:"修改密码"`
|
||||
OldPassword string `json:"old_password" v:"required#请输入原密码" dc:"原密码"`
|
||||
NewPassword string `json:"new_password" v:"required|length:8,64#请输入新密码|密码长度为8-64位" dc:"新密码"`
|
||||
}
|
||||
|
||||
type TenantChangePasswordRes struct{}
|
||||
|
||||
// TenantSessionListReq 活跃会话列表请求
|
||||
type TenantSessionListReq struct {
|
||||
g.Meta `path:"/auth/sessions" method:"get" mime:"json" tags:"租户控制台-认证" summary:"活跃会话列表"`
|
||||
}
|
||||
|
||||
type TenantSessionListRes struct {
|
||||
List []TenantSessionItem `json:"list"`
|
||||
}
|
||||
|
||||
type TenantSessionItem struct {
|
||||
ID int64 `json:"id"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
DeviceInfo string `json:"device_info"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
IsCurrent bool `json:"is_current"`
|
||||
}
|
||||
|
||||
// TenantRevokeSessionReq 踢出指定会话请求
|
||||
type TenantRevokeSessionReq struct {
|
||||
g.Meta `path:"/auth/sessions/{id}" method:"delete" mime:"json" tags:"租户控制台-认证" summary:"踢出指定会话"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定会话ID"`
|
||||
}
|
||||
|
||||
type TenantRevokeSessionRes struct{}
|
||||
@@ -0,0 +1,51 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户用量与账单 ===
|
||||
|
||||
type TenantUsageLogsReq struct {
|
||||
g.Meta `path:"/usage-logs" method:"get" mime:"json" tags:"租户控制台-用量" summary:"用量日志"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Username string `json:"username" in:"query" dc:"用户名(模糊匹配)"`
|
||||
Model string `json:"model" in:"query"`
|
||||
Status string `json:"status" in:"query"`
|
||||
RequestType int `json:"request_type" in:"query"`
|
||||
StartDate string `json:"start_date" in:"query"`
|
||||
EndDate string `json:"end_date" in:"query"`
|
||||
}
|
||||
|
||||
type TenantUsageLogsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantBillingRecordsReq struct {
|
||||
g.Meta `path:"/billing-records" method:"get" mime:"json" tags:"租户控制台-用量" summary:"账单记录"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantBillingRecordsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// TenantUsageLogsExportReq 导出用量日志请求
|
||||
type TenantUsageLogsExportReq struct {
|
||||
g.Meta `path:"/usage-logs/export" method:"get" mime:"json" tags:"租户控制台-用量" summary:"导出用量日志"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Username string `json:"username" in:"query" dc:"用户名(模糊匹配)"`
|
||||
Model string `json:"model" in:"query"`
|
||||
Status string `json:"status" in:"query"`
|
||||
RequestType int `json:"request_type" in:"query"`
|
||||
StartDate string `json:"start_date" in:"query"`
|
||||
EndDate string `json:"end_date" in:"query"`
|
||||
}
|
||||
|
||||
type TenantUsageLogsExportRes struct{}
|
||||
@@ -0,0 +1,17 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 生命周期 ===
|
||||
|
||||
type TenantRequestClosureReq struct {
|
||||
g.Meta `path:"/request-closure" method:"post" mime:"json" tags:"租户控制台-生命周期" summary:"申请关户"`
|
||||
}
|
||||
|
||||
type TenantRequestClosureRes struct{}
|
||||
|
||||
type TenantCancelClosureReq struct {
|
||||
g.Meta `path:"/cancel-closure" method:"post" mime:"json" tags:"租户控制台-生命周期" summary:"取消关户"`
|
||||
}
|
||||
|
||||
type TenantCancelClosureRes struct{}
|
||||
@@ -0,0 +1,67 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户仪表盘 ===
|
||||
|
||||
type TenantDashboardReq struct {
|
||||
g.Meta `path:"/dashboard" method:"get" mime:"json" tags:"租户控制台-仪表盘" summary:"仪表盘概览"`
|
||||
}
|
||||
|
||||
type TenantDashboardRes struct {
|
||||
Today map[string]any `json:"today"`
|
||||
Month map[string]any `json:"month"`
|
||||
Wallet map[string]any `json:"wallet"`
|
||||
ActiveKeys int `json:"active_keys"`
|
||||
MemberCount int `json:"member_count"`
|
||||
}
|
||||
|
||||
type TenantTokenTrendsReq struct {
|
||||
g.Meta `path:"/dashboard/token-trends" method:"get" mime:"json" tags:"租户控制台-仪表盘" summary:"Token趋势"`
|
||||
Days int `json:"days" in:"query" d:"7"`
|
||||
}
|
||||
|
||||
type TenantTokenTrendsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
}
|
||||
|
||||
type TenantModelDistributionReq struct {
|
||||
g.Meta `path:"/dashboard/model-distribution" method:"get" mime:"json" tags:"租户控制台-仪表盘" summary:"模型分布"`
|
||||
Days int `json:"days" in:"query" d:"7"`
|
||||
}
|
||||
|
||||
type TenantModelDistributionRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
}
|
||||
|
||||
type TenantBalancePredictionReq struct {
|
||||
g.Meta `path:"/dashboard/balance-prediction" method:"get" mime:"json" tags:"租户控制台-仪表盘" summary:"余额预测"`
|
||||
}
|
||||
|
||||
type TenantBalancePredictionRes struct {
|
||||
DailyAvgCost float64 `json:"daily_avg_cost"`
|
||||
AvailableBalance float64 `json:"available_balance"`
|
||||
WillExhaust bool `json:"will_exhaust"`
|
||||
DaysUntilExhaust *int `json:"days_until_exhaust,omitempty"`
|
||||
ExhaustDate *string `json:"exhaust_date,omitempty"`
|
||||
Message *string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
type TenantBudgetAlertsReq struct {
|
||||
g.Meta `path:"/dashboard/budget-alerts" method:"get" mime:"json" tags:"租户控制台-仪表盘" summary:"预算告警"`
|
||||
}
|
||||
|
||||
type TenantBudgetAlertsRes struct {
|
||||
Members []map[string]any `json:"members"`
|
||||
Projects []map[string]any `json:"projects"`
|
||||
}
|
||||
|
||||
type TenantMemberUsageRankingReq struct {
|
||||
g.Meta `path:"/dashboard/member-usage-ranking" method:"get" mime:"json" tags:"租户控制台-仪表盘" summary:"成员用量排名"`
|
||||
Days int `json:"days" in:"query" d:"7"`
|
||||
Limit int `json:"limit" in:"query" d:"10"`
|
||||
}
|
||||
|
||||
type TenantMemberUsageRankingRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// TenantSendCodeReq 发送验证码请求
|
||||
type TenantSendCodeReq struct {
|
||||
g.Meta `path:"/email/send-code" method:"post" mime:"json" tags:"租户控制台-邮箱" summary:"发送验证码" group:"public" middleware:"-"`
|
||||
Email string `json:"email" v:"required|email#请输入邮箱|邮箱格式不正确" dc:"邮箱"`
|
||||
Purpose string `json:"purpose" v:"required|in:register,reset_password,change_email#请选择用途|用途无效" dc:"用途:register / reset_password / change_email"`
|
||||
}
|
||||
|
||||
type TenantSendCodeRes struct{}
|
||||
|
||||
// TenantResetPasswordReq 密码重置请求
|
||||
type TenantResetPasswordReq struct {
|
||||
g.Meta `path:"/email/reset-password" method:"post" mime:"json" tags:"租户控制台-邮箱" summary:"密码重置" group:"public" middleware:"-"`
|
||||
Email string `json:"email" v:"required|email#请输入邮箱|邮箱格式不正确" dc:"邮箱"`
|
||||
Code string `json:"code" v:"required|length:6,6#请输入验证码|验证码为6位" dc:"验证码"`
|
||||
Password string `json:"password" v:"required|length:8,64#请输入新密码|密码长度为8-64位" dc:"新密码"`
|
||||
CaptchaKey string `json:"captcha_key" dc:"验证码key(验证码启用时必填)"`
|
||||
CaptchaX int `json:"captcha_x" dc:"滑块X坐标(验证码启用时必填)"`
|
||||
}
|
||||
|
||||
type TenantResetPasswordRes struct{}
|
||||
|
||||
// TenantChangeEmailReq 更换邮箱请求
|
||||
type TenantChangeEmailReq struct {
|
||||
g.Meta `path:"/email/change-email" method:"post" mime:"json" tags:"租户控制台-邮箱" summary:"更换邮箱"`
|
||||
NewEmail string `json:"new_email" v:"required|email#请输入新邮箱|邮箱格式不正确" dc:"新邮箱"`
|
||||
Code string `json:"code" v:"required|length:6,6#请输入验证码|验证码为6位" dc:"验证码"`
|
||||
}
|
||||
|
||||
type TenantChangeEmailRes struct{}
|
||||
@@ -0,0 +1,67 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 用户反馈(租户端) ===
|
||||
|
||||
type FeedbackCreateReq struct {
|
||||
g.Meta `path:"/feedbacks" method:"post" mime:"json" tags:"租户-反馈" summary:"提交反馈"`
|
||||
Category string `json:"category" v:"required|in:bug_report,feature_request,suggestion,complaint" dc:"反馈类型"`
|
||||
Title string `json:"title" v:"required|length:1,200" dc:"反馈标题"`
|
||||
Description string `json:"description" v:"required|length:1,5000" dc:"反馈详细描述"`
|
||||
Metadata map[string]any `json:"metadata,omitempty" dc:"元数据(环境信息、截图链接等)"`
|
||||
}
|
||||
|
||||
type FeedbackCreateRes struct {
|
||||
Id int64 `json:"id"`
|
||||
}
|
||||
|
||||
type FeedbackListReq struct {
|
||||
g.Meta `path:"/feedbacks" method:"get" mime:"json" tags:"租户-反馈" summary:"我的反馈列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
Category string `json:"category" in:"query"`
|
||||
}
|
||||
|
||||
type FeedbackItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Category string `json:"category"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Priority string `json:"priority"`
|
||||
AdminReply string `json:"admin_reply,omitempty"`
|
||||
Resolution string `json:"resolution,omitempty"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type FeedbackListRes struct {
|
||||
List []*FeedbackItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type FeedbackGetReq struct {
|
||||
g.Meta `path:"/feedbacks/{id}" method:"get" mime:"json" tags:"租户-反馈" summary:"反馈详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type FeedbackGetRes struct {
|
||||
Id int64 `json:"id"`
|
||||
Category string `json:"category"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Status string `json:"status"`
|
||||
Priority string `json:"priority"`
|
||||
AdminReply string `json:"admin_reply,omitempty"`
|
||||
Resolution string `json:"resolution,omitempty"`
|
||||
Metadata map[string]any `json:"metadata,omitempty"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 帮助中心(公开接口) ===
|
||||
|
||||
type HelpPublicCategoryListReq struct {
|
||||
g.Meta `path:"/help/categories" method:"get" mime:"json" tags:"公开-帮助中心" summary:"帮助分类列表(树结构)" group:"public" middleware:"-"`
|
||||
}
|
||||
|
||||
type HelpPublicCategoryItem struct {
|
||||
Id int64 `json:"id"`
|
||||
ParentId int64 `json:"parent_id"`
|
||||
Name string `json:"name"`
|
||||
Slug string `json:"slug"`
|
||||
Description string `json:"description"`
|
||||
Icon string `json:"icon"`
|
||||
ArticleCount int `json:"article_count"`
|
||||
Children []*HelpPublicCategoryItem `json:"children"`
|
||||
}
|
||||
|
||||
type HelpPublicCategoryListRes struct {
|
||||
List []*HelpPublicCategoryItem `json:"list"`
|
||||
}
|
||||
|
||||
type HelpPublicArticleListReq struct {
|
||||
g.Meta `path:"/help/categories/{categorySlug}/articles" method:"get" mime:"json" tags:"公开-帮助中心" summary:"分类下的文章列表" group:"public" middleware:"-"`
|
||||
CategorySlug string `json:"category_slug" in:"path" v:"required" dc:"分类slug"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type HelpPublicArticleItem struct {
|
||||
Id int64 `json:"id"`
|
||||
CategoryId int64 `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Slug string `json:"slug"`
|
||||
Summary string `json:"summary"`
|
||||
ViewCount int `json:"view_count"`
|
||||
PublishedAt *gtime.Time `json:"published_at"`
|
||||
}
|
||||
|
||||
type HelpPublicArticleListRes struct {
|
||||
List []*HelpPublicArticleItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type HelpPublicArticleGetReq struct {
|
||||
g.Meta `path:"/help/articles/{slug}" method:"get" mime:"json" tags:"公开-帮助中心" summary:"文章详情" group:"public" middleware:"-"`
|
||||
Slug string `json:"slug" in:"path" v:"required" dc:"文章slug"`
|
||||
}
|
||||
|
||||
type HelpPublicArticleGetRes struct {
|
||||
Id int64 `json:"id"`
|
||||
CategoryId int64 `json:"category_id"`
|
||||
Title string `json:"title"`
|
||||
Slug string `json:"slug"`
|
||||
Content string `json:"content"`
|
||||
Summary string `json:"summary"`
|
||||
ViewCount int `json:"view_count"`
|
||||
Keywords []string `json:"keywords"`
|
||||
PublishedAt *gtime.Time `json:"published_at"`
|
||||
}
|
||||
|
||||
type HelpPublicSearchReq struct {
|
||||
g.Meta `path:"/help/search" method:"get" mime:"json" tags:"公开-帮助中心" summary:"搜索文章" group:"public" middleware:"-"`
|
||||
Query string `json:"q" in:"query" v:"required|length:1,200" dc:"搜索关键词"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type HelpPublicSearchRes struct {
|
||||
List []*HelpPublicArticleItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// TenantMemberListReq 成员列表请求
|
||||
type TenantMemberListReq struct {
|
||||
g.Meta `path:"/members" method:"get" mime:"json" tags:"租户控制台-成员管理" summary:"成员列表"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" dc:"每页数量"`
|
||||
Keyword string `json:"keyword" dc:"搜索关键词(用户名/邮箱)"`
|
||||
Role string `json:"role" dc:"角色筛选"`
|
||||
}
|
||||
|
||||
type TenantMemberListRes struct {
|
||||
List []TenantMemberItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantMemberItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// TenantMemberInviteReq 生成邀请链接请求
|
||||
type TenantMemberInviteReq struct {
|
||||
g.Meta `path:"/members/invite" method:"post" mime:"json" tags:"租户控制台-成员管理" summary:"生成邀请链接"`
|
||||
Role string `json:"role" d:"member" v:"in:admin,member#角色无效" dc:"邀请角色"`
|
||||
ExpiresDays int `json:"expires_days" d:"7" v:"between:1,30" dc:"有效天数"`
|
||||
MaxUses int `json:"max_uses" d:"0" v:"min:0" dc:"最大使用次数,0表示不限"`
|
||||
}
|
||||
|
||||
type TenantMemberInviteRes struct {
|
||||
Code string `json:"code"`
|
||||
InviteURL string `json:"invite_url"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
MaxUses int `json:"max_uses"`
|
||||
}
|
||||
|
||||
// TenantInvitationListReq 邀请记录列表
|
||||
type TenantInvitationListReq struct {
|
||||
g.Meta `path:"/members/invitations" method:"get" mime:"json" tags:"租户控制台-成员管理" summary:"邀请记录列表"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" dc:"每页数量"`
|
||||
}
|
||||
|
||||
type TenantInvitationListRes struct {
|
||||
List []TenantInvitationItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantInvitationItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Code string `json:"code"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
InviteURL string `json:"invite_url,omitempty"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
MaxUses int `json:"max_uses"`
|
||||
UseCount int `json:"use_count"`
|
||||
UsedByName string `json:"used_by_name,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
CreatorName string `json:"creator_name"`
|
||||
}
|
||||
|
||||
// TenantInvitationRevokeReq 撤销邀请
|
||||
type TenantInvitationRevokeReq struct {
|
||||
g.Meta `path:"/members/invitations/{id}" method:"delete" mime:"json" tags:"租户控制台-成员管理" summary:"撤销邀请"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定邀请ID" dc:"邀请ID"`
|
||||
}
|
||||
|
||||
type TenantInvitationRevokeRes struct{}
|
||||
|
||||
// TenantInviteInfoReq 查询邀请信息(公开接口,免认证)
|
||||
type TenantInviteInfoReq struct {
|
||||
g.Meta `path:"/members/invite-info" method:"get" mime:"json" tags:"租户控制台-成员管理" summary:"查询邀请信息"`
|
||||
Code string `json:"code" in:"query" v:"required#请提供邀请码" dc:"邀请码"`
|
||||
}
|
||||
|
||||
type TenantInviteInfoRes struct {
|
||||
TenantName string `json:"tenant_name"`
|
||||
Role string `json:"role"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
Valid bool `json:"valid"`
|
||||
}
|
||||
|
||||
// TenantMemberJoinReq 通过邀请链接加入请求
|
||||
type TenantMemberJoinReq struct {
|
||||
g.Meta `path:"/members/join" method:"post" mime:"json" tags:"租户控制台-成员管理" summary:"通过邀请加入" group:"public" middleware:"-"`
|
||||
Code string `json:"code" v:"required#请提供邀请码" dc:"邀请码"`
|
||||
Username string `json:"username" v:"required|length:3,50#请输入用户名|用户名长度为3-50位" dc:"用户名"`
|
||||
Password string `json:"password" v:"required|length:8,64#请输入密码|密码长度为8-64位" dc:"密码"`
|
||||
Email string `json:"email" v:"required|email#请输入邮箱|邮箱格式不正确" dc:"邮箱"`
|
||||
DisplayName string `json:"display_name" dc:"显示名称"`
|
||||
}
|
||||
|
||||
type TenantMemberJoinRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
TenantCode string `json:"tenant_code"`
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
// TenantMemberCreateReq 直接创建成员请求
|
||||
type TenantMemberCreateReq struct {
|
||||
g.Meta `path:"/members/create" method:"post" mime:"json" tags:"租户控制台-成员管理" summary:"直接创建成员"`
|
||||
Username string `json:"username" v:"required|length:3,50#请输入用户名|用户名长度为3-50位" dc:"用户名"`
|
||||
Password string `json:"password" v:"required|length:8,64#请输入密码|密码长度为8-64位" dc:"密码"`
|
||||
Email string `json:"email" v:"email#邮箱格式不正确" dc:"邮箱"`
|
||||
DisplayName string `json:"display_name" dc:"显示名称"`
|
||||
Role string `json:"role" d:"member" v:"in:admin,member#角色无效" dc:"角色"`
|
||||
}
|
||||
|
||||
type TenantMemberCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
// TenantMemberResetPasswordReq 重置成员密码请求
|
||||
type TenantMemberResetPasswordReq struct {
|
||||
g.Meta `path:"/members/{id}/reset-password" method:"put" mime:"json" tags:"租户控制台-成员管理" summary:"重置成员密码"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"成员ID"`
|
||||
Password string `json:"password" v:"required|length:8,64#请输入新密码|密码长度为8-64位" dc:"新密码"`
|
||||
}
|
||||
|
||||
type TenantMemberResetPasswordRes struct{}
|
||||
|
||||
// TenantMemberRemoveReq 移除成员请求
|
||||
type TenantMemberRemoveReq struct {
|
||||
g.Meta `path:"/members/{id}" method:"delete" mime:"json" tags:"租户控制台-成员管理" summary:"移除成员"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type TenantMemberRemoveRes struct{}
|
||||
|
||||
// TenantMemberUpdateRoleReq 更新成员角色请求
|
||||
type TenantMemberUpdateRoleReq struct {
|
||||
g.Meta `path:"/members/{id}/role" method:"put" mime:"json" tags:"租户控制台-成员管理" summary:"更新成员角色"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"成员ID"`
|
||||
Role string `json:"role" v:"required|in:admin,member#请选择角色|角色无效" dc:"角色"`
|
||||
}
|
||||
|
||||
type TenantMemberUpdateRoleRes struct{}
|
||||
|
||||
// TenantMemberGetReq 成员详情请求
|
||||
type TenantMemberGetReq struct {
|
||||
g.Meta `path:"/members/{id}" method:"get" mime:"json" tags:"租户控制台-成员管理" summary:"成员详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type TenantMemberGetRes struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// TenantMemberUsageReq 成员用量统计请求
|
||||
type TenantMemberUsageReq struct {
|
||||
g.Meta `path:"/members/{id}/usage" method:"get" mime:"json" tags:"租户控制台-成员管理" summary:"成员用量统计"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"成员ID"`
|
||||
}
|
||||
|
||||
type TenantMemberUsageRes struct {
|
||||
TodayRequests float64 `json:"today_requests"`
|
||||
MonthRequests float64 `json:"month_requests"`
|
||||
MonthInputTokens float64 `json:"month_input_tokens"`
|
||||
MonthOutputTokens float64 `json:"month_output_tokens"`
|
||||
MonthTotalCost float64 `json:"month_total_cost"`
|
||||
}
|
||||
|
||||
// TenantMemberApiKeysReq 成员 API Key 列表请求
|
||||
type TenantMemberApiKeysReq struct {
|
||||
g.Meta `path:"/members/{id}/api-keys" method:"get" mime:"json" tags:"租户控制台-成员管理" summary:"成员API Key列表"`
|
||||
Id int64 `json:"id" in:"path" v:"required" dc:"成员ID"`
|
||||
Page int `json:"page" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" d:"20" dc:"每页数量"`
|
||||
}
|
||||
|
||||
type TenantMemberApiKeysRes struct {
|
||||
List []TenantMemberApiKeyItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantMemberApiKeyItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
KeyPrefix string `json:"key_prefix"`
|
||||
Scope string `json:"scope"`
|
||||
Status string `json:"status"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
TotalQuota float64 `json:"total_quota"`
|
||||
UsedQuota float64 `json:"used_quota"`
|
||||
}
|
||||
|
||||
// TenantMemberExportReq 导出成员列表请求
|
||||
type TenantMemberExportReq struct {
|
||||
g.Meta `path:"/members/export" method:"get" mime:"json" tags:"租户控制台-成员管理" summary:"导出成员列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Keyword string `json:"keyword" in:"query" dc:"搜索关键词(用户名/邮箱)"`
|
||||
Role string `json:"role" in:"query" dc:"角色筛选"`
|
||||
}
|
||||
|
||||
type TenantMemberExportRes struct{}
|
||||
@@ -0,0 +1,35 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户成员批量导入 ===
|
||||
|
||||
type TenantImportRecordsReq struct {
|
||||
g.Meta `path:"/members/import-records" method:"get" mime:"json" tags:"租户控制台-成员" summary:"导入记录列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantImportRecordsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantImportRecordGetReq struct {
|
||||
g.Meta `path:"/members/import-records/{id}" method:"get" mime:"json" tags:"租户控制台-成员" summary:"导入记录详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantImportRecordGetRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantMemberImportReq struct {
|
||||
g.Meta `path:"/members/import" method:"post" mime:"json" tags:"租户控制台-成员" summary:"批量导入成员"`
|
||||
}
|
||||
|
||||
type TenantMemberImportRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户成员额度管理 ===
|
||||
|
||||
type TenantMemberQuotaReq struct {
|
||||
g.Meta `path:"/members/{id}/quota" method:"get" mime:"json" tags:"租户控制台-成员" summary:"获取成员额度"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantMemberQuotaRes struct {
|
||||
QuotaType string `json:"quota_type"` // none / total / periodic
|
||||
QuotaLimit float64 `json:"quota_limit"` // 额度上限(USD)
|
||||
QuotaUsed float64 `json:"quota_used"` // 已使用额度(USD)
|
||||
Period string `json:"period"` // day / week / month
|
||||
NextResetAt string `json:"next_reset_at"` // 下次重置时间(仅 periodic)
|
||||
}
|
||||
|
||||
type TenantMemberQuotaSetReq struct {
|
||||
g.Meta `path:"/members/{id}/quota" method:"put" mime:"json" tags:"租户控制台-成员" summary:"设置成员额度"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
QuotaType string `json:"quota_type" v:"required|in:none,total,periodic#请选择额度类型|额度类型无效" dc:"额度类型"`
|
||||
QuotaLimit float64 `json:"quota_limit" v:"min:0#额度上限不能为负" dc:"额度上限(USD)"`
|
||||
Period string `json:"period" v:"in:day,week,month#周期类型无效" dc:"周期类型(periodic 时必填)"`
|
||||
}
|
||||
|
||||
type TenantMemberQuotaSetRes struct{}
|
||||
@@ -0,0 +1,22 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户成员模型范围 ===
|
||||
|
||||
type TenantMemberModelScopesReq struct {
|
||||
g.Meta `path:"/members/{id}/model-scopes" method:"get" mime:"json" tags:"租户控制台-成员" summary:"成员模型范围"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantMemberModelScopesRes struct {
|
||||
ModelIDs []int64 `json:"model_ids"`
|
||||
}
|
||||
|
||||
type TenantMemberModelScopesSetReq struct {
|
||||
g.Meta `path:"/members/{id}/model-scopes" method:"put" mime:"json" tags:"租户控制台-成员" summary:"设置成员模型范围"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
ModelIDs []int64 `json:"model_ids"`
|
||||
}
|
||||
|
||||
type TenantMemberModelScopesSetRes struct{}
|
||||
@@ -0,0 +1,49 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ModelComparisonReq compares 2-4 models across cost, latency, and success rate.
|
||||
type ModelComparisonReq struct {
|
||||
g.Meta `path:"/model-comparison" method:"get" tags:"TenantService" summary:"模型成本对比"`
|
||||
Models string `json:"models" in:"query" v:"required" dc:"对比的模型名称,英文逗号分隔,2-4 个"`
|
||||
Days int `json:"days" in:"query" v:"between:1,90" dc:"统计天数,默认 7" d:"7"`
|
||||
}
|
||||
|
||||
type ModelComparisonRes struct {
|
||||
Summary ModelComparisonSummary `json:"summary"`
|
||||
Items []ModelComparisonItem `json:"items"`
|
||||
Trends []ModelTrendDay `json:"trends"`
|
||||
}
|
||||
|
||||
type ModelComparisonSummary struct {
|
||||
TotalRequests int64 `json:"total_requests"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
Recommended string `json:"recommended"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
type ModelComparisonItem struct {
|
||||
ModelName string `json:"model_name"`
|
||||
Requests int64 `json:"requests"`
|
||||
SuccessRate float64 `json:"success_rate"`
|
||||
AvgLatencyMs float64 `json:"avg_latency_ms"`
|
||||
P95LatencyMs float64 `json:"p95_latency_ms"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
AvgCostPerRequest float64 `json:"avg_cost_per_request"`
|
||||
InputTokens int64 `json:"input_tokens"`
|
||||
OutputTokens int64 `json:"output_tokens"`
|
||||
Score float64 `json:"score"`
|
||||
IsRecommended bool `json:"is_recommended"`
|
||||
}
|
||||
|
||||
type ModelTrendDay struct {
|
||||
Date string `json:"date"`
|
||||
Details []ModelTrendDayItem `json:"details"`
|
||||
}
|
||||
|
||||
type ModelTrendDayItem struct {
|
||||
ModelName string `json:"model_name"`
|
||||
Requests int64 `json:"requests"`
|
||||
Cost float64 `json:"cost"`
|
||||
LatencyMs float64 `json:"latency_ms"`
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// TenantAvailableModelsReq 租户可用模型列表请求
|
||||
type TenantAvailableModelsReq struct {
|
||||
g.Meta `path:"/models" method:"get" mime:"json" tags:"租户控制台-模型" summary:"租户可用模型列表"`
|
||||
Category string `json:"category" dc:"模型分类筛选:chat/embedding/image/audio/rerank"`
|
||||
Search string `json:"search" dc:"搜索关键词(模型名或显示名)"`
|
||||
}
|
||||
|
||||
type TenantAvailableModelsRes struct {
|
||||
List []TenantAvailableModelItem `json:"list"`
|
||||
}
|
||||
|
||||
// TenantAvailableModelItem 租户可用模型信息
|
||||
type TenantAvailableModelItem struct {
|
||||
ID int64 `json:"id"`
|
||||
ModelId string `json:"model_id"`
|
||||
ModelName string `json:"model_name"`
|
||||
Category string `json:"category"`
|
||||
MaxContext int `json:"max_context_tokens"`
|
||||
MaxOutput int `json:"max_output_tokens"`
|
||||
Description string `json:"description"`
|
||||
Tags string `json:"tags"`
|
||||
BillingMode *string `json:"billing_mode"`
|
||||
PerRequestPrice *float64 `json:"per_request_price"`
|
||||
DiscountRatio *float64 `json:"discount_ratio"`
|
||||
MaxConcurrency *int `json:"max_concurrency"`
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 租户通知 ===
|
||||
|
||||
type TenantNotificationsReq struct {
|
||||
g.Meta `path:"/notifications" method:"get" mime:"json" tags:"租户控制台-通知" summary:"通知列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantNotificationItem struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Content string `json:"content"`
|
||||
Channel string `json:"channel"`
|
||||
IsRead int `json:"is_read"`
|
||||
IsBroadcast int `json:"is_broadcast"`
|
||||
Metadata string `json:"metadata"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type TenantNotificationsRes struct {
|
||||
List []*TenantNotificationItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantUnreadCountReq struct {
|
||||
g.Meta `path:"/notifications/unread-count" method:"get" mime:"json" tags:"租户控制台-通知" summary:"未读数量"`
|
||||
}
|
||||
|
||||
type TenantUnreadCountRes struct {
|
||||
UnreadCount int `json:"unread_count"`
|
||||
}
|
||||
|
||||
type TenantMarkReadReq struct {
|
||||
g.Meta `path:"/notifications/{id}/read" method:"post" mime:"json" tags:"租户控制台-通知" summary:"标记已读"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantMarkReadRes struct{}
|
||||
|
||||
type TenantMarkAllReadReq struct {
|
||||
g.Meta `path:"/notifications/read-all" method:"post" mime:"json" tags:"租户控制台-通知" summary:"全部已读"`
|
||||
}
|
||||
|
||||
type TenantMarkAllReadRes struct{}
|
||||
|
||||
type TenantNotificationPreferencesGetReq struct {
|
||||
g.Meta `path:"/notification-preferences" method:"get" mime:"json" tags:"租户控制台-通知" summary:"通知偏好"`
|
||||
}
|
||||
|
||||
type TenantNotificationPreferencesGetRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantNotificationPreferencesUpdateReq struct {
|
||||
g.Meta `path:"/notification-preferences" method:"put" mime:"json" tags:"租户控制台-通知" summary:"更新通知偏好"`
|
||||
Scope string `json:"scope" v:"required|in:user,org"`
|
||||
Preferences map[string]any `json:"preferences" v:"required"`
|
||||
}
|
||||
|
||||
type TenantNotificationPreferencesUpdateRes struct{}
|
||||
|
||||
type TenantAnnouncementsReq struct {
|
||||
g.Meta `path:"/announcements" method:"get" mime:"json" tags:"租户控制台-通知" summary:"公告列表"`
|
||||
}
|
||||
|
||||
type TenantAnnouncementItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"`
|
||||
Content string `json:"content"`
|
||||
IsPinned int `json:"is_pinned"`
|
||||
DisplayPosition string `json:"display_position"`
|
||||
EffectiveAt *gtime.Time `json:"effective_at"`
|
||||
ExpiresAt *gtime.Time `json:"expires_at"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type TenantAnnouncementsRes struct {
|
||||
List []*TenantAnnouncementItem `json:"list"`
|
||||
}
|
||||
|
||||
// TenantNotificationsExportReq 导出通知列表请求
|
||||
type TenantNotificationsExportReq struct {
|
||||
g.Meta `path:"/notifications/export" method:"get" mime:"json" tags:"租户控制台-通知" summary:"导出通知列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
}
|
||||
|
||||
type TenantNotificationsExportRes struct{}
|
||||
@@ -0,0 +1,59 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === OAuth 登录(租户端) ===
|
||||
|
||||
type OAuthAuthorizeReq struct {
|
||||
g.Meta `path:"/oauth/authorize" method:"get" mime:"json" tags:"租户-OAuth" summary:"获取 OAuth 授权跳转 URL" group:"public" middleware:"-"`
|
||||
Provider string `json:"provider" in:"query" v:"required|in:github,google"`
|
||||
}
|
||||
|
||||
type OAuthAuthorizeRes struct {
|
||||
AuthorizeUrl string `json:"authorize_url"`
|
||||
State string `json:"state"`
|
||||
}
|
||||
|
||||
type OAuthCallbackReq struct {
|
||||
g.Meta `path:"/oauth/{provider}/callback" method:"get" mime:"json" tags:"租户-OAuth" summary:"OAuth 回调处理" group:"public" middleware:"-"`
|
||||
Provider string `json:"provider" in:"path" v:"required|in:github,google"`
|
||||
Code string `json:"code" in:"query" v:"required"`
|
||||
State string `json:"state" in:"query" v:"required"`
|
||||
}
|
||||
|
||||
type OAuthCallbackRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
IsNewUser bool `json:"is_new_user"`
|
||||
}
|
||||
|
||||
type OAuthLinkReq struct {
|
||||
g.Meta `path:"/oauth/link" method:"post" mime:"json" tags:"租户-OAuth" summary:"绑定 OAuth 账号"`
|
||||
Provider string `json:"provider" v:"required|in:github,google"`
|
||||
Code string `json:"code" v:"required"`
|
||||
}
|
||||
|
||||
type OAuthLinkRes struct{}
|
||||
|
||||
type OAuthUnlinkReq struct {
|
||||
g.Meta `path:"/oauth/unlink" method:"post" mime:"json" tags:"租户-OAuth" summary:"解绑 OAuth 账号"`
|
||||
Provider string `json:"provider" v:"required|in:github,google"`
|
||||
}
|
||||
|
||||
type OAuthUnlinkRes struct{}
|
||||
|
||||
type OAuthListProvidersReq struct {
|
||||
g.Meta `path:"/oauth/providers" method:"get" mime:"json" tags:"租户-OAuth" summary:"获取已绑定的 OAuth 供应商列表"`
|
||||
}
|
||||
|
||||
type OAuthProviderItem struct {
|
||||
Provider string `json:"provider"`
|
||||
ProviderUserID string `json:"provider_user_id"`
|
||||
ProviderUsername string `json:"provider_username"`
|
||||
LinkedAt string `json:"linked_at,omitempty"`
|
||||
}
|
||||
|
||||
type OAuthListProvidersRes struct {
|
||||
List []OAuthProviderItem `json:"list"`
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ============================================================
|
||||
// 开放平台应用管理
|
||||
// ============================================================
|
||||
|
||||
// OpenAppListReq 应用列表
|
||||
type OpenAppListReq struct {
|
||||
g.Meta `path:"/open/apps" method:"get" tags:"租户控制台-开放平台" summary:"应用列表"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
Keyword string `json:"keyword" in:"query" dc:"搜索关键词"`
|
||||
}
|
||||
|
||||
type OpenAppListRes struct {
|
||||
List []OpenAppItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type OpenAppItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
AppID string `json:"app_id"`
|
||||
Permissions []string `json:"permissions"`
|
||||
Status string `json:"status"`
|
||||
IsSandbox bool `json:"is_sandbox"`
|
||||
RateLimit int `json:"rate_limit"`
|
||||
LastUsedAt string `json:"last_used_at,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// OpenAppCreateReq 创建应用
|
||||
type OpenAppCreateReq struct {
|
||||
g.Meta `path:"/open/apps" method:"post" mime:"json" tags:"租户控制台-开放平台" summary:"创建应用"`
|
||||
Name string `json:"name" v:"required|length:2,100#请输入应用名称|应用名称长度为2-100位" dc:"应用名称"`
|
||||
Description string `json:"description" v:"length:0,500#描述不超过500字" dc:"应用描述"`
|
||||
Permissions []string `json:"permissions" v:"required|length:1,20#请选择权限范围|权限数量不正确" dc:"权限范围"`
|
||||
IPWhitelist []string `json:"ip_whitelist" dc:"IP 白名单"`
|
||||
RateLimit int `json:"rate_limit" d:"60" dc:"每分钟请求上限"`
|
||||
}
|
||||
|
||||
type OpenAppCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
AppID string `json:"app_id"`
|
||||
AppSecret string `json:"app_secret"` // 仅创建时返回一次
|
||||
}
|
||||
|
||||
// OpenAppUpdateReq 更新应用
|
||||
type OpenAppUpdateReq struct {
|
||||
g.Meta `path:"/open/apps/{id}" method:"put" mime:"json" tags:"租户控制台-开放平台" summary:"更新应用"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定应用ID" dc:"应用ID"`
|
||||
Name *string `json:"name" dc:"应用名称"`
|
||||
Description *string `json:"description" dc:"应用描述"`
|
||||
Permissions []string `json:"permissions" dc:"权限范围"`
|
||||
IPWhitelist []string `json:"ip_whitelist" dc:"IP 白名单"`
|
||||
RateLimit *int `json:"rate_limit" dc:"每分钟请求上限"`
|
||||
}
|
||||
|
||||
type OpenAppUpdateRes struct{}
|
||||
|
||||
// OpenAppDeleteReq 删除应用
|
||||
type OpenAppDeleteReq struct {
|
||||
g.Meta `path:"/open/apps/{id}" method:"delete" tags:"租户控制台-开放平台" summary:"删除应用"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定应用ID" dc:"应用ID"`
|
||||
}
|
||||
|
||||
type OpenAppDeleteRes struct{}
|
||||
|
||||
// OpenAppResetSecretReq 重置密钥
|
||||
type OpenAppResetSecretReq struct {
|
||||
g.Meta `path:"/open/apps/{id}/reset-secret" method:"post" tags:"租户控制台-开放平台" summary:"重置应用密钥"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定应用ID" dc:"应用ID"`
|
||||
}
|
||||
|
||||
type OpenAppResetSecretRes struct {
|
||||
AppSecret string `json:"app_secret"` // 新密钥,仅返回一次
|
||||
}
|
||||
|
||||
// OpenAppToggleStatusReq 启用/禁用应用
|
||||
type OpenAppToggleStatusReq struct {
|
||||
g.Meta `path:"/open/apps/{id}/status" method:"put" mime:"json" tags:"租户控制台-开放平台" summary:"启用/禁用应用"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定应用ID" dc:"应用ID"`
|
||||
Status string `json:"status" v:"required|in:active,disabled#请选择状态|状态无效" dc:"状态"`
|
||||
}
|
||||
|
||||
type OpenAppToggleStatusRes struct{}
|
||||
|
||||
// ============================================================
|
||||
// Webhook 配置管理
|
||||
// ============================================================
|
||||
|
||||
// WebhookConfigListReq Webhook 配置列表
|
||||
type WebhookConfigListReq struct {
|
||||
g.Meta `path:"/open/webhooks" method:"get" tags:"租户控制台-开放平台" summary:"Webhook配置列表"`
|
||||
}
|
||||
|
||||
type WebhookConfigListRes struct {
|
||||
List []WebhookConfigItem `json:"list"`
|
||||
}
|
||||
|
||||
type WebhookConfigItem struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Events []string `json:"events"`
|
||||
IsActive bool `json:"is_active"`
|
||||
ConsecutiveFailures int `json:"consecutive_failures"`
|
||||
MaxConsecutiveFailures int `json:"max_consecutive_failures"`
|
||||
LastDeliveryAt string `json:"last_delivery_at,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// WebhookConfigCreateReq 创建 Webhook
|
||||
type WebhookConfigCreateReq struct {
|
||||
g.Meta `path:"/open/webhooks" method:"post" mime:"json" tags:"租户控制台-开放平台" summary:"创建Webhook配置"`
|
||||
Name string `json:"name" v:"required|length:2,100#请输入名称|名称长度2-100" dc:"配置名称"`
|
||||
URL string `json:"url" v:"required|length:10,500#请输入URL|URL长度不正确" dc:"回调URL(HTTPS)"`
|
||||
Events []string `json:"events" v:"required|length:1,50#请选择事件|事件数量不正确" dc:"订阅事件列表"`
|
||||
MaxConsecutiveFailures int `json:"max_consecutive_failures" d:"10" dc:"最大连续失败次数"`
|
||||
}
|
||||
|
||||
type WebhookConfigCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
SecretKey string `json:"secret_key"` // 签名密钥,仅创建时返回
|
||||
}
|
||||
|
||||
// WebhookConfigUpdateReq 更新 Webhook
|
||||
type WebhookConfigUpdateReq struct {
|
||||
g.Meta `path:"/open/webhooks/{id}" method:"put" mime:"json" tags:"租户控制台-开放平台" summary:"更新Webhook配置"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定配置ID" dc:"配置ID"`
|
||||
Name *string `json:"name" dc:"配置名称"`
|
||||
URL *string `json:"url" dc:"回调URL"`
|
||||
Events []string `json:"events" dc:"订阅事件列表"`
|
||||
IsActive *bool `json:"is_active" dc:"是否启用"`
|
||||
MaxConsecutiveFailures *int `json:"max_consecutive_failures" dc:"最大连续失败次数"`
|
||||
}
|
||||
|
||||
type WebhookConfigUpdateRes struct{}
|
||||
|
||||
// WebhookConfigDeleteReq 删除 Webhook
|
||||
type WebhookConfigDeleteReq struct {
|
||||
g.Meta `path:"/open/webhooks/{id}" method:"delete" tags:"租户控制台-开放平台" summary:"删除Webhook配置"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定配置ID" dc:"配置ID"`
|
||||
}
|
||||
|
||||
type WebhookConfigDeleteRes struct{}
|
||||
|
||||
// WebhookDeliveryLogsReq 投递日志
|
||||
type WebhookDeliveryLogsReq struct {
|
||||
g.Meta `path:"/open/webhooks/{id}/logs" method:"get" tags:"租户控制台-开放平台" summary:"投递日志"`
|
||||
Id int64 `json:"id" in:"path" v:"required#请指定配置ID" dc:"配置ID"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
Status string `json:"status" in:"query" dc:"按状态筛选"`
|
||||
}
|
||||
|
||||
type WebhookDeliveryLogsRes struct {
|
||||
List []WebhookDeliveryLogItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type WebhookDeliveryLogItem struct {
|
||||
ID int64 `json:"id"`
|
||||
EventID int64 `json:"event_id"`
|
||||
EventType string `json:"event_type"`
|
||||
Attempt int `json:"attempt"`
|
||||
ResponseStatus int `json:"response_status"`
|
||||
ResponseTimeMs int `json:"response_time_ms"`
|
||||
ErrorMessage string `json:"error_message,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// WebhookRetryReq 手动重试
|
||||
type WebhookRetryReq struct {
|
||||
g.Meta `path:"/open/webhooks/events/{eventId}/retry" method:"post" tags:"租户控制台-开放平台" summary:"手动重试事件"`
|
||||
EventId int64 `json:"eventId" in:"path" v:"required#请指定事件ID" dc:"事件ID"`
|
||||
}
|
||||
|
||||
type WebhookRetryRes struct{}
|
||||
@@ -0,0 +1,102 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 租户订单 ===
|
||||
|
||||
type TenantOrderCreateReq struct {
|
||||
g.Meta `path:"/orders/create" method:"post" mime:"json" tags:"租户控制台-订单" summary:"创建订单"`
|
||||
PlanID int64 `json:"plan_id" v:"required|min:1"`
|
||||
Months int `json:"months"`
|
||||
AutoRenew bool `json:"auto_renew"`
|
||||
}
|
||||
|
||||
type TenantOrderCreateRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantOrderPayReq struct {
|
||||
g.Meta `path:"/orders/{id}/pay" method:"post" mime:"json" tags:"租户控制台-订单" summary:"支付订单"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
PaymentChannelID int64 `json:"payment_channel_id"`
|
||||
PaymentMethod string `json:"payment_method"`
|
||||
}
|
||||
|
||||
type TenantOrderPayRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantOrderListReq struct {
|
||||
g.Meta `path:"/orders" method:"get" mime:"json" tags:"租户控制台-订单" summary:"订单列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
}
|
||||
|
||||
type TenantOrderItem struct {
|
||||
Id int64 `json:"id"`
|
||||
OrderNo string `json:"order_no"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
OrderType string `json:"order_type"`
|
||||
PlanId int64 `json:"plan_id"`
|
||||
Amount float64 `json:"amount"`
|
||||
DiscountAmount float64 `json:"discount_amount"`
|
||||
FinalAmount float64 `json:"final_amount"`
|
||||
Currency string `json:"currency"`
|
||||
PaymentChannel string `json:"payment_channel"`
|
||||
PaymentMethod string `json:"payment_method"`
|
||||
PaymentNo string `json:"payment_no"`
|
||||
Status string `json:"status"`
|
||||
PaidAt *gtime.Time `json:"paid_at"`
|
||||
FulfilledAt *gtime.Time `json:"fulfilled_at"`
|
||||
ExpiredAt *gtime.Time `json:"expired_at"`
|
||||
CancelledAt *gtime.Time `json:"cancelled_at"`
|
||||
RelatedOrderId int64 `json:"related_order_id"`
|
||||
Description string `json:"description"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type TenantOrderListRes struct {
|
||||
List []*TenantOrderItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantOrderDetailReq struct {
|
||||
g.Meta `path:"/orders/{id}" method:"get" mime:"json" tags:"租户控制台-订单" summary:"订单详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantOrderDetailRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantOrderCancelReq struct {
|
||||
g.Meta `path:"/orders/{id}/cancel" method:"post" mime:"json" tags:"租户控制台-订单" summary:"取消订单"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantOrderCancelRes struct{}
|
||||
|
||||
type TenantPaymentInfoReq struct {
|
||||
g.Meta `path:"/payment-info" method:"get" mime:"json" tags:"租户控制台-订单" summary:"支付信息"`
|
||||
}
|
||||
|
||||
type TenantPaymentInfoRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
// TenantOrderExportReq 导出订单列表请求
|
||||
type TenantOrderExportReq struct {
|
||||
g.Meta `path:"/orders/export" method:"get" mime:"json" tags:"租户控制台-订单" summary:"导出订单列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Status string `json:"status" in:"query"`
|
||||
}
|
||||
|
||||
type TenantOrderExportRes struct{}
|
||||
@@ -0,0 +1,78 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// TenantOrgInfoReq 获取组织信息请求
|
||||
type TenantOrgInfoReq struct {
|
||||
g.Meta `path:"/organization" method:"get" mime:"json" tags:"租户控制台-组织" summary:"获取组织信息"`
|
||||
}
|
||||
|
||||
type TenantOrgInfoRes struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
LogoURL string `json:"logo_url"`
|
||||
Status string `json:"status"`
|
||||
MaxMembers int `json:"max_members"`
|
||||
MemberCount int `json:"member_count"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// TenantOrgUpdateReq 更新组织信息请求
|
||||
type TenantOrgUpdateReq struct {
|
||||
g.Meta `path:"/organization" method:"put" mime:"json" tags:"租户控制台-组织" summary:"更新组织信息"`
|
||||
Name *string `json:"name" v:"length:2,100#组织名称长度为2-100位" dc:"组织名称"`
|
||||
LogoURL *string `json:"logo_url" dc:"Logo URL"`
|
||||
}
|
||||
|
||||
type TenantOrgUpdateRes struct{}
|
||||
|
||||
// TenantOrgTransferReq 转让所有权请求
|
||||
type TenantOrgTransferReq struct {
|
||||
g.Meta `path:"/organization/transfer" method:"post" mime:"json" tags:"租户控制台-组织" summary:"转让所有权"`
|
||||
NewOwnerID int64 `json:"new_owner_id" v:"required#请指定新所有者" dc:"新所有者用户ID"`
|
||||
Password string `json:"password" v:"required#请输入密码确认" dc:"当前用户密码"`
|
||||
}
|
||||
|
||||
type TenantOrgTransferRes struct{}
|
||||
|
||||
// TenantProfileReq 获取个人信息请求
|
||||
type TenantProfileReq struct {
|
||||
g.Meta `path:"/profile" method:"get" mime:"json" tags:"租户控制台-组织" summary:"获取个人信息"`
|
||||
}
|
||||
|
||||
type TenantProfileRes struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
DisplayName string `json:"display_name"`
|
||||
Role string `json:"role"`
|
||||
Status string `json:"status"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
// TenantProfileUpdateReq 更新个人信息请求
|
||||
type TenantProfileUpdateReq struct {
|
||||
g.Meta `path:"/profile" method:"put" mime:"json" tags:"租户控制台-组织" summary:"更新个人信息"`
|
||||
DisplayName *string `json:"display_name" dc:"显示名称"`
|
||||
}
|
||||
|
||||
type TenantProfileUpdateRes struct{}
|
||||
|
||||
// TenantIPWhitelistReq 获取/设置登录 IP 白名单
|
||||
type TenantIPWhitelistGetReq struct {
|
||||
g.Meta `path:"/security/ip-whitelist" method:"get" tags:"租户控制台-安全" summary:"获取登录IP白名单"`
|
||||
}
|
||||
|
||||
type TenantIPWhitelistGetRes struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Whitelist []string `json:"whitelist"`
|
||||
}
|
||||
|
||||
type TenantIPWhitelistUpdateReq struct {
|
||||
g.Meta `path:"/security/ip-whitelist" method:"put" mime:"json" tags:"租户控制台-安全" summary:"更新登录IP白名单"`
|
||||
Enabled *bool `json:"enabled" dc:"是否启用IP白名单"`
|
||||
Whitelist []string `json:"whitelist" v:"length:0,100#白名单IP数量不能超过100" dc:"IP地址列表(CIDR格式)"`
|
||||
}
|
||||
|
||||
type TenantIPWhitelistUpdateRes struct{}
|
||||
@@ -0,0 +1,127 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户个人看板 ===
|
||||
|
||||
// ---------- 1. Overview ----------
|
||||
|
||||
type PersonalDashboardReq struct {
|
||||
g.Meta `path:"/personal-dashboard" method:"get" mime:"application/json" tags:"租户控制台-个人看板" summary:"个人看板概览"`
|
||||
}
|
||||
|
||||
type PersonalDashboardRes struct {
|
||||
Today PersonalDayStats `json:"today"`
|
||||
Month PersonalDayStats `json:"month"`
|
||||
ErrorRate PersonalErrorRate `json:"error_rate"`
|
||||
Latency PersonalLatency `json:"latency"`
|
||||
Cache PersonalCache `json:"cache"`
|
||||
RequestTypes []PersonalReqTypeItem `json:"request_types"`
|
||||
Quota *PersonalQuotaStatus `json:"quota,omitempty"`
|
||||
}
|
||||
|
||||
type PersonalDayStats struct {
|
||||
Requests int `json:"requests"`
|
||||
InputTokens int64 `json:"input_tokens"`
|
||||
OutputTokens int64 `json:"output_tokens"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
}
|
||||
|
||||
type PersonalErrorRate struct {
|
||||
Total int `json:"total"`
|
||||
Success int `json:"success"`
|
||||
Error int `json:"error"`
|
||||
Timeout int `json:"timeout"`
|
||||
Cancelled int `json:"cancelled"`
|
||||
Rate float64 `json:"rate"`
|
||||
}
|
||||
|
||||
type PersonalLatency struct {
|
||||
AvgMs float64 `json:"avg_ms"`
|
||||
P50Ms float64 `json:"p50_ms"`
|
||||
P95Ms float64 `json:"p95_ms"`
|
||||
P99Ms float64 `json:"p99_ms"`
|
||||
AvgFirstTokenMs float64 `json:"avg_first_token_ms"`
|
||||
}
|
||||
|
||||
type PersonalCache struct {
|
||||
CacheCreationTokens int64 `json:"cache_creation_tokens"`
|
||||
CacheReadTokens int64 `json:"cache_read_tokens"`
|
||||
TotalInputTokens int64 `json:"total_input_tokens"`
|
||||
HitRatio float64 `json:"hit_ratio"`
|
||||
}
|
||||
|
||||
type PersonalReqTypeItem struct {
|
||||
Type string `json:"type"`
|
||||
Label string `json:"label"`
|
||||
Requests int `json:"requests"`
|
||||
Percentage float64 `json:"percentage"`
|
||||
}
|
||||
|
||||
type PersonalQuotaStatus struct {
|
||||
QuotaType string `json:"quota_type"`
|
||||
QuotaLimit float64 `json:"quota_limit"`
|
||||
QuotaUsed float64 `json:"quota_used"`
|
||||
Period string `json:"period"`
|
||||
UsagePercent float64 `json:"usage_percent"`
|
||||
NextResetAt string `json:"next_reset_at,omitempty"`
|
||||
}
|
||||
|
||||
// ---------- 2. Token Trends ----------
|
||||
|
||||
type PersonalTokenTrendsReq struct {
|
||||
g.Meta `path:"/personal-dashboard/trends" method:"get" mime:"application/json" tags:"租户控制台-个人看板" summary:"个人Token趋势"`
|
||||
Days int `json:"days" in:"query" d:"7"`
|
||||
}
|
||||
|
||||
type PersonalTokenTrendsRes struct {
|
||||
List []PersonalTrendPoint `json:"list"`
|
||||
}
|
||||
|
||||
type PersonalTrendPoint struct {
|
||||
Date string `json:"date"`
|
||||
InputTokens int64 `json:"input_tokens"`
|
||||
OutputTokens int64 `json:"output_tokens"`
|
||||
Requests int `json:"requests"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
}
|
||||
|
||||
// ---------- 3. Model Distribution ----------
|
||||
|
||||
type PersonalModelDistReq struct {
|
||||
g.Meta `path:"/personal-dashboard/models" method:"get" mime:"application/json" tags:"租户控制台-个人看板" summary:"个人模型分布"`
|
||||
Days int `json:"days" in:"query" d:"7"`
|
||||
}
|
||||
|
||||
type PersonalModelDistRes struct {
|
||||
List []PersonalModelItem `json:"list"`
|
||||
}
|
||||
|
||||
type PersonalModelItem struct {
|
||||
ModelName string `json:"model_name"`
|
||||
Requests int `json:"requests"`
|
||||
InputTokens int64 `json:"input_tokens"`
|
||||
OutputTokens int64 `json:"output_tokens"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
}
|
||||
|
||||
// ---------- 4. API Key Usage ----------
|
||||
|
||||
type PersonalApiKeyUsageReq struct {
|
||||
g.Meta `path:"/personal-dashboard/api-key-usage" method:"get" mime:"application/json" tags:"租户控制台-个人看板" summary:"个人API Key用量"`
|
||||
Days int `json:"days" in:"query" d:"7"`
|
||||
}
|
||||
|
||||
type PersonalApiKeyUsageRes struct {
|
||||
List []PersonalApiKeyItem `json:"list"`
|
||||
}
|
||||
|
||||
type PersonalApiKeyItem struct {
|
||||
ApiKeyId int64 `json:"api_key_id"`
|
||||
KeyName string `json:"key_name"`
|
||||
KeyPrefix string `json:"key_prefix"`
|
||||
Requests int `json:"requests"`
|
||||
InputTokens int64 `json:"input_tokens"`
|
||||
OutputTokens int64 `json:"output_tokens"`
|
||||
TotalCost float64 `json:"total_cost"`
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 租户套餐 ===
|
||||
|
||||
type TenantPlanItem struct {
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Identifier string `json:"identifier"`
|
||||
Description string `json:"description"`
|
||||
MonthlyPrice float64 `json:"monthly_price"`
|
||||
YearlyPrice float64 `json:"yearly_price"`
|
||||
MonthlyQuotaTokens int64 `json:"monthly_quota_tokens"`
|
||||
AllowedModels []string `json:"allowed_models"`
|
||||
IsRecommended bool `json:"is_recommended"`
|
||||
SortOrder int `json:"sort_order"`
|
||||
}
|
||||
|
||||
type TenantPlanListReq struct {
|
||||
g.Meta `path:"/plans" method:"get" mime:"json" tags:"租户控制台-套餐" summary:"套餐列表"`
|
||||
}
|
||||
|
||||
type TenantPlanListRes struct {
|
||||
List []*TenantPlanItem `json:"list"`
|
||||
}
|
||||
|
||||
type TenantPlanCurrentReq struct {
|
||||
g.Meta `path:"/plan/current" method:"get" mime:"json" tags:"租户控制台-套餐" summary:"当前套餐"`
|
||||
}
|
||||
|
||||
type TenantPlanCurrentRes struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
PlanId int64 `json:"plan_id"`
|
||||
Status string `json:"status"`
|
||||
StartAt *gtime.Time `json:"start_at"`
|
||||
EndAt *gtime.Time `json:"end_at"`
|
||||
AutoRenew bool `json:"auto_renew"`
|
||||
MonthlyQuotaTokens int64 `json:"monthly_quota_tokens"`
|
||||
UsedTokens int64 `json:"used_tokens"`
|
||||
LastResetAt *gtime.Time `json:"last_reset_at"`
|
||||
Name string `json:"name"`
|
||||
Identifier string `json:"identifier"`
|
||||
Description string `json:"description"`
|
||||
MonthlyPrice float64 `json:"monthly_price"`
|
||||
YearlyPrice float64 `json:"yearly_price"`
|
||||
}
|
||||
|
||||
type TenantPlanCancelAutoRenewReq struct {
|
||||
g.Meta `path:"/plan/cancel-auto-renew" method:"put" mime:"json" tags:"租户控制台-套餐" summary:"取消自动续费"`
|
||||
}
|
||||
|
||||
type TenantPlanCancelAutoRenewRes struct{}
|
||||
@@ -0,0 +1,172 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ============================================================
|
||||
// Playground(真实调用,产生费用)
|
||||
// ============================================================
|
||||
|
||||
// PlaygroundImageConfig Playground 图片生成配置
|
||||
type PlaygroundImageConfig struct {
|
||||
AspectRatio string `json:"aspect_ratio,omitempty" dc:"宽高比:1:1, 16:9, 3:4, 4:3 等"`
|
||||
ImageSize string `json:"image_size,omitempty" dc:"分辨率:512, 1K, 2K, 4K"`
|
||||
}
|
||||
|
||||
// PlaygroundChatReq Playground 对话请求
|
||||
type PlaygroundChatReq struct {
|
||||
g.Meta `path:"/playground/chat" method:"post" mime:"json" tags:"租户控制台-Playground" summary:"Playground对话"`
|
||||
Model string `json:"model" v:"required#请选择模型" dc:"模型名称"`
|
||||
Messages []PlaygroundMessage `json:"messages" v:"required#请输入消息" dc:"对话消息列表"`
|
||||
Temperature *float64 `json:"temperature" dc:"温度参数 (0-2)"`
|
||||
MaxTokens *int `json:"max_tokens" dc:"最大输出 Token 数"`
|
||||
TopP *float64 `json:"top_p" dc:"Top-P 采样参数"`
|
||||
FrequencyPenalty *float64 `json:"frequency_penalty" dc:"频率惩罚 (-2 ~ 2)"`
|
||||
PresencePenalty *float64 `json:"presence_penalty" dc:"存在惩罚 (-2 ~ 2)"`
|
||||
Stream bool `json:"stream" d:"true" dc:"是否流式响应"`
|
||||
ImageConfig *PlaygroundImageConfig `json:"image_config,omitempty" dc:"图片生成配置(仅图片模型)"`
|
||||
}
|
||||
|
||||
type PlaygroundChatRes struct {
|
||||
Model string `json:"model"`
|
||||
Content string `json:"content" dc:"响应内容(非流式时返回)"`
|
||||
PromptTokens int `json:"prompt_tokens" dc:"输入 Token 数"`
|
||||
CompletionTokens int `json:"completion_tokens" dc:"输出 Token 数"`
|
||||
TotalTokens int `json:"total_tokens" dc:"总 Token 数"`
|
||||
EstimatedCost string `json:"estimated_cost" dc:"预估费用"`
|
||||
}
|
||||
|
||||
type PlaygroundMessage struct {
|
||||
Role string `json:"role" v:"required|in:system,user,assistant#请指定角色|角色无效"`
|
||||
Content string `json:"content" v:"required#消息内容不能为空"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Playground — 图片生成
|
||||
// ============================================================
|
||||
|
||||
type PlaygroundImageReq struct {
|
||||
g.Meta `path:"/playground/image" method:"post" mime:"json" tags:"租户控制台-Playground" summary:"Playground图片生成"`
|
||||
Model string `json:"model" v:"required#请选择模型" dc:"模型名称"`
|
||||
Prompt string `json:"prompt" v:"required#请输入提示词" dc:"图片生成提示词"`
|
||||
N *int `json:"n,omitempty" dc:"生成数量 (1-4)"`
|
||||
Size string `json:"size,omitempty" dc:"图片尺寸:1024x1024, 1792x1024, 1024x1792 等"`
|
||||
Quality string `json:"quality,omitempty" dc:"图片质量:standard, hd"`
|
||||
}
|
||||
|
||||
type PlaygroundImageRes struct {
|
||||
Images []PlaygroundImageData `json:"images"`
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
CompletionTokens int `json:"completion_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
EstimatedCost string `json:"estimated_cost"`
|
||||
}
|
||||
|
||||
type PlaygroundImageData struct {
|
||||
B64JSON string `json:"b64_json,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
RevisedPrompt string `json:"revised_prompt,omitempty"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Playground — 语音合成 (TTS)
|
||||
// ============================================================
|
||||
|
||||
type PlaygroundAudioTTSReq struct {
|
||||
g.Meta `path:"/playground/audio/tts" method:"post" mime:"json" tags:"租户控制台-Playground" summary:"Playground语音合成"`
|
||||
Model string `json:"model" v:"required#请选择模型" dc:"模型名称"`
|
||||
Input string `json:"input" v:"required#请输入文本" dc:"待合成文本"`
|
||||
Voice string `json:"voice" v:"required#请选择语音" dc:"语音类型:alloy, echo, fable, onyx, nova, shimmer"`
|
||||
ResponseFormat string `json:"response_format,omitempty" d:"mp3" dc:"输出格式:mp3, wav, opus, aac, flac"`
|
||||
}
|
||||
|
||||
type PlaygroundAudioTTSRes struct {
|
||||
AudioBase64 string `json:"audio_base64"`
|
||||
ContentType string `json:"content_type"`
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
CompletionTokens int `json:"completion_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
EstimatedCost string `json:"estimated_cost"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Playground — 文本嵌入
|
||||
// ============================================================
|
||||
|
||||
type PlaygroundEmbeddingReq struct {
|
||||
g.Meta `path:"/playground/embedding" method:"post" mime:"json" tags:"租户控制台-Playground" summary:"Playground文本嵌入"`
|
||||
Model string `json:"model" v:"required#请选择模型" dc:"模型名称"`
|
||||
Input string `json:"input" v:"required#请输入文本" dc:"待嵌入文本"`
|
||||
Dimensions *int `json:"dimensions,omitempty" dc:"嵌入维度"`
|
||||
}
|
||||
|
||||
type PlaygroundEmbeddingRes struct {
|
||||
Embeddings []PlaygroundEmbeddingData `json:"embeddings"`
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
EstimatedCost string `json:"estimated_cost"`
|
||||
}
|
||||
|
||||
type PlaygroundEmbeddingData struct {
|
||||
Index int `json:"index"`
|
||||
Embedding []float64 `json:"embedding"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Playground — 重排序
|
||||
// ============================================================
|
||||
|
||||
type PlaygroundRerankReq struct {
|
||||
g.Meta `path:"/playground/rerank" method:"post" mime:"json" tags:"租户控制台-Playground" summary:"Playground重排序"`
|
||||
Model string `json:"model" v:"required#请选择模型" dc:"模型名称"`
|
||||
Query string `json:"query" v:"required#请输入查询" dc:"查询文本"`
|
||||
Documents []string `json:"documents" v:"required|length:1,100#请输入文档|文档数量超出限制" dc:"待排序文档列表"`
|
||||
TopN *int `json:"top_n,omitempty" dc:"返回前 N 个结果"`
|
||||
}
|
||||
|
||||
type PlaygroundRerankRes struct {
|
||||
Results []PlaygroundRerankResult `json:"results"`
|
||||
PromptTokens int `json:"prompt_tokens"`
|
||||
TotalTokens int `json:"total_tokens"`
|
||||
EstimatedCost string `json:"estimated_cost"`
|
||||
}
|
||||
|
||||
type PlaygroundRerankResult struct {
|
||||
Index int `json:"index"`
|
||||
RelevanceScore float64 `json:"relevance_score"`
|
||||
Document *PlaygroundRerankDoc `json:"document,omitempty"`
|
||||
}
|
||||
|
||||
type PlaygroundRerankDoc struct {
|
||||
Text string `json:"text"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// Sandbox(模拟调用,不计费)
|
||||
// ============================================================
|
||||
|
||||
// SandboxChatReq Sandbox 对话请求
|
||||
type SandboxChatReq struct {
|
||||
g.Meta `path:"/sandbox/chat" method:"post" mime:"json" tags:"租户控制台-Playground" summary:"Sandbox模拟对话"`
|
||||
Model string `json:"model" v:"required#请选择模型" dc:"模型名称"`
|
||||
Messages []PlaygroundMessage `json:"messages" v:"required|length:1,50#请输入消息|消息数量超出限制" dc:"对话消息列表"`
|
||||
Temperature *float64 `json:"temperature" dc:"温度参数 (0-2)"`
|
||||
MaxTokens *int `json:"max_tokens" dc:"最大输出 Token 数"`
|
||||
Stream bool `json:"stream" d:"true" dc:"是否流式响应"`
|
||||
}
|
||||
|
||||
type SandboxChatRes struct {
|
||||
Content string `json:"content"`
|
||||
IsSandbox bool `json:"is_sandbox"`
|
||||
RemainingQuota int `json:"remaining_quota" dc:"本月剩余沙箱额度"`
|
||||
}
|
||||
|
||||
// SandboxQuotaReq 沙箱额度查询
|
||||
type SandboxQuotaReq struct {
|
||||
g.Meta `path:"/sandbox/quota" method:"get" tags:"租户控制台-Playground" summary:"查询沙箱额度"`
|
||||
}
|
||||
|
||||
type SandboxQuotaRes struct {
|
||||
TotalQuota int `json:"total_quota"`
|
||||
RemainingQuota int `json:"remaining_quota"`
|
||||
UsedQuota int `json:"used_quota"`
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// TenantPluginListReq 租户可用插件列表
|
||||
type TenantPluginListReq struct {
|
||||
g.Meta `path:"/plugins" method:"get" mime:"json" tags:"租户控制台-插件" summary:"租户可用插件列表"`
|
||||
}
|
||||
|
||||
type TenantPluginItem struct {
|
||||
Name string `json:"name"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
Category string `json:"category"`
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type TenantPluginListRes struct {
|
||||
List []TenantPluginItem `json:"list"`
|
||||
}
|
||||
|
||||
// TenantPluginDetailReq 租户插件详情
|
||||
type TenantPluginDetailReq struct {
|
||||
g.Meta `path:"/plugins/{name}" method:"get" mime:"json" tags:"租户控制台-插件" summary:"租户插件详情"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type TenantPluginDetailRes struct {
|
||||
Name string `json:"name"`
|
||||
Label string `json:"label"`
|
||||
Description string `json:"description"`
|
||||
Version string `json:"version"`
|
||||
Category string `json:"category"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Config g.Map `json:"config"`
|
||||
}
|
||||
|
||||
// TenantPluginConfigUpdateReq 租户级配置覆盖
|
||||
type TenantPluginConfigUpdateReq struct {
|
||||
g.Meta `path:"/plugins/{name}/config" method:"put" mime:"json" tags:"租户控制台-插件" summary:"租户级配置覆盖"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
Config g.Map `json:"config" v:"required" dc:"插件配置"`
|
||||
}
|
||||
|
||||
type TenantPluginConfigUpdateRes struct{}
|
||||
|
||||
// TenantPluginEnableReq 租户启用插件
|
||||
type TenantPluginEnableReq struct {
|
||||
g.Meta `path:"/plugins/{name}/enable" method:"post" mime:"json" tags:"租户控制台-插件" summary:"租户启用插件"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type TenantPluginEnableRes struct{}
|
||||
|
||||
// TenantPluginDisableReq 租户禁用插件
|
||||
type TenantPluginDisableReq struct {
|
||||
g.Meta `path:"/plugins/{name}/disable" method:"post" mime:"json" tags:"租户控制台-插件" summary:"租户禁用插件"`
|
||||
Name string `json:"name" in:"path" v:"required" dc:"插件标识"`
|
||||
}
|
||||
|
||||
type TenantPluginDisableRes struct{}
|
||||
@@ -0,0 +1,122 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户项目管理 ===
|
||||
|
||||
type TenantProjectListReq struct {
|
||||
g.Meta `path:"/projects" method:"get" mime:"json" tags:"租户控制台-项目" summary:"项目列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantProjectListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantProjectCreateReq struct {
|
||||
g.Meta `path:"/projects" method:"post" mime:"json" tags:"租户控制台-项目" summary:"创建项目"`
|
||||
Name string `json:"name" v:"required"`
|
||||
Description string `json:"description"`
|
||||
Budget float64 `json:"budget"`
|
||||
}
|
||||
|
||||
type TenantProjectCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type TenantProjectUpdateReq struct {
|
||||
g.Meta `path:"/projects/{id}" method:"put" mime:"json" tags:"租户控制台-项目" summary:"更新项目"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Budget float64 `json:"budget"`
|
||||
}
|
||||
|
||||
type TenantProjectUpdateRes struct{}
|
||||
|
||||
type TenantProjectArchiveReq struct {
|
||||
g.Meta `path:"/projects/{id}/archive" method:"post" mime:"json" tags:"租户控制台-项目" summary:"归档项目"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantProjectArchiveRes struct{}
|
||||
|
||||
type TenantProjectUnarchiveReq struct {
|
||||
g.Meta `path:"/projects/{id}/unarchive" method:"post" mime:"json" tags:"租户控制台-项目" summary:"取消归档"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantProjectUnarchiveRes struct{}
|
||||
|
||||
type TenantProjectGetReq struct {
|
||||
g.Meta `path:"/projects/{id}" method:"get" mime:"json" tags:"租户控制台-项目" summary:"项目详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantProjectGetRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
// === 项目子资源(owner/admin 权限) ===
|
||||
|
||||
type TenantProjectApiKeyListReq struct {
|
||||
g.Meta `path:"/projects/{id}/api-keys" method:"get" mime:"json" tags:"租户控制台-项目" summary:"项目密钥列表"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantProjectApiKeyListRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantProjectApiKeyCreateReq struct {
|
||||
g.Meta `path:"/projects/{id}/api-keys" method:"post" mime:"json" tags:"租户控制台-项目" summary:"项目密钥创建"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Name string `json:"name" v:"required"`
|
||||
Scope string `json:"scope" d:"full"`
|
||||
ExpiresInDays int `json:"expires_in_days"`
|
||||
ModelNames []string `json:"model_names"`
|
||||
}
|
||||
|
||||
type TenantProjectApiKeyCreateRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantProjectApiKeyDeleteReq struct {
|
||||
g.Meta `path:"/projects/{id}/api-keys/{keyId}" method:"delete" mime:"json" tags:"租户控制台-项目" summary:"项目密钥删除"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
KeyId int64 `json:"keyId" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantProjectApiKeyDeleteRes struct{}
|
||||
|
||||
type TenantProjectUsageStatsReq struct {
|
||||
g.Meta `path:"/projects/{id}/usage-stats" method:"get" mime:"json" tags:"租户控制台-项目" summary:"项目用量统计"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantProjectUsageStatsRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantProjectUsageLogsReq struct {
|
||||
g.Meta `path:"/projects/{id}/usage-logs" method:"get" mime:"json" tags:"租户控制台-项目" summary:"项目用量日志"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantProjectUsageLogsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 租户兑换码 / 优惠码 ===
|
||||
|
||||
type TenantRedeemCodeReq struct {
|
||||
g.Meta `path:"/redemptions/redeem" method:"post" mime:"json" tags:"租户控制台-优惠" summary:"兑换码"`
|
||||
Code string `json:"code" v:"required"`
|
||||
}
|
||||
|
||||
type TenantRedeemCodeRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantValidatePromoCodeReq struct {
|
||||
g.Meta `path:"/promo-codes/validate" method:"post" mime:"json" tags:"租户控制台-优惠" summary:"验证优惠码"`
|
||||
Code string `json:"code" v:"required"`
|
||||
Amount float64 `json:"amount"`
|
||||
}
|
||||
|
||||
type TenantValidatePromoCodeRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantRedemptionUsagesReq struct {
|
||||
g.Meta `path:"/redemptions/usages" method:"get" mime:"json" tags:"租户控制台-优惠" summary:"我的兑换历史"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantRedemptionUsageItem struct {
|
||||
Id int64 `json:"id"`
|
||||
RedemptionId int64 `json:"redemption_id"`
|
||||
Code string `json:"code"`
|
||||
Type string `json:"type"`
|
||||
Value float64 `json:"value"`
|
||||
TransactionId int64 `json:"transaction_id"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type TenantRedemptionUsagesRes struct {
|
||||
List []*TenantRedemptionUsageItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// ============================================================
|
||||
// 2FA 启用流程
|
||||
// ============================================================
|
||||
|
||||
// Tenant2FASetupReq 开启 2FA 设置(生成密钥和 QR Code)
|
||||
type Tenant2FASetupReq struct {
|
||||
g.Meta `path:"/security/2fa/setup" method:"post" mime:"json" tags:"租户控制台-安全" summary:"开启2FA设置"`
|
||||
}
|
||||
|
||||
type Tenant2FASetupRes struct {
|
||||
Secret string `json:"secret"`
|
||||
URI string `json:"uri"`
|
||||
}
|
||||
|
||||
// Tenant2FAEnableReq 确认启用 2FA
|
||||
type Tenant2FAEnableReq struct {
|
||||
g.Meta `path:"/security/2fa/enable" method:"post" mime:"json" tags:"租户控制台-安全" summary:"确认启用2FA"`
|
||||
Code string `json:"code" v:"required|length:6,6#请输入验证码|验证码为6位" dc:"TOTP 验证码"`
|
||||
Password string `json:"password" v:"required#请输入密码" dc:"当前密码(安全确认)"`
|
||||
}
|
||||
|
||||
type Tenant2FAEnableRes struct {
|
||||
BackupCodes []string `json:"backup_codes"`
|
||||
}
|
||||
|
||||
// Tenant2FADisableReq 禁用 2FA
|
||||
type Tenant2FADisableReq struct {
|
||||
g.Meta `path:"/security/2fa/disable" method:"post" mime:"json" tags:"租户控制台-安全" summary:"禁用2FA"`
|
||||
Code string `json:"code" v:"required#请输入验证码或恢复码" dc:"TOTP 验证码或恢复码"`
|
||||
}
|
||||
|
||||
type Tenant2FADisableRes struct{}
|
||||
|
||||
// Tenant2FARegenerateBackupCodesReq 重新生成备用恢复码
|
||||
type Tenant2FARegenerateBackupCodesReq struct {
|
||||
g.Meta `path:"/security/2fa/backup-codes" method:"post" mime:"json" tags:"租户控制台-安全" summary:"重新生成备用恢复码"`
|
||||
Code string `json:"code" v:"required#请输入验证码" dc:"TOTP 验证码"`
|
||||
}
|
||||
|
||||
type Tenant2FARegenerateBackupCodesRes struct {
|
||||
BackupCodes []string `json:"backup_codes"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 2FA 登录验证
|
||||
// ============================================================
|
||||
|
||||
// Tenant2FAVerifyReq 登录时 2FA 验证
|
||||
type Tenant2FAVerifyReq struct {
|
||||
g.Meta `path:"/auth/2fa/verify" method:"post" mime:"json" tags:"租户控制台-认证" summary:"2FA登录验证" group:"public" middleware:"-"`
|
||||
Provisional string `json:"provisional_token" v:"required#缺少临时令牌" dc:"登录时返回的临时令牌"`
|
||||
Code string `json:"code" v:"required#请输入验证码" dc:"TOTP 验证码或恢复码"`
|
||||
}
|
||||
|
||||
type Tenant2FAVerifyRes struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
ExpiresAt string `json:"expires_at"`
|
||||
Tenant struct {
|
||||
ID int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Code string `json:"code"`
|
||||
} `json:"tenant"`
|
||||
User struct {
|
||||
ID int64 `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Role string `json:"role"`
|
||||
} `json:"user"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 高风险操作二次验证
|
||||
// ============================================================
|
||||
|
||||
// Tenant2FAConfirmReq 高风险操作二次验证
|
||||
type Tenant2FAConfirmReq struct {
|
||||
g.Meta `path:"/security/2fa/confirm" method:"post" mime:"json" tags:"租户控制台-安全" summary:"高风险操作二次验证"`
|
||||
Code string `json:"code" v:"required#请输入验证码" dc:"TOTP 验证码"`
|
||||
}
|
||||
|
||||
type Tenant2FAConfirmRes struct {
|
||||
ConfirmToken string `json:"confirm_token"`
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// 登录历史
|
||||
// ============================================================
|
||||
|
||||
// TenantLoginHistoryReq 登录历史列表
|
||||
type TenantLoginHistoryReq struct {
|
||||
g.Meta `path:"/security/login-history" method:"get" tags:"租户控制台-安全" summary:"登录历史"`
|
||||
Page int `json:"page" in:"query" d:"1" dc:"页码"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20" dc:"每页数量"`
|
||||
}
|
||||
|
||||
type TenantLoginHistoryRes struct {
|
||||
List []TenantLoginHistoryItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantLoginHistoryItem struct {
|
||||
ID int64 `json:"id"`
|
||||
LoginMethod string `json:"login_method"`
|
||||
IpAddress string `json:"ip_address"`
|
||||
UserAgent string `json:"user_agent"`
|
||||
Location string `json:"location"`
|
||||
IsNewDevice bool `json:"is_new_device"`
|
||||
Success bool `json:"success"`
|
||||
FailReason string `json:"fail_reason"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// === 租户工单 ===
|
||||
|
||||
type TenantTicketCreateReq struct {
|
||||
g.Meta `path:"/tickets" method:"post" mime:"json" tags:"租户控制台-工单" summary:"创建工单"`
|
||||
Category string `json:"category" v:"required|in:billing,technical,feature_request,other"`
|
||||
Title string `json:"title" v:"required"`
|
||||
Description string `json:"description" v:"required"`
|
||||
Urgency string `json:"urgency" v:"required|in:low,normal,high,urgent"`
|
||||
}
|
||||
|
||||
type TenantTicketCreateRes struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type TenantTicketListReq struct {
|
||||
g.Meta `path:"/tickets" method:"get" mime:"json" tags:"租户控制台-工单" summary:"工单列表"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
Status string `json:"status" in:"query"`
|
||||
}
|
||||
|
||||
type TenantTicketItem struct {
|
||||
Id int64 `json:"id"`
|
||||
TenantId int64 `json:"tenant_id"`
|
||||
UserId int64 `json:"user_id"`
|
||||
Category string `json:"category"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
Urgency string `json:"urgency"`
|
||||
Status string `json:"status"`
|
||||
AssignedAdminId int64 `json:"assigned_admin_id"`
|
||||
AssignedAdminName string `json:"assigned_admin_name"`
|
||||
CreatedAt *gtime.Time `json:"created_at"`
|
||||
UpdatedAt *gtime.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type TenantTicketListRes struct {
|
||||
List []*TenantTicketItem `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
type TenantTicketGetReq struct {
|
||||
g.Meta `path:"/tickets/{id}" method:"get" mime:"json" tags:"租户控制台-工单" summary:"工单详情"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantTicketGetRes struct {
|
||||
Data map[string]any `json:"data"`
|
||||
}
|
||||
|
||||
type TenantTicketReplyReq struct {
|
||||
g.Meta `path:"/tickets/{id}/reply" method:"post" mime:"json" tags:"租户控制台-工单" summary:"回复工单"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
Content string `json:"content" v:"required"`
|
||||
}
|
||||
|
||||
type TenantTicketReplyRes struct{}
|
||||
|
||||
type TenantTicketCloseReq struct {
|
||||
g.Meta `path:"/tickets/{id}/close" method:"post" mime:"json" tags:"租户控制台-工单" summary:"关闭工单"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantTicketCloseRes struct{}
|
||||
|
||||
type TenantTicketReopenReq struct {
|
||||
g.Meta `path:"/tickets/{id}/reopen" method:"post" mime:"json" tags:"租户控制台-工单" summary:"重新打开工单"`
|
||||
Id int64 `json:"id" in:"path" v:"required|min:1"`
|
||||
}
|
||||
|
||||
type TenantTicketReopenRes struct{}
|
||||
|
||||
// TenantTicketExportReq 导出工单列表请求
|
||||
type TenantTicketExportReq struct {
|
||||
g.Meta `path:"/tickets/export" method:"get" mime:"json" tags:"租户控制台-工单" summary:"导出工单列表"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
Status string `json:"status" in:"query"`
|
||||
}
|
||||
|
||||
type TenantTicketExportRes struct{}
|
||||
@@ -0,0 +1,38 @@
|
||||
package v1
|
||||
|
||||
import "github.com/gogf/gf/v2/frame/g"
|
||||
|
||||
// === 租户钱包 ===
|
||||
|
||||
type TenantWalletReq struct {
|
||||
g.Meta `path:"/wallet" method:"get" mime:"json" tags:"租户控制台-钱包" summary:"钱包信息"`
|
||||
}
|
||||
|
||||
type TenantWalletRes struct {
|
||||
Balance float64 `json:"balance"`
|
||||
FrozenBalance float64 `json:"frozen_balance"`
|
||||
AvailableBalance float64 `json:"available_balance"`
|
||||
WarningThreshold float64 `json:"warning_threshold"`
|
||||
Currency string `json:"currency"`
|
||||
}
|
||||
|
||||
type TenantWalletTransactionsReq struct {
|
||||
g.Meta `path:"/wallet/transactions" method:"get" mime:"json" tags:"租户控制台-钱包" summary:"交易记录"`
|
||||
Page int `json:"page" in:"query" d:"1"`
|
||||
PageSize int `json:"page_size" in:"query" d:"20"`
|
||||
}
|
||||
|
||||
type TenantWalletTransactionsRes struct {
|
||||
List []map[string]any `json:"list"`
|
||||
Total int `json:"total"`
|
||||
Page int `json:"page"`
|
||||
PageSize int `json:"page_size"`
|
||||
}
|
||||
|
||||
// TenantWalletTransactionsExportReq 导出交易记录请求
|
||||
type TenantWalletTransactionsExportReq struct {
|
||||
g.Meta `path:"/wallet/transactions/export" method:"get" mime:"json" tags:"租户控制台-钱包" summary:"导出交易记录"`
|
||||
Format string `json:"format" in:"query" d:"csv" v:"in:csv,xlsx" dc:"导出格式:csv / xlsx"`
|
||||
}
|
||||
|
||||
type TenantWalletTransactionsExportRes struct{}
|
||||
Whitespace-only changes.
@@ -0,0 +1,99 @@
|
||||
module github.com/qianfree/team-api
|
||||
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.6
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.16
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.15
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.99.1
|
||||
github.com/cloudflare/ahocorasick v0.0.0-20240916140611-054963ec9396
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0
|
||||
github.com/gogf/gf/v2 v2.10.0
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/pquerna/otp v1.5.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/shirou/gopsutil/v3 v3.24.5
|
||||
github.com/stripe/stripe-go/v81 v81.4.0
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.73
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
github.com/wenlng/go-captcha-assets v1.0.7
|
||||
github.com/wenlng/go-captcha/v2 v2.0.5
|
||||
golang.org/x/crypto v0.50.0
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.5.0 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.9 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.22 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 // indirect
|
||||
github.com/aws/smithy-go v1.25.0 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/clbanning/mxj v1.8.4 // indirect
|
||||
github.com/clbanning/mxj/v2 v2.7.0 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha // indirect
|
||||
github.com/fatih/color v1.18.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
|
||||
github.com/magiconair/properties v1.8.10 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/mozillazg/go-httpheader v0.2.1 // indirect
|
||||
github.com/olekukonko/errors v1.1.0 // indirect
|
||||
github.com/olekukonko/ll v0.0.9 // indirect
|
||||
github.com/olekukonko/tablewriter v1.1.0 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/redis/go-redis/v9 v9.12.1 // indirect
|
||||
github.com/richardlehane/mscfb v1.0.6 // indirect
|
||||
github.com/richardlehane/msoleps v1.0.6 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tiendc/go-deepcopy v1.7.2 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/xuri/efp v0.0.1 // indirect
|
||||
github.com/xuri/excelize/v2 v2.10.1 // indirect
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 // indirect
|
||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||
go.opentelemetry.io/otel v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.40.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.40.0 // indirect
|
||||
golang.org/x/image v0.25.0 // indirect
|
||||
golang.org/x/net v0.52.0 // indirect
|
||||
golang.org/x/sys v0.43.0 // indirect
|
||||
golang.org/x/text v0.36.0 // indirect
|
||||
golang.org/x/time v0.15.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -0,0 +1,265 @@
|
||||
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
|
||||
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible h1:8psS8a+wKfiLt1iVDX79F7Y6wUM49Lcha2FMXt4UM8g=
|
||||
github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.6 h1:1AX0AthnBQzMx1vbmir3Y4WsnJgiydmnJjiLu+LvXOg=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.6/go.mod h1:dy0UzBIfwSeot4grGvY1AqFWN5zgziMmWGzysDnHFcQ=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.9 h1:adBsCIIpLbLmYnkQU+nAChU5yhVTvu5PerROm+/Kq2A=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.9/go.mod h1:uOYhgfgThm/ZyAuJGNQ5YgNyOlYfqnGpTHXvk3cpykg=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.16 h1:Q0iQ7quUgJP0F/SCRTieScnaMdXr9h/2+wze1u3cNeM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.16/go.mod h1:duCCnJEFqpt2RC6no1iK6q+8HpwOAkiUua0pY507dQc=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.15 h1:fyvgWTszojq8hEnMi8PPBTvZdTtEVmAVyo+NFLHBhH4=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.15/go.mod h1:gJiYyMOjNg8OEdRWOf3CrFQxM2a98qmrtjx1zuiQfB8=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22 h1:IOGsJ1xVWhsi+ZO7/NW8OuZZBtMJLZbk4P5HDjJO0jQ=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.22/go.mod h1:b+hYdbU+jGKfXE8kKM6g1+h+L/Go3vMvzlxBsiuGsxg=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22 h1:GmLa5Kw1ESqtFpXsx5MmC84QWa/ZrLZvlJGa2y+4kcQ=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.22/go.mod h1:6sW9iWm9DK9YRpRGga/qzrzNLgKpT2cIxb7Vo2eNOp0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22 h1:dY4kWZiSaXIzxnKlj17nHnBcXXBfac6UlsAx2qL6XrU=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.22/go.mod h1:KIpEUx0JuRZLO7U6cbV204cWAEco2iC3l061IxlwLtI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23 h1:FPXsW9+gMuIeKmz7j6ENWcWtBGTe1kH8r9thNt5Uxx4=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.23/go.mod h1:7J8iGMdRKk6lw2C+cMIphgAnT8uTwBwNOsGkyOCm80U=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8 h1:HtOTYcbVcGABLOVuPYaIihj6IlkqubBwFj10K5fxRek=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.8/go.mod h1:VsK9abqQeGlzPgUr+isNWzPlK2vKe9INMLWnY65f5Xs=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.14 h1:xnvDEnw+pnj5mctWiYuFbigrEzSm35x7k4KS/ZkCANg=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.14/go.mod h1:yS5rNogD8e0Wu9+l3MUwr6eENBzEeGejvINpN5PAYfY=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22 h1:PUmZeJU6Y1Lbvt9WFuJ0ugUK2xn6hIWUBBbKuOWF30s=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.22/go.mod h1:nO6egFBoAaoXze24a2C0NjQCvdpk8OueRoYimvEB9jo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.22 h1:SE+aQ4DEqG53RRCAIHlCf//B2ycxGH7jFkpnAh/kKPM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.22/go.mod h1:ES3ynECd7fYeJIL6+oax+uIEljmfps0S70BaQzbMd/o=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.99.1 h1:kU/eBN5+MWNo/LcbNa4hWDdN76hdcd7hocU5kvu7IsU=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.99.1/go.mod h1:Fw9aqhJicIVee1VytBBjH+l+5ov6/PhbtIK/u3rt/ls=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.10 h1:a1Fq/KXn75wSzoJaPQTgZO0wHGqE9mjFnylnqEPTchA=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.10/go.mod h1:p6+MXNxW7IA6dMgHfTAzljuwSKD0NCm/4lbS4t6+7vI=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.16 h1:x6bKbmDhsgSZwv6q19wY/u3rLk/3FGjJWyqKcIRufpE=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.16/go.mod h1:CudnEVKRtLn0+3uMV0yEXZ+YZOKnAtUJ5DmDhilVnIw=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20 h1:oK/njaL8GtyEihkWMD4k3VgHCT64RQKkZwh0DG5j8ak=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.35.20/go.mod h1:JHs8/y1f3zY7U5WcuzoJ/yAYGYtNIVPKLIbp61euvmg=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.0 h1:ks8KBcZPh3PYISr5dAiXCM5/Thcuxk8l+PG4+A0exds=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.42.0/go.mod h1:pFw33T0WLvXU3rw1WBkpMlkgIn54eCB5FYLhjDc9Foo=
|
||||
github.com/aws/smithy-go v1.25.0 h1:Sz/XJ64rwuiKtB6j98nDIPyYrV1nVNJ4YU74gttcl5U=
|
||||
github.com/aws/smithy-go v1.25.0/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
|
||||
github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
|
||||
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
|
||||
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
|
||||
github.com/cloudflare/ahocorasick v0.0.0-20240916140611-054963ec9396 h1:W2HK1IdCnCGuLUeyizSCkwvBjdj0ZL7mxnJYQ3poyzI=
|
||||
github.com/cloudflare/ahocorasick v0.0.0-20240916140611-054963ec9396/go.mod h1:tGWUZLZp9ajsxUOnHmFFLnqnlKXsCn6GReG4jAD59H0=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha h1:dwFlh8pBg1VMOXWGipNMRt8v96dKAIvBehtCt6OtunU=
|
||||
github.com/emirpasic/gods/v2 v2.0.0-alpha/go.mod h1:W0y4M2dtBB9U5z3YlghmpuUhiaZT2h6yoeE+C1sCp6A=
|
||||
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
|
||||
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0 h1:39+jbTenm7KBj4hO2C8ANAxVHpX/7OuRDs1VcGC9ylA=
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.10.0/go.mod h1:B0s0fVzn0W220E8UTpSGzrrGKsop5KcB90twBeLCiz0=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0 h1:N/F9CuDdUZLoM1nVRqrDE/33pDZuhVxpNY4wYdeIaBs=
|
||||
github.com/gogf/gf/contrib/nosql/redis/v2 v2.10.0/go.mod h1:x6uoJGfZOtirIRQls8xUlYzC6f7T/eULPUa9er368X0=
|
||||
github.com/gogf/gf/v2 v2.10.0 h1:rzDROlyqGMe/eM6dCalSR8dZOuMIdLhmxKSH1DGhbFs=
|
||||
github.com/gogf/gf/v2 v2.10.0/go.mod h1:Svl1N+E8G/QshU2DUbh/3J/AJauqCgUnxHurXWR4Qx0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
|
||||
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
|
||||
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
|
||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs=
|
||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mozillazg/go-httpheader v0.2.1 h1:geV7TrjbL8KXSyvghnFm+NyTux/hxwueTSrwhe88TQQ=
|
||||
github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60=
|
||||
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
|
||||
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
|
||||
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
|
||||
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
|
||||
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
|
||||
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
|
||||
github.com/pquerna/otp v1.5.0 h1:NMMR+WrmaqXU4EzdGJEE1aUUI0AMRzsp96fFFWNPwxs=
|
||||
github.com/pquerna/otp v1.5.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||
github.com/redis/go-redis/v9 v9.12.1 h1:k5iquqv27aBtnTm2tIkROUDp8JBXhXZIVu1InSgvovg=
|
||||
github.com/redis/go-redis/v9 v9.12.1/go.mod h1:huWgSWd8mW6+m0VPhJjSSQ+d6Nh1VICQ6Q5lHuCH/Iw=
|
||||
github.com/richardlehane/mscfb v1.0.6 h1:eN3bvvZCp00bs7Zf52bxNwAx5lJDBK1tCuH19qq5aC8=
|
||||
github.com/richardlehane/mscfb v1.0.6/go.mod h1:pe0+IUIc0AHh0+teNzBlJCtSyZdFOGgV4ZK9bsoV+Jo=
|
||||
github.com/richardlehane/msoleps v1.0.6 h1:9BvkpjvD+iUBalUY4esMwv6uBkfOip/Lzvd93jvR9gg=
|
||||
github.com/richardlehane/msoleps v1.0.6/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/rs/dnscache v0.0.0-20230804202142-fc85eb664529/go.mod h1:qe5TWALJ8/a1Lqznoc5BDHpYX/8HU60Hm2AwRmqzxqA=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
|
||||
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
|
||||
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
|
||||
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
|
||||
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
|
||||
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/stripe/stripe-go/v81 v81.4.0 h1:AuD9XzdAvl193qUCSaLocf8H+nRopOouXhxqJUzCLbw=
|
||||
github.com/stripe/stripe-go/v81 v81.4.0/go.mod h1:C/F4jlmnGNacvYtBp/LUHCvVUJEZffFQCobkzwY1WOo=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.563/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.563/go.mod h1:uom4Nvi9W+Qkom0exYiJ9VWJjXwyxtPYTkKkaLMlfE0=
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.73 h1:uFfgp1A7cQaAGR6QP9DsIkoEQ67b8ewj5r1RV6XB540=
|
||||
github.com/tencentyun/cos-go-sdk-v5 v0.7.73/go.mod h1:STbTNaNKq03u+gscPEGOahKzLcGSYOj6Dzc5zNay7Pg=
|
||||
github.com/tencentyun/qcloud-cos-sts-sdk v0.0.0-20250515025012-e0eec8a5d123/go.mod h1:b18KQa4IxHbxeseW1GcZox53d7J0z39VNONTxvvlkXw=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
|
||||
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/tiendc/go-deepcopy v1.7.2 h1:Ut2yYR7W9tWjTQitganoIue4UGxZwCcJy3orjrrIj44=
|
||||
github.com/tiendc/go-deepcopy v1.7.2/go.mod h1:4bKjNC2r7boYOkD2IOuZpYjmlDdzjbpTRyCx+goBCJQ=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
|
||||
github.com/wenlng/go-captcha-assets v1.0.7 h1:tfF84A4un/i4p+TbRVHDqDPeQeatvddOfB2xbKvLVq8=
|
||||
github.com/wenlng/go-captcha-assets v1.0.7/go.mod h1:zinRACsdYcL/S6pHgI9Iv7FKTU41d00+43pNX+b9+MM=
|
||||
github.com/wenlng/go-captcha/v2 v2.0.5 h1:+1FpVwJZmLCqEHxOt+HvpUArFGo107nRxOeRVHkZhTc=
|
||||
github.com/wenlng/go-captcha/v2 v2.0.5/go.mod h1:5hac1em3uXoyC5ipZ0xFv9umNM/waQvYAQdr0cx/h34=
|
||||
github.com/xuri/efp v0.0.1 h1:fws5Rv3myXyYni8uwj2qKjVaRP30PdjeYe2Y6FDsCL8=
|
||||
github.com/xuri/efp v0.0.1/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI=
|
||||
github.com/xuri/excelize/v2 v2.10.1 h1:V62UlqopMqha3kOpnlHy2CcRVw1V8E63jFoWUmMzxN0=
|
||||
github.com/xuri/excelize/v2 v2.10.1/go.mod h1:iG5tARpgaEeIhTqt3/fgXCGoBRt4hNXgCp3tfXKoOIc=
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9 h1:+C0TIdyyYmzadGaL/HBLbf3WdLgC29pgyhTjAT/0nuE=
|
||||
github.com/xuri/nfp v0.0.2-0.20250530014748-2ddeb826f9a9/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms=
|
||||
go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g=
|
||||
go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g=
|
||||
go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||
go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw=
|
||||
go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
|
||||
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=
|
||||
golang.org/x/image v0.16.0 h1:9kloLAKhUufZhA12l5fwnx2NZW39/we1UhBesW433jw=
|
||||
golang.org/x/image v0.16.0/go.mod h1:ugSZItdV4nOxyqp56HmXwH0Ry0nBCpjnZdpDaIHdoPs=
|
||||
golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
|
||||
golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
|
||||
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg=
|
||||
golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
# CLI tool configuration, only used in development environment.
|
||||
# https://goframe.org/docs/cli
|
||||
gfcli:
|
||||
gen:
|
||||
dao:
|
||||
- link: "pgsql:<user>:<password>@tcp(<host>:<port>)/<database>"
|
||||
type: "pgsql"
|
||||
tables: ""
|
||||
tablesEx: ""
|
||||
prefix: ""
|
||||
removePrefix: ""
|
||||
descriptionTag: true
|
||||
noModelComment: false
|
||||
fieldTag: "json,cbor,yaml,xml,toml"
|
||||
jsonCase: "SnakeCase"
|
||||
path: "./"
|
||||
modelPath: "./internal/model"
|
||||
daoPath: "./internal/dao"
|
||||
doPath: "./internal/model/do"
|
||||
entityPath: "./internal/model/entity"
|
||||
ctrl:
|
||||
- apiPath: "./api"
|
||||
outPath: "./internal/controller"
|
||||
withService: true
|
||||
withModel: false
|
||||
|
||||
docker:
|
||||
build: "-a amd64 -s linux -p temp -ew"
|
||||
tagPrefixes:
|
||||
- team-api
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
# Install/Update to the latest CLI tool.
|
||||
.PHONY: cli
|
||||
cli:
|
||||
@set -e; \
|
||||
wget -O gf \
|
||||
https://github.com/gogf/gf/releases/latest/download/gf_$(shell go env GOOS)_$(shell go env GOARCH) && \
|
||||
chmod +x gf && \
|
||||
./gf install -y && \
|
||||
rm ./gf
|
||||
|
||||
|
||||
# Check and install CLI tool.
|
||||
.PHONY: cli.install
|
||||
cli.install:
|
||||
@set -e; \
|
||||
gf -v > /dev/null 2>&1 || if [[ "$?" -ne "0" ]]; then \
|
||||
echo "GoFame CLI is not installed, start proceeding auto installation..."; \
|
||||
make cli; \
|
||||
fi;
|
||||
@@ -0,0 +1,75 @@
|
||||
.DEFAULT_GOAL := build
|
||||
|
||||
# Update GoFrame and its CLI to latest stable version.
|
||||
.PHONY: up
|
||||
up: cli.install
|
||||
@gf up -a
|
||||
|
||||
# Build binary using configuration from hack/config.yaml.
|
||||
.PHONY: build
|
||||
build: cli.install
|
||||
@gf build -ew
|
||||
|
||||
# Parse api and generate controller/sdk.
|
||||
.PHONY: ctrl
|
||||
ctrl: cli.install
|
||||
@gf gen ctrl
|
||||
|
||||
# Generate Go files for DAO/DO/Entity.
|
||||
.PHONY: dao
|
||||
dao: cli.install
|
||||
@gf gen dao
|
||||
|
||||
# Parse current project go files and generate enums go file.
|
||||
.PHONY: enums
|
||||
enums: cli.install
|
||||
@gf gen enums
|
||||
|
||||
# Generate Go files for Service.
|
||||
.PHONY: service
|
||||
service: cli.install
|
||||
@gf gen service
|
||||
|
||||
|
||||
# Build docker image.
|
||||
.PHONY: image
|
||||
image: cli.install
|
||||
$(eval _TAG = $(shell git rev-parse --short HEAD))
|
||||
ifneq (, $(shell git status --porcelain 2>/dev/null))
|
||||
$(eval _TAG = $(_TAG).dirty)
|
||||
endif
|
||||
$(eval _TAG = $(if ${TAG}, ${TAG}, $(_TAG)))
|
||||
$(eval _PUSH = $(if ${PUSH}, ${PUSH}, ))
|
||||
@gf docker ${_PUSH} -tn $(DOCKER_NAME):${_TAG};
|
||||
|
||||
|
||||
# Build docker image and automatically push to docker repo.
|
||||
.PHONY: image.push
|
||||
image.push: cli.install
|
||||
@make image PUSH=-p;
|
||||
|
||||
|
||||
# Deploy image and yaml to current kubectl environment.
|
||||
.PHONY: deploy
|
||||
deploy: cli.install
|
||||
$(eval _TAG = $(if ${TAG}, ${TAG}, develop))
|
||||
|
||||
@set -e; \
|
||||
mkdir -p $(ROOT_DIR)/temp/kustomize;\
|
||||
cd $(ROOT_DIR)/manifest/deploy/kustomize/overlays/${_ENV};\
|
||||
kustomize build > $(ROOT_DIR)/temp/kustomize.yaml;\
|
||||
kubectl apply -f $(ROOT_DIR)/temp/kustomize.yaml; \
|
||||
if [ $(DEPLOY_NAME) != "" ]; then \
|
||||
kubectl patch -n $(NAMESPACE) deployment/$(DEPLOY_NAME) -p "{\"spec\":{\"template\":{\"metadata\":{\"labels\":{\"date\":\"$(shell date +%s)\"}}}}}"; \
|
||||
fi;
|
||||
|
||||
|
||||
# Parsing protobuf files and generating go files.
|
||||
.PHONY: pb
|
||||
pb: cli.install
|
||||
@gf gen pb
|
||||
|
||||
# Generate protobuf files for database tables.
|
||||
.PHONY: pbentity
|
||||
pbentity: cli.install
|
||||
@gf gen pbentity
|
||||
@@ -0,0 +1,367 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
|
||||
"github.com/qianfree/team-api/internal/consts"
|
||||
adminController "github.com/qianfree/team-api/internal/controller/admin"
|
||||
captchaController "github.com/qianfree/team-api/internal/controller/captcha"
|
||||
docsController "github.com/qianfree/team-api/internal/controller/docs"
|
||||
openController "github.com/qianfree/team-api/internal/controller/open"
|
||||
settingsController "github.com/qianfree/team-api/internal/controller/settings"
|
||||
tenantController "github.com/qianfree/team-api/internal/controller/tenant"
|
||||
"github.com/qianfree/team-api/internal/logic/admin"
|
||||
"github.com/qianfree/team-api/internal/logic/common"
|
||||
"github.com/qianfree/team-api/internal/logic/monitor"
|
||||
"github.com/qianfree/team-api/internal/logic/task"
|
||||
"github.com/qianfree/team-api/internal/logic/tenant"
|
||||
"github.com/qianfree/team-api/internal/middleware"
|
||||
"github.com/qianfree/team-api/internal/response"
|
||||
|
||||
"github.com/qianfree/team-api/internal/handler/public"
|
||||
"github.com/qianfree/team-api/internal/handler/relay"
|
||||
setupHandler "github.com/qianfree/team-api/internal/handler/setup"
|
||||
wsHandler "github.com/qianfree/team-api/internal/handler/ws"
|
||||
"github.com/qianfree/team-api/internal/plugin"
|
||||
)
|
||||
|
||||
var (
|
||||
Main = gcmd.Command{
|
||||
Name: "main",
|
||||
Usage: "main",
|
||||
Brief: "start http server of team-api",
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
s := g.Server()
|
||||
|
||||
printBanner()
|
||||
|
||||
// Initialize JWT secret
|
||||
common.InitJWTSecret(ctx)
|
||||
|
||||
// System initialization: env auto-init or detect setup mode
|
||||
autoInit, initErr := admin.AutoInitAdmin(ctx)
|
||||
if initErr != nil {
|
||||
g.Log().Errorf(ctx, "auto init admin: %v", initErr)
|
||||
}
|
||||
if !autoInit {
|
||||
exists, checkErr := admin.AdminExists(ctx)
|
||||
if checkErr != nil {
|
||||
g.Log().Errorf(ctx, "check admin existence: %v", checkErr)
|
||||
} else if !exists {
|
||||
setupHandler.SetSetupMode(true)
|
||||
g.Log().Info(ctx, "系统未初始化,进入设置模式 — 请访问 /setup 完成初始化")
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize config service
|
||||
common.Config().Warmup(ctx)
|
||||
common.Config().StartSubscriber(ctx)
|
||||
|
||||
// Initialize content filter engine
|
||||
common.InitContentFilter(ctx)
|
||||
|
||||
// Initialize WebSocket hub and broker
|
||||
wsHub := wsHandler.InitHub(ctx)
|
||||
go wsHub.Run(ctx)
|
||||
wsHandler.InitWsBroker(ctx)
|
||||
|
||||
// Initialize monitoring collector
|
||||
monitor.InitCollector(ctx)
|
||||
monitor.InitRequestTracker()
|
||||
go monitor.StartMonitorPusher(ctx)
|
||||
|
||||
// Ensure partitioned tables have current+future partitions
|
||||
if partitionErr := common.EnsurePartitions(ctx); partitionErr != nil {
|
||||
g.Log().Errorf(ctx, "ensure partitions: %v", partitionErr)
|
||||
}
|
||||
|
||||
// Initialize async usage log writer
|
||||
common.InitUsageLogWriter()
|
||||
|
||||
// Initialize async error log writer
|
||||
response.InitErrorLogWriter()
|
||||
|
||||
// Register cron jobs
|
||||
common.InitCronScheduler()
|
||||
cs := common.GetCronScheduler()
|
||||
cs.Register("ops_system_collector", "* * * * *", func(ctx context.Context) error {
|
||||
return monitor.CollectSystemMetrics(ctx)
|
||||
})
|
||||
cs.Register("ops_alert_detector", "* * * * *", func(ctx context.Context) error {
|
||||
return monitor.RunAlertDetection(ctx)
|
||||
})
|
||||
cs.Register("ops_metrics_cleanup", "0 3 * * *", func(ctx context.Context) error {
|
||||
return monitor.CleanupOldMetrics(ctx)
|
||||
})
|
||||
cs.Register("partition_ensure", "0 2 * * *", func(ctx context.Context) error {
|
||||
return common.EnsurePartitions(ctx)
|
||||
})
|
||||
cs.Register("health_snapshot", "*/5 * * * *", func(ctx context.Context) error {
|
||||
return task.SnapshotHealthScores(ctx)
|
||||
})
|
||||
cs.Register("channel_auto_test", "*/5 * * * *", func(ctx context.Context) error {
|
||||
task.AutoTestChannels(ctx)
|
||||
return nil
|
||||
})
|
||||
cs.Register("model_sunset_check", "0 0 * * *", func(ctx context.Context) error {
|
||||
return task.CheckModelSunset(ctx)
|
||||
})
|
||||
cs.Register("data_cleanup", "0 3 * * *", func(ctx context.Context) error {
|
||||
return admin.CleanupExpiredData(ctx)
|
||||
})
|
||||
cs.Register("export_file_cleanup", "0 4 * * *", func(ctx context.Context) error {
|
||||
return admin.CleanupExpiredExportFiles(ctx)
|
||||
})
|
||||
cs.Register("file_retention_check", "0 5 * * *", func(ctx context.Context) error {
|
||||
return admin.CheckFileRetention(ctx)
|
||||
})
|
||||
cs.Register("task_timeout_check", "*/10 * * * *", func(ctx context.Context) error {
|
||||
return admin.MarkStuckTasksFailed(ctx)
|
||||
})
|
||||
cs.Register("task_executor", "*/1 * * * *", func(ctx context.Context) error {
|
||||
task.RunPendingTasks(ctx)
|
||||
return nil
|
||||
})
|
||||
cs.Register("usage_log_cleanup", "0 3 * * *", func(ctx context.Context) error {
|
||||
retentionDays := common.Config().GetInt(ctx, "usage_log_retention_days")
|
||||
if retentionDays == 0 {
|
||||
retentionDays = 90
|
||||
}
|
||||
return task.ScheduleAutoCleanup(ctx, retentionDays)
|
||||
})
|
||||
cs.Register("oauth_token_refresh", "*/10 * * * *", func(ctx context.Context) error {
|
||||
return task.RefreshExpiringOAuthTokens(ctx)
|
||||
})
|
||||
cs.Register("cron_execution_cleanup", "30 3 * * *", func(ctx context.Context) error {
|
||||
retentionDays := common.Config().GetInt(ctx, "cron_execution_retention_days")
|
||||
if retentionDays == 0 {
|
||||
retentionDays = 30
|
||||
}
|
||||
_, err := g.DB().Ctx(ctx).Exec(ctx,
|
||||
"DELETE FROM sys_cron_job_executions WHERE created_at < NOW() - ($1 || ' days')::interval",
|
||||
retentionDays,
|
||||
)
|
||||
return err
|
||||
})
|
||||
cs.StartBackground(ctx)
|
||||
|
||||
// Initialize plugin system (must be after CronScheduler init)
|
||||
pluginApp := &plugin.App{
|
||||
Server: s,
|
||||
DB: g.DB(),
|
||||
Redis: g.Redis(),
|
||||
Hook: plugin.GlobalEmitter(),
|
||||
}
|
||||
if pluginErr := plugin.Bootstrap(ctx, pluginApp); pluginErr != nil {
|
||||
g.Log().Errorf(ctx, "plugin bootstrap: %v", pluginErr)
|
||||
}
|
||||
|
||||
// Global middleware
|
||||
s.Use(middleware.Recovery)
|
||||
s.Use(middleware.RequestId)
|
||||
|
||||
// Setup mode guard: block all requests until initialization is complete
|
||||
s.Use(func(r *ghttp.Request) {
|
||||
if !setupHandler.IsSetupMode() {
|
||||
r.Middleware.Next()
|
||||
return
|
||||
}
|
||||
// Double-check DB in case setup was completed by another request/instance
|
||||
exists, _ := admin.AdminExists(r.Context())
|
||||
if exists {
|
||||
setupHandler.SetSetupComplete()
|
||||
r.Middleware.Next()
|
||||
return
|
||||
}
|
||||
// Allow setup endpoints
|
||||
if r.URL.Path == "/setup" || r.URL.Path == "/api/setup/initialize" || r.URL.Path == "/api/setup/status" {
|
||||
r.Middleware.Next()
|
||||
return
|
||||
}
|
||||
// Block everything else
|
||||
accept := r.Header.Get("Accept")
|
||||
if len(accept) >= 4 && accept[:4] == "text" {
|
||||
r.Response.RedirectTo("/setup")
|
||||
} else {
|
||||
r.Response.WriteJson(g.Map{
|
||||
"code": consts.CodeSetupNotInitialized,
|
||||
"message": consts.MsgSetupNotInitialized,
|
||||
"data": nil,
|
||||
"request_id": r.GetCtxVar("RequestId"),
|
||||
})
|
||||
}
|
||||
r.Exit()
|
||||
})
|
||||
|
||||
// Setup routes (always registered, guard decides if accessible)
|
||||
s.Group("/", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/setup", setupHandler.HandleSetupPage)
|
||||
})
|
||||
s.Group("/api/setup", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(middleware.ErrorHandler)
|
||||
group.GET("/status", setupHandler.HandleSetupStatus)
|
||||
group.POST("/initialize", setupHandler.HandleSetupInitialize)
|
||||
})
|
||||
|
||||
// WebSocket endpoints — 独立于 MiddlewareHandlerResponse,避免升级后中间件干扰
|
||||
s.Group("/api/admin", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(middleware.AdminAuth)
|
||||
g.GET("/ws", wsHandler.HandleAdminWS)
|
||||
})
|
||||
s.Group("/api/tenant", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(middleware.MaintenanceMode, middleware.TenantAuth)
|
||||
g.GET("/ws", wsHandler.HandleTenantWS)
|
||||
})
|
||||
|
||||
// Register route groups
|
||||
s.Group("/api", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(middleware.MiddlewareHandlerResponse)
|
||||
|
||||
// Admin — public endpoints use g.Meta middleware:"-" to skip auth
|
||||
group.Group("/admin", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(middleware.DemoMode, middleware.AdminAuth, middleware.OperationLog)
|
||||
g.Bind(adminController.NewV1())
|
||||
})
|
||||
|
||||
// Tenant — public endpoints use g.Meta middleware:"-" to skip auth
|
||||
group.Group("/tenant", func(g *ghttp.RouterGroup) {
|
||||
g.Middleware(middleware.DemoMode, middleware.MaintenanceMode, middleware.TenantAuth)
|
||||
g.Bind(tenantController.NewV1())
|
||||
})
|
||||
|
||||
// Payment callbacks — manual registration (raw string response, not JSON)
|
||||
group.Middleware(middleware.ErrorHandler)
|
||||
registerPaymentCallbacks(group)
|
||||
|
||||
// Captcha — public, no auth required (shared by admin + tenant)
|
||||
group.Group("/captcha", func(g *ghttp.RouterGroup) {
|
||||
g.Bind(captchaController.NewV1())
|
||||
})
|
||||
// Settings — public settings, no auth required
|
||||
group.Group("/settings", func(g *ghttp.RouterGroup) {
|
||||
g.Bind(settingsController.NewV1())
|
||||
})
|
||||
|
||||
// Docs — public OpenAPI spec
|
||||
group.Group("/docs", func(g *ghttp.RouterGroup) {
|
||||
g.Bind(docsController.NewV1())
|
||||
})
|
||||
})
|
||||
|
||||
// Open Platform API — HMAC-SHA256 authentication
|
||||
s.Group("/api/open", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(middleware.MiddlewareHandlerResponse)
|
||||
group.Middleware(middleware.OpenPlatformAuth)
|
||||
group.Bind(openController.NewV1())
|
||||
})
|
||||
|
||||
// AI proxy endpoints (OpenAI compatible, /v1/xxx)
|
||||
registerRelayRoutes(s)
|
||||
|
||||
// Register plugin routes
|
||||
plugin.RegisterAllRoutes(ctx, s)
|
||||
|
||||
// Initialize active task count and start polling
|
||||
task.InitActiveCount(ctx)
|
||||
go task.StartAsyncPolling(ctx)
|
||||
|
||||
// Start webhook dispatcher (event-driven delivery)
|
||||
tenant.InitWebhookDispatcher(ctx)
|
||||
|
||||
// Flush usage log writer on shutdown (s.Run blocks until server stops)
|
||||
defer plugin.Shutdown(ctx)
|
||||
defer common.CloseUsageLogWriter()
|
||||
defer response.CloseErrorLogWriter()
|
||||
defer wsHandler.Shutdown()
|
||||
|
||||
s.Run()
|
||||
return nil
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// printBanner prints the startup banner with copyright information.
|
||||
func printBanner() {
|
||||
cyan := "\x1b[36;1m"
|
||||
green := "\x1b[32m"
|
||||
yellow := "\x1b[33m"
|
||||
dim := "\x1b[2m"
|
||||
reset := "\x1b[0m"
|
||||
|
||||
fmt.Println()
|
||||
fmt.Printf(" %s████████╗███████╗ █████╗ ███╗ ███╗ █████╗ ██████╗ ██╗%s\n", cyan, reset)
|
||||
fmt.Printf(" %s╚══██╔══╝██╔════╝██╔══██╗████╗ ████║ ██╔══██╗██╔══██╗██║%s\n", cyan, reset)
|
||||
fmt.Printf(" %s ██║ █████╗ ███████║██╔████╔██║█████╗███████║██████╔╝██║%s\n", cyan, reset)
|
||||
fmt.Printf(" %s ██║ ██╔══╝ ██╔══██║██║╚██╔╝██║╚════╝██╔══██║██╔═══╝ ██║%s\n", cyan, reset)
|
||||
fmt.Printf(" %s ██║ ███████╗██║ ██║██║ ╚═╝ ██║ ██║ ██║██║ ██║%s\n", cyan, reset)
|
||||
fmt.Printf(" %s ╚═╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝%s\n", cyan, reset)
|
||||
fmt.Println()
|
||||
fmt.Printf(" %sTeam-API%s %sv0.1.0%s\n", cyan, reset, green, reset)
|
||||
fmt.Printf(" %sMulti-tenant AI API Gateway%s\n", dim, reset)
|
||||
fmt.Println()
|
||||
fmt.Printf(" %sLicensed under GNU AGPL v3.0%s\n", yellow, reset)
|
||||
fmt.Printf(" %sCopyright © 2025-2026 Team-API Contributors%s\n", dim, reset)
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
// registerPaymentCallbacks registers payment callback routes.
|
||||
func registerPaymentCallbacks(group *ghttp.RouterGroup) {
|
||||
group.Group("/payment", func(g *ghttp.RouterGroup) {
|
||||
g.POST("/callback/{channel_id}", public.HandlePaymentCallback)
|
||||
g.GET("/callback/{channel_id}", public.HandlePaymentCallback)
|
||||
g.GET("/epay/return/{channel_id}", public.HandlePaymentEpayReturn)
|
||||
g.POST("/stripe/webhook/{channel_id}", public.HandlePaymentStripeWebhook)
|
||||
})
|
||||
}
|
||||
|
||||
// registerRelayRoutes registers AI proxy routes (/v1/xxx).
|
||||
func registerRelayRoutes(server *ghttp.Server) {
|
||||
server.Group("/v1", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(middleware.ApiMaintenance, middleware.MaintenanceMode, middleware.ApiKeyAuth, middleware.ContentFilter)
|
||||
|
||||
group.POST("/chat/completions", relay.HandleChatCompletions)
|
||||
group.GET("/models", relay.HandleModels)
|
||||
group.GET("/models/{model_id}", relay.HandleModelDetail)
|
||||
group.POST("/embeddings", relay.HandleEmbeddings)
|
||||
group.POST("/images/generations", relay.HandleImagesGenerations)
|
||||
group.POST("/completions", relay.HandleCompletions)
|
||||
group.POST("/responses", relay.HandleResponses)
|
||||
group.POST("/responses/compact", relay.HandleResponses)
|
||||
group.POST("/messages", relay.HandleMessages)
|
||||
group.POST("/audio/speech", relay.HandleAudioSpeech)
|
||||
group.POST("/audio/transcriptions", relay.HandleAudioTranscription)
|
||||
group.POST("/audio/translations", relay.HandleAudioTranslation)
|
||||
group.POST("/rerank", relay.HandleRerank)
|
||||
group.POST("/moderations", relay.HandleModerations)
|
||||
group.POST("/images/edits", relay.HandleImagesEdits)
|
||||
group.GET("/realtime", relay.HandleRealtime)
|
||||
})
|
||||
|
||||
// Gemini 兼容路由(/v1beta/models/{model}:generateContent)
|
||||
server.Group("/v1beta", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(middleware.ApiMaintenance, middleware.MaintenanceMode, middleware.ApiKeyAuth, middleware.ContentFilter)
|
||||
group.GET("/models", relay.HandleGeminiModels)
|
||||
group.GET("/models/{model}", relay.HandleGeminiModelDetail)
|
||||
group.POST("/models/{model}", relay.HandleGeminiGenerateContent)
|
||||
})
|
||||
|
||||
// 异步任务端点(视频/音乐生成)
|
||||
server.Group("/v1", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(middleware.ApiMaintenance, middleware.MaintenanceMode, middleware.ApiKeyAuth, middleware.ContentFilter)
|
||||
group.POST("/video/generations", relay.HandleTaskSubmit)
|
||||
group.GET("/video/generations/{task_id}", relay.HandleTaskFetch)
|
||||
})
|
||||
|
||||
// Suno 端点
|
||||
server.Group("/suno", func(group *ghttp.RouterGroup) {
|
||||
group.Middleware(middleware.ApiMaintenance, middleware.MaintenanceMode, middleware.ApiKeyAuth, middleware.ContentFilter)
|
||||
group.POST("/submit/{action}", relay.HandleTaskSubmit)
|
||||
group.POST("/fetch", relay.HandleSunoFetchBatch)
|
||||
group.GET("/fetch/{task_id}", relay.HandleTaskFetch)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
|
||||
"github.com/qianfree/team-api/internal/dao"
|
||||
"github.com/qianfree/team-api/internal/logic/common"
|
||||
"github.com/qianfree/team-api/internal/utility/crypto"
|
||||
)
|
||||
|
||||
var resetPwdCmd = gcmd.Command{
|
||||
Name: "reset-pwd",
|
||||
Usage: "reset-pwd -u <username> -p <password>",
|
||||
Brief: "重置管理员账号密码",
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) error {
|
||||
username := parser.GetOpt("u", "admin").String()
|
||||
password := parser.GetOpt("p").String()
|
||||
|
||||
if password == "" {
|
||||
fmt.Println("用法: team-api reset-pwd -u <用户名> -p <新密码>")
|
||||
fmt.Println(" -u 管理员用户名(默认 admin)")
|
||||
fmt.Println(" -p 新密码(必填,至少8位,需含大小写字母和数字)")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate password policy
|
||||
if err := common.ValidatePassword(password); err != nil {
|
||||
fmt.Println(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
// Hash password using the same crypto.HashPassword used by Login/InitSuperAdmin
|
||||
passwordHash, err := crypto.HashPassword(password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("密码加密失败: %w", err)
|
||||
}
|
||||
|
||||
// Check user exists, get id and status
|
||||
var user struct {
|
||||
Id int64 `orm:"id"`
|
||||
Status string `orm:"status"`
|
||||
}
|
||||
err = dao.SysAdminUsers.Ctx(ctx).
|
||||
Where("username", username).
|
||||
Fields("id,status").
|
||||
Scan(&user)
|
||||
if err != nil {
|
||||
return fmt.Errorf("查询用户失败: %w", err)
|
||||
}
|
||||
if user.Id == 0 {
|
||||
fmt.Printf("用户 '%s' 不存在\n", username)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update password and reactivate account in case it was disabled
|
||||
// 用 g.Map 直接写列名,避免 DO struct 的 any 类型字段被误处理
|
||||
_, err = dao.SysAdminUsers.Ctx(ctx).
|
||||
Where("id", user.Id).
|
||||
Data(g.Map{
|
||||
"password_hash": passwordHash,
|
||||
"status": "active",
|
||||
}).
|
||||
Update()
|
||||
if err != nil {
|
||||
return fmt.Errorf("更新密码失败: %w", err)
|
||||
}
|
||||
|
||||
// 回读数据库验证哈希是否正确落盘(诊断 ORM 写入问题)
|
||||
storedHash, err := dao.SysAdminUsers.Ctx(ctx).
|
||||
Where("id", user.Id).
|
||||
Fields("password_hash").
|
||||
Value()
|
||||
if err != nil {
|
||||
return fmt.Errorf("回读密码哈希失败: %w", err)
|
||||
}
|
||||
storedHashStr := storedHash.String()
|
||||
if !crypto.VerifyPassword(password, storedHashStr) {
|
||||
return fmt.Errorf("密码已写入但回读校验失败,哈希长度=%d,预期=60(bcrypt)。请检查数据库连接与 password_hash 字段是否被截断",
|
||||
len(storedHashStr))
|
||||
}
|
||||
|
||||
// 清理该用户的所有会话(避免老会话残留导致登录状态异常)
|
||||
_, _ = g.DB().Model("sys_sessions").Ctx(ctx).
|
||||
Where("user_type", "admin").
|
||||
Where("user_id", user.Id).
|
||||
Delete()
|
||||
|
||||
fmt.Printf("已重置用户 '%s' 的密码,回读校验通过,旧会话已清理\n", username)
|
||||
fmt.Printf(" - 用户ID: %d\n", user.Id)
|
||||
fmt.Printf(" - 原状态: %s → active\n", user.Status)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
err := Main.AddCommand(&resetPwdCmd)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("注册 reset-pwd 命令失败: %v", err))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
package consts
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
)
|
||||
|
||||
// Business error variables (using gerror for full stack traces)
|
||||
var (
|
||||
ErrUnauthorized = gerror.NewCode(gcode.New(CodeUnauthorized, MsgUnauthorized, nil), MsgUnauthorized)
|
||||
ErrKeyExpired = gerror.NewCode(gcode.New(CodeKeyExpired, MsgKeyExpired, nil), MsgKeyExpired)
|
||||
ErrKeyDisabled = gerror.NewCode(gcode.New(CodeKeyExpired, MsgUnauthorized, nil), MsgUnauthorized)
|
||||
ErrTenantSuspended = gerror.NewCode(gcode.New(CodeTenantSuspended, MsgTenantSuspended, nil), MsgTenantSuspended)
|
||||
ErrChannelUnavailable = gerror.NewCode(gcode.New(CodeChannelUnavailable, MsgChannelUnavailable, nil), MsgChannelUnavailable)
|
||||
ErrModelDisabled = gerror.NewCode(gcode.New(CodeModelDisabled, MsgModelDisabled, nil), MsgModelDisabled)
|
||||
ErrTotpRequired = gerror.NewCode(gcode.New(CodeTotpRequired, MsgTotpRequired, nil), MsgTotpRequired)
|
||||
ErrTotpInvalid = gerror.NewCode(gcode.New(CodeTotpInvalid, MsgTotpInvalid, nil), MsgTotpInvalid)
|
||||
ErrTurnstileFailed = gerror.NewCode(gcode.New(CodeTurnstileFailed, MsgTurnstileFailed, nil), MsgTurnstileFailed)
|
||||
ErrIpRestricted = gerror.NewCode(gcode.New(CodeIpRestricted, MsgIpRestricted, nil), MsgIpRestricted)
|
||||
ErrCaptchaRequired = gerror.NewCode(gcode.New(CodeCaptchaRequired, MsgCaptchaRequired, nil), MsgCaptchaRequired)
|
||||
ErrCaptchaFailed = gerror.NewCode(gcode.New(CodeCaptchaFailed, MsgCaptchaFailed, nil), MsgCaptchaFailed)
|
||||
)
|
||||
|
||||
// Error codes for business logic
|
||||
const (
|
||||
BusinessErrorCodePrefix = 10000
|
||||
|
||||
// Common errors
|
||||
CodeSuccess = 0
|
||||
CodeBadRequest = 400
|
||||
CodeUnauthorized = 401
|
||||
CodeForbidden = 403
|
||||
CodeNotFound = 404
|
||||
CodeTooManyRequests = 429
|
||||
CodeInternalServerError = 500
|
||||
|
||||
// Business errors (10000+)
|
||||
CodeInsufficientBalance = 10001
|
||||
CodeQuotaExceeded = 10002
|
||||
CodeChannelUnavailable = 10003
|
||||
CodeModelDisabled = 10004
|
||||
CodeTenantSuspended = 10005
|
||||
CodeKeyExpired = 10006
|
||||
CodeKeyScopeDenied = 10007
|
||||
CodeInvitationExpired = 10008
|
||||
CodeInvitationUsed = 10009
|
||||
CodeAccountLocked = 10010
|
||||
CodeInvalidCredentials = 10011
|
||||
CodeEmailVerifyExpired = 10012
|
||||
CodeEmailVerifyUsed = 10013
|
||||
CodeRateLimitExceeded = 10014
|
||||
CodePasswordTooWeak = 10015
|
||||
CodeUsernameExists = 10016
|
||||
CodeTenantCodeExists = 10017
|
||||
CodeSessionExpired = 10018
|
||||
CodeTokenExpired = 10019
|
||||
CodeTokenRevoked = 10020
|
||||
CodeMemberLimitReached = 10021
|
||||
CodeVerifyCodeInvalid = 10022
|
||||
CodeOldPasswordWrong = 10023
|
||||
|
||||
// Payment errors (10024+)
|
||||
CodePaymentChannelNotFound = 10024
|
||||
CodePaymentChannelDisabled = 10025
|
||||
CodePaymentCreateFailed = 10026
|
||||
CodePaymentCallbackFailed = 10027
|
||||
CodePaymentInvalidConfig = 10028
|
||||
CodePaymentBelowMinTopup = 10029
|
||||
CodeOrderAlreadyPaid = 10030
|
||||
|
||||
// Project errors (10031+)
|
||||
CodeProjectNotFound = 10031
|
||||
CodeProjectNotActive = 10032
|
||||
CodeProjectKeyForbidden = 10033
|
||||
CodeConsentRequired = 10034
|
||||
|
||||
// Data governance errors (10035+)
|
||||
CodeExportAlreadyPending = 10035
|
||||
CodeExportNotFound = 10036
|
||||
CodeExportExpired = 10037
|
||||
CodeDeletionRequestExists = 10038
|
||||
CodeDeletionRequestNotFound = 10039
|
||||
CodeTaskNotRetryable = 10040
|
||||
CodeOnboardingCompleted = 10041
|
||||
|
||||
// Status page errors (10042+)
|
||||
CodeComponentNotFound = 10042
|
||||
CodeIncidentNotFound = 10043
|
||||
CodeMaintenanceNotFound = 10044
|
||||
CodeSubscriptionExists = 10045
|
||||
CodeInvalidConfirmToken = 10046
|
||||
|
||||
// Security errors (10047+)
|
||||
CodeTotpRequired = 10047
|
||||
CodeTotpInvalid = 10048
|
||||
CodeTotpAlreadyEnabled = 10049
|
||||
CodeTotpNotEnabled = 10050
|
||||
CodeBackupCodeInvalid = 10051
|
||||
CodeTurnstileFailed = 10052
|
||||
CodeIpRestricted = 10053
|
||||
CodeHighRisk2FARequired = 10054
|
||||
CodeNoAvailableApiKey = 10055
|
||||
CodeSandboxQuotaExceeded = 10056
|
||||
CodeCaptchaRequired = 10057
|
||||
CodeCaptchaFailed = 10058
|
||||
|
||||
// OAuth errors (10059+)
|
||||
CodeOAuthDisabled = 10059
|
||||
CodeOAuthInvalidCode = 10060
|
||||
CodeOAuthTokenFailed = 10061
|
||||
CodeOAuthAlreadyLinked = 10062
|
||||
|
||||
// Feedback & Changelog errors (10063+)
|
||||
CodeFeedbackNotFound = 10063
|
||||
CodeChangelogNotFound = 10064
|
||||
|
||||
// Response cache errors (10068+)
|
||||
CodeCacheDisabled = 10068
|
||||
CodeCacheFull = 10069
|
||||
|
||||
// Help Center errors (10073+)
|
||||
CodeHelpCategoryNotFound = 10073
|
||||
CodeHelpCategorySlugExists = 10074
|
||||
CodeHelpArticleNotFound = 10075
|
||||
CodeHelpArticleSlugExists = 10076
|
||||
|
||||
// Registration errors
|
||||
CodeRegistrationDisabled = 10077
|
||||
CodeEmailVerificationDisabled = 10082
|
||||
|
||||
// Setup errors
|
||||
CodeSetupCompleted = 10078
|
||||
CodeSetupInvalidUsername = 10079
|
||||
CodeSetupPasswordMismatch = 10080
|
||||
CodeSetupNotInitialized = 10081
|
||||
|
||||
// Model errors
|
||||
CodeModelNameExists = 10083
|
||||
|
||||
// Demo mode
|
||||
CodeDemoModeRestricted = 10403
|
||||
|
||||
// Plugin errors (10404+)
|
||||
CodePluginNotFound = 10404
|
||||
CodePluginAlreadyInstalled = 10405
|
||||
CodePluginNotInstalled = 10406
|
||||
CodePluginNotEnabled = 10407
|
||||
CodePluginAlreadyEnabled = 10408
|
||||
CodePluginDependencyMissing = 10409
|
||||
CodePluginInstallFailed = 10410
|
||||
)
|
||||
|
||||
// Common error messages
|
||||
const (
|
||||
MsgSuccess = "OK"
|
||||
MsgBadRequest = "请求参数错误"
|
||||
MsgUnauthorized = "未授权"
|
||||
MsgForbidden = "无权限访问"
|
||||
MsgNotFound = "资源不存在"
|
||||
MsgTooManyRequests = "请求过于频繁"
|
||||
MsgInternalServerError = "服务器内部错误"
|
||||
|
||||
MsgInsufficientBalance = "余额不足"
|
||||
MsgQuotaExceeded = "额度已用完"
|
||||
MsgChannelUnavailable = "没有可用的渠道"
|
||||
MsgModelDisabled = "模型已禁用"
|
||||
MsgTenantSuspended = "租户已被暂停"
|
||||
MsgKeyExpired = "API Key 已过期"
|
||||
MsgKeyScopeDenied = "API Key 无权访问此接口"
|
||||
MsgInvitationExpired = "邀请链接已过期"
|
||||
MsgInvitationUsed = "邀请链接已被使用"
|
||||
MsgAccountLocked = "账号已被锁定"
|
||||
MsgInvalidCredentials = "用户名或密码错误"
|
||||
MsgEmailVerifyExpired = "验证码已过期"
|
||||
MsgEmailVerifyUsed = "验证码已使用"
|
||||
MsgRateLimitExceeded = "请求频率超限"
|
||||
MsgPasswordTooWeak = "密码不符合策略"
|
||||
MsgUsernameExists = "用户名已存在"
|
||||
MsgTenantCodeExists = "租户代码已存在"
|
||||
MsgSessionExpired = "会话已过期"
|
||||
MsgTokenExpired = "Token 已过期"
|
||||
MsgTokenRevoked = "Token 已被撤销"
|
||||
MsgMemberLimitReached = "成员数已达上限"
|
||||
MsgVerifyCodeInvalid = "验证码错误"
|
||||
MsgOldPasswordWrong = "原密码错误"
|
||||
// Payment errors
|
||||
MsgPaymentChannelNotFound = "支付渠道不存在"
|
||||
MsgPaymentChannelDisabled = "支付渠道已禁用"
|
||||
MsgPaymentCreateFailed = "创建支付失败"
|
||||
MsgPaymentCallbackFailed = "支付回调处理失败"
|
||||
MsgPaymentInvalidConfig = "支付渠道配置无效"
|
||||
MsgPaymentBelowMinTopup = "充值金额低于最低限额"
|
||||
MsgOrderAlreadyPaid = "订单已支付"
|
||||
// Project errors
|
||||
MsgProjectNotFound = "项目不存在"
|
||||
MsgProjectNotActive = "项目状态不可用"
|
||||
MsgProjectKeyForbidden = "仅管理员可管理项目密钥"
|
||||
MsgConsentRequired = "需要同意法律条款后才能继续"
|
||||
// Data governance errors
|
||||
MsgExportAlreadyPending = "已有导出任务进行中"
|
||||
MsgExportNotFound = "导出任务不存在"
|
||||
MsgExportExpired = "导出文件已过期"
|
||||
MsgDeletionRequestExists = "已有删除请求进行中"
|
||||
MsgDeletionRequestNotFound = "删除请求不存在"
|
||||
MsgTaskNotRetryable = "任务不可重试"
|
||||
MsgOnboardingCompleted = "引导流程已完成"
|
||||
// Status page errors
|
||||
MsgComponentNotFound = "组件不存在"
|
||||
MsgIncidentNotFound = "事件不存在"
|
||||
MsgMaintenanceNotFound = "维护计划不存在"
|
||||
MsgSubscriptionExists = "该邮箱已订阅"
|
||||
MsgInvalidConfirmToken = "确认令牌无效"
|
||||
// Security errors
|
||||
MsgTotpRequired = "需要双因素认证"
|
||||
MsgTotpInvalid = "验证码错误"
|
||||
MsgTotpAlreadyEnabled = "双因素认证已启用"
|
||||
MsgTotpNotEnabled = "未启用双因素认证"
|
||||
MsgBackupCodeInvalid = "恢复码无效"
|
||||
MsgTurnstileFailed = "人机验证失败"
|
||||
MsgIpRestricted = "IP 地址不在白名单中"
|
||||
MsgHighRisk2FARequired = "高风险操作需要二次验证"
|
||||
MsgCaptchaRequired = "请完成滑块验证"
|
||||
MsgCaptchaFailed = "滑块验证失败"
|
||||
// OAuth errors
|
||||
MsgOAuthDisabled = "该 OAuth 供应商未启用"
|
||||
MsgOAuthInvalidCode = "OAuth 授权码无效"
|
||||
MsgOAuthTokenFailed = "获取 OAuth 令牌失败"
|
||||
MsgOAuthAlreadyLinked = "该 OAuth 账号已绑定其他用户"
|
||||
// Feedback & Changelog errors
|
||||
MsgFeedbackNotFound = "反馈不存在"
|
||||
MsgChangelogNotFound = "更新日志不存在"
|
||||
// Response cache errors
|
||||
MsgCacheDisabled = "响应缓存未启用"
|
||||
MsgCacheFull = "缓存空间已满"
|
||||
// Help Center errors
|
||||
MsgHelpCategoryNotFound = "帮助分类不存在"
|
||||
MsgHelpCategorySlugExists = "分类标识已存在"
|
||||
MsgHelpArticleNotFound = "帮助文章不存在"
|
||||
MsgHelpArticleSlugExists = "文章标识已存在"
|
||||
// Registration errors
|
||||
MsgRegistrationDisabled = "注册功能已关闭"
|
||||
MsgEmailVerificationDisabled = "注册邮箱验证未启用"
|
||||
|
||||
// Setup errors
|
||||
MsgSetupCompleted = "系统已完成初始化"
|
||||
MsgSetupInvalidUsername = "用户名格式无效,仅支持字母、数字和下划线,长度3-20"
|
||||
MsgSetupPasswordMismatch = "两次输入的密码不一致"
|
||||
MsgSetupNotInitialized = "系统未初始化,请先完成设置"
|
||||
|
||||
// Model errors
|
||||
MsgModelNameExists = "模型名称已存在"
|
||||
)
|
||||
|
||||
// Demo mode messages
|
||||
const (
|
||||
MsgDemoModeRestricted = "演示环境,数据不可修改"
|
||||
// Plugin errors
|
||||
MsgPluginNotFound = "插件不存在"
|
||||
MsgPluginAlreadyInstalled = "插件已安装"
|
||||
MsgPluginNotInstalled = "插件未安装"
|
||||
MsgPluginNotEnabled = "插件未启用"
|
||||
MsgPluginAlreadyEnabled = "插件已启用"
|
||||
MsgPluginDependencyMissing = "插件依赖未满足"
|
||||
MsgPluginInstallFailed = "插件安装失败"
|
||||
)
|
||||
@@ -0,0 +1,5 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package admin
|
||||
@@ -0,0 +1,15 @@
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package admin
|
||||
|
||||
import (
|
||||
"github.com/qianfree/team-api/api/admin"
|
||||
)
|
||||
|
||||
type ControllerV1 struct{}
|
||||
|
||||
func NewV1() admin.IAdminV1 {
|
||||
return &ControllerV1{}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Admin2FAConfirm(ctx context.Context, req *v1.Admin2FAConfirmReq) (res *v1.Admin2FAConfirmRes, err error) {
|
||||
return service.Admin().ConfirmHighRisk(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Admin2FADisable(ctx context.Context, req *v1.Admin2FADisableReq) (res *v1.Admin2FADisableRes, err error) {
|
||||
return service.Admin().Disable2FA(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Admin2FAEnable(ctx context.Context, req *v1.Admin2FAEnableReq) (res *v1.Admin2FAEnableRes, err error) {
|
||||
return service.Admin().Enable2FA(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Admin2FARegenerateBackupCodes(ctx context.Context, req *v1.Admin2FARegenerateBackupCodesReq) (res *v1.Admin2FARegenerateBackupCodesRes, err error) {
|
||||
return service.Admin().RegenerateBackupCodes(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Admin2FASetup(ctx context.Context, req *v1.Admin2FASetupReq) (res *v1.Admin2FASetupRes, err error) {
|
||||
return service.Admin().Setup2FA(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) Admin2FAVerify(ctx context.Context, req *v1.Admin2FAVerifyReq) (res *v1.Admin2FAVerifyRes, err error) {
|
||||
return service.Admin().Verify2FA(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminAllPermissions(ctx context.Context, req *v1.AdminAllPermissionsReq) (res *v1.AdminAllPermissionsRes, err error) {
|
||||
return service.Admin().GetAllPermissions(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminBillingRecordExport(ctx context.Context, req *v1.AdminBillingRecordExportReq) (res *v1.AdminBillingRecordExportRes, err error) {
|
||||
return service.Admin().ExportBillingRecords(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminBillingRecordList(ctx context.Context, req *v1.AdminBillingRecordListReq) (res *v1.AdminBillingRecordListRes, err error) {
|
||||
return service.Admin().GetAllBillingRecords(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminChangePassword(ctx context.Context, req *v1.AdminChangePasswordReq) (res *v1.AdminChangePasswordRes, err error) {
|
||||
return service.Admin().ChangePassword(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminDashboard(ctx context.Context, req *v1.AdminDashboardReq) (res *v1.AdminDashboardRes, err error) {
|
||||
return service.Admin().GetDashboardStats(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminDashboardChannelHealth(ctx context.Context, req *v1.AdminDashboardChannelHealthReq) (res *v1.AdminDashboardChannelHealthRes, err error) {
|
||||
return service.Admin().GetDashboardChannelHealth(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminDashboardModelDistribution(ctx context.Context, req *v1.AdminDashboardModelDistributionReq) (res *v1.AdminDashboardModelDistributionRes, err error) {
|
||||
return service.Admin().GetModelDistribution(ctx, req)
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package admin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/qianfree/team-api/api/admin/v1"
|
||||
"github.com/qianfree/team-api/internal/service"
|
||||
)
|
||||
|
||||
func (c *ControllerV1) AdminDashboardRecentAlerts(ctx context.Context, req *v1.AdminDashboardRecentAlertsReq) (res *v1.AdminDashboardRecentAlertsRes, err error) {
|
||||
return service.Admin().GetDashboardRecentAlerts(ctx, req)
|
||||
}
|
||||
Loaded 100 of 1136 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user