Files
EmailBill/AGENTS.md
SunCheng 9921cd5fdf chore: migrate remaining ECharts components to Chart.js
- Migrated 4 components from ECharts to Chart.js:
  * MonthlyExpenseCard.vue (折线图)
  * DailyTrendChart.vue (双系列折线图)
  * ExpenseCategoryCard.vue (环形图)
  * BudgetChartAnalysis.vue (仪表盘 + 多种图表)

- Removed all ECharts imports and environment variable switches
- Unified all charts to use BaseChart.vue component
- Build verified: pnpm build success ✓
- No echarts imports remaining ✓

Refs: openspec/changes/migrate-remaining-echarts-to-chartjs
2026-02-16 21:55:38 +08:00

267 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PROJECT KNOWLEDGE BASE - EmailBill
**Generated:** 2026-02-10
**Commit:** 3e18283
**Branch:** main
## OVERVIEW
Full-stack budget tracking app with .NET 10 backend and Vue 3 frontend.
## Project Structure
```
EmailBill/
├── Common/ # Shared utilities and abstractions
├── Entity/ # Database entities (FreeSql ORM)
├── Repository/ # Data access layer
├── Service/ # Business logic layer
├── Application/ # Application layer (业务编排、DTO转换)
├── WebApi/ # ASP.NET Core Web API
├── WebApi.Test/ # Backend tests (xUnit)
├── Web/ # Vue 3 frontend (Vite + Vant UI)
└── .doc/ # Project documentation archive
```
## WHERE TO LOOK
| Task | Location | Notes |
|------|----------|-------|
| Entity definitions | Entity/ | BaseEntity pattern, FreeSql attributes |
| Data access | Repository/ | BaseRepository, GlobalUsings |
| Business logic | Service/ | Jobs, Email services, App settings |
| Application orchestration | Application/ | DTO 转换、业务编排、接口门面 |
| Icon search integration | Service/IconSearch/ | Iconify API, AI keyword generation |
| API endpoints | WebApi/Controllers/ | DTO patterns, REST controllers |
| Frontend views | Web/src/views/ | Vue composition API |
| Icon components | Web/src/components/ | Icon.vue, IconPicker.vue |
| API clients | Web/src/api/ | Axios-based HTTP clients |
| Tests | WebApi.Test/ | xUnit + NSubstitute + FluentAssertions |
| Documentation archive | .doc/ | Technical docs, migration guides |
## Build & Test Commands
### Backend (.NET 10)
```bash
# Build and run
dotnet build EmailBill.sln
dotnet run --project WebApi/WebApi.csproj
# Run all tests
dotnet test WebApi.Test/WebApi.Test.csproj
# Run single test class
dotnet test --filter "FullyQualifiedName~BudgetStatsTest"
# Run single test method
dotnet test --filter "FullyQualifiedName~BudgetStatsTest.GetCategoryStats_月度_Test"
# Clean
dotnet clean EmailBill.sln
```
### Frontend (Vue 3)
```bash
cd Web
# Setup and dev
pnpm install
pnpm dev
# Build and preview
pnpm build
pnpm preview
# Lint and format
pnpm lint # ESLint with auto-fix
pnpm format # Prettier formatting
```
## C# Code Style
**Namespaces & Imports:**
- File-scoped namespaces: `namespace Entity;`
- Global usings in `Common/GlobalUsings.cs`
- Sort using statements alphabetically
**Naming:**
- Classes/Methods: `PascalCase`
- Interfaces: `IPascalCase`
- Private fields: `_camelCase`
- Parameters/locals: `camelCase`
**Entities:**
- Inherit from `BaseEntity`
- Use `[Column]` attributes for FreeSql ORM
- IDs via Snowflake: `YitIdHelper.NextId()`
- Use XML docs (`///`) for public APIs
- **Chinese comments for business logic** (per `.github/csharpe.prompt.md`)
**Best Practices:**
- Use modern C# syntax (records, pattern matching, nullable types)
- Use `IDateTimeProvider` instead of `DateTime.Now` for testability
- Avoid deep nesting, keep code flat and readable
- Reuse utilities from `Common` project
**Example:**
```csharp
namespace Entity;
/// <summary>
/// 实体基类
/// </summary>
public abstract class BaseEntity
{
[Column(IsPrimary = true)]
public long Id { get; set; } = YitIdHelper.NextId();
public DateTime CreateTime { get; set; } = DateTime.Now;
}
```
## Vue/TypeScript Style
**Component Structure:**
```vue
<template>
<van-config-provider :theme="theme">
<div class="component-name">
<!-- Content -->
</div>
</van-config-provider>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { useMessageStore } from '@/stores/message'
const messageStore = useMessageStore()
</script>
<style scoped lang="scss">
.component-name {
padding: 16px;
}
</style>
```
**Rules:**
- Composition API with `<script setup lang="ts">`
- Import order: Vue APIs → external libs → internal modules
- Use `@/` alias for absolute imports, avoid `../../../`
- Vant UI components: `<van-*>`
- Pinia for state, Vue Router for navigation
- SCSS with BEM naming, mobile-first design
**ESLint Rules (see `Web/eslint.config.js`):**
- 2-space indentation
- Single quotes, no semicolons
- `const` over `let`, no `var`
- Always use `===` (strict equality)
- `space-before-function-paren: 'always'`
- Max 1 empty line between blocks
- Vue: multi-word component names disabled
**Prettier Rules (see `Web/.prettierrc.json`):**
- Single quotes, no semicolons
- Trailing commas: none
- Print width: 100 chars
**Chart.js Usage (替代 ECharts):**
- 使用 `chart.js` (v4.5+) + `vue-chartjs` (v5.3+) 进行图表渲染
- 通用组件:`@/components/Charts/BaseChart.vue`
- 主题配置:`@/composables/useChartTheme.ts`(自动适配 Vant 暗色模式)
- 工具函数:`@/utils/chartHelpers.ts`(格式化、颜色、数据抽样)
- 仪表盘插件:`@/plugins/chartjs-gauge-plugin.ts`Doughnut + 中心文本)
- 图表类型line, bar, pie, doughnut
- 特性支持响应式、触控交互、prefers-reduced-motion
**Example:**
```vue
<template>
<BaseChart
type="line"
:data="chartData"
:options="chartOptions"
/>
</template>
<script setup>
import BaseChart from '@/components/Charts/BaseChart.vue'
import { useChartTheme } from '@/composables/useChartTheme'
const { getChartOptions } = useChartTheme()
const chartData = {
labels: ['1月', '2月', '3月'],
datasets: [{
label: '支出',
data: [100, 200, 150],
borderColor: '#ff6b6b',
backgroundColor: 'rgba(255, 107, 107, 0.1)'
}]
}
const chartOptions = getChartOptions({
plugins: {
legend: { display: false }
}
})
</script>
```
## Testing
**Backend (xUnit + NSubstitute + FluentAssertions):**
```csharp
public class BudgetStatsTest : BaseTest
{
private readonly IBudgetRepository _repo = Substitute.For<IBudgetRepository>();
[Fact]
public async Task GetCategoryStats_月度_Test()
{
// Arrange
_repo.GetAllAsync().Returns(testData);
// Act
var result = await _service.GetCategoryStatsAsync(category, date);
// Assert
result.Month.Limit.Should().Be(2500);
}
}
```
- Arrange-Act-Assert pattern
- Constructor injection for dependencies
- Use Chinese test method names for domain clarity
**Frontend:**
- Vue Test Utils for components
- axios-mock-adapter for API mocking
## Development Workflow
1. **Before committing backend:** `dotnet test`
2. **Before committing frontend:** `pnpm lint && pnpm build`
3. **Database migrations:** Use FreeSql (check `Repository/`)
4. **API docs:** Scalar OpenAPI viewer
## Environment
**Required:**
- .NET 10 SDK
- Node.js 20.19+ or 22.12+
- pnpm
**Database:** SQLite (embedded)
**Config:**
- Backend: `appsettings.json`
- Frontend: `.env.development` / `.env.production`
## Critical Guidelines (from `.github/csharpe.prompt.md`)
- 优先使用新C#语法 (Use modern C# syntax)
- 优先使用中文注释 (Prefer Chinese comments for business logic)
- 优先复用已有方法 (Reuse existing methods)
- 不要深嵌套代码 (Avoid deep nesting)
- 保持代码简洁易读 (Keep code clean and readable)