🦐 捕虾场后台管理
管理 Admin 后台的「捕虾场」模块——职能虾定义、虾池库存、捕获记录。
前端展示文档见:🦐 捕虾场(Shrimp Market)
最后更新:2026-03-09
1. 页面总览
后台新增 3 个管理页面,挂载在侧边栏「捕虾场管理」分组下:
| 页面 | 路由 | 功能 |
|---|---|---|
| 职能虾管理 | /shrimp/professions | CRUD 职能虾定义 + 库存概览 |
| 虾池管理 | /shrimp/pool | 实例分配、回收、维护标记 |
| 捕获记录 | /shrimp/claims | 查看谁捕获了哪只虾 |
2. 职能虾管理(Professions)
2.1 列表页
表格字段:
| 列 | 来源 | 说明 |
|---|---|---|
| 图标 | icon | emoji 显示 |
| 名称 | name | 职能虾中文名 |
| Code | code | 唯一标识(如 shrimp-go) |
| 一句话 | tagline | 卡片副标题 |
| 库存 | 聚合查询 | 空闲 / 已分配 / 总计 |
| 状态 | is_active | 上架 / 下架 |
| 排序 | sort_order | 数字越小越靠前 |
| 操作 | — | 编辑 / 上下架 / 查看虾池 |
2.2 新增 / 编辑弹窗
表单字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | 文本 | ✅ | 中文名(如「Go 大师」) |
| code | 文本 | ✅ | 唯一 code(如 shrimp-go),创建后不可改 |
| icon | 文本 | ✅ | emoji(如 ⚡) |
| tagline | 文本 | ✅ | 一句话介绍 |
| description | 多行文本 | ❌ | 详细描述 |
| role_pack_id | 下拉选择 | ❌ | 关联 marketplace_items (type=role_pack) |
| sort_order | 数字 | ❌ | 排序权重,默认 0 |
| is_official | 开关 | ❌ | 是否官方虾 |
| is_active | 开关 | ❌ | 是否上架 |
2.3 库存统计 SQL
SELECT p.*,
(SELECT COUNT(*) FROM profession_instances pi
WHERE pi.profession_id = p.id AND pi.status = 'idle') AS stock_idle,
(SELECT COUNT(*) FROM profession_instances pi
WHERE pi.profession_id = p.id AND pi.status = 'allocated') AS stock_allocated,
(SELECT COUNT(*) FROM profession_instances pi
WHERE pi.profession_id = p.id) AS stock_total
FROM professions p
ORDER BY p.sort_order, p.created_at
3. 虾池管理(Pool)
3.1 列表页
表格字段:
| 列 | 来源 | 说明 |
|---|---|---|
| 池 ID | id | profession_instances.id |
| 职能虾 | JOIN professions | 虾名 + 图标 |
| 实例 ID | instance_id | 对应 OC 实例 |
| 服务器 | server_id | 所在服务器 |
| 状态 | status | idle / allocated / maintenance |
| 分配用户 | allocated_user_id → JOIN users | 用户邮箱(allocated 时显示) |
| 分配时间 | allocated_at | — |
3.2 状态筛选
Tab 页切换:全部 / 空闲 (idle) / 已分配 (allocated) / 维护中 (maintenance)
3.3 操作
| 操作 | 条件 | 说明 |
|---|---|---|
| 添加实例 | — | 选择职能虾 + 空闲实例 → INSERT |
| 回收实例 | status = allocated | 清空 allocated_user_id → status = idle,清理实例 workspace |
| 标记维护 | status = idle | idle → maintenance |
| 恢复上线 | status = maintenance | maintenance → idle |
| 批量添加 | — | 多选实例一次性入池 |
3.4 添加实例到池 SQL
INSERT INTO profession_instances (id, profession_id, instance_id, server_id, status)
VALUES (?, ?, ?, ?, 'idle')
3.5 回收实例 SQL
-- 1. 释放虾池
UPDATE profession_instances
SET status = 'idle', allocated_user_id = NULL, allocated_at = NULL
WHERE id = ?;
-- 2. 解绑用户
UPDATE user_instances
SET profession_id = NULL
WHERE instance_id = ? AND profession_id IS NOT NULL;
4. 捕获记录(Claims)
4.1 列表页(只读)
| 列 | 说明 |
|---|---|
| 用户 | email + 昵称 |
| 职能虾 | 图标 + 名称 |
| 实例 ID | 分配到的实例 |
| 捕获时间 | allocated_at |
4.2 筛选条件
- 按职能虾(下拉)
- 按用户(搜索)
- 按时间范围
4.3 查询 SQL
SELECT
pi.id,
u.email, u.name AS user_name,
p.icon, p.name AS profession_name,
pi.instance_id, pi.allocated_at
FROM profession_instances pi
JOIN professions p ON p.id = pi.profession_id
JOIN users u ON u.id = pi.allocated_user_id
WHERE pi.status = 'allocated'
ORDER BY pi.allocated_at DESC
LIMIT ? OFFSET ?
5. Admin API
5.1 职能虾
列表
GET /api/v1/professions?page=1&page_size=20&is_active=1
响应:
{
"code": "0000",
"data": {
"list": [
{
"id": "shrimp-go",
"name": "Go 大师",
"code": "shrimp-go",
"icon": "⚡",
"tagline": "高并发低延迟,虾写的代码跑得飞快",
"is_active": 1,
"is_official": 1,
"sort_order": 4,
"stock_idle": 1,
"stock_allocated": 0,
"stock_total": 1
}
],
"total": 10
}
}
新增
POST /api/v1/professions
Body: { name, code, icon, tagline, description?, role_pack_id?, sort_order?, is_official?, is_active? }
编辑
PATCH /api/v1/professions/:id
Body: { name?, icon?, tagline?, description?, role_pack_id?, sort_order?, is_active? }
删除(软删除)
DELETE /api/v1/professions/:id
→ UPDATE professions SET is_active = 0 WHERE id = ?
5.2 虾池
列表
GET /api/v1/profession-pool?status=idle&profession_id=shrimp-go&page=1&page_size=50
响应:
{
"code": "0000",
"data": {
"list": [
{
"id": "pool-jp3-03",
"profession_id": "shrimp-go",
"profession_name": "Go 大师",
"profession_icon": "⚡",
"instance_id": "oc-ai-jp-3-03",
"server_id": "ai-jp-3",
"status": "idle",
"allocated_user_id": null,
"allocated_email": null,
"allocated_at": null
}
],
"total": 6
}
}
添加实例到池
POST /api/v1/profession-pool
Body: { profession_id, instance_id, server_id? }
修改状态
PATCH /api/v1/profession-pool/:id
Body: { status: "idle" | "maintenance" }
回收操作(status 从 allocated → idle)额外清空 allocated_user_id 和关联的 user_instances.profession_id。
5.3 捕获记录
列表
GET /api/v1/profession-claims?profession_id=&user_email=&start_date=&end_date=&page=1&page_size=50
响应:
{
"code": "0000",
"data": {
"list": [
{
"user_email": "[email protected]",
"user_name": "测试用户",
"profession_icon": "⚡",
"profession_name": "Go 大师",
"instance_id": "oc-ai-jp-3-03",
"allocated_at": "2026-03-09T15:30:00Z"
}
],
"total": 1
}
}
6. Soybean Admin 前端
6.1 路由配置
// routes
{
name: 'shrimp',
path: '/shrimp',
meta: { title: '捕虾场管理', icon: 'mdi:shrimp' },
children: [
{ name: 'shrimp_professions', path: '/shrimp/professions', meta: { title: '职能虾管理' } },
{ name: 'shrimp_pool', path: '/shrimp/pool', meta: { title: '虾池管理' } },
{ name: 'shrimp_claims', path: '/shrimp/claims', meta: { title: '捕获记录' } },
]
}
6.2 组件结构
views/web/shrimp/
├── professions/index.vue # 职能虾 CRUD 表格 + 弹窗
├── pool/index.vue # 虾池列表 + 状态操作
└── claims/index.vue # 捕获记录(只读表格 + 筛选)
6.3 UI 组件
- 列表:NaiveUI
NDataTable+ 分页 - 弹窗:
NModal+NForm - 状态标签:
NTag(idle=绿, allocated=蓝, maintenance=黄) - 筛选:
NSelect+NDatePicker
7. 执行计划
| 步骤 | 内容 | 优先级 |
|---|---|---|
| 1 | Admin API 6 个接口(Go) | P0 |
| 2 | Soybean Admin 3 个页面(Vue) | P0 |
| 3 | 路由 + 菜单注册 | P0 |
| 4 | 构建部署 admin.sayclaw.ai | P0 |
| 5 | 截图验证 | P0 |
8. 依赖
- ✅ 数据库表
professions+profession_instances已存在(sayclaw_admin库) - ✅ Portal API
/me/professions+/me/professions/:id/claim已上线 - ✅ Admin API 已有 marketplace handler 可参考
- ⚠️ Soybean Admin 源码在 GitLab
sayclaw-admin(project 5)仓库