From 8a0dabb03c42b92df730cba9807ab34dace301b1 Mon Sep 17 00:00:00 2001 From: gpu Date: Tue, 20 Jan 2026 20:31:51 +0800 Subject: [PATCH] 333 --- .kiro/specs/admin-bugfix/design.md | 338 ++++++++++++++++++ .kiro/specs/admin-bugfix/requirements.md | 123 +++++++ .kiro/specs/admin-bugfix/tasks.md | 196 ++++++++++ ...表-002-用户盈亏统计搜索失败.md | 19 +- ...表-003-用户邀请统计搜索失败.md | 19 +- ...单管理-007-购买订单搜索失败.md | 17 +- ...单管理-008-回收订单搜索失败.md | 17 +- ...单管理-009-卡单订单搜索失败.md | 17 +- ...单管理-010-综合订单显示为空.md | 21 +- .../BUG修复任务计划.md | 154 ++++++++ docs/后台管理bug整理/BUG汇总清单.md | 26 +- .../Controllers/OrderController.cs | 27 ++ .../Models/Order/OrderModels.cs | 63 ++++ .../Models/User/StatsModels.cs | 18 +- .../Services/Interfaces/IOrderService.cs | 14 + .../Services/OrderService.cs | 157 ++++++++ .../admin-web/src/api/business/user.ts | 4 +- .../order/components/OrderSearchForm.vue | 5 +- .../src/views/business/order/recovery.vue | 5 +- .../src/views/business/user/invite-stats.vue | 6 +- .../src/views/business/user/profit-loss.vue | 6 +- 21 files changed, 1215 insertions(+), 37 deletions(-) create mode 100644 .kiro/specs/admin-bugfix/design.md create mode 100644 .kiro/specs/admin-bugfix/requirements.md create mode 100644 .kiro/specs/admin-bugfix/tasks.md create mode 100644 docs/后台管理bug整理/BUG修复任务计划.md diff --git a/.kiro/specs/admin-bugfix/design.md b/.kiro/specs/admin-bugfix/design.md new file mode 100644 index 00000000..1df6433d --- /dev/null +++ b/.kiro/specs/admin-bugfix/design.md @@ -0,0 +1,338 @@ +# Design Document + +## Overview + +本设计文档描述后台管理系统 9 个未修复 BUG 的技术修复方案。BUG 分布在统计报表、商品管理、营销活动和内容管理四个模块,主要涉及后端接口修复和少量前端调整。 + +## Architecture + +### 受影响模块架构 + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ 前端 (Vue 3 + Element Plus) │ +├─────────────────────────────────────────────────────────────────┤ +│ views/business/ │ +│ ├── statistics/ # 统计报表 (cs100_2, cs100_3) │ +│ ├── goods/ # 商品管理 (cs100_4, cs100_5, cs100_6) │ +│ ├── marketing/ # 营销活动 (cs100_11, cs100_13, cs100_14) │ +│ └── danye/ # 内容管理 (cs100_15) │ +└─────────────────────────────────────────────────────────────────┘ + │ + ▼ +┌─────────────────────────────────────────────────────────────────┐ +│ 后端 (ASP.NET Core) │ +├─────────────────────────────────────────────────────────────────┤ +│ HoneyBox.Admin.Business/ │ +│ ├── Controllers/ │ +│ │ ├── StatisticsController.cs # 统计报表接口 │ +│ │ ├── GoodsController.cs # 商品管理接口 │ +│ │ ├── MarketingController.cs # 营销活动接口 │ +│ │ └── DanyeController.cs # 单页管理接口 │ +│ └── Services/ │ +│ ├── StatisticsService.cs │ +│ ├── GoodsService.cs │ +│ ├── MarketingService.cs │ +│ └── DanyeService.cs │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Bug Analysis & Solutions + +### 1. 统计报表模块 (cs100_2, cs100_3) + +#### 问题分析 +- 用户盈亏统计和用户邀请统计按用户ID搜索时返回"请求失败" +- 可能原因: + 1. 用户ID参数类型不匹配(前端传string,后端期望int) + 2. 查询条件构建错误 + 3. 空值处理异常 + +#### 修复方案 +```csharp +// StatisticsService.cs +public async Task> GetUserProfitStatsAsync( + UserProfitStatsRequest request) +{ + var query = _dbContext.UserProfitStats.AsQueryable(); + + // 修复:正确处理用户ID搜索 + if (!string.IsNullOrEmpty(request.UserId)) + { + if (int.TryParse(request.UserId, out var userId)) + { + query = query.Where(x => x.UserId == userId); + } + } + + // ... 分页逻辑 +} +``` + +### 2. 商品管理模块 - 盒子类型搜索 (cs100_4) + +#### 问题分析 +- 盒子类型为"全部"时搜索无结果 +- 可能原因: + 1. "全部"选项传递了错误的值(如0)被当作有效类型过滤 + 2. 后端未正确处理"全部"情况 + +#### 修复方案 +```csharp +// GoodsService.cs +public async Task> GetBoxListAsync(BoxListRequest request) +{ + var query = _dbContext.Boxes.AsQueryable(); + + // 修复:当类型为0或null时,不添加类型过滤条件 + if (request.Type.HasValue && request.Type.Value > 0) + { + query = query.Where(x => x.Type == request.Type.Value); + } + + // ... 其他过滤和分页逻辑 +} +``` + +### 3. 商品管理模块 - 自动下架配置 (cs100_5) + +#### 问题分析 +- 开启"自动下架配置"后无法设置参数 +- 可能原因: + 1. 前端表单联动逻辑问题 + 2. 后端未返回自动下架相关字段 + 3. 保存接口未处理这些字段 + +#### 修复方案 + +**前端修复:** +```vue + + +``` + +**后端修复:** +```csharp +// BoxResponse.cs - 确保返回自动下架字段 +public class BoxResponse +{ + // ... 其他字段 + public bool AutoDelistEnabled { get; set; } + public DateTime? AutoDelistTime { get; set; } + public string? AutoDelistCondition { get; set; } +} +``` + +### 4. 商品管理模块 - 奖品等级分类显示 (cs100_6) + +#### 问题分析 +- 奖品等级显示"0级",分类显示"未知" +- 可能原因: + 1. 未进行关联查询获取等级和分类名称 + 2. DTO映射时字段未正确赋值 + +#### 修复方案 +```csharp +// GoodsService.cs +public async Task> GetPrizeListAsync(PrizeListRequest request) +{ + var query = from p in _dbContext.Prizes + join l in _dbContext.PrizeLevels on p.LevelId equals l.Id into levels + from level in levels.DefaultIfEmpty() + join c in _dbContext.PrizeCategories on p.CategoryId equals c.Id into categories + from category in categories.DefaultIfEmpty() + select new PrizeResponse + { + Id = p.Id, + Name = p.Name, + LevelId = p.LevelId, + LevelName = level != null ? level.Name : "未设置", // 修复 + CategoryId = p.CategoryId, + CategoryName = category != null ? category.Name : "未设置", // 修复 + // ... 其他字段 + }; + + // ... 分页逻辑 +} +``` + +### 5. 营销活动模块 - 领取记录搜索 (cs100_11) + +#### 问题分析 +- 按用户ID搜索领取记录时返回"请求失败" +- 与统计报表模块问题类似 + +#### 修复方案 +```csharp +// MarketingService.cs +public async Task> GetClaimRecordsAsync( + ClaimRecordRequest request) +{ + var query = _dbContext.ClaimRecords.AsQueryable(); + + // 修复:正确处理用户ID搜索 + if (!string.IsNullOrEmpty(request.UserId)) + { + if (int.TryParse(request.UserId, out var userId)) + { + query = query.Where(x => x.UserId == userId); + } + } + + // ... 分页逻辑 +} +``` + +### 6. 营销活动模块 - 周榜/月榜记录 (cs100_13, cs100_14) + +#### 问题分析 +- 访问周榜/月榜页面时返回"服务器内部错误" +- 可能原因: + 1. 日期范围计算错误 + 2. 数据聚合查询异常 + 3. 空数据处理异常 + +#### 修复方案 +```csharp +// MarketingService.cs +public async Task> GetWeeklyRankAsync(RankRequest request) +{ + try + { + // 修复:正确计算周起止日期 + var startOfWeek = GetStartOfWeek(request.Date ?? DateTime.Now); + var endOfWeek = startOfWeek.AddDays(7); + + var query = _dbContext.RankRecords + .Where(x => x.RecordDate >= startOfWeek && x.RecordDate < endOfWeek) + .OrderByDescending(x => x.Score); + + // 修复:处理空数据情况 + var result = await query.ToListAsync(); + return result ?? new List(); + } + catch (Exception ex) + { + _logger.LogError(ex, "获取周榜数据失败"); + throw new BusinessException("获取周榜数据失败,请稍后重试"); + } +} + +private DateTime GetStartOfWeek(DateTime date) +{ + var diff = (7 + (date.DayOfWeek - DayOfWeek.Monday)) % 7; + return date.AddDays(-diff).Date; +} +``` + +### 7. 内容管理模块 - 单页文章显示 (cs100_15) + +#### 问题分析 +- 文章内容显示原始HTML代码而非渲染内容 +- 原因:前端使用 `{{ content }}` 而非 `v-html` + +#### 修复方案 +```vue + + + + + + +``` + +## API Changes + +### 统计报表 API 修复 + +| 方法 | 路径 | 修复内容 | +|------|------|----------| +| GET | /api/business/statistics/user-profit | 修复用户ID参数处理 | +| GET | /api/business/statistics/user-invite | 修复用户ID参数处理 | + +### 商品管理 API 修复 + +| 方法 | 路径 | 修复内容 | +|------|------|----------| +| GET | /api/business/goods/boxes | 修复类型"全部"过滤逻辑 | +| GET | /api/business/goods/boxes/{id} | 添加自动下架字段返回 | +| PUT | /api/business/goods/boxes/{id} | 处理自动下架字段保存 | +| GET | /api/business/goods/prizes | 修复等级/分类关联查询 | + +### 营销活动 API 修复 + +| 方法 | 路径 | 修复内容 | +|------|------|----------| +| GET | /api/business/marketing/claim-records | 修复用户ID参数处理 | +| GET | /api/business/marketing/weekly-rank | 修复日期计算和异常处理 | +| GET | /api/business/marketing/monthly-rank | 修复日期计算和异常处理 | + +## Testing Strategy + +### 单元测试 +- 测试用户ID参数解析逻辑 +- 测试类型过滤条件构建 +- 测试日期范围计算 +- 测试关联查询结果映射 + +### 集成测试 +- 测试各搜索接口正常返回 +- 测试空数据情况处理 +- 测试边界条件(无效ID、特殊日期等) + +### 前端测试 +- 测试表单联动显示 +- 测试HTML内容渲染 +- 测试XSS防护 + +## Security Considerations + +1. **XSS防护**: 单页文章内容使用 DOMPurify 进行净化 +2. **参数验证**: 所有搜索参数进行类型验证 +3. **异常处理**: 统一异常处理,不暴露内部错误信息 + +## References + +- BUG汇总清单: `docs/后台管理bug整理/BUG汇总清单.md` +- 各BUG详细文档: `docs/后台管理bug整理/BUG-*.md` + diff --git a/.kiro/specs/admin-bugfix/requirements.md b/.kiro/specs/admin-bugfix/requirements.md new file mode 100644 index 00000000..1adc1631 --- /dev/null +++ b/.kiro/specs/admin-bugfix/requirements.md @@ -0,0 +1,123 @@ +# Requirements Document + +## Introduction + +本文档定义了后台管理系统中 9 个未修复 BUG 的修复需求。这些 BUG 涉及统计报表、商品管理、营销活动和内容管理四个模块,主要问题类型包括接口请求失败、服务器内部错误、数据显示异常和功能不可用。 + +## Glossary + +- **Admin_System**: 后台管理系统 +- **Statistics_Module**: 统计报表模块 +- **Goods_Module**: 商品管理模块 +- **Marketing_Module**: 营销活动模块 +- **Content_Module**: 内容管理模块 +- **User_Profit_Stats**: 用户盈亏统计 +- **User_Invite_Stats**: 用户邀请统计 +- **Box_Management**: 盒子管理 +- **Prize_Management**: 奖品管理 +- **Claim_Record**: 领取记录 +- **Weekly_Rank**: 周榜记录 +- **Monthly_Rank**: 月榜记录 +- **Danye_Management**: 单页管理 + +## Requirements + +### Requirement 1: 用户盈亏统计搜索修复 (cs100_2) + +**User Story:** As an administrator, I want to search user profit/loss statistics by user ID, so that I can analyze individual user's financial performance. + +#### Acceptance Criteria + +1. WHEN an administrator enters a user ID in the search field, THE Admin_System SHALL return the profit/loss statistics for that user +2. WHEN the search is executed, THE Admin_System SHALL NOT display "请求失败" error +3. THE Admin_System SHALL validate the user ID parameter before sending the request +4. THE Admin_System SHALL display appropriate message when no results are found + +### Requirement 2: 用户邀请统计搜索修复 (cs100_3) + +**User Story:** As an administrator, I want to search user invitation statistics by user ID, so that I can track user referral performance. + +#### Acceptance Criteria + +1. WHEN an administrator enters a user ID in the search field, THE Admin_System SHALL return the invitation statistics for that user +2. WHEN the search is executed, THE Admin_System SHALL NOT display "请求失败" error +3. THE Admin_System SHALL validate the user ID parameter before sending the request +4. THE Admin_System SHALL display appropriate message when no results are found + +### Requirement 3: 盒子类型全部搜索修复 (cs100_4) + +**User Story:** As an administrator, I want to search all box types when selecting "全部" filter, so that I can view the complete box list. + +#### Acceptance Criteria + +1. WHEN an administrator selects "全部" as box type filter, THE Admin_System SHALL return all boxes regardless of type +2. WHEN box type is "全部" (value 0 or empty), THE Admin_System SHALL skip the type filter condition in the query +3. THE Admin_System SHALL display the complete box list when "全部" is selected +4. THE Admin_System SHALL NOT return empty results when boxes exist in the database + +### Requirement 4: 自动下架配置修复 (cs100_5) + +**User Story:** As an administrator, I want to configure auto-delist settings when editing/creating a box, so that boxes can be automatically removed from listing. + +#### Acceptance Criteria + +1. WHEN an administrator enables "自动下架配置", THE Admin_System SHALL display the configuration parameters +2. THE Admin_System SHALL allow setting auto-delist time or conditions +3. WHEN the form is submitted, THE Admin_System SHALL save the auto-delist configuration correctly +4. THE Admin_System SHALL return auto-delist fields in the box detail response + +### Requirement 5: 奖品等级分类显示修复 (cs100_6) + +**User Story:** As an administrator, I want to see correct prize level and category names in the prize list, so that I can manage prizes effectively. + +#### Acceptance Criteria + +1. WHEN an administrator views the prize list, THE Admin_System SHALL display the correct level name (not "0级") +2. WHEN an administrator views the prize list, THE Admin_System SHALL display the correct category name (not "未知" or empty) +3. THE Admin_System SHALL perform proper join queries to fetch level and category information +4. THE Admin_System SHALL map the level and category fields correctly in the response DTO + +### Requirement 6: 领取记录搜索修复 (cs100_11) + +**User Story:** As an administrator, I want to search claim records by user ID, so that I can track user reward claims. + +#### Acceptance Criteria + +1. WHEN an administrator enters a user ID in the search field, THE Admin_System SHALL return the claim records for that user +2. WHEN the search is executed, THE Admin_System SHALL NOT display "请求失败" error +3. THE Admin_System SHALL validate the user ID parameter before sending the request +4. THE Admin_System SHALL display appropriate message when no results are found + +### Requirement 7: 周榜记录修复 (cs100_13) + +**User Story:** As an administrator, I want to view weekly ranking records, so that I can monitor weekly user performance. + +#### Acceptance Criteria + +1. WHEN an administrator accesses the weekly rank page, THE Admin_System SHALL display the ranking data +2. THE Admin_System SHALL NOT display "服务器内部错误" +3. THE Admin_System SHALL handle empty data gracefully +4. THE Admin_System SHALL calculate date ranges correctly for weekly data + +### Requirement 8: 月榜记录修复 (cs100_14) + +**User Story:** As an administrator, I want to view monthly ranking records, so that I can monitor monthly user performance. + +#### Acceptance Criteria + +1. WHEN an administrator accesses the monthly rank page, THE Admin_System SHALL display the ranking data +2. THE Admin_System SHALL NOT display "服务器内部错误" +3. THE Admin_System SHALL handle empty data gracefully +4. THE Admin_System SHALL calculate date ranges correctly for monthly data + +### Requirement 9: 单页文章内容渲染修复 (cs100_15) + +**User Story:** As an administrator, I want to view article content as rendered HTML, so that I can preview the actual display. + +#### Acceptance Criteria + +1. WHEN an administrator clicks on an article, THE Admin_System SHALL display rendered content (not raw HTML code) +2. THE Admin_System SHALL use v-html or equivalent to render HTML content +3. THE Admin_System SHALL sanitize HTML content to prevent XSS attacks +4. THE Admin_System SHALL preserve formatting and images in the rendered content + diff --git a/.kiro/specs/admin-bugfix/tasks.md b/.kiro/specs/admin-bugfix/tasks.md new file mode 100644 index 00000000..db876500 --- /dev/null +++ b/.kiro/specs/admin-bugfix/tasks.md @@ -0,0 +1,196 @@ +# Implementation Plan: 后台管理系统 BUG 修复 + +## Overview + +本实现计划针对后台管理系统中 9 个未修复 BUG 进行分批次修复。按模块和优先级组织任务,确保核心功能优先修复。 + +## 任务概览 + +| 批次 | 模块 | BUG数量 | 预计工时 | +|------|------|---------|----------| +| 1. 统计报表模块修复 | Statistics | 2 | 2h | +| 2. 商品管理模块修复 | Goods | 3 | 4h | +| 3. 营销活动模块修复 | Marketing | 3 | 3h | +| 4. 内容管理模块修复 | Content | 1 | 1h | +| 5. 测试验证 | All | - | 2h | +| **总计** | - | **9** | **12h** | + +--- + +## Tasks + +- [x] 1. 统计报表模块修复 + - [x] 1.1 修复用户盈亏统计搜索 (cs100_2) + - 定位 `StatisticsService.cs` 中用户盈亏统计方法 + - 检查用户ID参数接收和处理逻辑 + - 修复参数类型转换(string -> int) + - 添加空值和无效值处理 + - 测试搜索功能正常返回 + - _Requirements: 1.1, 1.2, 1.3, 1.4_ + + - [x] 1.2 修复用户邀请统计搜索 (cs100_3) + - 定位 `StatisticsService.cs` 中用户邀请统计方法 + - 检查用户ID参数接收和处理逻辑 + - 修复参数类型转换(string -> int) + - 添加空值和无效值处理 + - 测试搜索功能正常返回 + - _Requirements: 2.1, 2.2, 2.3, 2.4_ + + - [x] 1.3 Checkpoint - 统计报表模块验证 + - 验证用户盈亏统计搜索正常 + - 验证用户邀请统计搜索正常 + - 验证无结果时显示正确提示 + +- [ ] 2. 商品管理模块修复 + - [ ] 2.1 修复盒子类型全部搜索 (cs100_4) + - 定位 `GoodsService.cs` 中盒子列表查询方法 + - 检查类型过滤条件构建逻辑 + - 修复:当类型为0或null时跳过类型过滤 + - 前端检查"全部"选项传递的值 + - 测试选择"全部"时返回所有盒子 + - _Requirements: 3.1, 3.2, 3.3, 3.4_ + + - [ ] 2.2 修复自动下架配置 (cs100_5) + - 检查后端 `BoxResponse` 是否包含自动下架字段 + - 检查后端保存接口是否处理自动下架字段 + - 检查前端表单联动逻辑(v-if/v-show) + - 修复前端表单字段绑定 + - 测试开启配置后可正常设置参数 + - 测试保存后数据正确持久化 + - _Requirements: 4.1, 4.2, 4.3, 4.4_ + + - [ ] 2.3 修复奖品等级分类显示 (cs100_6) + - 定位 `GoodsService.cs` 中奖品列表查询方法 + - 添加等级表和分类表的关联查询(LEFT JOIN) + - 修复 DTO 映射,确保 LevelName 和 CategoryName 正确赋值 + - 处理关联数据为空的情况(显示"未设置") + - 测试奖品列表显示正确的等级和分类名称 + - _Requirements: 5.1, 5.2, 5.3, 5.4_ + + - [ ] 2.4 Checkpoint - 商品管理模块验证 + - 验证盒子类型"全部"搜索正常 + - 验证自动下架配置可正常设置 + - 验证奖品等级和分类显示正确 + +- [ ] 3. 营销活动模块修复 + - [ ] 3.1 修复领取记录搜索 (cs100_11) + - 定位营销活动相关 Service 中领取记录查询方法 + - 检查用户ID参数接收和处理逻辑 + - 修复参数类型转换(string -> int) + - 添加空值和无效值处理 + - 测试搜索功能正常返回 + - _Requirements: 6.1, 6.2, 6.3, 6.4_ + + - [ ] 3.2 修复周榜记录服务器错误 (cs100_13) + - 定位周榜记录查询方法 + - 检查服务器日志定位具体异常 + - 修复日期范围计算逻辑(周起止日期) + - 添加异常捕获和友好错误提示 + - 处理空数据情况 + - 测试周榜页面正常加载 + - _Requirements: 7.1, 7.2, 7.3, 7.4_ + + - [ ] 3.3 修复月榜记录服务器错误 (cs100_14) + - 定位月榜记录查询方法 + - 检查服务器日志定位具体异常 + - 修复日期范围计算逻辑(月起止日期) + - 添加异常捕获和友好错误提示 + - 处理空数据情况 + - 测试月榜页面正常加载 + - _Requirements: 8.1, 8.2, 8.3, 8.4_ + + - [ ] 3.4 Checkpoint - 营销活动模块验证 + - 验证领取记录搜索正常 + - 验证周榜记录页面正常加载 + - 验证月榜记录页面正常加载 + +- [ ] 4. 内容管理模块修复 + - [ ] 4.1 修复单页文章显示H5代码 (cs100_15) + - 定位单页详情/编辑组件 + - 将 `{{ content }}` 改为 `v-html="content"` + - 添加 DOMPurify 进行 XSS 防护 + - 添加内容区域样式(图片自适应等) + - 测试文章内容正确渲染 + - _Requirements: 9.1, 9.2, 9.3, 9.4_ + + - [ ] 4.2 Checkpoint - 内容管理模块验证 + - 验证单页文章内容正确渲染 + - 验证图片和格式正常显示 + - 验证XSS防护生效 + +- [ ] 5. 综合测试验证 + - [ ] 5.1 回归测试 + - 测试所有修复的功能点 + - 测试相关功能无副作用 + - 测试边界条件和异常情况 + + - [ ] 5.2 更新BUG状态 + - 更新 `docs/后台管理bug整理/BUG汇总清单.md` 状态 + - 更新各BUG详细文档状态 + - 记录修复方案和验证结果 + + - [ ] 5.3 Final Checkpoint + - 确认所有9个BUG已修复 + - 确认无新增问题 + - 如有问题,询问用户 + +--- + +## 验收检查清单 + +### 统计报表模块 +- [ ] cs100_2: 用户盈亏统计按用户ID搜索正常 +- [ ] cs100_3: 用户邀请统计按用户ID搜索正常 + +### 商品管理模块 +- [ ] cs100_4: 盒子类型"全部"搜索返回所有盒子 +- [ ] cs100_5: 自动下架配置可正常设置和保存 +- [ ] cs100_6: 奖品等级和分类显示正确名称 + +### 营销活动模块 +- [ ] cs100_11: 领取记录按用户ID搜索正常 +- [ ] cs100_13: 周榜记录页面正常加载 +- [ ] cs100_14: 月榜记录页面正常加载 + +### 内容管理模块 +- [ ] cs100_15: 单页文章内容正确渲染(非HTML代码) + +--- + +## 文件路径参考 + +### 后端文件(可能涉及) +- `server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/StatisticsController.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Services/StatisticsService.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/GoodsController.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Services/GoodsService.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/MarketingController.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Services/MarketingService.cs` + +### 前端文件(可能涉及) +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/statistics/` +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/goods/` +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/marketing/` +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/danye/` + +### 参考文档 +- `docs/后台管理bug整理/BUG汇总清单.md` +- `docs/后台管理bug整理/BUG-统计报表-002-用户盈亏统计搜索失败.md` +- `docs/后台管理bug整理/BUG-统计报表-003-用户邀请统计搜索失败.md` +- `docs/后台管理bug整理/BUG-商品管理-004-盒子类型全部搜索无结果.md` +- `docs/后台管理bug整理/BUG-商品管理-005-自动下架配置无法设置.md` +- `docs/后台管理bug整理/BUG-商品管理-006-奖品等级分类显示异常.md` +- `docs/后台管理bug整理/BUG-营销活动-011-领取记录搜索失败.md` +- `docs/后台管理bug整理/BUG-营销活动-013-周榜记录服务器错误.md` +- `docs/后台管理bug整理/BUG-营销活动-014-月榜记录服务器错误.md` +- `docs/后台管理bug整理/BUG-内容管理-015-单页文章显示H5代码.md` + +--- + +## Notes + +- 每个模块修复后进行 Checkpoint 验证 +- 优先修复高优先级 BUG(接口请求失败、服务器错误) +- 修复过程中如发现关联问题,及时记录 +- 所有修复需要在测试环境验证后再部署生产 + diff --git a/docs/后台管理bug整理/BUG-统计报表-002-用户盈亏统计搜索失败.md b/docs/后台管理bug整理/BUG-统计报表-002-用户盈亏统计搜索失败.md index 896060af..17a87af8 100644 --- a/docs/后台管理bug整理/BUG-统计报表-002-用户盈亏统计搜索失败.md +++ b/docs/后台管理bug整理/BUG-统计报表-002-用户盈亏统计搜索失败.md @@ -7,7 +7,7 @@ - **所属模块**: 统计报表 - **所属页面**: 用户盈亏统计 - **严重程度**: 高 -- **状态**: 未修改 +- **状态**: 已修复 - **类型**: 后端 ## 问题描述 @@ -22,7 +22,20 @@ 搜索时提示"请求失败",无法获取结果。 +## 修复方案 + +**根本原因**: 前端传递的用户ID为字符串类型,后端期望整数类型,导致模型绑定失败。 + +**修复内容**: +1. 修改 `ProfitLossListQuery` 模型,将 `UserId` 改为从字符串 `UserIdStr` 解析的计算属性 +2. 更新前端 API 接口,使用 `userIdStr` 参数名 +3. 更新前端视图,绑定到 `userIdStr` 字段 + +**修改文件**: +- `server/HoneyBox/src/HoneyBox.Admin.Business/Models/User/StatsModels.cs` +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/user.ts` +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/profit-loss.vue` + ## 备注 -- 需排查后端接口是否正常 -- 检查搜索参数传递是否正确 +- 修复日期: 2026-01-20 diff --git a/docs/后台管理bug整理/BUG-统计报表-003-用户邀请统计搜索失败.md b/docs/后台管理bug整理/BUG-统计报表-003-用户邀请统计搜索失败.md index 1db12d5d..2affb9d6 100644 --- a/docs/后台管理bug整理/BUG-统计报表-003-用户邀请统计搜索失败.md +++ b/docs/后台管理bug整理/BUG-统计报表-003-用户邀请统计搜索失败.md @@ -7,7 +7,7 @@ - **所属模块**: 统计报表 - **所属页面**: 用户邀请统计 - **严重程度**: 高 -- **状态**: 未修改 +- **状态**: 已修复 - **类型**: 后端 ## 问题描述 @@ -22,7 +22,20 @@ 搜索时提示"请求失败",无法获取结果。 +## 修复方案 + +**根本原因**: 前端传递的用户ID为字符串类型,后端期望整数类型,导致模型绑定失败。 + +**修复内容**: +1. 修改 `InviteStatsQuery` 模型,将 `UserId` 改为从字符串 `UserIdStr` 解析的计算属性 +2. 更新前端 API 接口,使用 `userIdStr` 参数名 +3. 更新前端视图,绑定到 `userIdStr` 字段 + +**修改文件**: +- `server/HoneyBox/src/HoneyBox.Admin.Business/Models/User/StatsModels.cs` +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/user.ts` +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/invite-stats.vue` + ## 备注 -- 需排查后端接口是否正常 -- 检查搜索参数传递是否正确 +- 修复日期: 2026-01-20 diff --git a/docs/后台管理bug整理/BUG-订单管理-007-购买订单搜索失败.md b/docs/后台管理bug整理/BUG-订单管理-007-购买订单搜索失败.md index 18d237d2..4060ede1 100644 --- a/docs/后台管理bug整理/BUG-订单管理-007-购买订单搜索失败.md +++ b/docs/后台管理bug整理/BUG-订单管理-007-购买订单搜索失败.md @@ -7,7 +7,7 @@ - **所属模块**: 订单管理 - **所属页面**: 购买订单 - **严重程度**: 高 -- **状态**: 未修改 +- **状态**: 已修复 - **类型**: 后端 ## 问题描述 @@ -26,3 +26,18 @@ - 后端接口可能存在异常 - 需检查接口日志定位具体错误原因 + + +## 修复记录 + +### 2026-01-20 修复 + +**问题分析**: +1. 后端 OrderService 逻辑经单元测试验证正常 +2. 前端搜索表单在用户输入非数字 userId 时,`parseInt` 返回 `NaN` 导致请求异常 + +**修复内容**: +1. 修复前端 `OrderSearchForm.vue` 中 userId 解析逻辑,添加 `isNaN` 检查 + +**修改文件**: +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/order/components/OrderSearchForm.vue` diff --git a/docs/后台管理bug整理/BUG-订单管理-008-回收订单搜索失败.md b/docs/后台管理bug整理/BUG-订单管理-008-回收订单搜索失败.md index 7250048e..24a5ba3b 100644 --- a/docs/后台管理bug整理/BUG-订单管理-008-回收订单搜索失败.md +++ b/docs/后台管理bug整理/BUG-订单管理-008-回收订单搜索失败.md @@ -7,7 +7,7 @@ - **所属模块**: 订单管理 - **所属页面**: 回收订单 - **严重程度**: 高 -- **状态**: 未修改 +- **状态**: 已修复 - **类型**: 后端 ## 问题描述 @@ -26,3 +26,18 @@ - 后端接口可能存在异常 - 需检查接口日志定位具体错误原因 + + +## 修复记录 + +### 2026-01-20 修复 + +**问题分析**: +1. 后端 OrderService 逻辑经单元测试验证正常 +2. 前端搜索表单在用户输入非数字 userId 时,`parseInt` 返回 `NaN` 导致请求异常 + +**修复内容**: +1. 修复前端 `recovery.vue` 中 userId 解析逻辑,添加 `isNaN` 检查 + +**修改文件**: +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/order/recovery.vue` diff --git a/docs/后台管理bug整理/BUG-订单管理-009-卡单订单搜索失败.md b/docs/后台管理bug整理/BUG-订单管理-009-卡单订单搜索失败.md index 7185f1a8..970bfbeb 100644 --- a/docs/后台管理bug整理/BUG-订单管理-009-卡单订单搜索失败.md +++ b/docs/后台管理bug整理/BUG-订单管理-009-卡单订单搜索失败.md @@ -7,7 +7,7 @@ - **所属模块**: 订单管理 - **所属页面**: 卡单订单 - **严重程度**: 高 -- **状态**: 未修改 +- **状态**: 已修复 - **类型**: 后端 ## 问题描述 @@ -26,3 +26,18 @@ - 后端接口可能存在异常 - 需检查接口日志定位具体错误原因 + + +## 修复记录 + +### 2026-01-20 修复 + +**问题分析**: +1. 后端 OrderService 逻辑经单元测试验证正常 +2. 前端搜索表单复用 `OrderSearchForm.vue` 组件,该组件已修复 + +**修复内容**: +1. 通过修复 `OrderSearchForm.vue` 组件间接修复此问题 + +**修改文件**: +- `server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/order/components/OrderSearchForm.vue` diff --git a/docs/后台管理bug整理/BUG-订单管理-010-综合订单显示为空.md b/docs/后台管理bug整理/BUG-订单管理-010-综合订单显示为空.md index 53146021..c8e015e5 100644 --- a/docs/后台管理bug整理/BUG-订单管理-010-综合订单显示为空.md +++ b/docs/后台管理bug整理/BUG-订单管理-010-综合订单显示为空.md @@ -7,7 +7,7 @@ - **所属模块**: 订单管理 - **所属页面**: 综合订单 - **严重程度**: 高 -- **状态**: 未修改 +- **状态**: 已修复 - **类型**: 后端 ## 问题描述 @@ -26,3 +26,22 @@ - 检查后端接口是否正常返回数据 - 检查前端是否正确渲染数据 + + +## 修复记录 + +### 2026-01-20 修复 + +**问题原因**: 后端缺少综合订单的 API 端点 `/api/admin/business/orders/list` 和 `/api/admin/business/orders/list/export` + +**修复内容**: +1. 在 `OrderModels.cs` 添加 `ComprehensiveOrderListRequest` 和 `ComprehensiveOrderExportRequest` 模型 +2. 在 `IOrderService.cs` 添加 `GetComprehensiveOrdersAsync` 和 `ExportComprehensiveOrdersAsync` 接口方法 +3. 在 `OrderService.cs` 实现综合订单查询和导出逻辑,支持按账号类型(测试/正常)和账号状态(正常/封号)过滤 +4. 在 `OrderController.cs` 添加 `GET /list` 和 `GET /list/export` 端点 + +**修改文件**: +- `server/HoneyBox/src/HoneyBox.Admin.Business/Models/Order/OrderModels.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Services/Interfaces/IOrderService.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Services/OrderService.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/OrderController.cs` diff --git a/docs/后台管理bug整理/BUG修复任务计划.md b/docs/后台管理bug整理/BUG修复任务计划.md new file mode 100644 index 00000000..f37cf37d --- /dev/null +++ b/docs/后台管理bug整理/BUG修复任务计划.md @@ -0,0 +1,154 @@ +# 后台管理系统 BUG 修复任务计划 + +> 创建时间: 2026-01-20 | 状态: 进行中 + +## 概述 + +本计划针对后台管理系统中 **9个未修复BUG** 进行分批次修复,按优先级和模块关联性组织任务。 + +## 修复批次规划 + +### 第一批:统计报表模块(预计 1 天) + +| 任务 | BUG编号 | 问题 | 类型 | 优先级 | +|------|---------|------|------|--------| +| 1.1 | cs100_2 | 用户盈亏统计搜索失败 | 后端 | 高 | +| 1.2 | cs100_3 | 用户邀请统计搜索失败 | 后端 | 高 | + +**修复思路:** +- 检查 `StatisticsController` 中用户盈亏/邀请统计接口 +- 排查搜索参数(用户ID)的传递和处理逻辑 +- 验证数据库查询语句是否正确 + +**涉及文件:** +- `server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/StatisticsController.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Services/StatisticsService.cs` +- 前端对应的 API 调用文件 + +--- + +### 第二批:商品管理模块(预计 1.5 天) + +| 任务 | BUG编号 | 问题 | 类型 | 优先级 | +|------|---------|------|------|--------| +| 2.1 | cs100_4 | 盒子类型"全部"搜索无结果 | 后端 | 高 | +| 2.2 | cs100_5 | 自动下架配置无法设置 | 前端+后端 | 中 | +| 2.3 | cs100_6 | 奖品等级/分类显示异常 | 后端 | 中 | + +**修复思路:** + +**2.1 盒子类型搜索问题:** +- 检查盒子列表接口的类型过滤逻辑 +- 当类型为"全部"(通常为0或空)时,应跳过类型过滤条件 + +**2.2 自动下架配置问题:** +- 检查前端表单的联动显示逻辑 +- 确认后端是否正确返回自动下架相关字段 +- 验证保存接口是否正确处理这些参数 + +**2.3 奖品等级/分类显示问题:** +- 检查奖品列表接口的关联查询(等级表、分类表) +- 确认返回的 DTO 中包含等级名称和分类名称 +- 检查前端字段映射是否正确 + +**涉及文件:** +- `server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/GoodsController.cs` +- `server/HoneyBox/src/HoneyBox.Admin.Business/Services/GoodsService.cs` +- `admin-web/src/views/business/goods/` 相关组件 + +--- + +### 第三批:营销活动模块(预计 1.5 天) + +| 任务 | BUG编号 | 问题 | 类型 | 优先级 | +|------|---------|------|------|--------| +| 3.1 | cs100_11 | 领取记录搜索失败 | 后端 | 高 | +| 3.2 | cs100_13 | 周榜记录服务器错误 | 后端 | 高 | +| 3.3 | cs100_14 | 月榜记录服务器错误 | 后端 | 高 | + +**修复思路:** + +**3.1 领取记录搜索问题:** +- 检查领取记录接口的用户ID搜索逻辑 +- 验证参数类型转换是否正确 + +**3.2 & 3.3 周榜/月榜服务器错误:** +- 查看服务器日志定位具体异常 +- 检查排行榜数据查询逻辑 +- 可能是日期范围计算、数据聚合或空数据处理问题 + +**涉及文件:** +- 营销活动相关 Controller 和 Service +- 排行榜相关数据库查询 + +--- + +### 第四批:内容管理模块(预计 0.5 天) + +| 任务 | BUG编号 | 问题 | 类型 | 优先级 | +|------|---------|------|------|--------| +| 4.1 | cs100_15 | 单页文章显示H5代码 | 前端 | 中 | + +**修复思路:** +- 检查单页详情组件是否使用 `v-html` 渲染富文本内容 +- 如果使用了 `{{ content }}`,需改为 `v-html="content"` +- 注意 XSS 安全,必要时对内容进行过滤 + +**涉及文件:** +- `admin-web/src/views/business/danye/` 相关组件 +- `DanyeFormDialog.vue` 或详情展示组件 + +--- + +## 任务清单 + +### ✅ 已完成 +- [x] cs100_7 - 购买订单搜索失败 +- [x] cs100_8 - 回收订单搜索失败 +- [x] cs100_9 - 卡单订单搜索失败 +- [x] cs100_10 - 综合订单显示为空 + +### 🔄 待修复(按优先级排序) + +#### 高优先级(6个) +- [ ] cs100_2 - 用户盈亏统计搜索失败 +- [ ] cs100_3 - 用户邀请统计搜索失败 +- [ ] cs100_4 - 盒子类型"全部"搜索无结果 +- [ ] cs100_11 - 领取记录搜索失败 +- [ ] cs100_13 - 周榜记录服务器错误 +- [ ] cs100_14 - 月榜记录服务器错误 + +#### 中优先级(3个) +- [ ] cs100_5 - 自动下架配置无法设置 +- [ ] cs100_6 - 奖品等级/分类显示异常 +- [ ] cs100_15 - 单页文章显示H5代码 + +--- + +## 时间估算 + +| 批次 | 模块 | BUG数量 | 预计工时 | +|------|------|---------|----------| +| 第一批 | 统计报表 | 2 | 1 天 | +| 第二批 | 商品管理 | 3 | 1.5 天 | +| 第三批 | 营销活动 | 3 | 1.5 天 | +| 第四批 | 内容管理 | 1 | 0.5 天 | +| **合计** | - | **9** | **4.5 天** | + +--- + +## 验收标准 + +每个BUG修复后需满足: +1. 功能正常,无报错 +2. 搜索/查询结果正确 +3. 数据显示完整 +4. 通过回归测试 + +--- + +## 备注 + +- 修复过程中如发现关联问题,及时记录并评估影响 +- 每批次完成后更新 `BUG汇总清单.md` 状态 +- 建议先在测试环境验证,再部署到生产环境 diff --git a/docs/后台管理bug整理/BUG汇总清单.md b/docs/后台管理bug整理/BUG汇总清单.md index 7ac12f66..c7b8d535 100644 --- a/docs/后台管理bug整理/BUG汇总清单.md +++ b/docs/后台管理bug整理/BUG汇总清单.md @@ -4,14 +4,14 @@ ## 统计概览 -| 模块 | BUG数量 | 高优先级 | 中优先级 | -|------|---------|----------|----------| -| 统计报表 | 2 | 2 | 0 | -| 商品管理 | 3 | 1 | 2 | -| 订单管理 | 4 | 4 | 0 | -| 营销活动 | 3 | 3 | 0 | +| 模块 | BUG数量 | 已修复 | 未修复 | +|------|---------|--------|--------| +| 统计报表 | 2 | **2** | 0 | +| 商品管理 | 3 | 0 | 3 | +| 订单管理 | 4 | **4** | 0 | +| 营销活动 | 3 | 0 | 3 | | 内容管理 | 1 | 0 | 1 | -| **合计** | **13** | **10** | **3** | +| **合计** | **13** | **6** | **7** | ## BUG 列表 @@ -19,8 +19,8 @@ | 编号 | 问题描述 | 严重程度 | 状态 | |------|----------|----------|------| -| cs100_2 | 用户盈亏统计,根据用户ID搜索提示请求失败 | 高 | 未修改 | -| cs100_3 | 用户邀请统计,根据用户ID搜索提示请求失败 | 高 | 未修改 | +| cs100_2 | 用户盈亏统计,根据用户ID搜索提示请求失败 | 高 | 已修复 | +| cs100_3 | 用户邀请统计,根据用户ID搜索提示请求失败 | 高 | 已修复 | ### 商品管理模块 @@ -34,10 +34,10 @@ | 编号 | 问题描述 | 严重程度 | 状态 | |------|----------|----------|------| -| cs100_7 | 购买订单,任意搜索方式都提示请求失败 | 高 | 未修改 | -| cs100_8 | 回收订单,任意搜索方式都提示请求失败 | 高 | 未修改 | -| cs100_9 | 卡单订单,任意搜索方式都提示请求失败 | 高 | 未修改 | -| cs100_10 | 综合订单,页面显示为空 | 高 | 未修改 | +| cs100_7 | 购买订单,任意搜索方式都提示请求失败 | 高 | 已修复 | +| cs100_8 | 回收订单,任意搜索方式都提示请求失败 | 高 | 已修复 | +| cs100_9 | 卡单订单,任意搜索方式都提示请求失败 | 高 | 已修复 | +| cs100_10 | 综合订单,页面显示为空 | 高 | 已修复 | ### 营销活动模块 diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/OrderController.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/OrderController.cs index f51ba1af..7bfe50a7 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/OrderController.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Controllers/OrderController.cs @@ -77,6 +77,19 @@ public class OrderController : BusinessControllerBase return Ok(result); } + /// + /// 获取综合订单列表(支持按账号类型和状态过滤) + /// + /// 查询请求 + /// 分页订单列表 + [HttpGet("list")] + [BusinessPermission("order:list")] + public async Task GetComprehensiveOrders([FromQuery] ComprehensiveOrderListRequest request) + { + var result = await _orderService.GetComprehensiveOrdersAsync(request); + return Ok(result); + } + #endregion #region 发货管理 @@ -225,5 +238,19 @@ public class OrderController : BusinessControllerBase return Ok(result); } + /// + /// 导出综合订单 + /// + /// 导出请求 + /// CSV文件 + [HttpGet("list/export")] + [BusinessPermission("order:export")] + public async Task ExportComprehensiveOrders([FromQuery] ComprehensiveOrderExportRequest request) + { + var bytes = await _orderService.ExportComprehensiveOrdersAsync(request); + var fileName = $"comprehensive_orders_{DateTime.Now:yyyyMMddHHmmss}.csv"; + return File(bytes, "text/csv", fileName); + } + #endregion } diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Order/OrderModels.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Order/OrderModels.cs index cae7294f..c345f303 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Order/OrderModels.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/Order/OrderModels.cs @@ -279,3 +279,66 @@ public class OrderPrizeItemDto /// public DateTime CreatedAt { get; set; } } + + +/// +/// 综合订单列表请求(支持按账号类型和状态过滤) +/// +public class ComprehensiveOrderListRequest : OrderListRequest +{ + /// + /// 账号类型(0-正常 1-推广 2-测试) + /// + public int? AccountType { get; set; } + + /// + /// 账号状态(0-正常 1-封号) + /// + public int? AccountStatus { get; set; } +} + +/// +/// 综合订单导出请求 +/// +public class ComprehensiveOrderExportRequest +{ + /// + /// 用户ID + /// + public int? UserId { get; set; } + + /// + /// 手机号 + /// + public string? Mobile { get; set; } + + /// + /// 订单编号 + /// + public string? OrderNum { get; set; } + + /// + /// 开始日期 + /// + public DateTime? StartDate { get; set; } + + /// + /// 结束日期 + /// + public DateTime? EndDate { get; set; } + + /// + /// 订单状态 + /// + public int? Status { get; set; } + + /// + /// 账号类型(0-正常 1-推广 2-测试) + /// + public int? AccountType { get; set; } + + /// + /// 账号状态(0-正常 1-封号) + /// + public int? AccountStatus { get; set; } +} diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/User/StatsModels.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/User/StatsModels.cs index 7a195b6d..3136509d 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Models/User/StatsModels.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Models/User/StatsModels.cs @@ -8,9 +8,14 @@ namespace HoneyBox.Admin.Business.Models.User; public class InviteStatsQuery : PagedRequest { /// - /// 用户ID + /// 用户ID(支持字符串输入,会自动转换为整数) /// - public int? UserId { get; set; } + public string? UserIdStr { get; set; } + + /// + /// 获取解析后的用户ID + /// + public int? UserId => !string.IsNullOrWhiteSpace(UserIdStr) && int.TryParse(UserIdStr.Trim(), out var id) ? id : null; /// /// 用户UID @@ -206,9 +211,14 @@ public class ProfitLossListQuery : PagedRequest public string? Uid { get; set; } /// - /// 用户ID + /// 用户ID(支持字符串输入,会自动转换为整数) /// - public int? UserId { get; set; } + public string? UserIdStr { get; set; } + + /// + /// 获取解析后的用户ID + /// + public int? UserId => !string.IsNullOrWhiteSpace(UserIdStr) && int.TryParse(UserIdStr.Trim(), out var id) ? id : null; /// /// 开始时间 diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Services/Interfaces/IOrderService.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Services/Interfaces/IOrderService.cs index 3537238b..2b1e2744 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Services/Interfaces/IOrderService.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Services/Interfaces/IOrderService.cs @@ -38,6 +38,13 @@ public interface IOrderService /// 分页兑换订单列表 Task> GetRecoveryOrdersAsync(OrderListRequest request); + /// + /// 获取综合订单列表(支持按账号类型和状态过滤) + /// + /// 查询请求 + /// 分页订单列表 + Task> GetComprehensiveOrdersAsync(ComprehensiveOrderListRequest request); + #endregion #region 发货管理 @@ -105,5 +112,12 @@ public interface IOrderService /// 统计信息 Task GetShippingStatsAsync(ShippingOrderListRequest request); + /// + /// 导出综合订单为CSV + /// + /// 导出请求 + /// CSV文件字节数组 + Task ExportComprehensiveOrdersAsync(ComprehensiveOrderExportRequest request); + #endregion } diff --git a/server/HoneyBox/src/HoneyBox.Admin.Business/Services/OrderService.cs b/server/HoneyBox/src/HoneyBox.Admin.Business/Services/OrderService.cs index e91ec11f..414e9e1c 100644 --- a/server/HoneyBox/src/HoneyBox.Admin.Business/Services/OrderService.cs +++ b/server/HoneyBox/src/HoneyBox.Admin.Business/Services/OrderService.cs @@ -250,6 +250,74 @@ public class OrderService : IOrderService return PagedResult.Create(list, total, request.Page, request.PageSize); } + /// + public async Task> GetComprehensiveOrdersAsync(ComprehensiveOrderListRequest request) + { + var query = _dbContext.Orders.AsNoTracking(); + + // 应用基础订单过滤条件 + query = ApplyOrderFilters(query, request); + + // 按手机号过滤 + if (!string.IsNullOrWhiteSpace(request.Mobile)) + { + var mobileUserIds = await _dbContext.Users + .AsNoTracking() + .Where(u => u.Mobile != null && u.Mobile.Contains(request.Mobile)) + .Select(u => u.Id) + .ToListAsync(); + query = query.Where(o => mobileUserIds.Contains(o.UserId)); + } + + // 按账号类型过滤(IsTest: 0-正常用户, 1-测试账号) + // 前端 AccountType: 0-正常, 1-推广, 2-测试 + if (request.AccountType.HasValue) + { + int isTestValue = request.AccountType.Value == 2 ? 1 : 0; // 2=测试 -> IsTest=1 + var accountTypeUserIds = await _dbContext.Users + .AsNoTracking() + .Where(u => u.IsTest == isTestValue) + .Select(u => u.Id) + .ToListAsync(); + query = query.Where(o => accountTypeUserIds.Contains(o.UserId)); + } + + // 按账号状态过滤(Status: 1-正常, 0-禁用) + // 前端 AccountStatus: 0-正常, 1-封号 + if (request.AccountStatus.HasValue) + { + byte statusValue = request.AccountStatus.Value == 0 ? (byte)1 : (byte)0; + var accountStatusUserIds = await _dbContext.Users + .AsNoTracking() + .Where(u => u.Status == statusValue) + .Select(u => u.Id) + .ToListAsync(); + query = query.Where(o => accountStatusUserIds.Contains(o.UserId)); + } + + // 获取总数 + var total = await query.CountAsync(); + + // 获取订单列表 + var orders = await query + .OrderByDescending(o => o.Id) + .Skip(request.Skip) + .Take(request.PageSize) + .ToListAsync(); + + // 获取用户信息 + var userIds = orders.Select(o => o.UserId).Distinct().ToList(); + var users = await _dbContext.Users + .AsNoTracking() + .Where(u => userIds.Contains(u.Id)) + .ToDictionaryAsync(u => u.Id); + + // 映射结果 + var list = orders.Select(o => MapToOrderListResponse(o, users)).ToList(); + + return PagedResult.Create(list, total, request.Page, request.PageSize); + } + #endregion #region 发货管理 @@ -640,6 +708,95 @@ public class OrderService : IOrderService }; } + /// + public async Task ExportComprehensiveOrdersAsync(ComprehensiveOrderExportRequest request) + { + var query = _dbContext.Orders.AsNoTracking(); + + // 应用过滤条件 + if (request.UserId.HasValue) + { + query = query.Where(o => o.UserId == request.UserId.Value); + } + + if (!string.IsNullOrWhiteSpace(request.OrderNum)) + { + query = query.Where(o => o.OrderNum.Contains(request.OrderNum)); + } + + if (request.StartDate.HasValue) + { + query = query.Where(o => o.CreatedAt >= request.StartDate.Value); + } + + if (request.EndDate.HasValue) + { + var endDate = request.EndDate.Value.AddDays(1); + query = query.Where(o => o.CreatedAt < endDate); + } + + if (request.Status.HasValue) + { + query = query.Where(o => o.Status == request.Status.Value); + } + + // 按手机号过滤 + if (!string.IsNullOrWhiteSpace(request.Mobile)) + { + var mobileUserIds = await _dbContext.Users + .AsNoTracking() + .Where(u => u.Mobile != null && u.Mobile.Contains(request.Mobile)) + .Select(u => u.Id) + .ToListAsync(); + query = query.Where(o => mobileUserIds.Contains(o.UserId)); + } + + // 按账号类型过滤(IsTest: 0-正常用户, 1-测试账号) + // 前端 AccountType: 0-正常, 1-推广, 2-测试 + if (request.AccountType.HasValue) + { + int isTestValue = request.AccountType.Value == 2 ? 1 : 0; // 2=测试 -> IsTest=1 + var accountTypeUserIds = await _dbContext.Users + .AsNoTracking() + .Where(u => u.IsTest == isTestValue) + .Select(u => u.Id) + .ToListAsync(); + query = query.Where(o => accountTypeUserIds.Contains(o.UserId)); + } + + // 按账号状态过滤(Status: 1-正常, 0-禁用) + // 前端 AccountStatus: 0-正常, 1-封号 + if (request.AccountStatus.HasValue) + { + byte statusValue = request.AccountStatus.Value == 0 ? (byte)1 : (byte)0; + var accountStatusUserIds = await _dbContext.Users + .AsNoTracking() + .Where(u => u.Status == statusValue) + .Select(u => u.Id) + .ToListAsync(); + query = query.Where(o => accountStatusUserIds.Contains(o.UserId)); + } + + // 获取订单数据 + var orders = await query + .OrderByDescending(o => o.Id) + .Take(10000) // 限制导出数量 + .ToListAsync(); + + // 获取用户信息 + var userIds = orders.Select(o => o.UserId).Distinct().ToList(); + var users = await _dbContext.Users + .AsNoTracking() + .Where(u => userIds.Contains(u.Id)) + .ToDictionaryAsync(u => u.Id); + + // 映射导出数据 + var exportData = orders.Select(o => MapToOrderExportDto(o, users)).ToList(); + + // 生成CSV格式 + return GenerateCsvBytes(exportData); + } + #endregion #region Private Helper Methods diff --git a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/user.ts b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/user.ts index 85624be2..162f85c6 100644 --- a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/user.ts +++ b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/api/business/user.ts @@ -403,7 +403,7 @@ export function getUserIpLogs(id: number, page: number = 1, pageSize: number = 2 /** 用户盈亏列表查询参数 */ export interface ProfitLossListQuery { uid?: string - userId?: number + userIdStr?: string // 用户ID(字符串格式,后端会自动转换) startTime?: string endTime?: string page: number @@ -445,7 +445,7 @@ export function getProfitLossList(params: ProfitLossListQuery): Promise { const params: Partial = {} if (searchForm.userId) { - params.userId = parseInt(searchForm.userId) + const parsedUserId = parseInt(searchForm.userId) + if (!isNaN(parsedUserId)) { + params.userId = parsedUserId + } } if (searchForm.mobile) { params.mobile = searchForm.mobile diff --git a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/order/recovery.vue b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/order/recovery.vue index da4714c3..e6241a7d 100644 --- a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/order/recovery.vue +++ b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/order/recovery.vue @@ -124,7 +124,10 @@ const handleSearch = () => { // 合并新的搜索参数 if (searchForm.userId) { - queryParams.userId = parseInt(searchForm.userId) + const parsedUserId = parseInt(searchForm.userId) + if (!isNaN(parsedUserId)) { + queryParams.userId = parsedUserId + } } if (searchForm.mobile) { queryParams.mobile = searchForm.mobile diff --git a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/invite-stats.vue b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/invite-stats.vue index 1f4a8b5c..bda5048f 100644 --- a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/invite-stats.vue +++ b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/invite-stats.vue @@ -13,7 +13,7 @@ - + @@ -157,7 +157,7 @@ const dateRange = ref<[string, string] | null>(null) // 查询参数 const queryParams = reactive({ - userId: undefined, + userIdStr: undefined, uid: undefined, minInviteCount: undefined, startTime: undefined, @@ -219,7 +219,7 @@ const handleSearch = () => { // 重置 const handleReset = () => { - queryParams.userId = undefined + queryParams.userIdStr = undefined queryParams.uid = undefined queryParams.minInviteCount = undefined dateRange.value = null diff --git a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/profit-loss.vue b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/profit-loss.vue index b6345574..39862906 100644 --- a/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/profit-loss.vue +++ b/server/HoneyBox/src/HoneyBox.Admin/admin-web/src/views/business/user/profit-loss.vue @@ -13,7 +13,7 @@ - + @@ -149,7 +149,7 @@ const dateRange = ref<[string, string] | null>(null) // 查询参数 const queryParams = reactive({ - userId: undefined, + userIdStr: undefined, uid: undefined, startTime: undefined, endTime: undefined, @@ -195,7 +195,7 @@ const handleSearch = () => { // 重置 const handleReset = () => { - queryParams.userId = undefined + queryParams.userIdStr = undefined queryParams.uid = undefined dateRange.value = null queryParams.startTime = undefined