138 lines
5.8 KiB
Markdown
138 lines
5.8 KiB
Markdown
---
|
||
name: 渠道编号自动生成
|
||
overview: 在 slot-admin 后端创建渠道时自动生成唯一 6 位字母数字编号,编辑时禁止修改;slot-admin-vue 前端对应隐藏创建输入、编辑只读展示,并移除前端校验。
|
||
todos:
|
||
- id: backend-add-generate
|
||
content: GameServerLogic:实现 add() + generateUniqueSource(),合并原 save() 逻辑;edit() unset source
|
||
status: completed
|
||
- id: backend-validate
|
||
content: GameServerValidate:save/update 场景移除 source 校验
|
||
status: completed
|
||
- id: frontend-edit-form
|
||
content: edit.vue:新增隐藏编号、编辑只读、移除校验、提交时不传 source
|
||
status: completed
|
||
- id: verify
|
||
content: Docker 内手工验证创建/编辑,跑 verify-slot-backend.sh
|
||
status: completed
|
||
isProject: false
|
||
---
|
||
|
||
# 渠道编号系统自动生成方案
|
||
|
||
## 背景与范围
|
||
|
||
渠道管理对应模块:
|
||
|
||
| 层级 | 路径 |
|
||
|------|------|
|
||
| 前端列表/表单 | [`slot-admin-vue/src/views/game/source/index.vue`](slot-admin-vue/src/views/game/source/index.vue)、[`edit.vue`](slot-admin-vue/src/views/game/source/edit.vue) |
|
||
| API | `POST /game/game-server/save`、`PUT /game/game-server/update` |
|
||
| 后端 | [`GameServerController`](slot-admin/app/game/controller/GameServerController.php) → [`GameServerLogic`](slot-admin/app/game/logic/GameServerLogic.php) → [`GameServerModel`](slot-admin/app/model/GameServerModel.php) |
|
||
| 校验 | [`GameServerValidate`](slot-admin/app/game/validate/GameServerValidate.php) |
|
||
|
||
当前行为:创建/编辑时前端手动填写 `source`(编号),后端 `save`/`update` 场景均校验 `source` 必填。
|
||
|
||
**额外发现(需一并修复)**:[`GameServerLogic::save()`](slot-admin/app/game/logic/GameServerLogic.php) 含 `secret_key` 生成、`extend_data` 格式化、Redis 同步等逻辑,但 [`BaseController::save()`](slot-admin/plugin/saimulti/basic/BaseController.php) 实际调用的是 `logic->add()`,导致创建时这些逻辑**未执行**。本次应改为在 `add()` 中统一处理(参照 [`GGameLogic::add()`](slot-admin/app/game/logic/GGameLogic.php) 模式)。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant Vue as slot-admin-vue
|
||
participant Ctrl as GameServerController
|
||
participant Logic as GameServerLogic
|
||
participant DB as game_server
|
||
|
||
Vue->>Ctrl: POST save(不含 source)
|
||
Ctrl->>Logic: add(data)
|
||
Logic->>Logic: generateUniqueSource()
|
||
Logic->>Logic: prepareCreateData()
|
||
Logic->>DB: insert
|
||
Logic->>Logic: sync(redis)
|
||
Ctrl-->>Vue: success
|
||
|
||
Vue->>Ctrl: PUT update(source 只读或不传)
|
||
Ctrl->>Logic: edit(id, data)
|
||
Logic->>Logic: unset source
|
||
Logic->>DB: update
|
||
Logic->>Logic: sync(redis)
|
||
```
|
||
|
||
---
|
||
|
||
## 编号规则(已确认)
|
||
|
||
- **格式**:6 位 **大写字母 + 数字** 混合(如 `A3K9X2`)
|
||
- **字符集**:`A-Z` + `0-9`(统一大写,与现有 `sync()` 中 `strtoupper($source)` 行为一致)
|
||
- **唯一性**:生成后查库 [`GameServerModel::getBySource()`](slot-admin/app/model/GameServerModel.php),冲突则重试(最多 20 次),失败抛 `ApiException`
|
||
- **存量数据**:已有渠道编号不变,仅新建渠道走自动生成
|
||
|
||
---
|
||
|
||
## 后端改动(slot-admin)
|
||
|
||
### 1. [`GameServerLogic.php`](slot-admin/app/game/logic/GameServerLogic.php)
|
||
|
||
**新增 `add()`**(替代当前未接入的 `save()`):
|
||
|
||
- 调用 `generateUniqueSource()` 写入 `$data['source']`,忽略前端传入值
|
||
- 复用现有 `save()` 内创建前处理:`secret_key`、`format(extend_data)`、`dot_type`/`fb_status`/`fb_pix`
|
||
- `parent::add($data)` 后 `sync($data['source'])`
|
||
- 删除或内联原 `save()` 方法,避免双入口
|
||
|
||
**新增私有方法**(均需中文 PHPDoc):
|
||
|
||
- `generateUniqueSource(): string` — 生成唯一 6 位编号
|
||
- `prepareCreateData(array $data): array` — 从原 `save()` 提取的创建前数据整理(可选,保持方法 ≤50 行)
|
||
|
||
**修改 `edit()`**:
|
||
|
||
- 在更新前 `unset($data['source'])`,防止通过 API 篡改编号
|
||
- 其余逻辑保持不变
|
||
|
||
### 2. [`GameServerValidate.php`](slot-admin/app/game/validate/GameServerValidate.php)
|
||
|
||
- `save` 场景:**移除** `source`(后端生成,不要求前端传)
|
||
- `update` 场景:**移除** `source`(不可编辑)
|
||
- 可保留 `source` 规则定义供其他场景复用,但不再出现在 save/update scene
|
||
|
||
### 3. [`GameServerModel.php`](slot-admin/app/model/GameServerModel.php)(可选小改)
|
||
|
||
- 新增 `existsBySource(string $source): bool`,供 Logic 查重,语义更清晰(非必须,可直接用 `getBySource`)
|
||
|
||
---
|
||
|
||
## 前端改动(slot-admin-vue)
|
||
|
||
### [`edit.vue`](slot-admin-vue/src/views/game/source/edit.vue)
|
||
|
||
**模板**(约 L19-23):
|
||
|
||
- **新增模式**:不展示编号输入框;可加一行提示文案「渠道编号将在创建后自动生成」
|
||
- **编辑模式**:展示 `source` 为 `disabled` 只读输入框
|
||
|
||
**校验规则**(约 L306-311):
|
||
|
||
- 移除 `source` 的 `required` 规则
|
||
|
||
**提交**(约 L344-357):
|
||
|
||
- 新增/编辑提交前均 `delete data.source`,避免误传
|
||
|
||
列表页 [`index.vue`](slot-admin-vue/src/views/game/source/index.vue) 已有「编号」列,创建成功后刷新即可看到生成结果,无需改动。
|
||
|
||
---
|
||
|
||
## 安全与兼容
|
||
|
||
- 后端 `edit()` 强制 `unset source` 为最终防线,不依赖前端
|
||
- 新建渠道若前端仍传 `source`,后端忽略并覆盖为系统生成值
|
||
- 不影响 [`refreshFb`](slot-admin/app/game/controller/GameServerController.php) 等按 `source` 查询的现有功能
|
||
|
||
---
|
||
|
||
## 验证步骤
|
||
|
||
1. Docker 内创建渠道:不传编号,保存成功,列表出现 6 位字母数字编号
|
||
2. 编辑渠道:编号字段只读,修改名称等其他字段保存成功,编号不变
|
||
3. 尝试通过 API 直接 PUT 修改 `source`,确认后端不更新该字段
|
||
4. 执行 `SLOT_ROOT=/Users/ray/Documents/project/www/ray ~/.cursor/hooks/verify-slot-backend.sh`
|