Initial sanitized code sync
This commit is contained in:
538
docs/web-panel-plan.md
Normal file
538
docs/web-panel-plan.md
Normal file
@@ -0,0 +1,538 @@
|
||||
# GPT-Plus Web 管理面板方案
|
||||
|
||||
## 一、技术选型
|
||||
|
||||
| 层 | 选型 | 理由 |
|
||||
|---|------|------|
|
||||
| Backend | Go + Gin | 与现有 Go 代码无缝集成,Gin 轻量高性能 |
|
||||
| Frontend | Vue 3 + Vite + Element Plus | 中后台组件库成熟,中文友好 |
|
||||
| Database | SQLite + GORM | 零部署依赖,单文件数据库,适合单机场景 |
|
||||
| Auth | JWT + bcrypt | .env 设置管理员密码,JWT 签发 token |
|
||||
| 部署 | 单二进制 + embed 前端 | `go:embed` 嵌入前端 dist,一个二进制即运行 |
|
||||
|
||||
## 二、目录结构
|
||||
|
||||
```
|
||||
gpt-plus/
|
||||
├── cmd/
|
||||
│ └── gptplus/
|
||||
│ └── main.go # 入口:启动 web server
|
||||
├── config/
|
||||
│ └── config.go # 保留,Web 化后从 DB 读取
|
||||
├── internal/
|
||||
│ ├── db/
|
||||
│ │ ├── db.go # GORM 初始化 + 自动迁移
|
||||
│ │ ├── models.go # 数据模型
|
||||
│ │ └── query.go # 查询/聚合方法
|
||||
│ ├── handler/
|
||||
│ │ ├── auth.go # POST /api/login
|
||||
│ │ ├── config.go # GET/PUT /api/config
|
||||
│ │ ├── task.go # 任务 CRUD + 控制
|
||||
│ │ ├── account.go # 账号列表/搜索/导出/检查
|
||||
│ │ └── middleware.go # JWT 鉴权中间件
|
||||
│ ├── task/
|
||||
│ │ ├── manager.go # 任务管理器(创建/运行/停止)
|
||||
│ │ ├── runner.go # 单任务执行器(调用现有 runOnce)
|
||||
│ │ └── types.go # 任务状态/事件类型
|
||||
│ └── service/
|
||||
│ ├── account_svc.go # 账号业务逻辑
|
||||
│ └── export_svc.go # 导出(单文件/ZIP 打包)
|
||||
├── pkg/ # 现有核心逻辑不动
|
||||
│ ├── auth/
|
||||
│ ├── chatgpt/
|
||||
│ ├── stripe/
|
||||
│ ├── httpclient/
|
||||
│ ├── provider/
|
||||
│ │ ├── card/
|
||||
│ │ ├── email/
|
||||
│ │ └── proxy/
|
||||
│ ├── captcha/
|
||||
│ └── storage/ # 保留文件导出,DB 为主存储
|
||||
├── web/
|
||||
│ └── frontend/ # Vue 3 SPA
|
||||
│ ├── src/
|
||||
│ │ ├── views/
|
||||
│ │ │ ├── Login.vue
|
||||
│ │ │ ├── Dashboard.vue # 概览(统计卡片)
|
||||
│ │ │ ├── Config.vue # 配置管理
|
||||
│ │ │ ├── Tasks.vue # 任务列表
|
||||
│ │ │ ├── TaskDetail.vue # 任务详情 + 实时进度
|
||||
│ │ │ ├── Accounts.vue # 账号面板
|
||||
│ │ │ └── AccountDetail.vue # 母号详情(含小号列表)
|
||||
│ │ ├── api/ # axios 封装
|
||||
│ │ ├── router/
|
||||
│ │ ├── stores/ # Pinia 状态管理
|
||||
│ │ └── components/
|
||||
│ ├── package.json
|
||||
│ └── vite.config.ts
|
||||
├── .env # ADMIN_PASSWORD=xxx, JWT_SECRET=xxx
|
||||
├── gptplus.db # SQLite 数据库文件 (运行时生成)
|
||||
└── go.mod
|
||||
```
|
||||
|
||||
## 三、数据模型
|
||||
|
||||
### 3.1 系统配置表 `configs`
|
||||
|
||||
```go
|
||||
type SystemConfig struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
Key string `gorm:"uniqueIndex;size:100"` // e.g. "proxy.url", "email.provider"
|
||||
Value string `gorm:"type:text"`
|
||||
Group string `gorm:"size:50;index"` // "proxy", "email", "card", "stripe", etc.
|
||||
Label string `gorm:"size:100"` // 中文显示名
|
||||
Type string `gorm:"size:20"` // "string", "int", "bool", "password", "textarea"
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
```
|
||||
|
||||
配置组 (Group):
|
||||
- `proxy` — 代理模式(直连/固定代理/B2Proxy动态代理)、B2Proxy API 地址、代理区域(国家代码,如 US/JP/KR)、协议(socks5/http)、会话时长等
|
||||
- `email` — 邮箱网关域名、API Key
|
||||
- `card` — 卡片默认绑定上限(max_binds)、默认地址信息、开卡 API 密钥
|
||||
- `stripe` — build_hash, tag_version, fingerprint_dir
|
||||
- `captcha` — 验证码提供商、API Key
|
||||
- `account` — 密码长度、locale
|
||||
- `team` — 开关、workspace 前缀、座位数、优惠券、邀请数
|
||||
|
||||
> 邮箱不再作为配置项,去掉 MailGateway,全量使用 Outlook。邮箱通过 mailboxes 表管理。
|
||||
|
||||
### 3.2 邮箱表 `mailboxes`
|
||||
|
||||
```go
|
||||
type Mailbox struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
Email string `gorm:"size:200;uniqueIndex"`
|
||||
Password string `gorm:"size:200"`
|
||||
ClientID string `gorm:"size:200"` // Outlook OAuth client_id
|
||||
RefreshToken string `gorm:"type:text"` // Outlook OAuth refresh_token
|
||||
|
||||
// 使用状态
|
||||
Status string `gorm:"size:20;index;default:available"`
|
||||
// available / in_use / used / used_member / failed / disabled
|
||||
|
||||
UsedByAccountID *uint `gorm:"index"`
|
||||
UsedForRole string `gorm:"size:20"` // "owner" / "member"
|
||||
UsedAt *time.Time
|
||||
TaskID string `gorm:"size:36;index"`
|
||||
|
||||
CreatedAt time.Time `gorm:"index"`
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
```
|
||||
|
||||
**邮箱生命周期**:
|
||||
```
|
||||
available → in_use → used (主号) / used_member (小号) / failed (可回收)
|
||||
→ disabled (管理员禁用)
|
||||
failed → available (回收重用)
|
||||
```
|
||||
|
||||
**适配**: 新增 `DBEmailProvider`,不再用内存索引,完全 DB 状态驱动。
|
||||
|
||||
**API**: 导入/回收/禁用/统计,邮箱面板可视化管理。
|
||||
|
||||
### 3.3 注册任务表 `tasks`
|
||||
|
||||
```go
|
||||
type Task struct {
|
||||
ID string `gorm:"primaryKey;size:36"` // UUID
|
||||
Type string `gorm:"size:20;index"` // "plus", "team", "both"
|
||||
TotalCount int // 本轮要注册多少个
|
||||
DoneCount int // 已完成(成功+失败)
|
||||
SuccessCount int // 成功数
|
||||
FailCount int // 失败数
|
||||
Status string `gorm:"size:20;index"` // pending/running/stopping/stopped/completed
|
||||
Config string `gorm:"type:text"` // 快照:任务创建时的配置 JSON
|
||||
CreatedAt time.Time `gorm:"index"`
|
||||
StartedAt *time.Time
|
||||
StoppedAt *time.Time
|
||||
}
|
||||
```
|
||||
|
||||
状态流转:
|
||||
```
|
||||
pending → running → completed
|
||||
→ stopping → stopped (graceful stop)
|
||||
```
|
||||
|
||||
### 3.3 任务日志表 `task_logs`
|
||||
|
||||
```go
|
||||
type TaskLog struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
TaskID string `gorm:"size:36;index"`
|
||||
Index int // 第几个账号 (1-based)
|
||||
Email string `gorm:"size:200"`
|
||||
Status string `gorm:"size:20"` // success/failed/skipped
|
||||
Plan string `gorm:"size:20"` // plus/team/free
|
||||
Error string `gorm:"type:text"`
|
||||
Duration int // 耗时(秒)
|
||||
CreatedAt time.Time
|
||||
}
|
||||
```
|
||||
|
||||
### 3.4 卡密表 `card_codes` + 卡片表 `cards`
|
||||
|
||||
两层管理:卡密(兑换码)→ 卡片(已开卡)。同一时间只有一张卡 active。
|
||||
|
||||
**CardCode**: unused → redeeming → redeemed(关联card) / failed
|
||||
**Card**: available → active(全局唯一) → exhausted / rejected / disabled
|
||||
|
||||
自动切换:active失效 → 找available → 无则兑换卡密 → 无则报错
|
||||
|
||||
API: `/api/cards` + `/api/card-codes` (CRUD + 激活 + 兑换 + 统计)
|
||||
UI: 两个Tab(卡片+卡密),顶部高亮当前激活卡
|
||||
|
||||
详见 Obsidian 完整文档。
|
||||
|
||||
### 3.5 账号表 `accounts`
|
||||
|
||||
```go
|
||||
type Account struct {
|
||||
ID uint `gorm:"primaryKey"`
|
||||
TaskID string `gorm:"size:36;index"` // 来源任务
|
||||
Email string `gorm:"size:200;uniqueIndex"`
|
||||
Password string `gorm:"size:100"`
|
||||
Plan string `gorm:"size:20;index"` // "plus", "team_owner", "team_member"
|
||||
ParentID *uint `gorm:"index"` // team_member → 指向 team_owner
|
||||
Parent *Account `gorm:"foreignKey:ParentID"`
|
||||
SubAccounts []Account `gorm:"foreignKey:ParentID"` // team_owner 的小号列表
|
||||
|
||||
// Auth tokens
|
||||
AccessToken string `gorm:"type:text"`
|
||||
RefreshToken string `gorm:"type:text"`
|
||||
IDToken string `gorm:"type:text"`
|
||||
AccountID string `gorm:"size:100"`
|
||||
DeviceID string `gorm:"size:100"`
|
||||
UserID string `gorm:"size:100"`
|
||||
|
||||
// Team specific
|
||||
TeamWorkspaceID string `gorm:"size:100"`
|
||||
WorkspaceToken string `gorm:"type:text"` // team workspace-scoped token
|
||||
|
||||
// Status
|
||||
Status string `gorm:"size:20;index;default:active"` // active/banned/unknown
|
||||
StatusCheckedAt *time.Time
|
||||
Note string `gorm:"type:text"` // 用户备注
|
||||
|
||||
CreatedAt time.Time `gorm:"index"`
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
```
|
||||
|
||||
## 四、API 设计
|
||||
|
||||
### 4.1 认证
|
||||
|
||||
```
|
||||
POST /api/login { password: "xxx" } → { token: "jwt..." }
|
||||
```
|
||||
|
||||
所有 `/api/*` 路由需 `Authorization: Bearer <jwt>` 头(中间件校验)。
|
||||
|
||||
### 4.2 配置管理
|
||||
|
||||
```
|
||||
GET /api/config → { groups: { proxy: [...], email: [...], ... } }
|
||||
PUT /api/config { items: [ {key, value}, ... ] }
|
||||
GET /api/config/test-connection → 测试代理/邮箱/卡片连通性
|
||||
```
|
||||
|
||||
### 4.3 任务管理
|
||||
|
||||
```
|
||||
POST /api/tasks { type: "plus", count: 10 } → { id: "uuid", status: "pending" }
|
||||
GET /api/tasks → [ { id, type, total, done, success, fail, status, created_at } ]
|
||||
GET /api/tasks/:id → { ...task, logs: [...] }
|
||||
POST /api/tasks/:id/start → 启动任务
|
||||
POST /api/tasks/:id/stop → 优雅停止(完成当前轮后停止)
|
||||
DELETE /api/tasks/:id → 删除已完成/已停止的任务
|
||||
```
|
||||
|
||||
**实时进度**: 前端轮询 `GET /api/tasks/:id`(2s 间隔),返回最新 done/success/fail 计数 + 最新日志。
|
||||
|
||||
### 4.4 账号管理
|
||||
|
||||
```
|
||||
GET /api/accounts ?plan=plus|team_owner&search=email&page=1&size=20
|
||||
GET /api/accounts/:id → 账号详情(含小号列表)
|
||||
POST /api/accounts/check { ids: [1,2,3] } → 批量检查状态
|
||||
PUT /api/accounts/:id/note { note: "xxx" } → 更新备注
|
||||
POST /api/accounts/export { ids: [1,2,3], note: "导出备注" } → 文件下载
|
||||
```
|
||||
|
||||
**账号列表规则**:
|
||||
- 默认只显示 `plan = plus` 和 `plan = team_owner`
|
||||
- `team_member` 不在列表中显示,归属于其 `parent` (team_owner)
|
||||
- 搜索可以搜到 team_member(显示其所属母号)
|
||||
|
||||
**导出规则**:
|
||||
- 导出 Plus 账号 → 单个 `{email}.auth.json`
|
||||
- 导出 Team 母号 → 母号 `.auth.json` + 所有小号 `.auth.json`
|
||||
- 导出文件数 > 1 → 自动打包为 `.zip`
|
||||
- 导出文件名: `export_{备注}_{timestamp}.zip` 或 `{email}.auth.json`
|
||||
|
||||
### 4.5 Dashboard
|
||||
|
||||
```
|
||||
GET /api/dashboard → { total_accounts, plus_count, team_count,
|
||||
active_tasks, recent_tasks: [...],
|
||||
today_registrations, success_rate }
|
||||
```
|
||||
|
||||
## 五、任务执行引擎
|
||||
|
||||
### 5.1 TaskManager
|
||||
|
||||
```go
|
||||
type TaskManager struct {
|
||||
mu sync.Mutex
|
||||
running map[string]*TaskRunner // taskID → runner
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func (m *TaskManager) Start(taskID string) error
|
||||
func (m *TaskManager) Stop(taskID string) error // 设置 stopping flag
|
||||
func (m *TaskManager) GetStatus(taskID string) *TaskStatus
|
||||
```
|
||||
|
||||
### 5.2 TaskRunner
|
||||
|
||||
```go
|
||||
type TaskRunner struct {
|
||||
task *db.Task
|
||||
config *config.Config // 从任务快照还原
|
||||
cancel context.CancelFunc
|
||||
stopping atomic.Bool // graceful stop signal
|
||||
}
|
||||
|
||||
func (r *TaskRunner) Run(ctx context.Context) {
|
||||
for i := 0; i < r.task.TotalCount; i++ {
|
||||
if r.stopping.Load() {
|
||||
break // 当前轮完成后停止
|
||||
}
|
||||
result := runOnce(ctx, i, ...) // 调用现有核心逻辑
|
||||
r.saveResult(result) // 写入 DB
|
||||
r.updateProgress() // 更新任务计数
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 停止逻辑
|
||||
|
||||
用户点击"停止" → `POST /api/tasks/:id/stop`:
|
||||
1. 设置 `task.Status = "stopping"` (DB)
|
||||
2. 设置 `runner.stopping = true` (内存)
|
||||
3. 当前正在执行的 `runOnce()` 会跑完
|
||||
4. 下一轮循环检测到 `stopping` → break
|
||||
5. 更新 `task.Status = "stopped"` (DB)
|
||||
|
||||
## 六、前端页面
|
||||
|
||||
### 6.0 全局布局架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ Navbar [Logo GPT-Plus] [配置] [任务] [账号] [■ 任务进度浮窗] [退出] │
|
||||
├─────────────────────────────────────────────────────┤
|
||||
│ │
|
||||
│ <router-view /> │
|
||||
│ (当前页面内容) │
|
||||
│ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**核心设计: 全局任务进度浮窗 (TaskProgressWidget)**
|
||||
|
||||
右上角常驻一个**任务进度迷你组件**,行为规则:
|
||||
- 有 running/stopping 状态的任务时**始终显示**,跨路由不消失
|
||||
- 登录页**不显示**(layout 不包含 navbar)
|
||||
- 无活跃任务时**隐藏**或显示为灰色空状态
|
||||
- 点击浮窗可**展开**查看详情或**跳转**到任务详情页
|
||||
|
||||
**浮窗 UI**:
|
||||
```
|
||||
┌──────────────────────────┐
|
||||
│ ● 任务进行中 3/10 │ ← 收起态:一行摘要 + 进度条
|
||||
│ ████████░░░░ 30% │
|
||||
│ [展开 ▼] │
|
||||
├──────────────────────────┤ ← 展开态:显示详细信息
|
||||
│ 类型: Plus │
|
||||
│ 成功: 2 失败: 1 │
|
||||
│ 当前: user_xxx@outlook.. │
|
||||
│ [查看详情] [停止任务] │
|
||||
└──────────────────────────┘
|
||||
```
|
||||
|
||||
**实现方式**:
|
||||
- `Pinia` 全局 store: `useTaskStore()` — 管理活跃任务状态
|
||||
- store 内置定时轮询(3s 间隔),**独立于路由组件生命周期**
|
||||
- 登录成功后启动轮询,退出登录时停止
|
||||
- 组件: `TaskProgressWidget.vue` 挂在 `AppLayout.vue` 的 navbar 中
|
||||
|
||||
```
|
||||
src/
|
||||
├── layouts/
|
||||
│ ├── AppLayout.vue # 已登录布局:navbar + sidebar + router-view
|
||||
│ └── BlankLayout.vue # 登录页布局:无 navbar
|
||||
├── components/
|
||||
│ └── TaskProgressWidget.vue # 全局任务进度浮窗
|
||||
├── stores/
|
||||
│ └── taskStore.ts # 全局任务状态 + 轮询逻辑
|
||||
```
|
||||
|
||||
**路由结构**:
|
||||
```typescript
|
||||
const routes = [
|
||||
{
|
||||
path: '/login',
|
||||
component: BlankLayout, // 无 navbar,无浮窗
|
||||
children: [{ path: '', component: Login }]
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
component: AppLayout, // 有 navbar + TaskProgressWidget
|
||||
meta: { requiresAuth: true },
|
||||
children: [
|
||||
{ path: '', component: Dashboard },
|
||||
{ path: 'config', component: Config },
|
||||
{ path: 'tasks', component: Tasks },
|
||||
{ path: 'tasks/:id', component: TaskDetail },
|
||||
{ path: 'accounts', component: Accounts },
|
||||
{ path: 'accounts/:id', component: AccountDetail },
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### 6.1 登录页 (BlankLayout)
|
||||
- 单密码输入框 + 登录按钮
|
||||
- JWT 存 localStorage
|
||||
- 登录成功 → 跳转 Dashboard + 启动 taskStore 轮询
|
||||
|
||||
### 6.2 Dashboard (首页)
|
||||
- 统计卡片: 总账号数、Plus 数、Team 数、今日注册数
|
||||
- 活跃任务列表(简要)
|
||||
- 最近注册记录
|
||||
|
||||
### 6.3 配置页
|
||||
- 分组表单 (Tabs: 代理 | 邮箱 | 卡片 | Stripe | 验证码 | 账号 | Team)
|
||||
- 每组内用 Element Plus 表单组件
|
||||
- 密码类型用 `el-input type="password"`
|
||||
- 底部"保存"按钮 + 连通性测试按钮
|
||||
|
||||
### 6.4 任务页
|
||||
- 顶部: "新建任务" 按钮 → 弹窗 (选类型 + 输入数量)
|
||||
- 任务列表表格: ID | 类型 | 进度 (3/10) | 成功/失败 | 状态 | 操作
|
||||
- 状态标签: pending=灰, running=蓝(动画), stopping=黄, stopped=橙, completed=绿
|
||||
- 操作: 启动 | 停止 | 查看详情 | 删除
|
||||
- 点击任务 → 任务详情页
|
||||
|
||||
### 6.5 任务详情页
|
||||
- 进度条 + 计数器 (成功/失败/总数)
|
||||
- 实时日志表格: 序号 | 邮箱 | 状态 | 类型 | 耗时 | 错误信息
|
||||
- 2 秒轮询刷新(与全局 store 复用数据)
|
||||
|
||||
### 6.6 账号面板
|
||||
- 筛选栏: 类型下拉(全部/Plus/Team母号) | 搜索框(邮箱) | 状态筛选(全部/正常/封禁)
|
||||
- 表格: 勾选框 | 邮箱 | 类型 | 状态 | 小号数 | 备注 | 创建时间 | 操作
|
||||
- 操作: 查看详情 | 编辑备注 | 检查状态 | 导出
|
||||
- 批量操作栏: 勾选后 → 批量导出 | 批量检查状态
|
||||
- 导出弹窗: 输入备注 → 确认导出 → 浏览器下载
|
||||
|
||||
### 6.7 账号详情页 (Team 母号)
|
||||
- 母号信息卡片
|
||||
- 小号列表表格 (最多 4 个): 邮箱 | 状态 | Token 概要
|
||||
|
||||
## 七、.env 配置
|
||||
|
||||
```env
|
||||
# 管理员密码 (必填)
|
||||
ADMIN_PASSWORD=your_secure_password
|
||||
|
||||
# JWT 密钥 (可选,默认随机生成)
|
||||
JWT_SECRET=random_secret_key
|
||||
|
||||
# 服务端口 (默认 8080)
|
||||
PORT=8080
|
||||
|
||||
# 数据库路径 (默认 ./gptplus.db)
|
||||
DB_PATH=./gptplus.db
|
||||
```
|
||||
|
||||
## 八、构建 & 部署
|
||||
|
||||
### 开发模式
|
||||
```bash
|
||||
# 前端
|
||||
cd web/frontend && npm run dev
|
||||
|
||||
# 后端 (代理前端)
|
||||
go run ./cmd/gptplus/ --dev
|
||||
```
|
||||
|
||||
### 生产构建
|
||||
```bash
|
||||
# 1. 构建前端
|
||||
cd web/frontend && npm run build
|
||||
|
||||
# 2. 构建后端 (embed 前端 dist)
|
||||
CGO_ENABLED=1 go build -o gptplus ./cmd/gptplus/
|
||||
# 注: SQLite 需要 CGO
|
||||
|
||||
# 3. 部署
|
||||
scp gptplus server:/root/gptplus/
|
||||
scp .env server:/root/gptplus/
|
||||
ssh server 'cd /root/gptplus && ./gptplus'
|
||||
```
|
||||
|
||||
### 单二进制方案
|
||||
```go
|
||||
//go:embed web/frontend/dist
|
||||
var frontendFS embed.FS
|
||||
|
||||
// Gin 中挂载
|
||||
router.StaticFS("/", http.FS(frontendFS))
|
||||
```
|
||||
|
||||
## 九、迁移计划
|
||||
|
||||
### Phase 1: 基础框架 (Day 1-2)
|
||||
- [ ] 初始化 SQLite + GORM + 数据模型
|
||||
- [ ] Gin 路由 + JWT 中间件
|
||||
- [ ] 配置 CRUD API
|
||||
- [ ] Vue 3 项目初始化 + 登录页 + 配置页
|
||||
|
||||
### Phase 2: 任务引擎 (Day 2-3)
|
||||
- [ ] TaskManager + TaskRunner
|
||||
- [ ] 重构 runOnce() 解耦:接受 config 参数而非全局状态
|
||||
- [ ] 任务 API + 前端任务页
|
||||
|
||||
### Phase 3: 账号面板 (Day 3-4)
|
||||
- [ ] Account 存储从文件 → DB
|
||||
- [ ] 搜索/筛选/分页 API
|
||||
- [ ] 导出(JSON/ZIP)
|
||||
- [ ] 状态检查 (调用 ChatGPT session API)
|
||||
- [ ] 前端账号面板
|
||||
|
||||
### Phase 4: 打磨 (Day 4-5)
|
||||
- [ ] Dashboard 统计
|
||||
- [ ] embed 前端 + 单二进制构建
|
||||
- [ ] 错误处理 + 日志
|
||||
- [ ] 部署到服务器
|
||||
|
||||
## 十、改动范围
|
||||
|
||||
| 动作 | 路径 | 说明 |
|
||||
|------|------|------|
|
||||
| 新增 | `internal/db/` | GORM 模型 + 查询 |
|
||||
| 新增 | `internal/handler/` | Gin HTTP handlers |
|
||||
| 新增 | `internal/task/` | 任务管理引擎 |
|
||||
| 新增 | `internal/service/` | 导出/检查业务逻辑 |
|
||||
| 新增 | `web/frontend/` | Vue 3 SPA |
|
||||
| 重写 | `cmd/gptplus/main.go` | CLI → Web Server |
|
||||
| 修改 | `config/config.go` | 支持从 DB 加载 |
|
||||
| 修改 | `pkg/storage/json.go` | 同时写 DB + 文件 |
|
||||
| 新增 | `.env` | 管理员密码 + JWT 密钥 |
|
||||
| 保留 | `pkg/*` 全部 | 核心业务逻辑不动 |
|
||||
Reference in New Issue
Block a user