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

7.0 KiB
Raw Permalink Blame History

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)

# 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)

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:

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:

<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.tsDoughnut + 中心文本)
  • 图表类型line, bar, pie, doughnut
  • 特性支持响应式、触控交互、prefers-reduced-motion

Example:

<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):

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)