333
This commit is contained in:
parent
ad08868ee8
commit
8a0dabb03c
338
.kiro/specs/admin-bugfix/design.md
Normal file
338
.kiro/specs/admin-bugfix/design.md
Normal file
|
|
@ -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<PagedResult<UserProfitStatsResponse>> 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<PagedResult<BoxResponse>> 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
|
||||
<!-- GoodsFormDialog.vue -->
|
||||
<template>
|
||||
<el-form-item label="自动下架配置">
|
||||
<el-switch v-model="form.autoDelistEnabled" />
|
||||
</el-form-item>
|
||||
|
||||
<!-- 修复:确保联动显示 -->
|
||||
<template v-if="form.autoDelistEnabled">
|
||||
<el-form-item label="下架时间">
|
||||
<el-date-picker v-model="form.autoDelistTime" type="datetime" />
|
||||
</el-form-item>
|
||||
<el-form-item label="下架条件">
|
||||
<el-input v-model="form.autoDelistCondition" />
|
||||
</el-form-item>
|
||||
</template>
|
||||
</template>
|
||||
```
|
||||
|
||||
**后端修复:**
|
||||
```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<PagedResult<PrizeResponse>> 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<PagedResult<ClaimRecordResponse>> 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<List<RankRecordResponse>> 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<RankRecordResponse>();
|
||||
}
|
||||
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
|
||||
<!-- DanyeFormDialog.vue 或详情组件 -->
|
||||
<template>
|
||||
<!-- 修复前 -->
|
||||
<!-- <div>{{ article.content }}</div> -->
|
||||
|
||||
<!-- 修复后:使用 v-html 渲染 -->
|
||||
<div class="article-content" v-html="sanitizedContent"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue'
|
||||
import DOMPurify from 'dompurify'
|
||||
|
||||
const props = defineProps<{
|
||||
article: { content: string }
|
||||
}>()
|
||||
|
||||
// 安全处理HTML内容
|
||||
const sanitizedContent = computed(() => {
|
||||
return DOMPurify.sanitize(props.article.content)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.article-content {
|
||||
/* 确保样式正确渲染 */
|
||||
line-height: 1.6;
|
||||
}
|
||||
.article-content img {
|
||||
max-width: 100%;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
## 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`
|
||||
|
||||
123
.kiro/specs/admin-bugfix/requirements.md
Normal file
123
.kiro/specs/admin-bugfix/requirements.md
Normal file
|
|
@ -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
|
||||
|
||||
196
.kiro/specs/admin-bugfix/tasks.md
Normal file
196
.kiro/specs/admin-bugfix/tasks.md
Normal file
|
|
@ -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(接口请求失败、服务器错误)
|
||||
- 修复过程中如发现关联问题,及时记录
|
||||
- 所有修复需要在测试环境验证后再部署生产
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
|
|||
154
docs/后台管理bug整理/BUG修复任务计划.md
Normal file
154
docs/后台管理bug整理/BUG修复任务计划.md
Normal file
|
|
@ -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` 状态
|
||||
- 建议先在测试环境验证,再部署到生产环境
|
||||
|
|
@ -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 | 综合订单,页面显示为空 | 高 | 已修复 |
|
||||
|
||||
### 营销活动模块
|
||||
|
||||
|
|
|
|||
|
|
@ -77,6 +77,19 @@ public class OrderController : BusinessControllerBase
|
|||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取综合订单列表(支持按账号类型和状态过滤)
|
||||
/// </summary>
|
||||
/// <param name="request">查询请求</param>
|
||||
/// <returns>分页订单列表</returns>
|
||||
[HttpGet("list")]
|
||||
[BusinessPermission("order:list")]
|
||||
public async Task<IActionResult> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出综合订单
|
||||
/// </summary>
|
||||
/// <param name="request">导出请求</param>
|
||||
/// <returns>CSV文件</returns>
|
||||
[HttpGet("list/export")]
|
||||
[BusinessPermission("order:export")]
|
||||
public async Task<IActionResult> 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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -279,3 +279,66 @@ public class OrderPrizeItemDto
|
|||
/// </summary>
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 综合订单列表请求(支持按账号类型和状态过滤)
|
||||
/// </summary>
|
||||
public class ComprehensiveOrderListRequest : OrderListRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 账号类型(0-正常 1-推广 2-测试)
|
||||
/// </summary>
|
||||
public int? AccountType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账号状态(0-正常 1-封号)
|
||||
/// </summary>
|
||||
public int? AccountStatus { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 综合订单导出请求
|
||||
/// </summary>
|
||||
public class ComprehensiveOrderExportRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// </summary>
|
||||
public int? UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 手机号
|
||||
/// </summary>
|
||||
public string? Mobile { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单编号
|
||||
/// </summary>
|
||||
public string? OrderNum { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 开始日期
|
||||
/// </summary>
|
||||
public DateTime? StartDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 结束日期
|
||||
/// </summary>
|
||||
public DateTime? EndDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 订单状态
|
||||
/// </summary>
|
||||
public int? Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账号类型(0-正常 1-推广 2-测试)
|
||||
/// </summary>
|
||||
public int? AccountType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 账号状态(0-正常 1-封号)
|
||||
/// </summary>
|
||||
public int? AccountStatus { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,14 @@ namespace HoneyBox.Admin.Business.Models.User;
|
|||
public class InviteStatsQuery : PagedRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// 用户ID(支持字符串输入,会自动转换为整数)
|
||||
/// </summary>
|
||||
public int? UserId { get; set; }
|
||||
public string? UserIdStr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取解析后的用户ID
|
||||
/// </summary>
|
||||
public int? UserId => !string.IsNullOrWhiteSpace(UserIdStr) && int.TryParse(UserIdStr.Trim(), out var id) ? id : null;
|
||||
|
||||
/// <summary>
|
||||
/// 用户UID
|
||||
|
|
@ -206,9 +211,14 @@ public class ProfitLossListQuery : PagedRequest
|
|||
public string? Uid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户ID
|
||||
/// 用户ID(支持字符串输入,会自动转换为整数)
|
||||
/// </summary>
|
||||
public int? UserId { get; set; }
|
||||
public string? UserIdStr { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取解析后的用户ID
|
||||
/// </summary>
|
||||
public int? UserId => !string.IsNullOrWhiteSpace(UserIdStr) && int.TryParse(UserIdStr.Trim(), out var id) ? id : null;
|
||||
|
||||
/// <summary>
|
||||
/// 开始时间
|
||||
|
|
|
|||
|
|
@ -38,6 +38,13 @@ public interface IOrderService
|
|||
/// <returns>分页兑换订单列表</returns>
|
||||
Task<PagedResult<RecoveryOrderResponse>> GetRecoveryOrdersAsync(OrderListRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// 获取综合订单列表(支持按账号类型和状态过滤)
|
||||
/// </summary>
|
||||
/// <param name="request">查询请求</param>
|
||||
/// <returns>分页订单列表</returns>
|
||||
Task<PagedResult<OrderListResponse>> GetComprehensiveOrdersAsync(ComprehensiveOrderListRequest request);
|
||||
|
||||
#endregion
|
||||
|
||||
#region 发货管理
|
||||
|
|
@ -105,5 +112,12 @@ public interface IOrderService
|
|||
/// <returns>统计信息</returns>
|
||||
Task<ShippingStatsResponse> GetShippingStatsAsync(ShippingOrderListRequest request);
|
||||
|
||||
/// <summary>
|
||||
/// 导出综合订单为CSV
|
||||
/// </summary>
|
||||
/// <param name="request">导出请求</param>
|
||||
/// <returns>CSV文件字节数组</returns>
|
||||
Task<byte[]> ExportComprehensiveOrdersAsync(ComprehensiveOrderExportRequest request);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -250,6 +250,74 @@ public class OrderService : IOrderService
|
|||
return PagedResult<RecoveryOrderResponse>.Create(list, total, request.Page, request.PageSize);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<PagedResult<OrderListResponse>> 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<OrderListResponse>.Create(list, total, request.Page, request.PageSize);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 发货管理
|
||||
|
|
@ -640,6 +708,95 @@ public class OrderService : IOrderService
|
|||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<byte[]> 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
|
||||
|
|
|
|||
|
|
@ -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<ApiRespo
|
|||
|
||||
/** 用户邀请统计查询参数 */
|
||||
export interface InviteStatsQuery {
|
||||
userId?: number
|
||||
userIdStr?: string // 用户ID(字符串格式,后端会自动转换)
|
||||
uid?: string
|
||||
minInviteCount?: number
|
||||
startTime?: string
|
||||
|
|
|
|||
|
|
@ -53,7 +53,10 @@ const handleSearch = () => {
|
|||
const params: Partial<OrderListRequest> = {}
|
||||
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<!-- 搜索表单 -->
|
||||
<el-form :model="queryParams" inline class="search-form">
|
||||
<el-form-item label="用户ID">
|
||||
<el-input v-model="queryParams.userId" placeholder="请输入用户ID" clearable style="width: 150px" />
|
||||
<el-input v-model="queryParams.userIdStr" placeholder="请输入用户ID" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="UID">
|
||||
<el-input v-model="queryParams.uid" placeholder="请输入UID" clearable style="width: 150px" />
|
||||
|
|
@ -157,7 +157,7 @@ const dateRange = ref<[string, string] | null>(null)
|
|||
|
||||
// 查询参数
|
||||
const queryParams = reactive<InviteStatsQuery>({
|
||||
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
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
<!-- 搜索表单 -->
|
||||
<el-form :model="queryParams" inline class="search-form">
|
||||
<el-form-item label="用户ID">
|
||||
<el-input v-model="queryParams.userId" placeholder="请输入用户ID" clearable style="width: 150px" />
|
||||
<el-input v-model="queryParams.userIdStr" placeholder="请输入用户ID" clearable style="width: 150px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="UID">
|
||||
<el-input v-model="queryParams.uid" placeholder="请输入UID" clearable style="width: 150px" />
|
||||
|
|
@ -149,7 +149,7 @@ const dateRange = ref<[string, string] | null>(null)
|
|||
|
||||
// 查询参数
|
||||
const queryParams = reactive<ProfitLossListQuery>({
|
||||
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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user