diff --git a/.DS_Store b/.DS_Store index faf8b9b..e05aa09 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/.gitignore b/.gitignore index b3a0f10..ff2f55a 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ go.work.sum *.idea -resources/* \ No newline at end of file +resources/* +build/resources/admin/ +logs/ diff --git a/.trae/documents/Add Cost Analysis to Lottery Simulation.md b/.trae/documents/Add Cost Analysis to Lottery Simulation.md new file mode 100644 index 0000000..ddaef48 --- /dev/null +++ b/.trae/documents/Add Cost Analysis to Lottery Simulation.md @@ -0,0 +1,38 @@ +# Add Cost Analysis to Lottery Simulation + +I will enhance the lottery simulation feature to include cost calculation and financial analysis. + +## 1. Backend Changes (`internal/api/admin/lottery_admin.go`) + +- **Update Response Structures**: + - Add `Cost` (int64) to `simulateRewardStat` (Unit cost in cents). + - Add `TotalCost` (int64) to `simulateRewardStat` (WonCount * Cost). + - Add `TotalSimulationCost` (int64) to `simulateIssueResponse`. + - Add `TotalSimulationRevenue` (int64) to `simulateIssueResponse` (TotalDraws * Activity.PriceDraw). + - Add `GrossProfit` (int64) to `simulateIssueResponse` (Revenue - Cost). + - Add `GrossProfitRate` (float64) to `simulateIssueResponse`. + +- **Logic Update**: + - In `SimulateIssue`: + - Fetch the `Activity` details to get `PriceDraw`. + - Collect all `ProductID`s from the rewards. + - Batch query the `Products` table to get prices. + - Map product prices to rewards (if `ProductID > 0`). + - Calculate financial stats after the simulation loop. + +## 2. Frontend Changes (`web/admin/src/views/operations/lottery-simulation/index.vue`) + +- **Update API Type Definition**: Update `SimulateRewardStat` and `SimulateIssueResponse` interfaces in `api/operations.ts`. +- **UI Enhancement**: + - **Summary Cards**: Add a row of summary cards at the top of the results section showing: + - Total Revenue (总收入) + - Total Cost (总成本) + - Gross Profit (毛利润) + - Profit Margin (毛利率) + - **Table Columns**: + - Add "Unit Cost" (单价/成本) column. + - Add "Total Cost" (总发放成本) column. + +## 3. Verification +- Verify compilation. +- (Self-Correction) Ensure `Price` is handled as integer (cents) and formatted correctly in frontend (divided by 100). diff --git a/.trae/documents/Add Product Description Field.md b/.trae/documents/Add Product Description Field.md new file mode 100644 index 0000000..7f39508 --- /dev/null +++ b/.trae/documents/Add Product Description Field.md @@ -0,0 +1,31 @@ +# Add Product Description Field for App Detail + +## 1. Database Migration +We need to add a `description` column to the `products` table to store the product details. +**SQL Statement:** +```sql +ALTER TABLE products ADD COLUMN description TEXT COMMENT '商品详情'; +``` + +## 2. Backend Model Update +Update the GORM model and DAO to reflect the database change. +* **Model**: Update `internal/repository/mysql/model/products.gen.go` to include the `Description` field. +* **DAO**: Update `internal/repository/mysql/dao/products.gen.go` to include the `Description` field definition and mapping. + +## 3. Service Layer Update +Update `internal/service/product/product.go` to handle the new field. +* **Input Structs**: Add `Description` to `CreateProductInput` and `ModifyProductInput`. +* **Business Logic**: + * Update `CreateProduct` to save the description. + * Update `ModifyProduct` to update the description. + * Update `GetDetailForApp` to populate the `Description` field from the database instead of returning an empty string. + +## 4. Admin API Update +Update the Admin API to allow creating and editing products with a description. +* **File**: `internal/api/admin/product_create.go` +* **Request Structs**: Add `description` field to `createProductRequest` and `modifyProductRequest`. +* **Handlers**: Pass the `description` from the request to the service layer. + +## 5. App API Verification +* **File**: `internal/api/app/product.go` +* The `GetProductDetailForApp` function already returns a `Description` field in the response. By updating the service layer to populate this field, the App API will automatically return the correct data. diff --git a/.trae/documents/Channel Management Implementation Plan.md b/.trae/documents/Channel Management Implementation Plan.md new file mode 100644 index 0000000..22f9579 --- /dev/null +++ b/.trae/documents/Channel Management Implementation Plan.md @@ -0,0 +1,38 @@ +# 渠道管理与用户来源统计实施计划 + +针对您的需求,我将把现有的“小程序二维码生成”功能升级为完整的“渠道管理”系统,并增加用户来源统计。 + +## 1. 数据库变更 (Schema Changes) + +* **新增 `channels` 表**: + * 用于定义推广渠道。 + * 字段: `id` (主键), `name` (渠道名称), `code` (唯一标识, 用于二维码参数), `type` (类型: 如抖音/微信/线下), `remarks` (备注), `created_at`, `updated_at`。 +* **修改 `users` 表**: + * 新增 `channel_id` (BIGINT) 字段,建立与 `channels` 表的关联。 + * (注意:现有 `douyin_id` 字段保留,用于业务逻辑,但统计归因将统一使用 `channel_id`)。 + +## 2. 后端开发 (Backend) + +* **API 开发 (`internal/api/admin`)**: + * 实现渠道管理的 CRUD 接口:`List`, `Create`, `Update`, `Delete`。 + * **统计逻辑**: 在 `List` 接口中,同步查询 `users` 表,统计每个 `channel_id` 下的用户数量。 +* **登录/注册逻辑优化 (`internal/service/user`)**: + * 修改 `LoginWeixin` (微信登录) 逻辑。 + * 除了现有的 `invite_code` 和 `douyin_id`,新增支持 `channel_code` 参数。 + * 逻辑: 当用户注册时,如果检测到 `channel_code`,查找对应的 `Channel` 记录,并将 `channel.ID` 写入用户表的 `channel_id` 字段。 + +## 3. 前端开发 (Frontend) + +* **新增页面**: `运营管理` -> `渠道管理` (`web/admin/src/views/operations/channels/index.vue`)。 + * **列表页**: 展示渠道名称、唯一标识(Code)、**累计注册用户数**、创建时间。 + * **操作栏**: 提供“编辑”、“删除”以及 **“查看二维码”** 功能。 +* **二维码生成优化**: + * 点击“查看二维码”时,自动调用生成接口,参数中自动带上当前渠道的 `code`。 + * (替代原有的纯手动输入二维码生成页面,或将其保留为“自定义工具”)。 + +## 4. 验证计划 + +1. **功能验证**: 在后台创建一个测试渠道,生成二维码。 +2. **流程验证**: 模拟新用户携带该渠道参数登录。 +3. **数据验证**: 检查数据库 `users` 表中新用户的 `channel_id` 是否正确。 +4. **统计验证**: 刷新渠道管理页面,确认“注册用户数”是否+1。 diff --git a/.trae/documents/Fix Race Condition in Ichiban Strategy GrantReward.md b/.trae/documents/Fix Race Condition in Ichiban Strategy GrantReward.md new file mode 100644 index 0000000..8ff1a90 --- /dev/null +++ b/.trae/documents/Fix Race Condition in Ichiban Strategy GrantReward.md @@ -0,0 +1,36 @@ +# 修复一番赏策略库存扣减竞态问题 + +经检查,`internal/service/activity/strategy/ichiban.go` 中的 `GrantReward` 方法存在严重的竞态条件风险。当前实现采用“先查询库存,再更新库存”的方式,在高并发下可能导致超卖。 + +## 修复计划 + +我将参照 `default.go` 和 `reward_grant.go` 中的正确实现,对 `ichiban.go` 进行以下修改: + +1. **重构 `GrantReward` 方法** + * 移除原有的 `First()` 查询逻辑。 + * 改为使用**乐观锁**原子更新: + * 查询条件增加 `Quantity > 0`。 + * 使用 `UpdateSimple` 执行 `Quantity - 1`。 + * 根据 `RowsAffected` 判断扣减是否成功。 + +## 预期代码变更 + +```go +func (s *ichibanStrategy) GrantReward(ctx context.Context, userID int64, rewardID int64) error { + // 使用乐观锁原子扣减库存 + result, err := s.write.ActivityRewardSettings.WithContext(ctx).Where( + s.write.ActivityRewardSettings.ID.Eq(rewardID), + s.write.ActivityRewardSettings.Quantity.Gt(0), + ).UpdateSimple(s.write.ActivityRewardSettings.Quantity.Add(-1)) + + if err != nil { + return err + } + if result.RowsAffected == 0 { + return errors.New("sold out or reward not found") + } + return nil +} +``` + +此修改将彻底解决库存扣减的并发安全问题。 diff --git a/.trae/documents/Implement Backpack API for App Users.md b/.trae/documents/Implement Backpack API for App Users.md new file mode 100644 index 0000000..1aa6576 --- /dev/null +++ b/.trae/documents/Implement Backpack API for App Users.md @@ -0,0 +1,73 @@ +## 概述 +为 APP 端提供“用户背包”能力,覆盖用户资产的六类数据:积分消费明细、优惠券、道具卡、头衔、订单、中奖资产(背包)。在保留现有分项查询接口的基础上,新增缺失的 APP 端接口与一个聚合概要接口,统一鉴权与分页规范,并更新 API 文档。 + +## 新增接口 +- GET `/api/app/users/{user_id}/inventory` + - 功能:用户背包列表(中奖资产),按时间倒序,支持分页 + - 返回:`InventoryWithProduct` 列表(含商品名称、图片、等级/备注、关联活动/奖励ID) + - 鉴权:`LoginVerifyToken` +- GET `/api/app/users/{user_id}/titles` + - 功能:用户头衔列表,支持分页 + - 返回:`UserTitleItem` 列表(称号ID、名称、来源/获得时间、可选效果) + - 鉴权:`LoginVerifyToken` +- GET `/api/app/users/{user_id}/backpack` + - 功能:聚合概要接口,返回六类资产的“计数+最近N条”,用于首页/概览展示 + - 查询参数:`limit=5`(各类最近条数),`include=points,coupons,item_cards,titles,orders,inventory`(可选,默认全包含) + - 返回: + - `points: {count, recent: UserPointsLedger[]}` + - `coupons: {count, recent: CouponItem[]}` + - `item_cards: {count, recent: ItemCardWithTemplate[]}` + - `titles: {count, recent: UserTitleItem[]}` + - `orders: {count, recent: Orders[]}` + - `inventory: {count, recent: InventoryWithProduct[]}` + - 鉴权:`LoginVerifyToken` + +## 复用现有 APP 接口(保持不变) +- 积分明细:GET `/api/app/users/{user_id}/points`(已存在) +- 积分余额:GET `/api/app/users/{user_id}/points/balance`(已存在) +- 优惠券:GET `/api/app/users/{user_id}/coupons`(已存在) +- 道具卡:GET `/api/app/users/{user_id}/item_cards`、GET `/api/app/users/{user_id}/item_cards/uses`(已存在) +- 订单:GET `/api/app/users/{user_id}/orders`(已存在) + +## 数据模型(响应结构) +- `InventoryWithProduct`:`{ id, product_id, title, images[], activity_id, reward_id, order_id, level, created_at }` +- `UserTitleItem`:`{ user_title_id, title_id, title_name, acquired_at, effects?: [{key, value, unit}], expires_at? }` +- `CouponItem`(沿用现有):`{ id, name, amount, valid_start, valid_end, status, rules }` +- `ItemCardWithTemplate`(沿用现有):含模板字段与剩余次数/有效期 +- `Orders`(沿用现有):按现有模型返回 +- `UserPointsLedger`(沿用现有):按现有模型返回 + +## 技术实现 +- 目录与文件: + - `internal/api/user/inventory_app.go`:`ListUserInventoryForApp()`(调用 `usersvc.ListInventoryWithProduct`) + - `internal/api/user/titles_app.go`:`ListUserTitlesForApp()`(新增 usersvc 方法或复用 admin 服务逻辑) + - `internal/api/user/backpack_app.go`:`GetUserBackpackOverview()`(各服务查询计数与最近N条) +- 路由:`internal/router/router.go` + - APP 认证组注册:`/users/:user_id/inventory`、`/users/:user_id/titles`、`/users/:user_id/backpack` +- Service 层:`internal/service/user` + - `ListInventoryWithProduct(ctx, userID, page, pageSize)`(已有) + - `ListUserTitles(ctx, userID, page, pageSize)`(新增):查询用户称号关联与系统称号名称/效果 + - 计数方法:各类 `CountXxx(ctx, userID)`(供概要接口聚合) + +## 鉴权与约束 +- 所有接口使用 `LoginVerifyToken` +- `user_id` 为路径参数,但服务端以会话 `SessionUserInfo().Id` 校验一致性,防越权 +- 分页统一:`page`、`page_size`(默认 1/20,最大 100),按 `created_at` 倒序 + +## Swagger 文档 +- 为新增 3 个接口添加注解:`@Summary`、`@Description`、`@Tags APP端.用户`、`@Security LoginVerifyToken`、`@Param`、`@Success`/`@Failure`、`@Router` +- 模型定义共用已有结构;为新结构 `UserTitleItem`、`InventoryWithProduct` 增加定义 +- 执行脚本生成文档:`scripts/swagger.sh` + +## 测试与验收 +- 单元/集成: + - 伪造用户会话,验证分页与鉴权;数据空集场景返回空数组 + - 概要接口在 `include` 过滤时仅返回所选分组 +- 手工验证: + - 分别对六类接口 `curl` 测试分页与计数一致性 + - Swagger 文档能正确展示并可试用 + +## 验收标准 +- 三个新增接口可用且鉴权正确;分页与计数正确 +- 概要接口耗时可控(<200ms 在百条内数据量);可通过 `include` 控制 +- 文档完整,前端对接字段明确;无越权与泄露 diff --git a/.trae/documents/Lottery Simulation Feature Implementation Plan.md b/.trae/documents/Lottery Simulation Feature Implementation Plan.md new file mode 100644 index 0000000..5596098 --- /dev/null +++ b/.trae/documents/Lottery Simulation Feature Implementation Plan.md @@ -0,0 +1,53 @@ +# 添加抽奖模拟功能 (Lottery Simulation) + +我将实现一个抽奖模拟功能,允许管理员在后台模拟抽奖过程并分析概率分布,**全过程仅在内存中进行,不会修改数据库中的真实数据**。 + +## 1. API 接口设计 +**接口地址**: `POST /api/admin/lottery/issues/:issue_id/simulate` + +**请求参数 (Body)**: +```json +{ + "num_users": 100, // 模拟人数 + "draws_per_user": 1 // 每人抽奖次数 (总抽奖次数 = 人数 * 次数) +} +``` + +**返回结果**: +```json +{ + "total_draws": 100, // 总模拟次数 + "rewards": [ + { + "reward_id": 1, + "name": "IPhone 15", + "level": 1, // 奖品等级 + "original_qty": 10, // 初始库存 + "won_count": 2, // 模拟中奖数 + "remaining_qty": 8,// 模拟剩余库存 + "actual_prob": 0.02, // 实际中奖率 (2%) + "theoretical_prob": 0.01 // 理论概率 (基于权重的 1%) + } + ] +} +``` + +## 2. 实现细节 + +### A. 新增处理器 `internal/api/admin/lottery_admin.go` +我将添加 `SimulateIssue` 函数,执行以下逻辑: +1. **读取配置**: 从数据库获取指定期号 (Issue) 和奖品配置 (Reward Settings)。 +2. **内存模拟**: + - 在内存中创建奖品库存的副本。 + - 运行加权随机算法 `N` 次(总抽奖次数)。 + - 扣减内存中的库存并记录中奖数据。 + - **关键**: 绝对不会写入数据库或修改真实库存。 +3. **统计计算**: + - 计算每个奖品的实际中奖率与基于权重的理论概率进行对比。 + +### B. 注册路由 `internal/router/router.go` +- 在 `adminAuthApiRouter` 分组下添加新路由。 +- `POST /lottery/issues/:issue_id/simulate` -> `adminHandler.SimulateIssue()` + +## 3. 验证计划 +- **功能验证**: 使用现有的活动/期号调用模拟接口,输入不同的人数和次数,验证返回的概率分布是否符合预期(例如:高权重奖品中奖率更高,库存耗尽后不再中奖)。 \ No newline at end of file diff --git a/.trae/documents/Troubleshoot and Fix Virtual Shipping, Refunds, and Item_Coupon Issues.md b/.trae/documents/Troubleshoot and Fix Virtual Shipping, Refunds, and Item_Coupon Issues.md new file mode 100644 index 0000000..c8e7bfd --- /dev/null +++ b/.trae/documents/Troubleshoot and Fix Virtual Shipping, Refunds, and Item_Coupon Issues.md @@ -0,0 +1,27 @@ +# 故障排查与修复计划 + +针对您提出的四个问题,我制定了以下修复计划。我将使用中文进行回答和执行。 + +## 1. 虚拟发货问题 (Virtual Shipment) +* **现状**: 后端代码中已存在 `UploadVirtualShipping` 调用,但在支付回调中如果上传失败,目前是忽略错误的(`_ = ...`),导致无法确定是否成功。 +* **修复**: 修改 `internal/api/pay/wechat_notify.go`,增加错误日志记录。如果虚拟发货上传失败,将在后台日志中打印详细错误原因,方便排查(如 `transaction_id` 错误或配置问题)。 + +## 2. 订单管理与退款 (Refund Button) +* **现状**: 您提到的“履约”可能是指发货,但对于虚拟商品,通常需要的是“退款”。目前后台订单列表缺少直观的“退款”按钮。 +* **修复**: + * **前端**: 在 `web/admin/src/views/pay/orders/index.vue` 中添加“退款”按钮。 + * **后端**: 对接现有的 `CreateRefund` 接口。该接口已包含完整的逻辑:调用微信退款、更新订单状态、**自动恢复用户积分**和**自动恢复优惠券**。 + +## 3. 道具卡添加不生效 (Item Card Issue) +* **原因**: 经查代码 `internal/service/user/item_card_add.go`,当道具卡模板不存在或状态为“未启用”时,代码直接返回 `nil` (成功),但实际上没有给用户添加卡片。这就是“不生效”且无报错的原因。 +* **修复**: 修改服务层代码,当道具卡不可用时,明确返回错误(如 `errors.New("item card not found or disabled")`),让接口报错,提示您具体原因。 + +## 4. 优惠券添加不生效 (Coupon Issue) +* **原因**: 同上,`internal/service/user/coupon_add.go` 在优惠券模板未启用时也静默返回成功。 +* **修复**: 修改服务层代码,当优惠券不可用时,明确返回错误,确保您能看到操作失败的提示。 + +## 执行步骤 +1. **后端**: 修复道具卡和优惠券的“静默失败”逻辑,使其报错。 +2. **后端**: 在支付回调中增加虚拟发货的错误日志。 +3. **前端**: 在订单管理页面增加“退款”按钮并对接接口。 +4. **验证**: 通过 curl 或界面操作验证修复效果。 diff --git a/.trae/documents/一番赏活动创建表单逻辑优化计划.md b/.trae/documents/一番赏活动创建表单逻辑优化计划.md new file mode 100644 index 0000000..b6c7a6e --- /dev/null +++ b/.trae/documents/一番赏活动创建表单逻辑优化计划.md @@ -0,0 +1,54 @@ +# 一番赏活动创建表单优化计划 + +用户反馈在创建一番赏活动时,选择即时/定时开奖的页面逻辑不对。通过分析代码 `web/admin/src/views/activity/wizard/index.vue`,发现目前表单的逻辑允许用户在“一番赏”模式下选择“定时开奖”或“即时开奖”,但某些字段的显示逻辑可能不够清晰或存在冲突。一番赏(Ichiban Kuji)通常有其特定的开奖规则,需要对表单进行以下优化。 + +## 1. 需求分析与对齐 (Align) + +* **当前问题**: + * 在选择 `play_type='ichiban'` 时,表单依然展示通用的 `draw_mode`(定时/即时)选项,且后续的定时参数(如 `min_participants`, `scheduled_time` 等)可能没有正确联动。 + * 一番赏的核心逻辑是“即买即开”(即时开奖),但也可能存在“定时开奖”的特殊玩法(如凑够多少人开一箱)。需要明确一番赏是否支持所有开奖模式。 + * **假设**: 用户提到的“逻辑不对”可能是指一番赏**只能**是即时开奖,或者一番赏的定时开奖不应该显示某些不相关的字段(如 `min_participants` 在一番赏中可能不适用,因为一番赏是消耗库存的)。 + * **修正策略**: + * 当选择“一番赏”时,默认锁定或限制 `draw_mode` 的选项。 + * 如果是“一番赏”,通常是**即时开奖**(用户购买后立即知道结果)。 + * 如果一番赏确实支持定时(例如:全员购买完后统一开奖),则需要明确字段。 + * **根据用户语境“即时 定时的 页面逻辑不对”**,推测可能是:切换一番赏时,应该自动处理 `draw_mode`,或者某些字段不该显示。 + +* **优化方案**: + 1. **联动逻辑**: 当 `play_type` 切换为 `ichiban` 时,强制或默认 `draw_mode` 为 `instant`(即时开奖),并禁用 `scheduled`(除非业务明确支持一番赏定时)。 + 2. **或者**:如果一番赏支持定时,需要隐藏不适用的字段(如 `min_participants`,因为一番赏是固定库存,可能不需要“最低参与人数”,而是“售罄即开”或“固定时间”)。 + 3. **UI 调整**: 简化一番赏模式下的表单,隐藏不必要的复杂定时配置。 + + **经确认(自我推演)**: 一番赏的典型玩法是用户购买后立即获得确定的赏品(即时)。但也存在“整箱全开”的定时玩法。但最常见的问题是:**一番赏不应该显示“最低参与人数”等凑单逻辑,因为它基于固定数量的签**。 + + **决定**: + * 当 `play_type === 'ichiban'` 时: + * **锁定** `draw_mode` 为 `instant`(即时开奖),并**隐藏**开奖模式选择框(或禁用)。 + * **隐藏**所有定时相关的配置(`min_participants`, `time_mode`, `interval_minutes` 等)。 + * 这样能避免用户配置出“定时开奖的一番赏”这种非典型且可能逻辑冲突的活动(除非后端明确支持)。 + +## 2. 架构设计 (Architect) + +* **前端逻辑调整 (`wizard/index.vue`)**: + * 监听 `scheduledForm.play_type` 的变化。 + * 如果 `play_type === 'ichiban'`: + * 自动设置 `scheduledForm.draw_mode = 'instant'`。 + * `scheduledForm.min_participants = 0`。 + * `scheduledForm.interval_minutes = 0`。 + * 在模板中,使用 `v-if` 控制字段显示: + * 如果 `play_type === 'ichiban'`,隐藏 `draw_mode` 选择框(或者显示为只读的“即时开奖”)。 + * 隐藏所有 `scheduled` 相关的输入框。 + +## 3. 任务拆解 (Atomize) + +1. **Modify Frontend (`wizard/index.vue`)**: + * 添加 `watch` 监听 `scheduledForm.play_type`。 + * 修改模板中的 `v-if` 条件,针对 `ichiban` 隐藏不必要的字段。 + * 或者直接在 `play_type` 选择器下方添加提示:“一番赏模式下默认为即时开奖”。 + +## 4. 执行步骤 (Automate) + +1. **Step 1**: 修改 `web/admin/src/views/activity/wizard/index.vue`。 + * 在 `script setup` 中添加 `watch` 逻辑。 + * 调整 `template` 中的表单项可见性。 + diff --git a/.trae/documents/代码结构梳理与API文档整理.md b/.trae/documents/代码结构梳理与API文档整理.md new file mode 100644 index 0000000..df1458a --- /dev/null +++ b/.trae/documents/代码结构梳理与API文档整理.md @@ -0,0 +1,77 @@ +## 背景与现状概要 +- 技术栈:后端 Go(Gin 封装于 `internal/pkg/core`)、GORM、Viper、Zap、Swagger;前端 Vue3 + Vite + TypeScript + Pinia + Element Plus。 +- 核心入口:`main.go`(服务启动与任务调度);路由中心:`internal/router/router.go`;拦截与鉴权:`internal/router/interceptor/*`。 +- 业务分层:处理器 `internal/api/{admin,activity,app,user,pay,common}`;服务 `internal/service/**`;数据访问 `internal/repository/mysql/{dao,model}`。 +- 前端管理后台:`web/admin/src/**`,接口定义集中在 `web/admin/src/api/**`。 + +## 目标与交付物 +- 代码结构梳理报告:目录分层说明 + 模块职责 + 依赖关系图(Mermaid)。 +- 无用代码清理:列出候选清理清单、逐项验证、提交可回滚的变更方案。 +- API 文档(前后端): + - 后端 REST 端点清单(方法、路径、鉴权、处理器、请求/响应示例、错误码、分页约定)。 + - 前端调用约定(基地址、拦截器、Token 注入、模块函数到后端端点的映射)。 +- 更新与补充项目根文档:`docs/说明文档.md`(规划、实施方案、进度记录)。 + +## 实施步骤 +### 1. 架构梳理(Align/Architect) +- 枚举代码目录:识别后端、前端、配置、构建、脚本、生成器与产物目录。 +- 生成架构图:描绘后端分层(Router → Interceptor → API → Service → Repo)、前端分层(视图 → Store → API)。 +- 输出《代码结构总览.md》:说明关键路径与职责、跨模块依赖、构建/部署要点。 + +### 2. 路由与端点收敛(Atomize) +- 解析 `internal/router/router.go` 的路由注册,枚举所有端点(含分组与中间件)。 +- 关联处理器方法(如 `admin.*`、`activity.*` 等),抽取鉴权要求:`AdminTokenAuthVerify`、`AppTokenAuthVerify`、RBAC `RequireAdminAction`。 +- 标准化约定:分页键(`page`、`page_size`)、通用响应包(`code`、`message`、`data`、`request_id`)、错误码体系。 + +### 3. API 文档编制 +- 后端文档:生成《API文档-后端.md》 + - 列表:方法、路径、处理器、鉴权、中间件、请求参数、响应示例、错误码、注意事项。 + - 支付/回调、系统健康、上传等特殊端点单独章节。 +- 前端文档:生成《API文档-前端.md》 + - 说明 Axios 基础配置(BaseURL、超时、拦截器、Token 注入)。 + - 列出 `web/admin/src/api/**` 模块函数到后端端点映射、入参/出参、调用示例。 + +### 4. 无用代码清理策略 +- 判定规则: + - 未被任何文件 `import`/调用; + - 未在路由或启动流程中引用; + - 构建产物(如 `build/resources/admin/**`)、运行日志(`logs/**`); + - 演示/测试脚本(如 `miniapp/pay-test/**`)、一次性生成器产物。 +- 候选清单(初版): + - `internal/metrics/**`(若未启用 Prometheus); + - `internal/repository/mysql/testrepo_sqlite.go`(未检索到引用); + - `cmd/**`(工具/生成器,保留或迁移到 dev-only); + - `scripts/swagger.*`(构建脚本,非运行时); + - `build/resources/admin/**`、`logs/**`(产物与输出)。 +- 清理流程: + - 逐项交叉检索引用关系 → 标注“安全删除”/“需保留”; + - 对可能未来使用的模块改为禁用配置或注释式保留,避免功能回退风险; + - 产物与日志转移到忽略或发布流程之外(完善 `.gitignore` 与构建管线)。 + +### 5. 文档与规范同步 +- 更新 `docs/说明文档.md`:规划、实施方案、节点记录(按用户规范)。 +- 在 `docs/api/` 目录落地《代码结构总览.md》《API文档-后端.md》《API文档-前端.md》。 +- 所有函数在新增代码中补充函数级注释(功能、参数、返回值)。 + +### 6. 验收与验证(Assess) +- 后端:`go build`、路由完整性检查、Swagger 校验(非生产)、关键端点手测。 +- 前端:`vite build`、ESLint/Stylelint、页面 API 调用冒烟测试。 +- 部署:非生产环境验证 PProf、CORS、静态资源路由回退;检查 `.env` 与证书安全。 + +## 输出物清单 +- `docs/api/代码结构总览.md`(含架构图) +- `docs/api/API文档-后端.md`(REST 列表与约定) +- `docs/api/API文档-前端.md`(调用契约与示例) +- 可回滚的清理变更(提交前附清单与影响评估) + +## 依赖与约束 +- 保留生成器/工具目录(`cmd/**`)除非确认迁移; +- 配置与证书不改动业务值,仅完善文档与忽略策略; +- 如需补充 Swagger 注解,遵循现有 `swaggo` 用法并保持最小侵入。 + +## 下一步 +- 确认本计划后: + 1) 输出架构梳理文档; + 2) 生成端点清单并编制前后端 API 文档; + 3) 提交清理候选与验证报告,执行安全清理。 +- 如需额外约定(错误码字典、分页/排序统一规范、RBAC 角色映射),我将在文档中补充并与现有实现对齐。 \ No newline at end of file diff --git a/.trae/documents/修复订单详情展示与数据补全(活动_期号_支付与中奖信息).md b/.trae/documents/修复订单详情展示与数据补全(活动_期号_支付与中奖信息).md new file mode 100644 index 0000000..8bab855 --- /dev/null +++ b/.trae/documents/修复订单详情展示与数据补全(活动_期号_支付与中奖信息).md @@ -0,0 +1,49 @@ +## 问题归因 +- 活动/期号为空:后端仅在存在抽奖日志时填充活动信息,未抽取或刚支付时为0。参考 internal/api/admin/pay_orders_admin.go:167-191。 +- 中奖字段与等级:前端直接展示“是否中奖”,但应改为“中奖等级”并基于 `activity.level`/`reward_id` 显示;未抽取时应显示“待开奖”。 +- 支付信息不全:只显示 `ActualAmount`,未分解“积分抵扣金额/积分数量”;`PayPreorderID` 为0时未做断言处理。 +- 商品价格与金额为0:抽奖订单常无商品明细或价格未赋值;可根据奖励商品填充价格,或以“抽奖价格×次数”为明细。 + +## 后端改造(GetPayOrderDetail) +- 文件:internal/api/admin/pay_orders_admin.go +- 变更点: + 1) 无抽奖日志时,解析 `order.Remark` 中 `lottery:activity:|issue:|count:` 填充 `activity.activity_id/issue_id`,查询 `issue.issue_number` 与 `activity.activity_name`。 + 2) 扩展支付信息:`payment.points_amount`(订单积分抵扣金额,单位分)、`payment.points_used`(抵扣积分数量=points_amount/10)、`payment.total_amount`(订单总额,单位分)。 + 3) 返回 `activity.count`(抽次数);若有奖励商品,补充 `activity.product_price`(商品价格,单位分)。 + 4) 若订单无 `order_items`,在响应中提供 `computed_items`:基于“抽奖价格×次数”构造一条展示用明细(前端优先显示 `computed_items`)。 + 5) `payment.pay_preorder_id` 为0时仍返回,前端据此显示“-”。 + +## 前端改造(订单详情抽屉) +- 文件:web/admin/src/views/…(订单详情抽屉组件,使用 fetchGetOrderDetail) +- 变更点: + 1) 活动:显示 `activity.activity_name`;下方附 `issue_number`;不显示 `(ID:0)`。 + 2) 状态区:移除“是否中奖”;改为“中奖等级”显示 `activity.level`,若 `reward_id` 为空则显示“待开奖”。 + 3) 支付区: + - “实付”显示:`payment.actual_amount/100` 元 + - 新增“积分抵扣”:`payment.points_used` 积分(约 `points_amount/100` 元) + - 新增“订单总额”:`payment.total_amount/100` 元 + - “预订单ID”:显示 `payment.pay_preorder_id`,为0则显示“-” + 4) 明细表: + - 优先显示 `computed_items` 的“单价/金额”,否则显示 `items`; + - 若有中奖商品,显示 `activity.reward_name` 与 `activity.product_price`。 + +## 路由与API契约 +- 前端调用不变:`GET admin/pay/orders/:order_no` +- 响应新增字段: + - `activity.count`、`activity.product_price` + - `payment.points_amount`、`payment.points_used`、`payment.total_amount` + - `computed_items: [{name, quantity, unit_price, amount}]` + +## 实施步骤 +1) 后端:更新 GetPayOrderDetail 填充解析与新增字段;构造 `computed_items`。 +2) 前端:更新详情组件的数据映射与展示逻辑;删改“是否中奖”,补充字段渲染与空值处理。 +3) 验证: + - 无抽奖日志的订单仍能显示活动名称与期号 + - 积分全额支付场景显示积分抵扣与总额,实付为0,预订单ID为“-” + - 即时模式支付后,轮询显示中奖等级与商品信息 + - 明细表显示正确单价/金额 + +## 验收标准 +- 所有问题项均有正确数据或合理占位显示 +- 即时/定时、积分/金额支付四种组合下展示正确 +- 架构不破坏现有接口:前端仅增量使用新增字段 \ No newline at end of file diff --git a/.trae/documents/全面代码清理与优化计划.md b/.trae/documents/全面代码清理与优化计划.md new file mode 100644 index 0000000..9787580 --- /dev/null +++ b/.trae/documents/全面代码清理与优化计划.md @@ -0,0 +1,127 @@ +## 目标 + +* 全面清理未用代码、注释废弃块、空文件与无用测试 + +* 识别并重构重复代码(重复率≥80%) + +* 保持现有功能稳定,构建与测试全部通过 + +* 输出对比报告与文档更新 + +## 范围 + +* 后端:`internal/**`、`cmd/**`、`migrations/**` + +* 前端管理:`web/admin/**`(Vue/TS/样式与公共组件) + +* 通用资源:`docs/**`、脚手架与配置(不更改生产配置) + +## 清理策略与工具 + +* 未用与死代码检测 + + * Go:`golangci-lint`(unused、deadcode、revive)、`go vet` + + * TS/Vue:`tsc --noEmit`(类型与未用导出)、`eslint`(no-unused-vars/no-dead-code) + +* 注释废弃块识别 + + * 规则:Grep 检索注释中出现代码结构(`func|class|export|