仰望星辰工作室

better-staridc-MNBT

better-staridc-MNBT/ docs/prd/docker-shop.md 13.3 KB · 270 行 原始文件
Z zfhsh first commit 1 天前
1---
2title: docker_shop Docker 售卖插件 PRD
3description: Docker 容器售卖插件(docker_shop)与 tdesign 用户中心 account 主题改造的产品需求文档
4---
5
6# docker_shop Docker 售卖插件 PRD
7
8> 版本:v0.1(初稿)
9> 日期:2026-08-10
10> 状态:评审中
11> 关联文档:[插件开发手册](../development/plugin/guide.md)、[hosting_shop 主机售卖插件](../development/plugin/builtin/hosting-shop.md)、[Docker 集成 PRD](./docker.md)、[Docker 魔方财务对接](../integration/idcsmart-docker.md)
12
13## 1. 背景与目标
14
15### 1.1 背景
16
17MNBT 已具备两套并行业务线:
18
191. **虚拟主机业务**(`MN_zj` / `MN_bt`):通过 `hosting_shop` 插件实现了完整的售卖闭环——管理员配置套餐价格、用户浏览下单、余额/在线支付、`order.paid` 钩子自动开通。
202. **Docker 容器业务**(`MN_docker_user` / `MN_docker_plan` / `MN_docker_node`):已有独立控制台(`docker/` scope)、独立认证(`docker_token`)、管理员端节点/套餐/用户管理,以及魔方财务对接(`api/docker.php`)。但 **Docker 没有自营售卖闭环**——管理员无法通过后台把 Docker 配额套餐挂上价格卖给 user_info 用户。
21
22当前只有 `hosting_shop` 主机售卖插件,缺少 Docker 售卖插件;tdesign 主题的 **account(用户中心)** 部分仅展示主机商城(ShopView/HostingView/OrdersView),无法售卖和查看 Docker 资产。
23
24### 1.2 目标
25
261. 新增 **docker_shop** 插件,参照 `hosting_shop` 模式实现 Docker 售卖闭环:
27 - 管理员配置「售卖套餐」(绑定现有 Docker 配额套餐 + 固定开通节点 + 周期价格)
28 - 用户(user_info 账号)浏览 Docker 套餐、下单、支付(余额/在线支付)
29 - 支付成功后 `order.paid` 钩子自动开通 Docker 账号(写入 `MN_docker_user`)
30 - 资产页展示 Docker 账号凭据与容器状态,一键进入 Docker 控制台
312. 改造 **tdesign 主题 account 部分**:新增「Docker 商城 / 我的 Docker / Docker 订单」菜单与页面,与现有主机商城并列。
32
33### 1.3 非目标(本期不做)
34
35- 不接管/修改现有 Docker 控制台(`docker/` scope)与独立认证逻辑
36- 不改动 `MN_docker_user` / `MN_docker_plan` / `MN_docker_node` 核心表结构
37- 不做 Docker 套餐自助续费(续费由管理员后台人工处理,后续版本可加)
38- 不做多容器/自定义镜像购买(沿用单容器模型,容器由用户在控制台创建)
39
40## 2. 现状与差距
41
42| 环节 | hosting_shop(主机) | Docker(现状) | 差距 |
43|------|----------------------|----------------|------|
44| 套餐价格配置 | `MN_plugin_hosting_plan`(周期价格) | `MN_docker_plan` 仅 `jg` 单价格,无周期 | 缺售卖价格模型 |
45| 用户下单 | P2 路由 `/shop/*` + `MN_dd` 支付 | 无 | 缺购买链路 |
46| 自动开通 | `order.paid` → `hosting_open_host()` 写 `MN_zj` | `api/docker.php?gn=kt` 仅外部 API | 缺内部开通函数 |
47| 用户资产页 | `MN_plugin_hosting_asset` + HostingView | 无自营资产 | 缺资产模型 |
48| 用户中心入口 | account SPA「商城」分组 | 无 | 缺菜单/页面 |
49
50## 3. 范围(P0)
51
52- `docker_shop` 插件:3 张插件自有表、开通逻辑、订单/资产管理、管理员端页面
53- tdesign account SPA:新增 Docker 商城/资产/订单三个页面与菜单入口
54- 文档:本 PRD + 内置插件文档
55
56## 4. 架构总览
57
58```
59user_info 用户(account SPA / tdesign 主题)
60 │ 浏览 /docker-shop/api/*(P2 路由)
61 ▼
62docker_shop 插件
63 ├─ 售卖套餐 MN_plugin_docker_plan ──引用──▶ MN_docker_plan(配额,复用控制台强制)
64 ├─ 订单 MN_plugin_docker_order ──关联──▶ MN_dd.ddh(支付系统)
65 ├─ 资产 MN_plugin_docker_asset ──记录──▶ MN_docker_user(Docker 账号)
66 │
67 └─ order.paid 钩子(lx=docker)→ docker_shop_open_account()
68 │ 生成账号密码 / 计算到期 / 写 MN_docker_user
69 ▼
70 Docker 控制台(docker/login.php,docker_token 独立登录)
71```
72
73关键设计:**售卖套餐与配额套餐分离**。
74
75- `MN_docker_plan` 是 Docker 配额基准(`cpu_max/mem_max/disk_max/proxy_max`),由 Docker 控制台与管理员 Docker 套餐页管理,**不动核心表**。
76- `MN_plugin_docker_plan` 是售卖配置(周期价格 + 固定节点 + 绑定基准套餐),由插件管理。
77- 开通时 `MN_docker_user.plan_id = 基准套餐 id`、`MN_docker_user.ssbt = 节点 id`,Docker 控制台的配额强制逻辑直接生效。
78
79## 5. 数据库设计(插件自有表,前缀 `MN_plugin_`)
80
81### 5.1 `MN_plugin_docker_plan` — 售卖套餐
82
83| 字段 | 类型 | 说明 |
84|------|------|------|
85| id | INT AUTO_INCREMENT | 主键 |
86| name | VARCHAR(120) | 售卖套餐名称 |
87| description | TEXT | 售卖介绍 |
88| category | VARCHAR(50) | 分类 |
89| node | INT | 固定开通节点 `MN_docker_node.id` |
90| base_plan_id | INT | 绑定配额套餐 `MN_docker_plan.id` |
91| price_month_cents | INT | 月付价格(分) |
92| price_quarter_cents | INT | 季付价格(分) |
93| price_half_year_cents | INT | 半年付价格(分) |
94| price_year_cents | INT | 年付价格(分) |
95| price_two_year_cents | INT | 两年付价格(分) |
96| price_three_year_cents | INT | 三年付价格(分) |
97| enabled_periods | VARCHAR(255) | 允许周期,逗号分隔 |
98| status | VARCHAR(20) | active/inactive |
99| sort | INT | 排序 |
100| created_at / updated_at | VARCHAR(50) | 时间戳 |
101
102### 5.2 `MN_plugin_docker_order` — 订单
103
104| 字段 | 类型 | 说明 |
105|------|------|------|
106| id | INT AUTO_INCREMENT | 主键 |
107| user_id | INT | user_info 用户 ID |
108| plan_id | INT | 售卖套餐 ID |
109| plan_name | VARCHAR(120) | 套餐名称快照 |
110| period | VARCHAR(10) | 周期 |
111| amount_cents | INT | 金额(分) |
112| order_no | VARCHAR(64) | 关联 `MN_dd.ddh` |
113| node | INT | 开通节点 |
114| docker_user_id | INT | 开通后回填 `MN_docker_user.id` |
115| status | VARCHAR(20) | pending/paid/opened/failed/cancelled |
116| remark | TEXT | 备注/失败原因/账号密码 |
117| created_at / paid_at / opened_at | VARCHAR(50) | 时间 |
118
119### 5.3 `MN_plugin_docker_asset` — 资产
120
121| 字段 | 类型 | 说明 |
122|------|------|------|
123| id | INT AUTO_INCREMENT | 主键 |
124| user_id | INT | 所属用户 |
125| order_id | INT | 开通订单 |
126| docker_user_id | INT | `MN_docker_user.id` |
127| plan_id | INT | 售卖套餐 ID |
128| plan_name | VARCHAR(120) | 套餐名快照 |
129| docker_username | VARCHAR(64) | Docker 控制台登录名(明文冗余,同 `MN_zj.user` 惯例) |
130| docker_password | VARCHAR(64) | Docker 控制台登录密码(明文冗余,同 `MN_zj.pass` 惯例) |
131| expire_at | VARCHAR(50) | 到期时间(0000-00-00=永久) |
132| status | VARCHAR(20) | active/expired/cancelled |
133| created_at | VARCHAR(50) | 创建时间 |
134
135## 6. 插件设计
136
137### 6.1 依赖
138
139- **user_info**(认证):购买用户即 user_info 用户
140- **balance**(支付):余额扣款作为可用支付方式
141- 核心 Docker 能力(`MN_docker_user` / `MN_docker_plan` / `MN_docker_node`、`docker_auth_password_hash()`)——非插件依赖,按核心函数存在性保护
142
143### 6.2 访问路径(P2 路由)
144
145| 页面 | URL |
146|------|-----|
147| Docker 商城 | `index.php?_r=/docker-shop` |
148| Docker 下单 | `index.php?_r=/docker-shop/order/{plan_id}` |
149| 我的 Docker | `index.php?_r=/docker-shop/assets` |
150| Docker 订单 | `index.php?_r=/docker-shop/orders` |
151| 控制台入口 | `{base}/docker/login.php`(独立登录) |
152
153### 6.3 API 路由
154
155| 方法 | 路径 | 说明 |
156|------|------|------|
157| GET | `/docker-shop/api/plans` | 售卖套餐列表(含基准配额展示) |
158| GET | `/docker-shop/api/plan/{plan_id}` | 套餐详情 + 支付方式 |
159| GET | `/docker-shop/api/assets` | 我的 Docker 资产 |
160| GET | `/docker-shop/api/orders` | Docker 订单(分页) |
161| GET | `/docker-shop/api/methods` | 可用支付方式 |
162| POST | `/docker-shop/api/create_order` | 创建订单(创建 `MN_dd` lx=docker + 分发支付网关) |
163| POST | `/docker-shop/api/reset_password` | 重置 Docker 账号密码(返回新密码一次) |
164
165### 6.4 核心流程
166
167```
168用户选择售卖套餐 → 校验周期/价格/节点/基准套餐
169 → 创建 MN_plugin_docker_order(status=pending)
170 → 创建 MN_dd(lx=docker, zffs=支付方式) → 分发支付网关
171 → 支付回调 → mnbt_pay_settle_order → order.paid 钩子
172 → docker_shop_open_account():
173 1. 校验订单 paid 未开通
174 2. 生成 Docker 登录名(优先 user_info username,冲突则加随机后缀)
175 3. 生成随机密码(12 位),docker_auth_password_hash 写入
176 4. 计算到期时间(周期 months),写入 MN_docker_user
177 (plan_id=基准套餐, ssbt=节点, qk=active, container_status=none)
178 5. 写入 MN_plugin_docker_asset(含明文账号密码)
179 6. 回填订单 status=opened, docker_user_id
180 7. 触发 docker.user.created 钩子
181 → 用户在前端资产页查看凭据 → 前往 Docker 控制台登录
182```
183
184**0 元免费套餐**:下单后直接标记 paid 并开通,不经过支付网关(同 hosting_shop)。
185
186### 6.5 管理员端
187
188| 页面 | 入口 |
189|------|------|
190| 售卖套餐管理 | `plugin.php?p=docker_shop&page=plans` |
191| 售卖套餐编辑 | `plugin.php?p=docker_shop&page=plan_edit&id={id}` |
192| 订单管理 | `plugin.php?p=docker_shop&page=orders` |
193| 资产管理 | `plugin.php?p=docker_shop&page=assets` |
194
195侧边栏菜单「Docker 售卖」(三级结构,同 hosting_shop)。套餐编辑页提供「绑定配额套餐(`MN_docker_plan` 下拉)+ 固定节点(`MN_docker_node` 下拉)+ 周期价格 + 启用周期」表单。
196
197### 6.6 钩子
198
199| 钩子 | 优先级 | 说明 |
200|------|--------|------|
201| `order.paid` | 20 | 处理 `lx=docker` 订单:防重复 → 标记 paid → 开通 |
202
203### 6.7 安全边界
204
205- 所有 API 路由前置 `user_info_auth_current()` 校验,未登录返回 `not_login`
206- 开通函数禁止由前端直接调用(仅 `order.paid` 钩子与 0 元下单内部触发)
207- 管理员页面沿用 `mnbt_plugin_require_admin()` 鉴权
208- 密码仅明文存资产表(同 `MN_zj.pass` 惯例),API 返回资产列表时**剔除 `password_hash`**
209- 节点信息仅返回 id/名称,不暴露 `btip/btdk/ptl/btmy`
210
211## 7. tdesign 主题 account 部分改造
212
213### 7.1 入口 boot(`templates/tdesign/account/_spa_boot.php`)
214
215- `plugins.docker_shop`:插件启用标志(account SPA 据此显示 Docker 菜单)
216- `dockerUrl`:Docker 控制台登录入口(`{base}/docker/login.php`)
217
218### 7.2 SPA 前端(`templates/tdesign/spa/src/account/`)
219
220| 文件 | 改动 |
221|------|------|
222| `api/plugins.js` | 新增 docker_shop API 封装:`getDockerShopPlans` / `getDockerShopAssets` / `getDockerShopOrders` / `createDockerShopOrder` / `resetDockerPassword` / `dockerConsoleUrl` |
223| `router/index.js` | 新增路由:`/docker-shop`、`/docker-assets`、`/docker-orders` |
224| `layouts/AccountLayout.vue` | 新增「Docker」侧栏分组(Docker 商城 / 我的 Docker / Docker 订单),用户菜单下拉补充入口 |
225| `views/DockerShopView.vue` | 售卖套餐卡片 + 下单对话框(复用 ShopView 交互:周期 + 支付方式 + 0 元提示) |
226| `views/DockerAssetsView.vue` | Docker 资产卡片:账号密码、到期时间、容器状态(含「刷新状态」「重置密码」)、进入控制台 |
227| `views/DockerOrdersView.vue` | Docker 订单列表(分页,状态标签) |
228| `views/DashboardView.vue` | 概览卡片与快速入口按 `plugins.docker_shop` 追加 Docker 资产数/入口 |
229
230### 7.3 构建
231
232`cd templates/tdesign/spa && npm run build:account`,产物输出到 `templates/tdesign/account/dist/`。
233
234## 8. 文件结构
235
236```
237app_plugins/docker_shop/
238├── plugin.json
239├── bootstrap.php # 主入口(钩子 + 路由 + 管理员页面 + 菜单 + AJAX)
240├── install.sql
241├── uninstall.sql
242├── lib/
243│ └── docker_shop.php # 周期/URL/认证/套餐/订单/资产/开通
244├── assets/
245│ └── style.css
246└── views/
247 ├── layout.php # 用户端公共布局
248 ├── shop.php # Docker 商城(非 SPA 兜底)
249 ├── order.php # 下单页(兜底)
250 ├── assets.php # 我的 Docker(兜底)
251 ├── orders.php # Docker 订单(兜底)
252 └── admin/
253 ├── plans.php # 售卖套餐管理
254 ├── plan_edit.php # 售卖套餐编辑
255 ├── orders.php # 订单管理
256 └── assets.php # 资产管理
257```
258
259## 9. 自测清单
260
261- [ ] 插件可安装/启用;后台侧栏出现「Docker 售卖」菜单
262- [ ] 管理员可创建售卖套餐(绑定配额套餐 + 节点 + 周期价格);下架后用户端不可见
263- [ ] 未登录访问 `/docker-shop` 跳登录
264- [ ] 余额支付购买成功 → `order.paid` → Docker 账号开通,订单/资产状态正确
265- [ ] 0 元套餐直接开通
266- [ ] 同一用户名重复购买生成不冲突的 Docker 登录名
267- [ ] 在线支付(epay)购买成功回调后同样开通
268- [ ] account SPA:Docker 菜单按插件启用与否显隐;资产页凭据可查看、可重置密码
269- [ ] 用开通的 Docker 账号可在 `/docker/login.php` 登录控制台,配额套餐生效
270- [ ] 禁用插件后菜单/路由失效