HaniBlindBox/.kiro/specs/admin-bugfix/design.md
2026-01-20 20:31:51 +08:00

11 KiB
Raw Blame History

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. 空值处理异常

修复方案

// 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. 后端未正确处理"全部"情况

修复方案

// 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. 保存接口未处理这些字段

修复方案

前端修复:

<!-- 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>

后端修复:

// 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映射时字段未正确赋值

修复方案

// 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搜索领取记录时返回"请求失败"
  • 与统计报表模块问题类似

修复方案

// 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. 空数据处理异常

修复方案

// 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

修复方案

<!-- 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