diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..9c0eedc9
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,167 @@
+name: CI/CD Pipeline
+
+on:
+ push:
+ branches: [ main, develop ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ test:
+ name: 测试
+ runs-on: ubuntu-latest
+
+ strategy:
+ matrix:
+ node-version: [18.x, 20.x]
+
+ steps:
+ - name: 检出代码
+ uses: actions/checkout@v4
+
+ - name: 设置 Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v4
+ with:
+ node-version: ${{ matrix.node-version }}
+ cache: 'npm'
+ cache-dependency-path: frontend/package-lock.json
+
+ - name: 安装依赖
+ working-directory: ./frontend
+ run: npm ci
+
+ - name: 类型检查
+ working-directory: ./frontend
+ run: npm run type-check
+
+ - name: 代码风格检查
+ working-directory: ./frontend
+ run: npm run lint
+
+ - name: 代码格式检查
+ working-directory: ./frontend
+ run: npm run format:check
+
+ - name: 运行单元测试
+ working-directory: ./frontend
+ run: npm run test:unit:coverage
+
+ - name: 上传覆盖率报告到 Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ file: ./frontend/coverage/lcov.info
+ flags: unittests
+ name: codecov-umbrella
+
+ - name: 构建应用
+ working-directory: ./frontend
+ run: npm run build
+
+ - name: 安装 Playwright
+ working-directory: ./frontend
+ run: npx playwright install --with-deps
+
+ - name: 运行 E2E 测试
+ working-directory: ./frontend
+ run: npm run test:e2e
+
+ - name: 上传 E2E 测试报告
+ uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: playwright-report
+ path: frontend/playwright-report/
+ retention-days: 30
+
+ - name: 上传测试结果
+ uses: actions/upload-artifact@v3
+ if: always()
+ with:
+ name: test-results
+ path: frontend/test-results/
+ retention-days: 30
+
+ security:
+ name: 安全检查
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: 检出代码
+ uses: actions/checkout@v4
+
+ - name: 设置 Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.x'
+ cache: 'npm'
+ cache-dependency-path: frontend/package-lock.json
+
+ - name: 安装依赖
+ working-directory: ./frontend
+ run: npm ci
+
+ - name: 运行安全审计
+ working-directory: ./frontend
+ run: npm audit --audit-level moderate
+
+ - name: 运行 Snyk 安全扫描
+ uses: snyk/actions/node@master
+ continue-on-error: true
+ env:
+ SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
+ with:
+ args: --severity-threshold=high
+
+ deploy:
+ name: 部署
+ needs: [test, security]
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/main' && github.event_name == 'push'
+
+ steps:
+ - name: 检出代码
+ uses: actions/checkout@v4
+
+ - name: 设置 Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20.x'
+ cache: 'npm'
+ cache-dependency-path: frontend/package-lock.json
+
+ - name: 安装依赖
+ working-directory: ./frontend
+ run: npm ci
+
+ - name: 构建应用
+ working-directory: ./frontend
+ run: npm run build
+
+ - name: 部署到服务器
+ uses: appleboy/ssh-action@v1.0.0
+ with:
+ host: ${{ secrets.HOST }}
+ username: ${{ secrets.USERNAME }}
+ key: ${{ secrets.SSH_KEY }}
+ script: |
+ cd /var/www/html
+ git pull origin main
+ cd frontend
+ npm ci --production
+ npm run build
+ pm2 restart frontend-app
+
+ notify:
+ name: 通知
+ needs: [test, security, deploy]
+ runs-on: ubuntu-latest
+ if: always()
+
+ steps:
+ - name: 发送通知到 Slack
+ uses: 8398a7/action-slack@v3
+ with:
+ status: ${{ job.status }}
+ channel: '#ci-cd'
+ webhook_url: ${{ secrets.SLACK_WEBHOOK }}
+ fields: repo,message,commit,author,action,eventName,ref,workflow
\ No newline at end of file
diff --git a/HardwarePerformance.Tests/HardwarePerformance.Tests.csproj b/HardwarePerformance.Tests/HardwarePerformance.Tests.csproj
deleted file mode 100644
index 1310f582..00000000
--- a/HardwarePerformance.Tests/HardwarePerformance.Tests.csproj
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
- net9.0
- enable
- enable
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/HardwarePerformance.Tests/Services/CategoryServiceTests.cs b/HardwarePerformance.Tests/Services/CategoryServiceTests.cs
deleted file mode 100644
index d30d80fa..00000000
--- a/HardwarePerformance.Tests/Services/CategoryServiceTests.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using AutoMapper;
-using HardwarePerformance.Models;
-using HardwarePerformance.Models.DTOs;
-using HardwarePerformance.Services;
-using Moq;
-
-namespace HardwarePerformance.Tests.Services
-{
- public class CategoryServiceTests
- {
- private readonly Mock _mockCategoryRepository;
- private readonly Mock _mockMapper;
- private readonly CategoryService _categoryService;
-
- public CategoryServiceTests()
- {
- _mockCategoryRepository = new Mock();
- _mockMapper = new Mock();
- _categoryService = new CategoryService(_mockCategoryRepository.Object, _mockMapper.Object);
- }
-
- [Fact]
- public async Task GetAllCategoriesAsync_ReturnsAllCategories()
- {
- // Arrange
- var categories = new List
- {
- new Category { Id = 1, Name = "手机CPU", Description = "手机处理器" },
- new Category { Id = 2, Name = "电脑CPU", Description = "电脑处理器" }
- };
-
- var categoryDtos = new List
- {
- new CategoryDto { Id = 1, Name = "手机CPU", Description = "手机处理器" },
- new CategoryDto { Id = 2, Name = "电脑CPU", Description = "电脑处理器" }
- };
-
- _mockCategoryRepository.Setup(repo => repo.GetAllAsync())
- .ReturnsAsync(categories);
-
- _mockMapper.Setup(m => m.Map>(categories))
- .Returns(categoryDtos);
-
- // Act
- var result = await _categoryService.GetAllCategoriesAsync();
-
- // Assert
- Assert.NotNull(result);
- Assert.Equal(2, result.Count());
- _mockCategoryRepository.Verify(repo => repo.GetAllAsync(), Times.Once);
- _mockMapper.Verify(m => m.Map>(categories), Times.Once);
- }
-
- [Fact]
- public async Task GetCategoryByIdAsync_ExistingCategory_ReturnsCategoryDto()
- {
- // Arrange
- var categoryId = 1;
- var category = new Category { Id = categoryId, Name = "手机CPU", Description = "手机处理器" };
- var categoryDto = new CategoryDto { Id = categoryId, Name = "手机CPU", Description = "手机处理器" };
-
- _mockCategoryRepository.Setup(repo => repo.GetByIdAsync(categoryId))
- .ReturnsAsync(category);
-
- _mockMapper.Setup(m => m.Map(category))
- .Returns(categoryDto);
-
- // Act
- var result = await _categoryService.GetCategoryByIdAsync(categoryId);
-
- // Assert
- Assert.NotNull(result);
- Assert.Equal(categoryId, result.Id);
- Assert.Equal("手机CPU", result.Name);
- _mockCategoryRepository.Verify(repo => repo.GetByIdAsync(categoryId), Times.Once);
- _mockMapper.Verify(m => m.Map(category), Times.Once);
- }
-
- [Fact]
- public async Task GetCategoryByIdAsync_NonExistingCategory_ReturnsNull()
- {
- // Arrange
- var categoryId = 999;
-
- _mockCategoryRepository.Setup(repo => repo.GetByIdAsync(categoryId))
- .ReturnsAsync((Category?)null);
-
- // Act
- var result = await _categoryService.GetCategoryByIdAsync(categoryId);
-
- // Assert
- Assert.Null(result);
- _mockCategoryRepository.Verify(repo => repo.GetByIdAsync(categoryId), Times.Once);
- _mockMapper.Verify(m => m.Map(It.IsAny()), Times.Never);
- }
- }
-}
\ No newline at end of file
diff --git a/HardwarePerformance.Tests/Services/ComparisonServiceTests.cs b/HardwarePerformance.Tests/Services/ComparisonServiceTests.cs
deleted file mode 100644
index 6bd34baf..00000000
--- a/HardwarePerformance.Tests/Services/ComparisonServiceTests.cs
+++ /dev/null
@@ -1,173 +0,0 @@
-using AutoMapper;
-using HardwarePerformance.Models;
-using HardwarePerformance.Models.DTOs;
-using HardwarePerformance.Services;
-using Moq;
-
-namespace HardwarePerformance.Tests.Services
-{
- public class ComparisonServiceTests
- {
- private readonly Mock _mockProductRepository;
- private readonly Mock _mockMapper;
- private readonly ComparisonService _comparisonService;
-
- public ComparisonServiceTests()
- {
- _mockProductRepository = new Mock();
- _mockMapper = new Mock();
- _comparisonService = new ComparisonService(_mockProductRepository.Object, _mockMapper.Object);
- }
-
- [Fact]
- public async Task CompareProductsAsync_ValidProductIds_ReturnsComparisonData()
- {
- // Arrange
- var productIds = new List { 1, 2 };
-
- var products = new List
- {
- new Product
- {
- Id = 1,
- Name = "Intel Core i9",
- Manufacturer = "Intel",
- CategoryId = 1,
- CurrentRank = 1,
- ReleaseDate = DateTime.Now.AddMonths(-6),
- Price = 500,
- PerformanceScore = 4000,
- PerformanceScores = new List
- {
- new PerformanceScore { Id = 1, ProductId = 1, TestType = "Single-Core", Score = 1500 },
- new PerformanceScore { Id = 2, ProductId = 1, TestType = "Multi-Core", Score = 8000 }
- },
- Specifications = new List
- {
- new Specification { Id = 1, ProductId = 1, Name = "Cores", Value = "8" },
- new Specification { Id = 2, ProductId = 1, Name = "Threads", Value = "16" }
- }
- },
- new Product
- {
- Id = 2,
- Name = "AMD Ryzen 9",
- Manufacturer = "AMD",
- CategoryId = 1,
- CurrentRank = 2,
- ReleaseDate = DateTime.Now.AddMonths(-4),
- Price = 450,
- PerformanceScore = 3800,
- PerformanceScores = new List
- {
- new PerformanceScore { Id = 3, ProductId = 2, TestType = "Single-Core", Score = 1400 },
- new PerformanceScore { Id = 4, ProductId = 2, TestType = "Multi-Core", Score = 7500 }
- },
- Specifications = new List
- {
- new Specification { Id = 3, ProductId = 2, Name = "Cores", Value = "8" },
- new Specification { Id = 4, ProductId = 2, Name = "Threads", Value = "16" }
- }
- }
- };
-
- var productDtos = new List
- {
- new ProductDto
- {
- Id = 1,
- Name = "Intel Core i9",
- Manufacturer = "Intel",
- CategoryId = 1,
- CurrentRank = 1,
- ReleaseDate = DateTime.Now.AddMonths(-6),
- Price = 500,
- PerformanceScore = 4000,
- PerformanceScores = new List
- {
- new PerformanceScore { Id = 1, ProductId = 1, TestType = "Single-Core", Score = 1500 },
- new PerformanceScore { Id = 2, ProductId = 1, TestType = "Multi-Core", Score = 8000 }
- },
- Specifications = new List
- {
- new Specification { Id = 1, ProductId = 1, Name = "Cores", Value = "8" },
- new Specification { Id = 2, ProductId = 1, Name = "Threads", Value = "16" }
- }
- },
- new ProductDto
- {
- Id = 2,
- Name = "AMD Ryzen 9",
- Manufacturer = "AMD",
- CategoryId = 1,
- CurrentRank = 2,
- ReleaseDate = DateTime.Now.AddMonths(-4),
- Price = 450,
- PerformanceScore = 3800,
- PerformanceScores = new List
- {
- new PerformanceScore { Id = 3, ProductId = 2, TestType = "Single-Core", Score = 1400 },
- new PerformanceScore { Id = 4, ProductId = 2, TestType = "Multi-Core", Score = 7500 }
- },
- Specifications = new List
- {
- new Specification { Id = 3, ProductId = 2, Name = "Cores", Value = "8" },
- new Specification { Id = 4, ProductId = 2, Name = "Threads", Value = "16" }
- }
- }
- };
-
- _mockProductRepository.Setup(repo => repo.GetByIdsAsync(productIds))
- .ReturnsAsync(products);
-
- _mockMapper.Setup(m => m.Map>(products))
- .Returns(productDtos);
-
- // Act
- var result = await _comparisonService.CompareProductsAsync(productIds);
-
- // Assert
- Assert.NotNull(result);
- Assert.Equal(2, result.Products.Count);
- Assert.NotNull(result.ComparisonMatrix);
- _mockProductRepository.Verify(repo => repo.GetByIdsAsync(productIds), Times.Once);
- _mockMapper.Verify(m => m.Map>(products), Times.Once);
- }
-
- [Fact]
- public async Task CompareProductsAsync_EmptyProductIds_ThrowsArgumentException()
- {
- // Arrange
- var productIds = new List();
-
- // Act & Assert
- await Assert.ThrowsAsync(async () =>
- await _comparisonService.CompareProductsAsync(productIds));
- }
-
- [Fact]
- public async Task CompareProductsAsync_TooManyProductIds_ThrowsArgumentException()
- {
- // Arrange
- var productIds = new List { 1, 2, 3, 4, 5 };
-
- // Act & Assert
- await Assert.ThrowsAsync(async () =>
- await _comparisonService.CompareProductsAsync(productIds));
- }
-
- [Fact]
- public async Task CompareProductsAsync_NonExistingProductIds_ThrowsKeyNotFoundException()
- {
- // Arrange
- var productIds = new List { 1, 2 };
-
- _mockProductRepository.Setup(repo => repo.GetByIdsAsync(productIds))
- .ReturnsAsync(new List());
-
- // Act & Assert
- await Assert.ThrowsAsync(async () =>
- await _comparisonService.CompareProductsAsync(productIds));
- }
- }
-}
\ No newline at end of file
diff --git a/HardwarePerformance.Tests/Services/ProductServiceTests.cs b/HardwarePerformance.Tests/Services/ProductServiceTests.cs
deleted file mode 100644
index 2ec1be1f..00000000
--- a/HardwarePerformance.Tests/Services/ProductServiceTests.cs
+++ /dev/null
@@ -1,184 +0,0 @@
-using AutoMapper;
-using HardwarePerformance.Models;
-using HardwarePerformance.Models.DTOs;
-using HardwarePerformance.Services;
-using Moq;
-
-namespace HardwarePerformance.Tests.Services
-{
- public class ProductServiceTests
- {
- private readonly Mock _mockProductRepository;
- private readonly Mock _mockMapper;
- private readonly ProductService _productService;
-
- public ProductServiceTests()
- {
- _mockProductRepository = new Mock();
- _mockMapper = new Mock();
- _productService = new ProductService(_mockProductRepository.Object, _mockMapper.Object);
- }
-
- [Fact]
- public async Task GetProductsByCategoryAsync_ReturnsPagedProducts()
- {
- // Arrange
- var categoryId = 1;
- var page = 1;
- var pageSize = 10;
- var sortBy = "Name";
- var sortOrder = "asc";
-
- var products = new List
- {
- new Product { Id = 1, Name = "Intel Core i9", CategoryId = categoryId },
- new Product { Id = 2, Name = "AMD Ryzen 9", CategoryId = categoryId }
- };
-
- var productDtos = new List
- {
- new ProductListDto { Id = 1, Name = "Intel Core i9" },
- new ProductListDto { Id = 2, Name = "AMD Ryzen 9" }
- };
-
- var pagedResult = new PagedResultDto
- {
- Items = productDtos,
- TotalCount = 2,
- Page = page,
- PageSize = pageSize
- };
-
- _mockProductRepository.Setup(repo => repo.GetByCategoryAsync(categoryId, page, pageSize, sortBy, sortOrder))
- .ReturnsAsync(products);
-
- _mockProductRepository.Setup(repo => repo.CountAsync(categoryId))
- .ReturnsAsync(2);
-
- _mockMapper.Setup(m => m.Map>(products))
- .Returns(productDtos);
-
- // Act
- var result = await _productService.GetProductsByCategoryAsync(categoryId, page, pageSize, sortBy, sortOrder);
-
- // Assert
- Assert.NotNull(result);
- Assert.Equal(2, result.TotalCount);
- Assert.Equal(2, result.Items.Count());
- _mockProductRepository.Verify(repo => repo.GetByCategoryAsync(categoryId, page, pageSize, sortBy, sortOrder), Times.Once);
- _mockProductRepository.Verify(repo => repo.CountAsync(categoryId), Times.Once);
- _mockMapper.Verify(m => m.Map>(products), Times.Once);
- }
-
- [Fact]
- public async Task GetProductByIdAsync_ExistingProduct_ReturnsProductDto()
- {
- // Arrange
- var productId = 1;
- var product = new Product
- {
- Id = productId,
- Name = "Intel Core i9",
- CategoryId = 1,
- PerformanceScores = new List(),
- Specifications = new List()
- };
-
- var productDto = new ProductDto
- {
- Id = productId,
- Name = "Intel Core i9",
- CategoryId = 1,
- PerformanceScores = new List(),
- Specifications = new List()
- };
-
- _mockProductRepository.Setup(repo => repo.GetByIdAsync(productId))
- .ReturnsAsync(product);
-
- _mockMapper.Setup(m => m.Map(product))
- .Returns(productDto);
-
- // Act
- var result = await _productService.GetProductByIdAsync(productId);
-
- // Assert
- Assert.NotNull(result);
- Assert.Equal(productId, result.Id);
- Assert.Equal("Intel Core i9", result.Name);
- _mockProductRepository.Verify(repo => repo.GetByIdAsync(productId), Times.Once);
- _mockMapper.Verify(m => m.Map(product), Times.Once);
- }
-
- [Fact]
- public async Task GetProductByIdAsync_NonExistingProduct_ReturnsNull()
- {
- // Arrange
- var productId = 999;
-
- _mockProductRepository.Setup(repo => repo.GetByIdAsync(productId))
- .ReturnsAsync((Product?)null);
-
- // Act
- var result = await _productService.GetProductByIdAsync(productId);
-
- // Assert
- Assert.Null(result);
- _mockProductRepository.Verify(repo => repo.GetByIdAsync(productId), Times.Once);
- _mockMapper.Verify(m => m.Map(It.IsAny()), Times.Never);
- }
-
- [Fact]
- public async Task SearchProductsAsync_ReturnsPagedSearchResults()
- {
- // Arrange
- var query = "Intel";
- var categoryId = 1;
- var manufacturer = "Intel";
- var minScore = 1000;
- var maxScore = 5000;
- var page = 1;
- var pageSize = 10;
-
- var products = new List
- {
- new Product { Id = 1, Name = "Intel Core i9", Manufacturer = "Intel", CategoryId = categoryId, PerformanceScore = 4000 },
- new Product { Id = 2, Name = "Intel Core i7", Manufacturer = "Intel", CategoryId = categoryId, PerformanceScore = 3000 }
- };
-
- var productDtos = new List
- {
- new ProductListDto { Id = 1, Name = "Intel Core i9" },
- new ProductListDto { Id = 2, Name = "Intel Core i7" }
- };
-
- var pagedResult = new PagedResultDto
- {
- Items = productDtos,
- TotalCount = 2,
- Page = page,
- PageSize = pageSize
- };
-
- _mockProductRepository.Setup(repo => repo.SearchAsync(query, categoryId, manufacturer, minScore, maxScore, page, pageSize))
- .ReturnsAsync(products);
-
- _mockProductRepository.Setup(repo => repo.CountSearchResultsAsync(query, categoryId, manufacturer, minScore, maxScore))
- .ReturnsAsync(2);
-
- _mockMapper.Setup(m => m.Map>(products))
- .Returns(productDtos);
-
- // Act
- var result = await _productService.SearchProductsAsync(query, categoryId, manufacturer, minScore, maxScore, page, pageSize);
-
- // Assert
- Assert.NotNull(result);
- Assert.Equal(2, result.TotalCount);
- Assert.Equal(2, result.Items.Count());
- _mockProductRepository.Verify(repo => repo.SearchAsync(query, categoryId, manufacturer, minScore, maxScore, page, pageSize), Times.Once);
- _mockProductRepository.Verify(repo => repo.CountSearchResultsAsync(query, categoryId, manufacturer, minScore, maxScore), Times.Once);
- _mockMapper.Verify(m => m.Map>(products), Times.Once);
- }
- }
-}
\ No newline at end of file
diff --git a/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.dgspec.json b/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.dgspec.json
deleted file mode 100644
index add2f89e..00000000
--- a/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.dgspec.json
+++ /dev/null
@@ -1,95 +0,0 @@
-{
- "format": 1,
- "restore": {
- "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj": {}
- },
- "projects": {
- "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj": {
- "version": "1.0.0",
- "restore": {
- "projectUniqueName": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "projectName": "HardwarePerformance.Tests",
- "projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "packagesPath": "C:\\Users\\代\\.nuget\\packages\\",
- "outputPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\obj\\",
- "projectStyle": "PackageReference",
- "fallbackFolders": [
- "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
- ],
- "configFilePaths": [
- "C:\\Users\\代\\AppData\\Roaming\\NuGet\\NuGet.Config",
- "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
- "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
- ],
- "originalTargetFrameworks": [
- "net9.0"
- ],
- "sources": {
- "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
- "https://api.nuget.org/v3/index.json": {},
- "https://nuget.cdn.azure.cn/v3/index.json": {},
- "https://packages.chinacloudapi.cn/v3/index.json": {},
- "https://packages.microsoft.com/dotnet": {},
- "https://www.nuget.org/api/v2/": {}
- },
- "frameworks": {
- "net9.0": {
- "targetAlias": "net9.0",
- "projectReferences": {}
- }
- },
- "warningProperties": {
- "warnAsError": [
- "NU1605"
- ]
- },
- "restoreAuditProperties": {
- "enableAudit": "true",
- "auditLevel": "low",
- "auditMode": "direct"
- },
- "SdkAnalysisLevel": "9.0.300"
- },
- "frameworks": {
- "net9.0": {
- "targetAlias": "net9.0",
- "dependencies": {
- "Microsoft.NET.Test.Sdk": {
- "target": "Package",
- "version": "[17.12.0, )"
- },
- "coverlet.collector": {
- "target": "Package",
- "version": "[6.0.2, )"
- },
- "xunit": {
- "target": "Package",
- "version": "[2.9.2, )"
- },
- "xunit.runner.visualstudio": {
- "target": "Package",
- "version": "[2.8.2, )"
- }
- },
- "imports": [
- "net461",
- "net462",
- "net47",
- "net471",
- "net472",
- "net48",
- "net481"
- ],
- "assetTargetFallback": true,
- "warn": true,
- "frameworkReferences": {
- "Microsoft.NETCore.App": {
- "privateAssets": "all"
- }
- },
- "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.g.props b/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.g.props
deleted file mode 100644
index b085de15..00000000
--- a/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.g.props
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- True
- NuGet
- $(MSBuildThisFileDirectory)project.assets.json
- $(UserProfile)\.nuget\packages\
- C:\Users\代\.nuget\packages\;C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages
- PackageReference
- 6.14.0
-
-
-
-
-
-
\ No newline at end of file
diff --git a/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.g.targets b/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.g.targets
deleted file mode 100644
index 3dc06ef3..00000000
--- a/HardwarePerformance.Tests/obj/HardwarePerformance.Tests.csproj.nuget.g.targets
+++ /dev/null
@@ -1,2 +0,0 @@
-
-
\ No newline at end of file
diff --git a/HardwarePerformance.Tests/obj/project.assets.json b/HardwarePerformance.Tests/obj/project.assets.json
deleted file mode 100644
index c6b16628..00000000
--- a/HardwarePerformance.Tests/obj/project.assets.json
+++ /dev/null
@@ -1,126 +0,0 @@
-{
- "version": 3,
- "targets": {
- "net9.0": {}
- },
- "libraries": {},
- "projectFileDependencyGroups": {
- "net9.0": [
- "Microsoft.NET.Test.Sdk >= 17.12.0",
- "coverlet.collector >= 6.0.2",
- "xunit >= 2.9.2",
- "xunit.runner.visualstudio >= 2.8.2"
- ]
- },
- "packageFolders": {
- "C:\\Users\\代\\.nuget\\packages\\": {},
- "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages": {}
- },
- "project": {
- "version": "1.0.0",
- "restore": {
- "projectUniqueName": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "projectName": "HardwarePerformance.Tests",
- "projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "packagesPath": "C:\\Users\\代\\.nuget\\packages\\",
- "outputPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\obj\\",
- "projectStyle": "PackageReference",
- "fallbackFolders": [
- "C:\\Program Files (x86)\\Microsoft Visual Studio\\Shared\\NuGetPackages"
- ],
- "configFilePaths": [
- "C:\\Users\\代\\AppData\\Roaming\\NuGet\\NuGet.Config",
- "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.FallbackLocation.config",
- "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config"
- ],
- "originalTargetFrameworks": [
- "net9.0"
- ],
- "sources": {
- "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {},
- "https://api.nuget.org/v3/index.json": {},
- "https://nuget.cdn.azure.cn/v3/index.json": {},
- "https://packages.chinacloudapi.cn/v3/index.json": {},
- "https://packages.microsoft.com/dotnet": {},
- "https://www.nuget.org/api/v2/": {}
- },
- "frameworks": {
- "net9.0": {
- "targetAlias": "net9.0",
- "projectReferences": {}
- }
- },
- "warningProperties": {
- "warnAsError": [
- "NU1605"
- ]
- },
- "restoreAuditProperties": {
- "enableAudit": "true",
- "auditLevel": "low",
- "auditMode": "direct"
- },
- "SdkAnalysisLevel": "9.0.300"
- },
- "frameworks": {
- "net9.0": {
- "targetAlias": "net9.0",
- "dependencies": {
- "Microsoft.NET.Test.Sdk": {
- "target": "Package",
- "version": "[17.12.0, )"
- },
- "coverlet.collector": {
- "target": "Package",
- "version": "[6.0.2, )"
- },
- "xunit": {
- "target": "Package",
- "version": "[2.9.2, )"
- },
- "xunit.runner.visualstudio": {
- "target": "Package",
- "version": "[2.8.2, )"
- }
- },
- "imports": [
- "net461",
- "net462",
- "net47",
- "net471",
- "net472",
- "net48",
- "net481"
- ],
- "assetTargetFallback": true,
- "warn": true,
- "frameworkReferences": {
- "Microsoft.NETCore.App": {
- "privateAssets": "all"
- }
- },
- "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\9.0.304/PortableRuntimeIdentifierGraph.json"
- }
- }
- },
- "logs": [
- {
- "code": "NU1301",
- "level": "Error",
- "message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='coverlet.collector'&semVerLevel=2.0.0”检索有关“coverlet.collector”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
- "libraryId": "coverlet.collector"
- },
- {
- "code": "NU1301",
- "level": "Error",
- "message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='xunit'&semVerLevel=2.0.0”检索有关“xunit”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
- "libraryId": "xunit"
- },
- {
- "code": "NU1301",
- "level": "Error",
- "message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NET.Test.Sdk'&semVerLevel=2.0.0”检索有关“Microsoft.NET.Test.Sdk”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
- "libraryId": "Microsoft.NET.Test.Sdk"
- }
- ]
-}
\ No newline at end of file
diff --git a/HardwarePerformance.Tests/obj/project.nuget.cache b/HardwarePerformance.Tests/obj/project.nuget.cache
deleted file mode 100644
index e31f825a..00000000
--- a/HardwarePerformance.Tests/obj/project.nuget.cache
+++ /dev/null
@@ -1,36 +0,0 @@
-{
- "version": 2,
- "dgSpecHash": "HWf5d7t+LFg=",
- "success": false,
- "projectFilePath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "expectedPackageFiles": [],
- "logs": [
- {
- "code": "NU1301",
- "level": "Error",
- "message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='coverlet.collector'&semVerLevel=2.0.0”检索有关“coverlet.collector”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
- "projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "filePath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "libraryId": "coverlet.collector",
- "targetGraphs": []
- },
- {
- "code": "NU1301",
- "level": "Error",
- "message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='xunit'&semVerLevel=2.0.0”检索有关“xunit”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
- "projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "filePath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "libraryId": "xunit",
- "targetGraphs": []
- },
- {
- "code": "NU1301",
- "level": "Error",
- "message": "未能从远程源“https://www.nuget.org/api/v2/FindPackagesById()?id='Microsoft.NET.Test.Sdk'&semVerLevel=2.0.0”检索有关“Microsoft.NET.Test.Sdk”的信息。\r\n 不知道这样的主机。 (null:80)\r\n 不知道这样的主机。",
- "projectPath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "filePath": "C:\\work\\电脑硬件-01\\HardwarePerformance.Tests\\HardwarePerformance.Tests.csproj",
- "libraryId": "Microsoft.NET.Test.Sdk",
- "targetGraphs": []
- }
- ]
-}
\ No newline at end of file
diff --git a/MinimalAPI/MappingProfile.cs b/MinimalAPI/MappingProfile.cs
deleted file mode 100644
index 18ca2f8e..00000000
--- a/MinimalAPI/MappingProfile.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using AutoMapper;
-using HardwarePerformance.Models;
-using HardwarePerformance.Models.DTOs;
-
-namespace HardwarePerformance
-{
- public class MappingProfile : Profile
- {
- public MappingProfile()
- {
- CreateMap();
-
- CreateMap()
- .ForMember(dest => dest.PerformanceScores, opt => opt.Ignore())
- .ForMember(dest => dest.Specifications, opt => opt.Ignore());
-
- CreateMap();
- }
- }
-}
\ No newline at end of file
diff --git a/MinimalAPI/MinimalAPI.csproj b/MinimalAPI/MinimalAPI.csproj
deleted file mode 100644
index ff6c99a9..00000000
--- a/MinimalAPI/MinimalAPI.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
- net9.0
- enable
- enable
-
-
-
-
-
-
-
diff --git a/MinimalAPI/Models/DTOs/CategoryDto.cs b/MinimalAPI/Models/DTOs/CategoryDto.cs
deleted file mode 100644
index 5216bf99..00000000
--- a/MinimalAPI/Models/DTOs/CategoryDto.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace HardwarePerformance.Models.DTOs
-{
- public class CategoryDto
- {
- public int Id { get; set; }
- public string Name { get; set; } = string.Empty;
- public string Description { get; set; } = string.Empty;
- }
-}
\ No newline at end of file
diff --git a/MinimalAPI/Models/DTOs/PagedResultDto.cs b/MinimalAPI/Models/DTOs/PagedResultDto.cs
deleted file mode 100644
index 695485a5..00000000
--- a/MinimalAPI/Models/DTOs/PagedResultDto.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace HardwarePerformance.Models.DTOs
-{
- public class PagedResultDto
- {
- public List Items { get; set; } = new();
- public int Total { get; set; }
- public int CurrentPage { get; set; }
- public int PageSize { get; set; }
- public int TotalPages { get; set; }
- }
-}
\ No newline at end of file
diff --git a/MinimalAPI/Models/DTOs/ProductDto.cs b/MinimalAPI/Models/DTOs/ProductDto.cs
deleted file mode 100644
index 9e881500..00000000
--- a/MinimalAPI/Models/DTOs/ProductDto.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.Collections.Generic;
-
-namespace HardwarePerformance.Models.DTOs
-{
- public class ProductDto
- {
- public int Id { get; set; }
- public string Name { get; set; } = string.Empty;
- public string Model { get; set; } = string.Empty;
- public string Manufacturer { get; set; } = string.Empty;
- public int CategoryId { get; set; }
- public int CurrentRank { get; set; }
- public DateTime ReleaseDate { get; set; }
- public decimal? Price { get; set; }
- public int? PerformanceScore { get; set; }
- public CategoryDto? Category { get; set; }
- public List PerformanceScores { get; set; } = new();
- public List Specifications { get; set; } = new();
- }
-}
\ No newline at end of file
diff --git a/MinimalAPI/Models/DTOs/ProductListDto.cs b/MinimalAPI/Models/DTOs/ProductListDto.cs
deleted file mode 100644
index 4fdfa030..00000000
--- a/MinimalAPI/Models/DTOs/ProductListDto.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace HardwarePerformance.Models.DTOs
-{
- public class ProductListDto
- {
- public int Id { get; set; }
- public string Name { get; set; } = string.Empty;
- public string Model { get; set; } = string.Empty;
- public string Manufacturer { get; set; } = string.Empty;
- public int CategoryId { get; set; }
- public int CurrentRank { get; set; }
- public DateTime ReleaseDate { get; set; }
- public decimal? Price { get; set; }
- public int? PerformanceScore { get; set; }
- }
-}
\ No newline at end of file
diff --git a/MinimalAPI/Program.cs b/MinimalAPI/Program.cs
deleted file mode 100644
index 19b43543..00000000
--- a/MinimalAPI/Program.cs
+++ /dev/null
@@ -1,184 +0,0 @@
-using System.IO.Compression;
-using System.Text.Json.Serialization;
-
-namespace MinimalAPI
-{
- // 定义数据模型
- record Category(int Id, string Name, string Description);
- record Product(int Id, string Name, string Model, string Manufacturer, int CategoryId, int CurrentRank, DateTime ReleaseDate, decimal? Price);
- record ApiResponse(bool Success, T? Data, string? Message = null);
- record PagedResponse(List Items, int TotalCount, int PageNumber, int PageSize, int TotalPages);
- record ComparisonRequest(List ProductIds);
-
- public class Program
- {
- public static void Main(string[] args)
- {
- var builder = WebApplication.CreateBuilder(args);
-
- // 配置响应压缩
- builder.Services.AddResponseCompression(options =>
- {
- options.EnableForHttps = true;
- options.Providers.Add();
- options.Providers.Add();
- options.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat(new[]
- {
- "application/json",
- "application/javascript",
- "text/css",
- "text/html",
- "text/plain",
- "text/xml"
- });
- });
-
- builder.Services.Configure(options =>
- {
- options.Level = CompressionLevel.Fastest;
- });
-
- builder.Services.Configure(options =>
- {
- options.Level = CompressionLevel.Fastest;
- });
-
- // 配置JSON序列化选项
- builder.Services.Configure(options =>
- {
- options.SerializerOptions.PropertyNamingPolicy = System.Text.Json.JsonNamingPolicy.CamelCase;
- options.SerializerOptions.Converters.Add(new JsonStringEnumConverter());
- });
-
- // 配置CORS
- builder.Services.AddCors(options =>
- {
- options.AddPolicy("AllowAll", policy =>
- {
- policy.AllowAnyOrigin()
- .AllowAnyMethod()
- .AllowAnyHeader();
- });
- });
-
- // 注册服务
- builder.Services.AddScoped();
- builder.Services.AddScoped();
- builder.Services.AddScoped();
-
- var app = builder.Build();
-
- // 添加响应压缩中间件
- app.UseResponseCompression();
-
- // 使用CORS
- app.UseCors("AllowAll");
-
- // 模拟数据
- var categories = new List
- {
- new(1, "手机CPU", "移动设备处理器"),
- new(2, "手机GPU", "移动设备图形处理器"),
- new(3, "电脑CPU", "桌面和笔记本处理器"),
- new(4, "电脑GPU", "桌面和笔记本图形处理器")
- };
-
- var products = new List
- {
- new(1, "Apple A17 Pro", "A17 Pro", "Apple", 1, 1, new DateTime(2023, 9, 12), null),
- new(2, "Snapdragon 8 Gen 3", "SM8650-AB", "Qualcomm", 1, 2, new DateTime(2023, 10, 24), null),
- new(3, "Intel Core i9-13900K", "Core i9-13900K", "Intel", 3, 1, new DateTime(2022, 10, 20), 589.99m),
- new(4, "AMD Ryzen 9 7950X", "Ryzen 9 7950X", "AMD", 3, 2, new DateTime(2022, 9, 27), 699.99m),
- new(5, "NVIDIA GeForce RTX 4090", "RTX 4090", "NVIDIA", 4, 1, new DateTime(2022, 10, 12), 1599.99m),
- new(6, "AMD Radeon RX 7900 XTX", "RX 7900 XTX", "AMD", 4, 2, new DateTime(2022, 12, 3), 999.99m)
- };
-
- // API端点
-
- // 类别相关
- app.MapGet("/api/categories", async (ICategoryService categoryService) =>
- {
- var categories = await categoryService.GetAllCategoriesAsync();
- return Results.Ok(new ApiResponse>(true, categories));
- });
-
- app.MapGet("/api/categories/{id}", async (int id, ICategoryService categoryService) =>
- {
- var category = await categoryService.GetCategoryByIdAsync(id);
- if (category == null)
- {
- return Results.NotFound(new ApiResponse