--- name: manage-backend-sync-with-business overview: 将管理后台 /root/zt-closet-manage-backend 与业务服务 /root/zt-closet-backend 的最新改动对齐:补齐额度枚举(source=4、change_type=7)与订单两列、按「封禁为主」改造仪表盘审核指标、人工发放/回收额度补写流水、对齐免费额度配置值,并同步前端仪表盘字段。 todos: - id: dashboard-alignment content: 用 [skill:lsp-code-analysis] 定位字段引用后,改 stats.go、dto/dashboard.go、service/dashboard.go,待办与穿搭概况改为公开/封禁口径 status: completed - id: frontend-sync content: 同步前端 types/dashboard.ts 与 DashboardView.vue:待办改三项,穿搭饼图改为公开/私密/已封禁 status: completed dependencies: - dashboard-alignment - id: enum-and-order-fields content: 补齐枚举与订单列:constants.go 加 source=4、change_type=7,模型与 DTO 补 order 两列快照及映射 status: completed - id: quota-flow-logs content: 人工发放与凭证回收在同一事务内补写额度流水,回收流水使用独立 order_no 避免撞唯一索引 status: completed - id: config-and-readme content: 对齐 Quota 配置值为 OutfitShare=3、ClosetShare=0,更新 README 说明审核口径、枚举、流水与生产配置同步 status: completed - id: verify content: 后端 gofmt、go build、go vet 全通过,前端执行构建与类型检查通过,核对无遗留引用 status: completed dependencies: - dashboard-alignment - frontend-sync - enum-and-order-fields - quota-flow-logs - config-and-readme --- ## 需求概述 业务服务已更新为「用户公开穿搭即自动过审」等内容治理与额度体系新实现,管理后台存在口径滞后。本次需让管理后台与业务服务最新实现对齐:修正已失效的仪表盘审核口径(改为以封禁为主)、补齐新增枚举与订单快照字段、让管理员人工发放与回收额度产生额度流水,并对齐免费额度配置值。 ## 核心功能 - 仪表盘待办区不再展示恒为 0 的「待审核穿搭」,改为展示「公开穿搭总数」与「已封禁穿搭数」;穿搭内容概况图由「待审核/已通过/未通过」改为「公开/私密/已封禁」,管理后台前端同步展示。 - 内容治理以封禁为主:审核通过/驳回接口保留但降级为兼容用途(实际已无待审数据);封禁后内容立即从小程序社区隐藏,且用户自行取消公开再重新公开也无法恢复可见。 - 用户额度凭证的来源标识新增「体验会员赠送」,额度流水新增「到期失效」类型,用户详情与文档能正确解释这些取值,不再出现未知来源。 - 订单列表与详情新增展示「商品类型快照」与「额度有效期天数快照」,便于人工退款与权益核对。 - 管理员人工发放额度、回收额度时同步产生一条「人工调整」额度流水,小程序端额度明细能看到对应的增加与扣减记录,不再出现只有到期失效扣减、没有发放来源的账实不符。 - 免费额度配置值与管理后台展示口径对齐业务服务实际配置(社区分享 3、衣柜分享 0),用户详情页每日额度显示不再偏大。 ## 技术栈 - 后端:Go 1.26 + Gin + GORM + MySQL + go-redis + viper + OpenTelemetry(沿用现有四层架构,不新增任何依赖) - 前端:Vue3 + TypeScript + Element Plus + ECharts(沿用现有工程与图表组件) - 数据库:与业务服务共用同一 MySQL 库,管理后台只读写业务表、不做任何业务表 DDL ## 实现方案 按「数据口径优先、展示跟随、文档收尾」推进,全部改动为存量文件修改,无新增模块。 1. **仪表盘口径对齐(封禁为主)**:删除不可达的 `is_public=2 AND audit_status=1` 统计,待办改为两个有效指标——公开穿搭总数(`is_public=2`)与已封禁穿搭(`status=2`);穿搭内容概况由 `audit_status` 分组改为 `is_public` 分组(公开/私密)并保留封禁数。选择该口径而非仅修统计条件,是因为业务侧公开动作在同一事务内写入 `is_public=2` 与 `audit_status=2`,审核已不再是公开的前置环节,封禁才是唯一有效治理手段。 2. **枚举与镜像补齐**:按业务侧常量新增 `QuotaGrantSourceTrial=4`、`QuotaChangeTypeExpire=7`,同步补齐 DTO 与模型注释;Order 模型补 `GoodsType`、`QuotaValidDays` 两列快照并在订单 DTO 与映射函数中透出。 3. **补写人工额度流水**:在人工发放与凭证回收的既有事务内各写一条 `quota_flow_logs` 记录(`change_type=5` 人工调整、`change_target=1` 调整),字段语义与唯一索引规则完全照搬业务侧实现,使业务侧到期失效任务补记的流水能与发放流水形成闭环。 4. **配置对齐**:仅修改显式 YAML 值(示例模板与本地配置),代码内兜底常量保持与业务服务兜底一致不动;生产机配置不随代码发布,README 明确提示需手工同步。 5. **前端同步**:后端字段变更后前端需同步,否则待办区仍显示「待审核穿搭」空值、饼图标签失真。 ## 实现注意事项 - **流水唯一索引**:`quota_flow_logs` 唯一索引为 `(order_no, quota_type, change_type)`。发放流水沿用 `order_no = ref_id (manual_)` 与业务侧到期失效任务按 `ref_id` 关联的习惯一致;**回收流水必须使用不同的 order_no**(如 `revoke_`),否则与同一凭证的发放流水(同为 change_type=5)撞唯一索引导致写入失败。 - **事务内取数**:发放/回收的 `old_value`/`new_value` 必须基于同一事务连接读取调整前后的有效额度,不能读全局引擎(会读到事务外的旧值)。优先复用用户详情已有的额度计算逻辑,必要时抽取为可传入事务句柄的内部函数;发放场景亦可按「新增量」直接推算。 - **流水失败即整体回滚**:流水写入必须与凭证写入同事务,避免出现「凭证已发但无流水」的新一轮账实不符。 - **配置兜底值不动**:只改 `configs/config.example.yaml` 与 `configs/config.yaml` 的显式值,`internal/service/constants.go` 中的兜底常量保持不变(与业务服务兜底值一致,实施时复核业务侧确认)。 - **生产机配置需手工同步**:`configs/config.yaml` 被 .gitignore 忽略,部署走挂载,发布后需手工改生产机文件,README 必须写明,否则线上展示仍偏大。 - **不要顺带统一 Redis 前缀**:管理后台全局前缀是 `ztclosetadmin:`,通知未读计数必须继续使用独立的 `ztcloset:` 前缀(已与业务服务一致),本次不涉及。 - **不要镜像 `clothes.original_image_path`**:该列是业务服务本地路径,同步进模型或 DTO 会泄露服务器路径,保持现状。 - **不补未镜像表**:`closet_share_items`、`outfit_shares`、`benefit_grant_tasks` 等 10 张表按用户决定本次不补。 - **前端引用需先全量检索**:改前端类型定义前先检索仓库内对 `todo.outfit_pending_audit`、`content.outfit` 的全部引用,避免漏改导致类型检查失败。 - **仪表盘统计开销**:待办新增一次 `status=2` 计数,`outfits` 表该列无独立前导索引,属可接受的全表计数;若后续穿搭量级变大,可复用内容概况已有的封禁统计结果,避免重复查询。 ## 架构设计 沿用现有分层,不引入新模式。改动链路为:业务服务写入的业务表 → 管理后台 `mysqldao` 聚合/读写 → `service` 组装口径 → `dto` 输出 → 管理后台前端渲染。 - 仪表盘:`mysqldao/stats.go`(聚合)→ `service/dashboard.go`(映射)→ `dto/dashboard.go`(契约)→ 前端 `types/dashboard.ts` + `DashboardView.vue` - 订单:`mysqlmodel/business.go`(镜像列)→ `service/order.go`(映射)→ `dto/order.go`(契约) - 额度:`service/user.go`(事务编排)→ `mysqldao/user.go`(新增流水写入)→ `mysqlmodel`(流水模型,已有) ## 目录结构 ``` zt-closet-manage-backend/ ├── internal/ │ ├── mysqldao/ │ │ ├── stats.go # [MODIFY] 待办统计去掉不可达条件,改为 is_public=2 与 status=2 两次计数; │ │ │ # 穿搭内容概况由 audit_status 分组改为 is_public 分组,内部结构体的 │ │ │ # OutfitPending/Passed/Rejected 替换为 OutfitPublic/OutfitPrivate,保留封禁计数 │ │ └── user.go # [MODIFY] 新增额度流水写入方法(插入 quota_flow_logs), │ │ # 并新增/抽取可在事务连接上计算某用户某额度类型有效额度的读方法 │ ├── dto/ │ │ ├── dashboard.go # [MODIFY] DashboardTodo 去掉 OutfitPendingAudit,新增 OutfitPublicTotal、 │ │ │ # OutfitBanned;DashboardOutfitStats 改为 Total/Public/Private/Banned │ │ ├── order.go # [MODIFY] OrderItem 新增 goods_type、quota_valid_days 两个 JSON 字段 │ │ └── user.go # [MODIFY] UserGrantItem.Source 注释补 4=体验会员赠送 │ ├── mysqlmodel/ │ │ └── business.go # [MODIFY] Order 模型补 GoodsType、QuotaValidDays 两列(与业务表列名严格一致); │ │ # QuotaGrant.Source 注释补 4;QuotaFlowLog.ChangeType 注释补 7 │ └── service/ │ ├── constants.go # [MODIFY] 新增 QuotaGrantSourceTrial=4、QuotaChangeTypeExpire=7, │ │ # 并对齐业务侧注释(兜底额度常量保持不变) │ ├── dashboard.go # [MODIFY] 按新字段结构映射待办与穿搭概况 │ ├── order.go # [MODIFY] buildOrderItem 透出 goods_type、quota_valid_days │ └── user.go # [MODIFY] 人工发放、凭证回收在同一事务内补写额度流水 │ # (发放 change_num 为增量,回收为负的凭证数量; │ # 回收的 order_no 不得与发放相同) ├── configs/ │ ├── config.example.yaml # [MODIFY] Quota 段 OutfitShare 10 改 3、ClosetShare 5 改 0 │ └── config.yaml # [MODIFY] 同上(本地实际配置,已被 .gitignore 忽略) └── README.md # [MODIFY] 说明公开即自动过审、治理靠封禁(且封禁不可被用户绕过)、 # 仪表盘新字段含义、source=4 与 change_type=7、人工发放/回收会写流水、 # 免费额度值对齐说明与生产机配置需手工同步的提示 zt-closet-manage-frontend/ ├── src/types/dashboard.ts # [MODIFY] 待办类型去掉 outfit_pending_audit、新增 outfit_public_total 与 │ # outfit_banned;穿搭概况类型改为 public/private/banned └── src/views/dashboard/ └── DashboardView.vue # [MODIFY] 待办区改为「待处理退款 / 公开穿搭 / 已封禁」三项; # 穿搭饼图数据源改为公开/私密/已封禁并更新图例与配色 ``` ## 关键代码结构 仪表盘契约(改后): ``` // DashboardTodo 待办与内容概览。 type DashboardTodo struct { RefundPending int64 `json:"refund_pending"` // 待处理退款 OutfitPublicTotal int64 `json:"outfit_public_total"` // 公开穿搭总数(is_public=2) OutfitBanned int64 `json:"outfit_banned"` // 已封禁穿搭(status=2) GoodsOnShelf int64 `json:"goods_on_shelf"` // 上架商品数 } // DashboardOutfitStats 穿搭内容概况。 type DashboardOutfitStats struct { Total int64 `json:"total"` // 穿搭总数 Public int64 `json:"public"` // 公开(is_public=2) Private int64 `json:"private"` // 私密(is_public=1) Banned int64 `json:"banned"` // 已封禁(status=2) } ``` 额度流水写入(新增 DAO 方法签名,实现照搬业务侧字段语义): ``` // QuotaFlowLogCreate 写入一条额度流水(调用方需传入事务句柄,保证与凭证变更同事务)。 func (d *UserDao) QuotaFlowLogCreate(ctx context.Context, tx *gorm.DB, flow *mysqlmodel.QuotaFlowLog) error ``` ## Agent Extensions ### Skill - **lsp-code-analysis** - Purpose: 在修改仪表盘与订单相关结构体字段前,做语义级影响分析——定位 `DashboardTodo`、`DashboardOutfitStats`、`OrderItem`、`UserGrantItem` 等类型的全部定义与引用位置,并在前端仓库定位 `outfit_pending_audit`、`content.outfit` 的所有使用点 - Expected outcome: 输出完整的引用清单,确保后端字段重命名与前端类型调整不遗漏任何调用点,避免出现未被察觉的契约断裂