Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 39s
refactor(service): 修改banner和guild删除逻辑为软删除 fix(service): 修复删除操作使用软删除而非物理删除 build: 添加SQLite测试仓库实现 docs: 新增奖励管理字段拆分和批量抽奖UI改造文档 ci: 更新CI忽略文件 style: 清理无用资源文件
6.3 KiB
6.3 KiB
目标
- 将活动创建流程改造成“清晰、可操作、可回退”的向导式体验,显著降低填写负担、减少出错率,并确保与现有后端接口完全对齐。
- 统一字段与交互:活动、期、奖励配置的字段、校验与排序一致;消除重复输入与歧义(如奖励名称以选品自动回填)。
- 杜绝常见错误:时间格式、权限校验、表单必填项、动态模块加载等问题在交互层面被提前防护。
现状与痛点
- 后端接口已齐备(管理端):
- 创建活动:
POST /api/admin/activities(internal/router/router.go:78;控制器internal/api/admin/activities_admin.go:41;服务层internal/service/activity/activity_create.go:12-41) - 创建期:
POST /api/admin/activities/:activity_id/issues(internal/router/router.go:83;控制器internal/api/admin/issues_admin.go;服务层internal/service/activity/issue_create.go:13-32) - 创建奖励:
POST /api/admin/activities/:activity_id/issues/:issue_id/rewards
- 创建活动:
- 前端存在两套创建入口:
- 独立向导页:
web/admin/src/views/activity/wizard/index.vue(“下一步”仅切换步骤,提交由各步的“提交”触发) - 管理页弹窗向导:
web/admin/src/views/activity/manage/index.vue(“下一步”实际调用创建并推进)
- 独立向导页:
- 痛点汇总:
- 两处入口的字段命名、排序不一致;奖励有的手填名称,有的选商品
- 时间未填时易触发数据库零日期错误(
TRADITIONAL SQL模式下) - “下一步”与“提交”含义不统一,用户易误操作
- 表格行式编辑密度过高,填写多项参数不友好
- 动态导入失败来源于 SFC 结构不合法、重复脚本块或未声明变量导致编译失败
重构设计(交互与结构)
向导统一(单入口)
- 入口:统一从“管理页弹窗向导”打开;支持跳转到独立页,但独立页沿用同一套逻辑(避免两套逻辑分歧)
- 步骤:
- 基本信息(活动):名称、分类、状态、门票价格、Boss、开始/结束时间
- 期信息(活动期):期号、状态、排序
- 奖励配置:按商品选择与参数设置(权重、数量、原始数量、等级、排序、Boss)
- 确认提交:汇总校验与最终提交
- 导航:
- “下一步”即执行当前步的提交(成功后推进),失败则停留并有明确错误提示
- “上一步”回退不丢数据;每步保存草稿状态在组件内存
表单布局与输入体验
- 两列栅格布局(
ElRow/ElCol):提升可读性与并行填写效率 - 奖励配置交互:
- 改为“卡片列表 + 弹窗表单”,卡片上显示商品名称及关键参数;“新增奖励/编辑奖励”在弹窗中填写,分两列布局
- 商品选择:远程搜索
admin/products(web/admin/src/api/product.ts),选择后自动回填奖励名称(传递给后端以兼容) - 支持复制卡片、删除卡片、批量导入(CSV/JSON)作为扩展项(初版可不做批量)
- 字段统一:奖励行统一字段为
product_id、weight、quantity、original_qty、level、sort、is_boss;name由选品自动补齐,不再手填 - 权限与提示:检测
SessionUserInfo.IsSuper(控制器内已做),前端在 403/400 的返回文案时专门弹出“权限不足”提示
校验与防错
- 实时校验规则:
- 活动:名称与分类必填;开始/结束时间支持空,但若为空则前端默认以
ISO8601当前时间传入或后端统一允许NULL - 期:期号必填;排序与状态为数值校验
- 奖励:
product_id必填;数值项均为非负或正数;level合法枚举
- 活动:名称与分类必填;开始/结束时间支持空,但若为空则前端默认以
- 时间防错:
- 方案优先级A:数据库将
start_time/end_time改为可NULL且默认NULL(推荐); - 方案优先级B:前端在未选择时默认传当前时间的
toISOString(); - 后端保留
Omit逻辑(internal/service/activity/activity_create.go:29-35),避免强行写零日期
- 方案优先级A:数据库将
代码结构与可维护性
- 组件结构:每个步骤独立子组件(
ActivityStepBasic.vue、ActivityStepIssue.vue、ActivityStepRewards.vue)+ 容器(ActivityWizard.vue) - 状态管理:使用本地状态(
ref/reactive)即可;如需跨页保持,用pinia记录向导草稿 - API层:沿用
web/admin/src/api/adminActivities.ts,奖励提交前统一映射自动补齐name - 动态导入稳定性:
- 确保每个 SFC 仅一个
<template>和一个<script setup>,无重复导入、重复变量与重复函数 - 编译错误先清理其他页面的类型错误(如
shipping-stats/index.vue的remoteLoading.orders与reconcile/diff/index.vue的formatDetail),避免影响整体构建可用性
- 确保每个 SFC 仅一个
后端约束与对齐
- 保持接口不变:
CreateActivity/CreateIssue/CreateIssueRewards - 修改建议(可选):
- 数据库列允许
NULL(避免零日期); - 在
CreateActivity中对StartTime/EndTime为空时不写入(现有已 Omit)
- 数据库列允许
验收标准
- 用户可通过统一向导完成活动创建:每步“下一步”均会发起对应请求并进入下一步;错误有明确提示
- 奖励配置以选择商品为主,不再手填名称;行字段与顺序一致
- 复杂表单两列布局,填写效率明显提升;可编辑/删除奖励卡片
- 构建通过(无 SFC 结构错误与类型错误);页面加载不再出现“动态模块导入失败”
实施步骤
- 重构向导组件结构与路由入口;统一使用弹窗向导(保留独立页入口但复用组件)
- 基本信息与期信息改为两列布局;“下一步”触发提交与推进
- 奖励配置改为卡片 + 弹窗表单;远程选品与字段统一;提交前自动补齐名称
- 表单校验与错误提示完善;未填时间的兜底(前端默认或后端允许 NULL)
- 清理页面内无关类型错误(
shipping-stats/index.vue、reconcile/diff/index.vue)保证构建与动态导入稳定 - 编写端到端测试用例:
- 正常流程:活动→期→奖励→提交 成功
- 边界:缺少必填项、非超级管理员、时间为空等
- 性能:奖励 50+ 条下的编辑与提交
交付物
- 统一的向导组件及子组件
- API 映射与表单校验实现
- 样式与布局更新,卡片/弹窗交互
- 测试用例与构建通过证明