Files
ray zhou f71a5c59af ok
2026-05-29 11:21:40 +08:00

28 lines
32 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{"role":"user","message":{"content":[{"type":"text","text":"<user_query>\n在 /Users/ray/Documents/project/www/slot/backend/slot_admin_vue 这个 Vue 管理后台前端工程里,需要梳理\"活动配置\"的编辑表单实现,特别是 activity_type / 活动类型字段相关的渲染。\n\n请回答以下问题并标出具体的文件路径与代码片段包含行号\n\n1. 活动列表与编辑页面入口(路由、列表组件、编辑组件)所在文件路径。\n2. 活动类型枚举在前端是怎么定义的?目前已经支持哪些 type 值(数字)?类型 11 现在是否已经有定义是怎么显示的select 选项 label\n3. 编辑表单里\"活动类型\"切换后,会根据不同 type 渲染什么不同的子表单?现在已有的类型(比如 1,2,3 ...)是怎么做分支渲染的,是 v-if、动态组件、还是 schema 驱动?请给出代码示例。\n4. 活动详情 / 编辑接口前端是怎么请求的API 文件路径、URL提交时的字段结构是什么样\n5. 活动配置config字段在 form 中是平铺的还是放在嵌套 JSON 里?后端 activity 表是否有专门的 config / extra 字段?\n6. 类型 11首充前免费余额定格与分档释放在前端有任何残留代码 / 注释 / 占位吗?\n\n直接读 backend/slot_admin_vue/src 下面的代码,不要修改任何东西。返回时请用 markdown 列表形式给出关键文件路径、关键代码片段(用代码块包裹,附上文件路径和行号),以及你的总结结论。\n</user_query>"}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"梳理活动配置编辑表单,先从路由、活动类型枚举与相关组件入手。\n\n[REDACTED]"},{"type":"tool_use","name":"updateCurrentStep","input":{"current_step":"Exploring activity form code"}},{"type":"tool_use","name":"Grep","input":{"pattern":"activity","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src","glob":"**/router/**","-i":true}},{"type":"tool_use","name":"Glob","input":{"target_directory":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src","glob_pattern":"**/*activit*"}},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type|activityType|ACTIVITY_TYPE","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type|activity","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src","glob":"**/*.{js,ts,vue,json}"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/index.vue"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/api/game/activity.js"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"activity|activity_type","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue","glob":"**/*.{js,ts,json,vue}"}},{"type":"tool_use","name":"Grep","input":{"pattern":"\\b11\\b|type.*11|首充|free_credits|定格|分档","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue","-i":true}},{"type":"tool_use","name":"Glob","input":{"target_directory":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue","glob_pattern":"**/router/**"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"game/activity|activity","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/router"}},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type","path":"/Users/ray/Documents/project/www/slot/backend"}},{"type":"tool_use","name":"Grep","input":{"pattern":"sa-select|dict","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/components","glob":"**/*","head_limit":30}},{"type":"tool_use","name":"Glob","input":{"target_directory":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src","glob_pattern":"**/sa-select/**"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/router/index.js"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/components/sa-select/index.vue"}},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type|ActivityType","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin"}},{"type":"tool_use","name":"Grep","input":{"pattern":"formData\\.type|type ===|type ==|type !==","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"dict|activity","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/store"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/router/webRouter.js","limit":80}},{"type":"tool_use","name":"Glob","input":{"target_directory":"/Users/ray/Documents/project/www/slot/backend/slot_admin","glob_pattern":"**/*Activity*"}},{"type":"tool_use","name":"Grep","input":{"pattern":"type.*11|TYPE.*11|activity.*11","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin","-i":true}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin/app/game/controller/ActivityController.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin/app/game/validate/ActivityValidate.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/store/modules/dict.js"}},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type|game/activity","path":"/Users/ray/Documents/project/www/slot/backend"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type","path":"/Users/ray/Documents/project/www/slot","glob":"**/*.{sql,php,js,vue,ts}","head_limit":50}},{"type":"tool_use","name":"Grep","input":{"pattern":"class ActivityService|ext_config|ActivityModel","path":"/Users/ray/Documents/project/www/slot/slot_lib"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/store/modules/user.js","limit":120}},{"type":"tool_use","name":"Grep","input":{"pattern":"game/activity|views/game/activity","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_lib/src/services/ActivityService.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/store/modules/user.js","offset":115}},{"type":"tool_use","name":"Grep","input":{"pattern":"ActivityType|ACTIVITY_TYPE|activity.*type.*=.*11|type.*11","path":"/Users/ray/Documents/project/www/slot","glob":"**/*.{php,ts,js}","head_limit":40}},{"type":"tool_use","name":"Grep","input":{"pattern":"ext_config|activity","path":"/Users/ray/Documents/project/www/slot/slot_hub","glob":"**/*Activity*","head_limit":30}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_lib/src/common/const/Consts.php","limit":80}},{"type":"tool_use","name":"Grep","input":{"pattern":"ACTIVITY_TYPE|type.*10|type.*11","path":"/Users/ray/Documents/project/www/slot/slot_lib"}},{"type":"tool_use","name":"Grep","input":{"pattern":"ext_config|activity","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"**/*activity*","head_limit":40}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credits|定格|分档|type.*11","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"ACTIVITY_TYPE.*10|type.*=.*10|破产","path":"/Users/ray/Documents/project/www/slot","glob":"**/*.{php,vue,js}","head_limit":30}},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type","path":"/Users/ray/Documents/project/www/slot/slot_console"}},{"type":"tool_use","name":"Glob","input":{"target_directory":"/Users/ray/Documents/project/www/slot/slot_console","glob_pattern":"**/*Activity*Model*"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/api/common.js","limit":50}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/model/common/RechargeGiftConfigModel.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/model/common/ActivityConfigModel.php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"dictAll|dict/all","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue"}},{"type":"tool_use","name":"Grep","input":{"pattern":"free_credits|FREE_CREDITS|type.*11|TYPE.*11","path":"/Users/ray/Documents/project/www/slot/slot_console"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type|'activity_type'","path":"/Users/ray/Documents/project/www/slot","glob":"**/*.sql","head_limit":30}},{"type":"tool_use","name":"Glob","input":{"target_directory":"/Users/ray/Documents/project/www/slot/slot_console","glob_pattern":"**/*Activity*Controller*"}},{"type":"tool_use","name":"Grep","input":{"pattern":"getPageList|function add|function update|ext_config","path":"/Users/ray/Documents/project/www/slot/slot_console","glob":"**/innerapi/**Activity*"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/innerapi/controller/ActivityController.php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"recharge_gift_config|ext_config","path":"/Users/ray/Documents/project/www/slot/slot_console/db"}},{"type":"tool_use","name":"Grep","input":{"pattern":"game/activity|activity/index","path":"/Users/ray/Documents/project/www/slot/backend","glob":"**/*.sql","head_limit":20}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"addActivityConfig|updateActivityConfig|ext_config","path":"/Users/ray/Documents/project/www/slot/slot_console/app/entity/activity/ActivityConfigEntity.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/entity/activity/ActivityConfigEntity.php","limit":120}},{"type":"tool_use","name":"Grep","input":{"pattern":"s_recharge_gift_config","path":"/Users/ray/Documents/project/www/slot","glob":"**/*.sql","head_limit":15}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/entity/activity/ActivityConfigEntity.php","offset":480,"limit":120}},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type|首冲|破产|兑换码|Free Credits","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin","glob":"**/*","head_limit":30}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/advertisement/index.vue","limit":80}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"activity_type","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin/plugin"}},{"type":"tool_use","name":"Grep","input":{"pattern":"details|read","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/api/game/activity.js"}},{"type":"tool_use","name":"Grep","input":{"pattern":"formData\\.type|type === 11|type == 11","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md","limit":80}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"ext_config|type.*11|后台|管理","path":"/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md","head_limit":40}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/recharge/first/edit.vue.bak","limit":80}},{"type":"tool_use","name":"Grep","input":{"pattern":"dictAll|dict_data|activity_type","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin","glob":"**/*.php","head_limit":25}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/docs/requirements/首充前免费余额定格与分档释放需求文档.md","offset":1040,"limit":50}},{"type":"tool_use","name":"Grep","input":{"pattern":"ext_config|release_tier|first_cash","path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php","head_limit":30}},{"type":"tool_use","name":"Grep","input":{"pattern":"ext_config","path":"/Users/ray/Documents/project/www/slot/slot_console/config/free_credits.php"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/config/free_credits.php"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Glob","input":{"target_directory":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/advertisement","glob_pattern":"**/*"}},{"type":"tool_use","name":"Grep","input":{"pattern":"type.*5|红包","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity"}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/api/common.js","offset":95,"limit":15}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/advertisement/edit.vue","limit":40}},{"type":"tool_use","name":"Grep","input":{"pattern":"game/activity","path":"/Users/ray/Documents/project/www/slot","glob":"**/*.{sql,json,md}","head_limit":15}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/advertisement/index.vue","offset":80}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php","offset":750,"limit":60}},{"type":"tool_use","name":"updateCurrentStep","input":{"current_step":"Compiling activity form report","final_summary":"活动配置在 `slot_admin_vue` 中由列表页 + 弹窗编辑组成,路由来自后台菜单动态注册;活动类型通过字典 `activity_type` 下拉展示,子表单用 `v-if` 按 type 分支。类型 11Free Credits在后端 `RechargeGiftConfigModel` 已定义,但前端无任何分支、占位或 `ext_config` 编辑 UI。","completed_subtitle":"Mapped activity form implementation"}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/slot_console/app/api/logic/FreeCreditsLogic.php","offset":20,"limit":25}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"dictList|dict\\[","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/components","head_limit":20}},{"type":"tool_use","name":"Read","input":{"path":"/Users/ray/Documents/project/www/slot/backend/slot_admin/plugin/saimulti/app/controller/AdminCommonController.php","offset":38,"limit":40}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"[REDACTED]"},{"type":"tool_use","name":"Grep","input":{"pattern":"value|label","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin/plugin/saimulti/app/model/system/SystemDictData.php"}},{"type":"tool_use","name":"Grep","input":{"pattern":"getLabel","path":"/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/utils/tool.js","-A":5}}]}}
{"role":"assistant","message":{"content":[{"type":"text","text":"以下为对 `backend/slot_admin_vue/src` 的梳理结论(只读代码,未改任何文件)。\n\n---\n\n## 1. 活动列表与编辑页面入口\n\n### 路由(动态菜单,非静态路由表)\n\n- 静态路由只有 `layout` / `login` / 404见 `/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/router/webRouter.js`。\n- **活动页路由由登录后后台菜单动态注入**`component` 字段映射到 `views/${component}.vue`。\n\n```141:161:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/store/modules/user.js\nconst views = import.meta.glob('../../views/**/**.vue')\n// ...\nconst filterAsyncRouter = (routerMap) => {\n // ...\n const route = {\n path: item.path,\n name: item.name,\n // ...\n component: views[`../../views/${item.component}.vue`]\n }\n```\n\n活动配置页面对应组件路径应为 **`game/activity/index`**(菜单里 `component` 配这个值时),路由 `name` 由后台菜单决定(常见为 `game/activity/index`)。\n\n### 列表页\n\n- **路径**`/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/index.vue`\n- 使用 `sa-table` + `api.getPageList`;新增/编辑通过子组件弹窗。\n\n```60:61:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/index.vue\n <!-- 编辑表单 -->\n <edit-form ref=\"editRef\" @success=\"refresh\"/>\n```\n\n```111:135:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/index.vue\n add: {\n show: true,\n auth: ['/game/activity/add'],\n func: async () => {\n editRef.value?.open()\n },\n },\n edit: {\n show: true,\n // ...\n func: async (record) => {\n record.show_time = [\n record.show_start_time,\n record.show_end_time,\n ];\n const d = {...record};\n d.goods = record.goods?.map((item) => {\n return {...item};\n });\n editRef.value?.open('edit')\n editRef.value?.setFormData(d)\n },\n },\n```\n\n**说明**:编辑**没有单独详情接口**,直接用列表行 `record` 回填弹窗。\n\n### 编辑组件Modal 弹窗,非独立路由页)\n\n- **路径**`/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue`\n- 由 `index.vue` 以 `<edit-form>` 引入,`defineExpose({ open, setFormData })`。\n\n### 相关 API 封装\n\n- **路径**`/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/api/game/activity.js`\n\n---\n\n## 2. 活动类型枚举在前端如何定义?支持哪些 typetype 11\n\n### 前端没有本地 TS/JS 枚举\n\n- 表单字段名是 **`type`**(不是 `activity_type`)。\n- 下拉用字典码 **`activity_type`**,数据来自登录后 `dictAll` 接口,存入 Pinia。\n\n```31:33:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue\n <a-form-item label=\"活动类型\" field=\"type\" :style=\"{width:'300px'}\">\n <sa-select v-model=\"formData.type\" dict=\"activity_type\" placeholder=\"请选择活动类型\"/>\n```\n\n```18:21:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/store/modules/dict.js\n async initData() {\n const { data } = await commonApi.dictAll()\n this.data = data\n```\n\n```99:103:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/api/common.js\n dictAll() {\n return request({\n url: '/saimulti/system/dictAll',\n method: 'get'\n```\n\n```5:6:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/components/sa-select/index.vue\n :options=\"dictList[props.dict] ?? []\"\n```\n\n选项格式为 `{ value, label }`(见 `tool.getLabel`)。\n\n### 代码里能推断的 type 含义(来自分支逻辑 + 后端注释)\n\n| type | 前端是否有专门 UI | 含义(后端/注释) |\n|------|------------------|-------------------|\n| 1,2,3,4 | 通用「赠送配置」卡片 | 首充/二充/三充/普通 |\n| 5 | 列表侧被后端过滤 | 红包拉新(管理端 `getPageList` 排除 type=5 |\n| 6 | `ext_config.gift_amount` + 赠送卡片百分比 | 每日优惠 |\n| 7,8 | `onlyGift`:隐藏商品类型 | 注册赠送 / 下载赠送 |\n| 9 | 频道链接、兑换表等 | 兑换码 |\n| 10 | 破产保护字段块 | 破产保护 |\n| **11** | **无** | 首充前 Free Credits仅后端已定义 |\n\n`slot_lib` 常量只到 9\n\n```15:25:/Users/ray/Documents/project/www/slot/slot_lib/src/common/const/Consts.php\n const ACTIVITY_TYPE_FIRST_RECHARGE = 1; //活动类型标识 首次充值\n const ACTIVITY_TYPE_SECOND_RECHARGE = 2; //活动类型标识 第二次充值\n const ACTIVITY_TYPE_THIRD_RECHARGE = 3; //活动类型标识 第三次充值\n const ACTIVITY_TYPE_COMMON = 4; //活动类型标识 普通类型\n const ACTIVITY_TYPE_RED_PACKET = 5; //活动类型标识 红包拉新\n const ACTIVITY_TYPE_DISCOUNT = 6; //活动类型标识 每日优惠\n const ACTIVITY_TYPE_REG = 7; //活动类型标识 注册赠送\n const ACTIVITY_TYPE_DOWNLOAD = 8; //活动类型标识 下载赠送\n const ACTIVITY_TYPE_EXCHANGE_CODE = 9; //活动类型标识 兑换码赠送\n```\n\n后端 `RechargeGiftConfigModel` 另有 10、11\n\n```68:71:/Users/ray/Documents/project/www/slot/slot_console/app/model/common/RechargeGiftConfigModel.php\n const TYPE_BRANKRUPTCY = 10; // 破产保护\n\n /** 首充前免费余额定格与分档释放;配置存 ext_config玩家状态见 free_credits_* 表 */\n const TYPE_FREE_CREDITS = 11;\n```\n\n### type 11 在前端字典里有没有?\n\n- **`src` 内没有任何 `activity_type` 的硬编码条目**`activity_type` 在仓库 SQL/前端里都搜不到静态定义。\n- **是否在 select 里出现,取决于 DB `sm_system_dict_data` 是否配置了 value=`11` 的项**;当前前端代码**没有**为 type 11 写 label 或表单项。\n- 若字典未配 11仍可能通过接口保存 `type: 11`但下拉无友好选项且会走「默认赠送卡片」UI见下一节。\n\n---\n\n## 3. 编辑表单按 type 如何分支渲染?\n\n**机制:`v-if` / `template v-if` + 少量 `computed`,不是动态组件,也不是 schema 驱动。**\n\n### 分支一览\n\n| 条件 | 额外 UI |\n|------|---------|\n| `type == 6` | `ext_config.gift_amount` 额外赠送 |\n| `type == 9` | 频道链接、每日生成/兑换次数、发送模板、兑换概率表 |\n| `type === 10` | `reg_end_h`、`ext_config.amount/balance/times`(提交时 amount/balance ×1000 |\n| `type !== 10` | 显示「添加赠送」按钮 |\n| `type == 9` | 兑换表;否则 `goods` 卡片列表 |\n| `onlyGift`7/8/9 | 隐藏「商品类型」单选 |\n| `[1,4,6]` | 赠送金额/Bonus 百分比展示 |\n\n核心片段\n\n```42:46:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue\n <a-col :span=\"8\" v-if=\"formData.type == 6\">\n <a-form-item label=\"额外赠送\">\n <a-input-number v-model=\"formData.ext_config.gift_amount\" placeholder=\"请输入额外赠送\"/>\n```\n\n```83:123:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue\n <template v-if=\"formData.type == 9\">\n <a-form-item label=\"频道链接\" field=\"ext_config.link\" :rules=\"rules.link\">\n <a-input v-model=\"formData.ext_config.link\" placeholder=\"请输入频道链接\"/>\n </a-form-item>\n <!-- ... exchange_count, send_template, send_template_photo ... -->\n </template>\n\n <template v-if=\"formData.type === 10\">\n <a-form-item label=\"注册失效\" help=\"单位小时\" ...>\n <a-input v-model=\"formData.reg_end_h\" placeholder=\"输入小时数\" />\n </a-form-item>\n <a-form-item label=\"赠送金额\" ...>\n <a-input v-model=\"formData.ext_config.amount\" placeholder=\"赠送金额\" />\n </a-form-item>\n <!-- balance, times -->\n </template>\n```\n\n```125:180:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue\n <template v-if=\"formData.type !== 10\">\n <a-button type=\"primary\" ... @click=\"add()\">添加赠送</a-button>\n </template>\n <!-- type==9: exchangeList 表格v-else: goods 卡片循环 -->\n <a-row :gutter=\"20\" v-else>\n <a-col :span=\"12\" v-for=\"(item, i) in formData.goods\">\n <a-card :title=\"'赠送配置' + (i + 1)\">\n <!-- 商品/售价、amount、bonustype in [1,4,6] 显示百分比 -->\n```\n\n```211:214:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue\nlet onlyGift = computed(() => {\n return formData.type == 7 || formData.type == 8 || formData.type == 9;\n})\n```\n\n**type 11**:无任何 `v-if`;若选中 11会落到 `type !== 10` 的通用 `goods` 赠送 UI与 Free Credits 的 `ext_config` 配置需求不匹配。\n\n---\n\n## 4. 详情/编辑接口与提交字段结构\n\n### API 文件与 URL\n\n`/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/api/game/activity.js`\n\n| 操作 | Method | URL |\n|------|--------|-----|\n| 列表(兼“详情”数据源) | GET | `/game/activity/index` |\n| 新增 | POST | `/game/activity/save` |\n| 更新 | POST | `/game/activity/update?id={id}`body 带 `updateData: 1` |\n| 删除 | DELETE | `/game/activity/destroy` |\n| 改状态 | POST | `/game/activity/update`(无 `updateData` |\n\n```12:38:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/api/game/activity.js\n getPageList(params = {}) {\n return request({\n url: '/game/activity/index',\n method: 'get',\n params\n })\n },\n save(params = {}) {\n return request({\n url: '/game/activity/save',\n method: 'post',\n data: params\n })\n },\n update(id, params = {}) {\n params['updateData'] = 1;\n return request({\n url: '/game/activity/update?id=' + id,\n method: 'post',\n data: params\n })\n },\n```\n\n**无** `read` / `details` 方法;`activity.js` 里也没有单独详情 URL。\n\n### 提交 payload前端 `submit`\n\n```358:382:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue\nconst submit = async (done) => {\n const validate = await formRef.value?.validate()\n if (!validate) {\n loading.value = true\n let data = {...formData}\n let result = {}\n data.modelId = formData.model_id\n data.goods = formData.goods.map(item => {\n return {...item}\n })\n\n if(formData.type === 10){\n data.ext_config.balance = data.ext_config.balance*1000\n data.ext_config.amount = data.ext_config.amount*1000\n }\n\n if (mode.value === 'add') {\n data.id = undefined\n result = await api.save(data)\n } else {\n result = await api.update(data.id, data)\n }\n```\n\n`formData` 默认结构:\n\n```242:260:/Users/ray/Documents/project/www/slot/backend/slot_admin_vue/src/views/game/activity/edit.vue\nconst formData = reactive({\n id: null,\n model_id: '',\n source: '',\n type: 1,\n goods: [],\n goods_type: 1,\n show_time: [],\n status: 1,\n end_time_type: 1,\n is_count_down: 2,\n title: '',\n min_amount_qf:0,\n reg_end_h: 99999,\n sub_title: '',\n help: '',\n ext_config: {},\n sort_num: 0,\n})\n```\n\n后端 `ActivityConfigEntity::updateConfig` 会消费:`type`, `show_time[0/1]`, `goods_type`, `title`, `sub_title`, `help`, `reg_end_h`, `status`, `sort_num`, **`ext_config`**, **`goods`**, `source`, `modelId` 等(经 slot_admin → slot_console innerapi。\n\n---\n\n## 5. config 在 form 里是平铺还是嵌套?后端表字段?\n\n### 前端\n\n- **没有名为 `config` 的字段**。\n- 类型相关扩展放在 **`ext_config` 对象**(嵌套),例如 `ext_config.gift_amount`、`ext_config.link`、`ext_config.exchangeList`。\n- 档位赠送在 **`goods` 数组**(与 `ext_config` 并列,非塞进单一 JSON 文本框)。\n\n### 后端表(供对照,不在 vue 工程内)\n\n活动主表为 **`s_recharge_gift_config`**,模型注释含 **`ext_config`json**、**`goods`json**,无单独 `config` / `extra` 列名:\n\n```21:36:/Users/ray/Documents/project/www/slot/slot_console/app/model/common/RechargeGiftConfigModel.php\n * @property integer $type 活动类型1首冲 2二充 3 三充4普通5:红包拉新 6:每日优惠 7:注册 8:下载 9:兑换码 10:破产保护\n * ...\n * @property array|null $ext_config json格式\n```\n\ntype 11 的业务配置预期写在 **`ext_config`**(如 `win_threshold`、`recharge_unlock_amount`、`first_cash_amount`、`package_amount` 等,见 `FreeCreditsLogic`),玩家状态在 **`free_credits_player` / `free_credits_package`** 表,不在 activity 表单里。\n\n---\n\n## 6. type 11 在前端是否有残留/注释/占位?\n\n在 **`slot_admin_vue/src` 全目录检索结果**\n\n- **无** `type === 11` / `type == 11`\n- **无** `free_credits`、`定格`、`分档释放`、`TYPE_FREE_CREDITS`\n- **无** type 11 专用表单项或注释\n\n唯一相关是 **通用活动编辑**;若 DB 字典加了 value=11也只会显示为普通下拉项**没有专属子表单**。\n\n需求文档 §17 规划了独立「首充前免费余额配置」后台模块,**当前 vue 工程未实现**。\n\n---\n\n## 总结结论\n\n1. **入口**:动态路由 `game/activity/index` → `views/game/activity/index.vue`;编辑为同目录 `edit.vue` 弹窗,非独立路由页。 \n2. **活动类型**:前端**不维护枚举**,用字典 `activity_type` + 字段 `type`;代码显式处理 **6、7、8、9、10** 及 **1/4/6 百分比****11 在前端零实现**,字典是否在 DB 配置未知。 \n3. **分支渲染**:纯 **`v-if` 模板分支**,非 schema/动态组件type 11 会误用通用 `goods` 表单。 \n4. **接口**:列表 `GET /game/activity/index` 即编辑数据源;保存 `POST save/update`,无单独详情 API。 \n5. **配置形态**`ext_config` + `goods` **嵌套在 formData**;表字段为 **`ext_config` JSON**,无 `config` 列。 \n6. **type 11**:后端 `TYPE_FREE_CREDITS = 11` 已有,**管理端 vue 无任何占位或专用 UI**,需新增字典项 + `edit.vue` 分支(及可能的新菜单页)才能按需求文档配置。\n\n[REDACTED]"}]}}