测试
This commit is contained in:
30
MinimalAPI/Services/CategoryService.cs
Normal file
30
MinimalAPI/Services/CategoryService.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using AutoMapper;
|
||||
using HardwarePerformance.Models.DTOs;
|
||||
using HardwarePerformance.Repositories;
|
||||
|
||||
namespace HardwarePerformance.Services
|
||||
{
|
||||
public class CategoryService : ICategoryService
|
||||
{
|
||||
private readonly ICategoryRepository _categoryRepository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public CategoryService(ICategoryRepository categoryRepository, IMapper mapper)
|
||||
{
|
||||
_categoryRepository = categoryRepository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<CategoryDto>> GetAllCategoriesAsync()
|
||||
{
|
||||
var categories = await _categoryRepository.GetAllAsync();
|
||||
return _mapper.Map<IEnumerable<CategoryDto>>(categories);
|
||||
}
|
||||
|
||||
public async Task<CategoryDto?> GetCategoryByIdAsync(int id)
|
||||
{
|
||||
var category = await _categoryRepository.GetByIdAsync(id);
|
||||
return category != null ? _mapper.Map<CategoryDto>(category) : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
271
MinimalAPI/Services/ComparisonService.cs
Normal file
271
MinimalAPI/Services/ComparisonService.cs
Normal file
@@ -0,0 +1,271 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using MinimalAPI.Data;
|
||||
using MinimalAPI.Models;
|
||||
using MinimalAPI.Models.DTOs;
|
||||
|
||||
namespace MinimalAPI.Services
|
||||
{
|
||||
public class ComparisonService : IComparisonService
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ComparisonService(AppDbContext context, IMapper mapper)
|
||||
{
|
||||
_context = context;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<object> CompareProductsAsync(List<int> productIds)
|
||||
{
|
||||
// 验证输入
|
||||
if (productIds == null || productIds.Count < 2 || productIds.Count > 4)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取产品
|
||||
var products = await _context.Products
|
||||
.Include(p => p.Category)
|
||||
.Where(p => productIds.Contains(p.Id))
|
||||
.ToListAsync();
|
||||
|
||||
if (products.Count != productIds.Count)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查是否所有产品属于同一类别
|
||||
var categoryIds = products.Select(p => p.CategoryId).Distinct().ToList();
|
||||
if (categoryIds.Count > 1)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// 获取性能分数
|
||||
var productIdsList = products.Select(p => p.Id).ToList();
|
||||
var performanceScores = await _context.PerformanceScores
|
||||
.Where(ps => productIdsList.Contains(ps.ProductId))
|
||||
.ToListAsync();
|
||||
|
||||
// 获取规格参数
|
||||
var specifications = await _context.Specifications
|
||||
.Where(s => productIdsList.Contains(s.ProductId))
|
||||
.ToListAsync();
|
||||
|
||||
// 创建产品DTO列表
|
||||
var productDtos = products.Select(p => {
|
||||
var dto = _mapper.Map<ProductDto>(p);
|
||||
dto.PerformanceScores = performanceScores
|
||||
.Where(ps => ps.ProductId == p.Id)
|
||||
.ToList();
|
||||
dto.Specifications = specifications
|
||||
.Where(s => s.ProductId == p.Id)
|
||||
.ToList();
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
// 生成对比矩阵
|
||||
var comparisonMatrix = GenerateComparisonMatrix(productDtos);
|
||||
|
||||
return new
|
||||
{
|
||||
Products = productDtos,
|
||||
Comparison = comparisonMatrix
|
||||
};
|
||||
}
|
||||
|
||||
private List<Dictionary<string, object>> GenerateComparisonMatrix(List<ProductDto> products)
|
||||
{
|
||||
var matrix = new List<Dictionary<string, object>>();
|
||||
|
||||
// 添加基本信息行
|
||||
matrix.Add(new Dictionary<string, object> { ["指标"] = "产品名称", ["类型"] = "基本信息" });
|
||||
foreach (var product in products)
|
||||
{
|
||||
matrix[0][$"{product.Name}"] = product.Name;
|
||||
}
|
||||
|
||||
// 添加制造商行
|
||||
matrix.Add(new Dictionary<string, object> { ["指标"] = "制造商", ["类型"] = "基本信息" });
|
||||
foreach (var product in products)
|
||||
{
|
||||
matrix[1][$"{product.Name}"] = product.Manufacturer;
|
||||
}
|
||||
|
||||
// 添加型号行
|
||||
matrix.Add(new Dictionary<string, object> { ["指标"] = "型号", ["类型"] = "基本信息" });
|
||||
foreach (var product in products)
|
||||
{
|
||||
matrix[2][$"{product.Name}"] = product.Model;
|
||||
}
|
||||
|
||||
// 添加排名行
|
||||
matrix.Add(new Dictionary<string, object> { ["指标"] = "当前排名", ["类型"] = "性能指标" });
|
||||
foreach (var product in products)
|
||||
{
|
||||
matrix[3][$"{product.Name}"] = product.CurrentRank;
|
||||
}
|
||||
|
||||
// 添加发布日期行
|
||||
matrix.Add(new Dictionary<string, object> { ["指标"] = "发布日期", ["类型"] = "基本信息" });
|
||||
foreach (var product in products)
|
||||
{
|
||||
matrix[4][$"{product.Name}"] = product.ReleaseDate.ToString("yyyy-MM-dd");
|
||||
}
|
||||
|
||||
// 添加价格行
|
||||
matrix.Add(new Dictionary<string, object> { ["指标"] = "价格", ["类型"] = "基本信息" });
|
||||
foreach (var product in products)
|
||||
{
|
||||
matrix[5][$"{product.Name}"] = product.Price?.ToString("C") ?? "N/A";
|
||||
}
|
||||
|
||||
// 添加性能分数行
|
||||
var benchmarkTypes = products
|
||||
.SelectMany(p => p.PerformanceScores)
|
||||
.Select(ps => ps.BenchmarkType)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
foreach (var benchmarkType in benchmarkTypes)
|
||||
{
|
||||
var rowIndex = matrix.Count;
|
||||
matrix.Add(new Dictionary<string, object> { ["指标"] = benchmarkType, ["类型"] = "性能指标" });
|
||||
|
||||
foreach (var product in products)
|
||||
{
|
||||
var score = product.PerformanceScores
|
||||
.FirstOrDefault(ps => ps.BenchmarkType == benchmarkType)?.Score;
|
||||
matrix[rowIndex][$"{product.Name}"] = score?.ToString() ?? "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
// 添加规格参数行
|
||||
var specNames = products
|
||||
.SelectMany(p => p.Specifications)
|
||||
.Select(s => s.Name)
|
||||
.Distinct()
|
||||
.ToList();
|
||||
|
||||
foreach (var specName in specNames)
|
||||
{
|
||||
var rowIndex = matrix.Count;
|
||||
matrix.Add(new Dictionary<string, object> { ["指标"] = specName, ["类型"] = "规格参数" });
|
||||
|
||||
foreach (var product in products)
|
||||
{
|
||||
var specValue = product.Specifications
|
||||
.FirstOrDefault(s => s.Name == specName)?.Value;
|
||||
matrix[rowIndex][$"{product.Name}"] = specValue ?? "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
// 标记最优和最差值
|
||||
MarkBestAndWorstValues(matrix, products);
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
private void MarkBestAndWorstValues(List<Dictionary<string, object>> matrix, List<ProductDto> products)
|
||||
{
|
||||
// 对于排名,越小越好
|
||||
var rankRow = matrix.FirstOrDefault(m => m["指标"].ToString() == "当前排名");
|
||||
if (rankRow != null)
|
||||
{
|
||||
var ranks = products.Select(p => p.CurrentRank).ToList();
|
||||
var minRank = ranks.Min();
|
||||
var maxRank = ranks.Max();
|
||||
|
||||
foreach (var product in products)
|
||||
{
|
||||
var rank = product.CurrentRank;
|
||||
if (rank == minRank)
|
||||
{
|
||||
rankRow[$"{product.Name}_isBest"] = true;
|
||||
}
|
||||
else if (rank == maxRank)
|
||||
{
|
||||
rankRow[$"{product.Name}_isWorst"] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 对于价格,越小越好
|
||||
var priceRow = matrix.FirstOrDefault(m => m["指标"].ToString() == "价格");
|
||||
if (priceRow != null)
|
||||
{
|
||||
var prices = products.Where(p => p.Price.HasValue).Select(p => p.Price!.Value).ToList();
|
||||
if (prices.Any())
|
||||
{
|
||||
var minPrice = prices.Min();
|
||||
var maxPrice = prices.Max();
|
||||
|
||||
foreach (var product in products)
|
||||
{
|
||||
if (product.Price.HasValue)
|
||||
{
|
||||
if (product.Price == minPrice)
|
||||
{
|
||||
priceRow[$"{product.Name}_isBest"] = true;
|
||||
}
|
||||
else if (product.Price == maxPrice)
|
||||
{
|
||||
priceRow[$"{product.Name}_isWorst"] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 对于性能分数,越大越好
|
||||
var performanceRows = matrix.Where(m => m["类型"].ToString() == "性能指标" &&
|
||||
m["指标"].ToString() != "当前排名").ToList();
|
||||
|
||||
foreach (var row in performanceRows)
|
||||
{
|
||||
var benchmarkType = row["指标"].ToString();
|
||||
var scores = new List<decimal?>();
|
||||
|
||||
foreach (var product in products)
|
||||
{
|
||||
var scoreStr = row[$"{product.Name}"]?.ToString();
|
||||
if (decimal.TryParse(scoreStr, out var score))
|
||||
{
|
||||
scores.Add(score);
|
||||
}
|
||||
else
|
||||
{
|
||||
scores.Add(null);
|
||||
}
|
||||
}
|
||||
|
||||
var validScores = scores.Where(s => s.HasValue).Select(s => s!.Value).ToList();
|
||||
if (validScores.Any())
|
||||
{
|
||||
var maxScore = validScores.Max();
|
||||
var minScore = validScores.Min();
|
||||
|
||||
for (int i = 0; i < products.Count; i++)
|
||||
{
|
||||
if (scores[i].HasValue)
|
||||
{
|
||||
if (scores[i] == maxScore)
|
||||
{
|
||||
row[$"{products[i].Name}_isBest"] = true;
|
||||
}
|
||||
else if (scores[i] == minScore)
|
||||
{
|
||||
row[$"{products[i].Name}_isWorst"] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
10
MinimalAPI/Services/ICategoryService.cs
Normal file
10
MinimalAPI/Services/ICategoryService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using HardwarePerformance.Models.DTOs;
|
||||
|
||||
namespace HardwarePerformance.Services
|
||||
{
|
||||
public interface ICategoryService
|
||||
{
|
||||
Task<IEnumerable<CategoryDto>> GetAllCategoriesAsync();
|
||||
Task<CategoryDto?> GetCategoryByIdAsync(int id);
|
||||
}
|
||||
}
|
||||
10
MinimalAPI/Services/IComparisonService.cs
Normal file
10
MinimalAPI/Services/IComparisonService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace MinimalAPI.Services
|
||||
{
|
||||
public interface IComparisonService
|
||||
{
|
||||
Task<object> CompareProductsAsync(List<int> productIds);
|
||||
}
|
||||
}
|
||||
12
MinimalAPI/Services/IProductService.cs
Normal file
12
MinimalAPI/Services/IProductService.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using HardwarePerformance.Models.DTOs;
|
||||
|
||||
namespace HardwarePerformance.Services
|
||||
{
|
||||
public interface IProductService
|
||||
{
|
||||
Task<PagedResultDto<ProductListDto>> GetProductsByCategoryAsync(int categoryId, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string order = "asc");
|
||||
Task<ProductDto?> GetProductByIdAsync(int id);
|
||||
Task<PagedResultDto<ProductListDto>> SearchProductsAsync(string query, int? categoryId = null, string? manufacturer = null, int? minScore = null, int? maxScore = null, int page = 1, int pageSize = 20);
|
||||
Task<PagedResultDto<ProductListDto>> FilterProductsAsync(int categoryId, string? manufacturer = null, int? minScore = null, int? maxScore = null, int? releaseYear = null, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string order = "asc");
|
||||
}
|
||||
}
|
||||
91
MinimalAPI/Services/ProductService.cs
Normal file
91
MinimalAPI/Services/ProductService.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using AutoMapper;
|
||||
using HardwarePerformance.Models.DTOs;
|
||||
using HardwarePerformance.Repositories;
|
||||
|
||||
namespace HardwarePerformance.Services
|
||||
{
|
||||
public class ProductService : IProductService
|
||||
{
|
||||
private readonly IProductRepository _productRepository;
|
||||
private readonly IMapper _mapper;
|
||||
|
||||
public ProductService(IProductRepository productRepository, IMapper mapper)
|
||||
{
|
||||
_productRepository = productRepository;
|
||||
_mapper = mapper;
|
||||
}
|
||||
|
||||
public async Task<PagedResultDto<ProductListDto>> GetProductsByCategoryAsync(int categoryId, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string order = "asc")
|
||||
{
|
||||
var products = await _productRepository.GetByCategoryAsync(categoryId, page, pageSize, sortBy, order);
|
||||
var totalCount = await _productRepository.CountAsync(categoryId);
|
||||
|
||||
var productDtos = _mapper.Map<IEnumerable<ProductListDto>>(products);
|
||||
|
||||
return new PagedResultDto<ProductListDto>
|
||||
{
|
||||
Items = productDtos.ToList(),
|
||||
Total = totalCount,
|
||||
CurrentPage = page,
|
||||
PageSize = pageSize,
|
||||
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<ProductDto?> GetProductByIdAsync(int id)
|
||||
{
|
||||
var product = await _productRepository.GetByIdAsync(id);
|
||||
if (product == null) return null;
|
||||
|
||||
var productDto = _mapper.Map<ProductDto>(product);
|
||||
|
||||
// 获取类别信息
|
||||
var category = await _productRepository.GetCategoryByProductIdAsync(id);
|
||||
if (category != null)
|
||||
{
|
||||
productDto.Category = new CategoryDto
|
||||
{
|
||||
Id = category.Id,
|
||||
Name = category.Name,
|
||||
Description = category.Description
|
||||
};
|
||||
}
|
||||
|
||||
return productDto;
|
||||
}
|
||||
|
||||
public async Task<PagedResultDto<ProductListDto>> SearchProductsAsync(string query, int? categoryId = null, string? manufacturer = null, int? minScore = null, int? maxScore = null, int page = 1, int pageSize = 20)
|
||||
{
|
||||
var products = await _productRepository.SearchAsync(query, categoryId, manufacturer, minScore, maxScore, page, pageSize);
|
||||
var totalCount = await _productRepository.CountSearchResultsAsync(query, categoryId, manufacturer, minScore, maxScore);
|
||||
|
||||
var productDtos = _mapper.Map<IEnumerable<ProductListDto>>(products);
|
||||
|
||||
return new PagedResultDto<ProductListDto>
|
||||
{
|
||||
Items = productDtos.ToList(),
|
||||
Total = totalCount,
|
||||
CurrentPage = page,
|
||||
PageSize = pageSize,
|
||||
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
|
||||
};
|
||||
}
|
||||
|
||||
public async Task<PagedResultDto<ProductListDto>> FilterProductsAsync(int categoryId, string? manufacturer = null, int? minScore = null, int? maxScore = null, int? releaseYear = null, int page = 1, int pageSize = 20, string sortBy = "CurrentRank", string order = "asc")
|
||||
{
|
||||
var products = await _productRepository.FilterAsync(categoryId, manufacturer, minScore, maxScore, releaseYear, page, pageSize, sortBy, order);
|
||||
var totalCount = await _productRepository.CountFilterResultsAsync(categoryId, manufacturer, minScore, maxScore, releaseYear);
|
||||
|
||||
var productDtos = _mapper.Map<IEnumerable<ProductListDto>>(products);
|
||||
|
||||
return new PagedResultDto<ProductListDto>
|
||||
{
|
||||
Items = productDtos.ToList(),
|
||||
Total = totalCount,
|
||||
CurrentPage = page,
|
||||
PageSize = pageSize,
|
||||
TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user