## 总体方案 - 引入统一软删除机制:所有支持回收站的业务表增加 `deleted_at DATETIME NULL`、`deleted_by BIGINT NULL` 字段,并在 ORM 层启用 GORM Soft Delete 以默认过滤已删除记录。 - 提供中心化回收站接口与界面:集中列出各类型的软删除数据,支持恢复与彻底删除(二次确认)。 - 权限与菜单对齐:仅管理员可访问回收站;侧边栏在“系统管理”下新增“回收站”菜单,配置角色可见与按钮权限。 ## 数据库改造 - 目标表(根据现有模型与端点清单):`activities`、`activity_issues`、`activity_reward_settings`、`products`、`product_categories`、`banner`、`guild`、`system_titles`、`system_title_effects`、`system_item_cards`、`system_coupons`、`menus`、`menu_actions`、`roles`、`role_users`。 - 变更内容: - 添加列:`deleted_at DATETIME NULL`(建立索引以提升查询效率)、`deleted_by BIGINT NULL`。 - 后续通过 `cmd/gormgen` 重新生成 `internal/repository/mysql/{model,dao}/*.gen.go`,使模型包含 `gorm.DeletedAt` 与 `DeletedBy` 字段。 - 迁移策略:当前仓库未集成迁移工具,计划新增 `migrations/` 与 SQL 脚本(或集成 `goose`),在测试/生产库执行列新增与索引建立,完成后重新生成 ORM 代码。 ## 后端改造 - 技术栈:`gin` + `gorm`(已存在),读写库封装见 `internal/repository/mysql/mysql.go`,路由集中在 `internal/router/router.go`。 - 删除逻辑切换为软删除: - 将所有 `DELETE /api/...` 对应的处理器由物理删除改为 `gorm` 软删除:`db.Delete(&model)`,自动写入 `deleted_at`;同时通过上下文注入当前用户 ID 写入 `deleted_by`(更新列)。 - 涉及端点示例(集中定义于 `internal/router/router.go` 对应 handler):活动、期数、奖励、工会、商品、分类、轮播图、称号/特效、道具卡、优惠券、系统菜单/动作、角色、角色成员等。 - 查询默认过滤: - 使用含 `gorm.DeletedAt` 的模型,`gorm` 默认生成 `WHERE deleted_at IS NULL`;确保服务与 DAO 层不使用 `Unscoped()`,避免误返回已删除数据。 - 回收站接口:新增 `internal/api/admin/system_recycle.go` 与服务层 `internal/service/recycle/recycle_service.go`: - `GET /api/admin/recycle`:参数 `type`(枚举:activity、issue、reward、product...)、分页;实现为 `Unscoped().Where("deleted_at IS NOT NULL")` 列表,返回原始字段与 `deleted_at`、`deleted_by`。 - `POST /api/admin/recycle/restore`:参数 `type,id`;`Unscoped()` 更新目标记录 `deleted_at=NULL, deleted_by=NULL`,恢复数据。 - `DELETE /api/admin/recycle`:参数 `type,id`;`Unscoped().Delete(&model)` 执行物理删除。 - 关联完整性: - 软删除不级联子表;外键仍保持,恢复后关联自然可用。 - 若业务场景需要父子一致软删除(可选扩展),在服务层增加按类型的联动策略,但默认不做级联以降低风险。 - 权限拦截: - 以上回收站接口全部走管理员认证中间件 `internal/router/interceptor/admin_auth.go::AdminTokenAuthVerify`。 - 彻底删除在服务层进行额外二次确认校验(配合前端确认对话框),后端也校验 `role` 或 `action` 权限。 ## 前端改造(web/admin) - 框架:`vue3` + `vue-router` + `pinia` + `element-plus`,侧边栏位于 `web/admin/src/components/core/layouts/art-menus/art-sidebar-menu`,菜单数据由路由模块/后端菜单驱动。 - 路由与页面: - 新增路由模块 `web/admin/src/router/modules/system/recycle.ts`,`path:'/system/recycle'`,`meta.roles:['admin']`,`meta.authList:['recycle:list','recycle:restore','recycle:forceDelete']`。 - 新增页面 `web/admin/src/views/system/recycle/index.vue`: - 顶部类型筛选(下拉:活动、商品、工会…)。 - 表格列出删除数据(含关键原字段、`deleted_at`、`deleted_by`),分页。 - 行操作:`恢复`(调用 `POST /api/admin/recycle/restore`)、`彻底删除`(`ElMessageBox.confirm` 二次确认后调用 `DELETE /api/admin/recycle`)。 - API 封装:`web/admin/src/api/system/recycle.ts`(使用现有 Axios 封装 `web/admin/src/utils/http/index.ts`):`listDeleted(type,page,size)`、`restore(type,id)`、`forceDelete(type,id)`。 - 菜单项: - 后端在 `menus` 表增加“系统管理/回收站”,`path:'/system/recycle'`,并在角色分配接口 `POST /api/role/:role_id/menus` 仅赋予管理员;前端 `ListSimpleMenus` 拉取后自动渲染。 - 权限指令与守卫: - 按按钮权限 `meta.authList` 与角色 `meta.roles` 控制显示;普通用户不显示菜单,无法访问路由或调用接口。 ## 权限控制细则 - 仅管理员角色拥有“回收站”菜单与相关按钮权限;普通用户删除操作也走软删除,但无法访问回收站接口。 - 彻底删除在前端强制二次确认,并在后端再次校验权限与保护条件(如必须管理员)。 ## 测试方案 - 后端(Go `testing`): - `internal/api/admin/system_recycle_test.go`: - 删除后记录存在于回收站接口,原查询不可见(验证 `deleted_at` 与默认过滤)。 - 恢复后记录重新可见,`deleted_at`/`deleted_by` 为空。 - 权限:非管理员访问回收站接口返回 `401/403`;管理员正常。 - 关联完整性:恢复后关联查询正常(父子外键未破坏)。 - 前端(Vitest): - `web/admin/src/tests/system/recycle/recycle.test.ts`: - 菜单与路由权限:管理员可见“回收站”,普通用户不可见。 - 列表加载与分页、恢复按钮触发成功提示与刷新、彻底删除二次确认弹窗与成功流程。 - 401/403 拦截按现有拦截器工作(参考 `src/tests/auth/401-error-handling.test.ts`)。 ## 交付与验证 - 执行数据库迁移并生成 ORM 代码 → 修改删除逻辑到软删除 → 新增回收站接口与前端页面 → 配置菜单与角色 → 编写并运行测试。 - 验收标准: - 所有默认查询不返回已删除记录。 - 回收站能列出各类删除记录,恢复/彻底删除工作正常。 - 权限严格生效;普通用户删除进入回收站但不可访问回收站界面。 - 恢复后关联数据完整、功能正常。