管理员核心 API
管理员核心路由,包含用户管理、团队管理、角色权限管理、模拟登录、Ollama 模型同步、静态 HTML 生成,以及硬件管理(品牌、产品、传感器、库存)子路由。
基础路径
/admin认证方式
所有端点均需 JWT Bearer Token 认证(combinedAuth 中间件),且需要 site:admin 权限。部分写入操作同时使用 adminAudit 审计中间件记录操作日志。
Authorization: Bearer <jwt_token>权限要求:用户在 grants 表中拥有 site:admin 权限。模拟登录相关端点需要 site:impersonate 权限。
用户管理
POST /admin/users
获取用户列表(含 email 和 profile 信息)。
请求参数(Body)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
page | number | 否 | 1 | 页码 |
page_size | number | 否 | 20 | 每页数量 |
响应格式
{
"success": true,
"users": [
{
"user_id": "uuid",
"email": "user@example.com",
"display_name": "用户名",
"avatar_url": "https://...",
"bio": "个人简介",
"created_at": "2026-01-01T00:00:00Z"
}
],
"total": 100,
"page": 1,
"page_size": 20
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取用户列表失败 |
POST /admin/impersonate
开始模拟登录。为目标用户生成 Magic Link,管理员可以以目标用户身份登录。
权限要求:site:impersonate
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
target_user_id | string | 是 | 目标用户 ID |
redirect_url | string | 是 | 登录后重定向 URL |
响应格式
{
"success": true,
"token_hash": "hashed_token_value",
"target_email": "target@example.com",
"expires_at": 1709812345000
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少必填字段 / 不能模拟自己 |
| 403 | 仅支持 JWT 认证 / 缺少 site:impersonate 权限 |
| 404 | 目标用户不存在 |
| 500 | 生成 Magic Link 失败 |
POST /admin/end-impersonation
结束模拟登录。不需要用户认证(因为当前身份是被模拟者),但会验证 admin_user_id 是否有 site:impersonate 权限。
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
admin_user_id | string | 是 | 管理员用户 ID |
target_user_id | string | 是 | 被模拟的用户 ID |
target_email | string | 否 | 被模拟用户的邮箱 |
started_at | string | 是 | 模拟开始时间(ISO 格式) |
响应格式
{
"success": true
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少必填字段 |
| 403 | admin_user_id 没有 site:impersonate 权限 |
POST /admin/sync-document-metadata
批量同步文档元数据。调用 sync-document-metadata Edge Function。
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
projectId | string | 是 | 项目 ID |
documentId | string | 否 | 指定文档 ID(不传则同步整个项目) |
响应格式
返回 Edge Function 的响应结果。
错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少 projectId / 无效的请求体 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 服务器配置错误 / 同步失败 |
GET /admin/analytics/stats
获取平台统计数据。
请求参数(Query)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
timeRange | string | 否 | 30d | 时间范围:7d / 30d / 90d / all |
响应格式
{
"totalUsers": 1000,
"newUsersThisPeriod": 50,
"totalTeams": 200,
"activeTeams": 140,
"totalRuns": 50000,
"runsThisPeriod": 3000,
"revenueThisPeriod": 150000,
"revenueGrowth": 12.5,
"modelUsage": [
{
"model": "gpt-4o",
"runs": 500,
"tokens": 0,
"revenue": 50000
}
],
"topTeams": [],
"recentActivity": []
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取统计数据失败 |
团队管理
POST /admin/teams
获取团队列表(含订阅和积分信息)。
请求参数(Body)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
page | number | 否 | 1 | 页码 |
page_size | number | 否 | 20 | 每页数量 |
plan_code | string | 否 | 无 | 按计划代码筛选(如 free、pro、business) |
sort_by | string | 否 | created_at | 排序字段:created_at / balance / members / plan |
sort_order | string | 否 | desc | 排序方向:asc / desc |
响应格式
{
"success": true,
"teams": [
{
"id": "uuid",
"name": "团队名称",
"slug": "team-slug",
"description": "描述",
"created_at": "2026-01-01T00:00:00Z",
"owner": {
"user_id": "uuid",
"email": "owner@example.com",
"display_name": "所有者"
},
"subscription": {
"plan_code": "pro",
"status": "active",
"monthly_credits": 100000,
"current_period_start": "2026-03-01",
"current_period_end": "2026-04-01"
},
"credits": {
"balance_credits": 50000,
"grant_balance_credits": 30000,
"purchase_balance_credits": 20000,
"subscription_grant_credits": 25000,
"topup_grant_credits": 5000
},
"member_count": 5
}
],
"total": 200,
"page": 1,
"page_size": 20,
"stats": {
"total_teams": 200,
"plan_distribution": {
"free": 100,
"pro": 60,
"business": 30,
"infrastructure": 10
},
"total_credits": 5000000,
"total_grant_credits": 3000000,
"total_purchase_credits": 2000000
}
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取团队列表失败 |
角色管理
GET /admin/roles
获取所有角色及其权限。
请求参数(Query)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
scope | string | 否 | 无 | 按作用域筛选:project / site |
响应格式
{
"success": true,
"roles": [
{
"id": "uuid",
"code": "admin",
"name": "管理员",
"scope": "site",
"description": "站点管理员角色",
"created_at": "2026-01-01T00:00:00Z",
"permissions": ["site:admin", "site:impersonate"]
}
],
"permissions": [
{
"code": "site:admin",
"description": "站点管理权限"
}
]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取角色列表失败 |
POST /admin/roles
创建角色。
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
code | string | 是 | 角色代码(唯一) |
name | string | 是 | 角色名称 |
scope | string | 是 | 作用域:project / site |
description | string | 否 | 角色描述 |
permissions | string[] | 否 | 初始权限代码列表 |
响应格式
{
"success": true,
"role": {
"id": "uuid",
"code": "editor",
"name": "编辑者",
"scope": "project",
"description": "项目编辑权限",
"created_at": "2026-03-07T00:00:00Z"
}
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少必填字段(code、name、scope) |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 409 | 角色代码已存在 |
| 500 | 创建角色失败 |
PUT /admin/roles/:id
更新角色。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 角色 ID |
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 否 | 角色名称 |
description | string | 否 | 角色描述 |
响应格式
{
"success": true,
"role": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 更新角色失败 |
DELETE /admin/roles/:id
删除角色(软删除)。如有用户正在使用此角色则拒绝删除。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 角色 ID |
响应格式
{
"success": true
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 有用户正在使用此角色,无法删除 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 删除角色失败 |
PUT /admin/roles/:id/permissions
更新角色权限(全量替换)。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 角色 ID |
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
permissions | string[] | 是 | 新的权限代码列表 |
响应格式
{
"success": true,
"permissions": ["site:admin", "site:impersonate"]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少 permissions 数组 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 角色不存在 |
| 500 | 更新权限失败 |
Ollama 模型管理
POST /admin/ollama/sync-models
同步 Ollama 模型到数据库。从 Ollama API 获取模型列表,同步到 model_provider_costs 表,并自动创建/更新 billing_rules 路由规则。
请求参数
无。
响应格式
{
"success": true,
"message": "同步完成:新增 3,更新 2,跳过 0",
"results": {
"added": 3,
"updated": 2,
"skipped": 0,
"errors": []
},
"models": [
{
"name": "qwen3:8b",
"size": "8B",
"capabilities": ["text", "structured", "tools", "reasoning"]
}
]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 缺少 OLLAMA_BASE_URL 环境变量 / Ollama API 请求失败 |
GET /admin/ollama/models
获取 Ollama 模型列表(仅查询,不同步数据库)。
请求参数
无。
响应格式
{
"success": true,
"models": [
{
"name": "qwen3:8b",
"size": 5368709120,
"parameter_size": "8B",
"quantization": "Q4_K_M",
"family": "qwen3",
"capabilities": ["text", "structured", "tools", "reasoning"],
"modified_at": "2026-03-06T12:00:00Z"
}
]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 缺少 OLLAMA_BASE_URL 环境变量 / Ollama API 请求失败 |
静态 HTML 生成
POST /admin/generate-static-html
从 site_settings 读取 SEO 和品牌配置,生成静态 HTML 并上传到 Supabase Storage 的 static 桶。
请求参数
无。
响应格式
{
"success": true,
"message": "Static HTML generated successfully. URL: https://...",
"timestamp": "2026-03-07T10:00:00.000Z"
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 读取配置失败 / 上传失败 |
硬件管理 - 品牌
GET /admin/hardware/brands
获取品牌列表。按 is_first_party 降序、name 升序排列。
请求参数
无。
响应格式
{
"success": true,
"brands": [
{
"id": "uuid",
"name": "品牌名称",
"is_first_party": true,
"logo_url": "https://...",
"website_url": "https://...",
"description": "品牌描述",
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-01T00:00:00Z"
}
]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取品牌列表失败 |
POST /admin/hardware/brands
创建品牌。
请求参数(Body)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
name | string | 是 | - | 品牌名称(唯一) |
is_first_party | boolean | 否 | false | 是否为自有品牌 |
logo_url | string | 否 | null | Logo URL |
website_url | string | 否 | null | 官网 URL |
description | string | 否 | null | 品牌描述 |
响应格式
{
"success": true,
"brand": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少 name |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 409 | 品牌名称已存在 |
| 500 | 创建失败 |
PUT /admin/hardware/brands/:id
更新品牌。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 品牌 ID |
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 否 | 品牌名称 |
is_first_party | boolean | 否 | 是否为自有品牌 |
logo_url | string | 否 | Logo URL |
website_url | string | 否 | 官网 URL |
description | string | 否 | 品牌描述 |
响应格式
{
"success": true,
"brand": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 品牌不存在 |
| 500 | 更新失败 |
DELETE /admin/hardware/brands/:id
删除品牌(硬删除)。如有产品引用此品牌则拒绝删除。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 品牌 ID |
响应格式
{
"success": true
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 品牌被产品引用,无法删除 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 删除失败 |
硬件管理 - 产品型号
GET /admin/hardware/products
获取产品型号列表(含品牌信息)。
请求参数(Query)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
page | number | 否 | 1 | 页码 |
page_size | number | 否 | 20 | 每页数量 |
status | string | 否 | 无 | 状态筛选:draft / active / coming_soon / discontinued |
brand_id | string | 否 | 无 | 品牌 ID 筛选 |
search | string | 否 | 无 | 按名称或系列搜索 |
响应格式
{
"success": true,
"products": [
{
"id": "uuid",
"name": "产品名称",
"brand": { "id": "uuid", "name": "品牌", "logo_url": "..." },
"series": "系列",
"status": "active",
"..."
}
],
"total": 50,
"page": 1,
"page_size": 20
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取产品列表失败 |
GET /admin/hardware/products/:id
获取单个产品详情(含品牌和传感器信息)。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 产品 ID |
响应格式
{
"success": true,
"product": {
"id": "uuid",
"name": "产品名称",
"brand": { "id": "uuid", "name": "品牌", "logo_url": "...", "is_first_party": true },
"sensors": [
{ "id": "uuid", "name": "温度传感器", "identifier": "temperature", "icon": null, "capabilities": ["read"] }
],
"..."
}
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 产品不存在 |
| 500 | 获取产品详情失败 |
POST /admin/hardware/products
创建产品。
请求参数(Body)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
name | string | 是 | - | 产品名称 |
brand_id | string | 否 | null | 品牌 ID |
series | string | 否 | null | 系列名 |
color | string | 否 | null | 颜色 |
cover_image_url | string | 否 | null | 封面图 URL |
detail_images | string[] | 否 | [] | 详情图 URL 数组 |
sensor_ids | string[] | 否 | [] | 传感器 ID 数组 |
connection_type | string | 否 | null | 连接类型 |
config | object | 否 | {} | 配置信息(含 bluetooth_prefix 等) |
requires_inventory_check | boolean | 否 | true | 是否需要库存校验 |
status | string | 否 | draft | 状态:draft / active / coming_soon / discontinued |
description | string | 否 | null | 产品描述 |
响应格式
HTTP 201:
{
"success": true,
"product": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少 name / status 值无效 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 创建失败 |
PUT /admin/hardware/products/:id
更新产品。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 产品 ID |
请求参数(Body)
与创建时的可选字段相同(name、brand_id、series、color、cover_image_url、detail_images、sensor_ids、connection_type、config、requires_inventory_check、status、description)。所有字段均为可选。
响应格式
{
"success": true,
"product": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | status 值无效 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 产品不存在 |
| 500 | 更新失败 |
DELETE /admin/hardware/products/:id
删除产品(硬删除)。如有库存记录或用户设备引用则拒绝删除。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 产品 ID |
响应格式
{
"success": true
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 产品有库存记录或用户设备引用,无法删除 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 删除失败 |
POST /admin/hardware/products/:id/images
上传产品图片。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 产品 ID |
请求参数(FormData)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
file | File | 是 | - | 图片文件(支持 JPEG/PNG/GIF/WebP,最大 5MB) |
type | string | 否 | detail | 图片类型:cover(封面图)/ detail(详情图) |
响应格式
{
"success": true,
"url": "https://...",
"path": "hardware/products/uuid/filename.jpg"
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 未上传文件 / 不支持的图片格式 / 图片超过 5MB |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 产品不存在 |
| 500 | 上传失败 |
硬件管理 - 传感器
GET /admin/hardware/sensors
获取传感器列表。按 sort_order 升序、created_at 升序排列。
请求参数
无。
响应格式
{
"success": true,
"sensors": [
{
"id": "uuid",
"name": "温度传感器",
"identifier": "temperature",
"description": "测量温度",
"icon": "thermometer",
"capabilities": ["read"],
"sort_order": 0,
"is_active": true,
"created_at": "2026-01-01T00:00:00Z"
}
]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取传感器列表失败 |
GET /admin/hardware/sensors/:id
获取单个传感器详情。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 传感器 ID |
响应格式
{
"success": true,
"sensor": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 传感器不存在 |
| 500 | 获取传感器详情失败 |
POST /admin/hardware/sensors
创建传感器。
请求参数(Body)
| 字段 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
name | string | 是 | - | 传感器名称 |
identifier | string | 是 | - | 标识符(snake_case,唯一) |
description | string | 否 | null | 描述 |
icon | string | 否 | null | 图标名称 |
capabilities | string[] | 否 | [] | 能力列表 |
sort_order | number | 否 | 0 | 排序权重 |
is_active | boolean | 否 | true | 是否启用 |
响应格式
HTTP 201:
{
"success": true,
"sensor": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少 name 或 identifier / identifier 格式无效 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 409 | 传感器标识符已存在 |
| 500 | 创建失败 |
PUT /admin/hardware/sensors/:id
更新传感器。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 传感器 ID |
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
name | string | 否 | 传感器名称 |
description | string | 否 | 描述 |
icon | string | 否 | 图标名称 |
capabilities | string[] | 否 | 能力列表 |
sort_order | number | 否 | 排序权重 |
is_active | boolean | 否 | 是否启用 |
响应格式
{
"success": true,
"sensor": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 传感器不存在 |
| 500 | 更新失败 |
DELETE /admin/hardware/sensors/:id
删除传感器(硬删除)。如有产品引用此传感器则拒绝删除。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 传感器 ID |
响应格式
{
"success": true
}错误时包含引用产品信息:
{
"success": false,
"error": "该传感器被 3 个产品引用,无法删除:产品A, 产品B, 产品C",
"referenced_products": [
{ "id": "uuid", "name": "产品A" }
],
"total_references": 3
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 传感器被产品引用,无法删除 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 删除失败 |
PATCH /admin/hardware/sensors/reorder
批量更新传感器排序。
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
items | Array<{id: string, sort_order: number}> | 是 | 排序项数组 |
响应格式
{
"success": true
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少 items 数组 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 更新排序失败 |
硬件管理 - 库存
GET /admin/hardware/inventory
获取库存列表(含产品型号信息)。
请求参数(Query)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
page | number | 否 | 1 | 页码 |
page_size | number | 否 | 20 | 每页数量 |
product_model_id | string | 否 | 无 | 按产品型号 ID 筛选 |
status | string | 否 | 无 | 绑定状态:bound / unbound |
batch_no | string | 否 | 无 | 按批次号搜索(模糊匹配) |
search | string | 否 | 无 | 按硬件 ID 搜索(大小写不敏感) |
响应格式
{
"success": true,
"items": [
{
"id": "uuid",
"hardware_id": "WN-ABC12345",
"product_model_id": "uuid",
"product_model": { "id": "uuid", "name": "产品名", "brand_id": "uuid", "series": "...", "color": "..." },
"batch_no": "B20260301",
"production_date": "2026-03-01",
"color": "白色",
"bound_user_id": null,
"bound_at": null,
"created_at": "2026-03-01T00:00:00Z"
}
],
"total": 500,
"page": 1,
"page_size": 20
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取库存列表失败 |
GET /admin/hardware/inventory/stats
获取库存统计数据。
请求参数
无。
响应格式
{
"success": true,
"stats": {
"total": 500,
"bound": 200,
"unbound": 300
}
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取统计失败 |
GET /admin/hardware/inventory/template
下载库存导入 CSV 模板。
请求参数
无。
响应格式
返回 CSV 文件,Content-Type 为 text/csv; charset=utf-8。
错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 生成模板失败 |
GET /admin/hardware/inventory/export
导出库存数据(CSV 格式)。最大导出 10000 条。
请求参数(Query)
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
product_model_id | string | 否 | 无 | 按产品型号 ID 筛选 |
status | string | 否 | 无 | 绑定状态:bound / unbound |
batch_no | string | 否 | 无 | 按批次号搜索 |
search | string | 否 | 无 | 按硬件 ID 搜索 |
响应格式
返回 CSV 文件,Content-Type 为 text/csv; charset=utf-8,包含 BOM 头。
CSV 列:硬件 ID、产品型号、批次号、生产日期、颜色、绑定状态、绑定时间、入库时间。
错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 导出失败 |
GET /admin/hardware/inventory/:id
获取单个库存详情(含产品型号、绑定用户和操作日志)。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 库存记录 ID |
响应格式
{
"success": true,
"item": {
"id": "uuid",
"hardware_id": "WN-ABC12345",
"product_model": { "..." },
"bound_user": { "id": "uuid", "nickname": "用户名", "email": "...", "avatar_url": "..." },
"..."
},
"operation_logs": [
{
"id": "uuid",
"operation_type": "bind",
"operator_id": "uuid",
"status": "success",
"error_message": null,
"details": {},
"created_at": "2026-03-07T00:00:00Z"
}
]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 库存记录不存在 |
| 500 | 获取详情失败 |
POST /admin/hardware/inventory
创建库存记录。
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
hardware_id | string | 是 | 硬件 ID(5-100 字符,仅允许字母/数字/连字符/下划线,自动转大写) |
product_model_id | string | 是 | 产品型号 ID |
batch_no | string | 是 | 批次号 |
production_date | string | 是 | 生产日期(不能是未来日期) |
color | string | 否 | 颜色 |
extra_data | object | 否 | 扩展数据 |
响应格式
HTTP 201:
{
"success": true,
"item": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 缺少必填字段 / hardware_id 格式无效 / 生产日期无效或为未来日期 / 产品型号不存在 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 409 | 硬件 ID 已存在 |
| 500 | 创建失败 |
PUT /admin/hardware/inventory/:id
更新库存记录。hardware_id 和 product_model_id 不可修改。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 库存记录 ID |
请求参数(Body)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
batch_no | string | 否 | 批次号 |
production_date | string | 否 | 生产日期 |
color | string | 否 | 颜色 |
extra_data | object | 否 | 扩展数据 |
响应格式
{
"success": true,
"item": { "..." }
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 生产日期格式无效或为未来日期 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 库存记录不存在 |
| 500 | 更新失败 |
DELETE /admin/hardware/inventory/:id
删除库存记录(硬删除)。仅允许删除未绑定的记录。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 库存记录 ID |
响应格式
{
"success": true
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 设备已绑定用户,无法删除 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 库存记录不存在 |
| 500 | 删除失败 |
POST /admin/hardware/inventory/:id/unbind
强制解绑设备。将设备从用户解绑,清除库存表的绑定信息,并设置关联的 hw_user_devices 为非活跃。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
id | Path | string | 是 | 库存记录 ID |
响应格式
{
"success": true
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 设备未绑定 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 404 | 库存记录不存在 |
| 500 | 解绑失败 |
POST /admin/hardware/inventory/import/preview
批量导入预览。上传 CSV 文件进行解析和验证,返回预览结果但不执行导入。
请求参数(FormData)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
file | File | 是 | CSV 文件 |
响应格式
{
"success": true,
"total_rows": 100,
"valid_count": 95,
"error_count": 5,
"valid_rows": ["..."],
"errors": [
{ "row": 3, "field": "hardware_id", "message": "格式无效" }
]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 未上传文件 / 不支持的文件格式 / 文件内容为空 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 导入预览失败 |
POST /admin/hardware/inventory/import
执行批量导入。上传 CSV 文件,解析、验证后执行导入。
请求参数(FormData)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
file | File | 是 | CSV 文件 |
响应格式
{
"success": true,
"success_count": 95,
"failed_count": 5,
"errors": ["..."]
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | 未上传文件 / 文件内容为空 / 没有有效数据 |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 导入失败 |
ROMP 聊天管理
GET /admin/romp/stats
获取站点 ROMP 聊天统计数据(来自 stats_snapshots 通用统计表的最新每日快照)。
响应格式
{
"metrics": {
"total_users_with_conversations": 128,
"total_conversations": 350,
"total_messages": 5600,
"total_files_count": 200,
"total_files_size_bytes": 2147483648
},
"period_start": "2026-03-09T00:00:00Z"
}metrics 为 null 表示尚无统计数据(cron 任务未执行过)。
错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取统计数据失败 |
GET /admin/users/:userId/romp-stats
获取指定用户的 ROMP 聊天统计 + 禁用状态。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
userId | Path | string | 是 | 用户 ID |
响应格式
{
"metrics": {
"conversations": 5,
"messages_sent": 42,
"messages_received": 38,
"files_count": 3,
"files_size_bytes": 10485760,
"last_active_at": "2026-03-09T08:00:00Z"
},
"period_start": "2026-03-09T00:00:00Z",
"disabled": false
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 获取用户统计失败 |
POST /admin/users/:userId/romp-status
设置用户 ROMP 聊天启用/禁用状态。通过 user_permissions 表管理 romp:disabled 权限码实现。操作记录到审计日志。
请求参数
| 参数 | 位置 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
userId | Path | string | 是 | 目标用户 ID |
请求体
{
"disabled": true
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
disabled | boolean | 是 | true 禁用,false 启用 |
响应格式
{
"success": true,
"disabled": true
}错误码
| HTTP 状态码 | 说明 |
|---|---|
| 400 | disabled 不是 boolean |
| 403 | 仅支持 JWT 认证 / 权限不足 |
| 500 | 更新状态失败 |
POST /admin/users 变更说明
用户列表接口响应新增 romp_disabled 字段:
{
"success": true,
"users": [
{
"user_id": "uuid",
"email": "user@example.com",
"display_name": "用户名",
"avatar_url": "https://...",
"bio": "个人简介",
"created_at": "2026-01-01T00:00:00Z",
"romp_disabled": false
}
],
"total": 100
}源码
- 路由文件:
apps/backend/src/routes/admin.ts - 硬件管理入口:
apps/backend/src/routes/admin/hardware/index.ts - 品牌路由:
apps/backend/src/routes/admin/hardware/brands.ts - 产品路由:
apps/backend/src/routes/admin/hardware/products.ts - 传感器路由:
apps/backend/src/routes/admin/hardware/sensors.ts - 库存路由:
apps/backend/src/routes/admin/hardware/inventory.ts