Przeglądaj źródła

docs(story): 创建故事016.003 - 数据处理函数模块化搬迁

创建了故事016.003,用于将u-charts核心库中的数据处理相关函数搬迁到独立模块并添加TypeScript类型定义。

## 故事范围
- 系列数据处理函数(fillSeries、fixPieSeries、dataCombine等)
- 坐标轴计算函数(calXAxisData、calYAxisData等)
- 分类数据处理函数(calCategoriesData等)
- 提示框数据计算函数(getToolTipData等)

## 关键内容
- 详细的类型定义示例(SeriesItem、ChartOptions、UChartsConfig等)
- 4个新模块文件的完整类型规范
- 前置故事(016.001、016.002)的技术决策总结
- 完整的开发流程和验证标准

🤖 Generated with [Claude Code](https://claude.com/claude-code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 3 tygodni temu
rodzic
commit
0a7f762e83
1 zmienionych plików z 585 dodań i 0 usunięć
  1. 585 0
      docs/stories/016.003.story.md

+ 585 - 0
docs/stories/016.003.story.md

@@ -0,0 +1,585 @@
+# <!-- Powered by BMAD™ Core -->
+
+# Story 016.003: 搬迁数据处理函数到独立模块并添加类型定义
+
+## Status
+
+Approved
+
+## Story
+
+**作为** 图表库开发者,
+**我想要** 将 u-charts 核心库中的数据处理相关函数**搬迁**到独立模块并添加 TypeScript 类型定义,
+**以便** 提高代码的可维护性、可测试性和类型安全性,为后续 React 组件封装打下基础。
+
+## Acceptance Criteria
+
+1. `data-processing/` 目录下所有文件创建完成
+2. 所有数据处理函数都有完整类型注解
+3. 类型检查通过(pnpm typecheck),无 any 类型(除非必要)
+4. 每个文件控制在 500 行以内
+5. 代码逻辑与原始 u-charts.ts 完全一致
+
+## Tasks / Subtasks
+
+- [ ] Task 1: 分析数据处理函数 (AC: 1, 2, 5)
+  - [ ] 1.1 识别系列数据处理函数(fillSeries、fixPieSeries、dataCombine、dataCombineStack等)
+  - [ ] 1.2 识别坐标轴计算函数(calXAxisData、calYAxisData、calYAxisSeries等)
+  - [ ] 1.3 识别分类数据处理函数(calCategoriesData等)
+  - [ ] 1.4 识别提示框数据计算函数(getToolTipData等)
+
+- [ ] Task 2: 创建 data-processing 模块目录结构 (AC: 1)
+  - [ ] 2.1 创建 `src/lib/data-processing/` 目录
+  - [ ] 2.2 创建 `series-calculator.ts` 文件
+  - [ ] 2.3 创建 `axis-calculator.ts` 文件
+  - [ ] 2.4 创建 `categories-calculator.ts` 文件
+  - [ ] 2.5 创建 `tooltip-calculator.ts` 文件
+  - [ ] 2.6 创建 `index.ts` 统一导出文件
+
+- [ ] Task 3: **搬迁**系列数据处理函数并添加类型注解 (AC: 2, 3, 4, 5)
+  - [ ] 3.1 将 fillSeries 函数**搬迁**到 series-calculator.ts
+  - [ ] 3.2 将 fixPieSeries 函数**搬迁**到 series-calculator.ts
+  - [ ] 3.3 将 dataCombine 函数**搬迁**到 series-calculator.ts
+  - [ ] 3.4 将 dataCombineStack 函数**搬迁**到 series-calculator.ts
+  - [ ] 3.5 将 fillCustomColor 函数**搬迁**到 series-calculator.ts
+  - [ ] 3.6 将 getDataRange 函数**搬迁**到 series-calculator.ts
+  - [ ] 3.7 为所有系列数据处理函数添加完整的 TypeScript 类型注解
+
+- [ ] Task 4: **搬迁**坐标轴计算函数并添加类型注解 (AC: 2, 3, 4, 5)
+  - [ ] 4.1 将 calXAxisData 函数**搬迁**到 axis-calculator.ts
+  - [ ] 4.2 将 calYAxisData 函数**搬迁**到 axis-calculator.ts
+  - [ ] 4.3 将 calYAxisSeries 函数**搬迁**到 axis-calculator.ts
+  - [ ] 4.4 将 getXAxisPoints 函数**搬迁**到 axis-calculator.ts
+  - [ ] 4.5 将 getYAxisPoints 函数**搬迁**到 axis-calculator.ts
+  - [ ] 4.6 为所有坐标轴计算函数添加完整的 TypeScript 类型注解
+
+- [ ] Task 5: **搬迁**分类数据处理函数并添加类型注解 (AC: 2, 3, 4, 5)
+  - [ ] 5.1 将 calCategoriesData 函数**搬迁**到 categories-calculator.ts
+  - [ ] 5.2 将 getCategoriesDataPoints 函数**搬迁**到 categories-calculator.ts
+  - [ ] 5.3 为分类数据处理函数添加完整的 TypeScript 类型注解
+
+- [ ] Task 6: **搬迁**提示框数据计算函数并添加类型注解 (AC: 2, 3, 4, 5)
+  - [ ] 6.1 将 getToolTipData 函数**搬迁**到 tooltip-calculator.ts
+  - [ ] 6.2 将 buildToolTipOption 函数**搬迁**到 tooltip-calculator.ts
+  - [ ] 6.3 为提示框数据计算函数添加完整的 TypeScript 类型注解
+
+- [ ] Task 7: 更新导出和验证搬迁结果 (AC: 1, 2, 3, 5)
+  - [ ] 7.1 更新 `src/lib/data-processing/index.ts` 统一导出所有数据处理函数
+  - [ ] 7.2 更新 `src/index.ts` 导出新模块
+  - [ ] 7.3 运行类型检查验证所有类型注解正确
+  - [ ] 7.4 确保所有数据处理函数正确导出
+  - [ ] 7.5 确认代码逻辑与原始文件完全一致
+  - [ ] 7.6 验证每个文件控制在 500 行以内
+
+## Dev Notes
+
+### 前置故事见解
+
+**故事 016.001 完成状态**:
+- ✅ 已创建 `mini-charts` 包基础结构
+- ✅ 已迁移 u-charts 核心库到 `src/lib/u-charts.ts`(7680行代码)
+- ✅ 包可以成功构建和类型检查通过
+- ⚠️ 使用 `@ts-nocheck` 绕过原始库中的类型问题
+
+**故事 016.002 完成状态**:
+- ✅ 已创建 `config.ts` 和 `utils/` 目录及所有子模块文件
+- ✅ 所有文件行数均在 500 行以内(最大 201 行 misc.ts)
+- ✅ 类型检查通过(pnpm typecheck)
+- ✅ 为 Canvas 上下文使用 `any` 类型以兼容小程序环境
+
+**故事 016.002 关键技术决策**:
+- 保持代码逻辑完全不变,只改变文件组织方式
+- 只在搬迁过程中添加 TypeScript 类型注解,不修改代码的实现逻辑
+- 为复杂参数和返回值定义 TypeScript 接口
+- 使用 ES6 `export` 语法导出函数和类型
+
+**迁移策略**: 保持 u-charts 核心绘制逻辑不变,渐进式模块化并添加类型定义
+
+### 技术栈要求
+
+**来源**: [tech-stack.md](../../architecture/tech-stack.md)
+
+- **TypeScript**: 5.4.5 [来源: tech-stack.md]
+- **React**: 18.0.0(mini 包使用 React 18,不是 React 19)[来源: 故事 016.001 Dev Notes]
+- **Taro**: 4.1.4 [来源: tech-stack.md]
+- **Node.js**: 20.18.3(运行时环境)[来源: tech-stack.md]
+- **包管理器**: pnpm workspace [来源: source-tree.md]
+
+### 项目结构指南
+
+**来源**: [source-tree.md](../../architecture/source-tree.md)
+
+```
+mini-ui-packages/
+└── mini-charts/              # mini-charts 包
+    ├── src/
+    │   ├── index.ts          # 主入口文件
+    │   └── lib/
+    │       ├── u-charts.ts   # u-charts 核心库(7680行)
+    │       ├── config.ts     # [已完成] 配置对象
+    │       ├── utils/        # [已完成] 工具函数目录
+    │       └── data-processing/  # [新增] 数据处理模块
+    │           ├── index.ts  # 数据处理模块统一导出
+    │           ├── series-calculator.ts  # 系列数据处理
+    │           ├── axis-calculator.ts  # 坐标轴计算
+    │           ├── categories-calculator.ts  # 分类数据处理
+    │           └── tooltip-calculator.ts  # 提示框数据计算
+    ├── tests/
+    │   └── u-charts.test.ts
+    ├── package.json
+    ├── tsconfig.json
+    └── jest.config.cjs
+```
+
+### TypeScript 配置规范
+
+**来源**: [ui-package-standards.md](../../architecture/ui-package-standards.md#typescript配置)
+
+```json
+{
+  "compilerOptions": {
+    "target": "ES2020",
+    "lib": ["DOM", "DOM.Iterable", "ES2020"],
+    "module": "ESNext",
+    "skipLibCheck": true,
+    "moduleResolution": "bundler",
+    "allowImportingTsExtensions": true,
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "noEmit": true,
+    "jsx": "react-jsx",
+    "strict": true,
+    "noUnusedLocals": true,
+    "noUnusedParameters": true,
+    "noFallthroughCasesInSwitch": true
+  },
+  "include": ["src"]
+}
+```
+
+**本故事重要**: 需要为所有函数添加完整的类型注解,确保 `strict: true` 模式下无类型错误。
+
+### u-charts 数据处理函数分析
+
+**来源**: [mini-charts/src/lib/u-charts.ts](../../mini-ui-packages/mini-charts/src/lib/u-charts.ts)
+
+#### 系列数据处理函数
+
+1. **fillSeries(series, opts, config)**: 填充系列数据,确保所有系列数据长度一致
+2. **fixPieSeries(series, opts, config)**: 修复饼图系列数据,处理百分比和累计值
+3. **dataCombine(series)**: 数据合并,合并多个系列的数据
+4. **dataCombineStack(series, len)**: 堆叠数据合并,处理堆叠图表的数据合并
+5. **fillCustomColor(linearType, customColor, series, config)**: 填充自定义颜色,为系列数据设置颜色
+6. **getDataRange(minData, maxData)**: 获取数据范围,计算最小值和最大值的范围
+
+#### 坐标轴计算函数
+
+1. **calXAxisData(opts, config)**: 计算X轴数据,包括刻度、标签等
+2. **calYAxisData(series, opts, config, eachSpacing)**: 计算Y轴数据,包括刻度、标签等
+3. **calYAxisSeries(series, opts, config, eachSpacing)**: 计算Y轴系列数据,用于多轴图表
+4. **getXAxisPoints(opts, config)**: 获取X轴数据点坐标
+5. **getYAxisPoints(opts, config)**: 获取Y轴数据点坐标
+
+#### 分类数据处理函数
+
+1. **calCategoriesData(opts, config)**: 计算分类数据,处理分类轴的数据
+2. **getCategoriesDataPoints(opts, config)**: 获取分类数据点,用于分类图表
+
+#### 提示框数据计算函数
+
+1. **getToolTipData(opts, config)**: 获取提示框数据,计算tooltip显示的数据
+2. **buildToolTipOption(opts, config, seriesData)**: 构建提示框选项,生成tooltip配置对象
+
+### 类型定义规范
+
+**来源**: [ui-package-standards.md](../../architecture/ui-package-standards.md#类型定义规范)
+
+**本故事重要**: 必须为所有函数添加完整的类型注解,避免使用 `any` 类型(除非必要)。
+
+**类型定义示例**:
+
+```typescript
+// series-calculator.ts 类型定义示例
+export interface SeriesItem {
+  data: (number | null)[];
+  name: string;
+  color?: string;
+  index?: number;
+  type?: string;
+}
+
+export interface ChartOptions {
+  type: string;
+  categories?: string[];
+  extra?: Record<string, any>;
+  [key: string]: any;
+}
+
+export interface UChartsConfig {
+  version: string;
+  color: string[];
+  // ... 其他配置项
+}
+
+export function fillSeries(
+  series: SeriesItem[],
+  opts: ChartOptions,
+  config: UChartsConfig
+): SeriesItem[] {
+  // 实现逻辑
+}
+
+export function fixPieSeries(
+  series: SeriesItem[],
+  opts: ChartOptions,
+  config: UChartsConfig
+): SeriesItem[] {
+  // 实现逻辑
+}
+
+export function dataCombine(series: SeriesItem[]): (number | null)[] {
+  // 实现逻辑
+}
+
+export function dataCombineStack(
+  series: SeriesItem[],
+  len: number
+): (number | null)[][] {
+  // 实现逻辑
+}
+
+export function fillCustomColor(
+  linearType: string,
+  customColor: string[],
+  series: SeriesItem[],
+  config: UChartsConfig
+): SeriesItem[] {
+  // 实现逻辑
+}
+
+export interface DataRange {
+  min: number;
+  max: number;
+}
+
+export function getDataRange(minData: number, maxData: number): DataRange {
+  // 实现逻辑
+}
+```
+
+```typescript
+// axis-calculator.ts 类型定义示例
+export interface XAxisData {
+  xAxisCategories: string[];
+  xAxisPoints: number[];
+  xAxisText: string[];
+  xAxisPointsHeight: number;
+  // ... 其他X轴数据
+}
+
+export interface YAxisData {
+  yAxisData: {
+    categories?: string[];
+    ranges: number[][];
+    min?: number;
+    max?: number;
+  }[];
+  yAxisWidth: number;
+  // ... 其他Y轴数据
+}
+
+export function calXAxisData(
+  opts: ChartOptions,
+  config: UChartsConfig
+): XAxisData {
+  // 实现逻辑
+}
+
+export function calYAxisData(
+  series: SeriesItem[],
+  opts: ChartOptions,
+  config: UChartsConfig,
+  eachSpacing: number
+): YAxisData {
+  // 实现逻辑
+}
+
+export function calYAxisSeries(
+  series: SeriesItem[],
+  opts: ChartOptions,
+  config: UChartsConfig,
+  eachSpacing: number
+): YAxisData {
+  // 实现逻辑
+}
+
+export interface AxisPoints {
+  points: number[];
+  eachSpacing: number;
+  start: number;
+  end: number;
+}
+
+export function getXAxisPoints(
+  opts: ChartOptions,
+  config: UChartsConfig
+): AxisPoints {
+  // 实现逻辑
+}
+
+export function getYAxisPoints(
+  opts: ChartOptions,
+  config: UChartsConfig
+): AxisPoints {
+  // 实现逻辑
+}
+```
+
+```typescript
+// categories-calculator.ts 类型定义示例
+export interface CategoriesData {
+  categories: string[];
+  categoriesPoints: number[];
+  // ... 其他分类数据
+}
+
+export function calCategoriesData(
+  opts: ChartOptions,
+  config: UChartsConfig
+): CategoriesData {
+  // 实现逻辑
+}
+
+export function getCategoriesDataPoints(
+  opts: ChartOptions,
+  config: UChartsConfig
+): CategoriesData {
+  // 实现逻辑
+}
+```
+
+```typescript
+// tooltip-calculator.ts 类型定义示例
+export interface ToolTipData {
+  index: number;
+  textList: {
+    text: string;
+    color: string;
+  }[];
+  offset: number;
+  // ... 其他tooltip数据
+}
+
+export interface ToolTipOption {
+  textList: {
+    text: string;
+    color: string;
+  }[];
+  x: number;
+  y: number;
+  // ... 其他tooltip选项
+}
+
+export function getToolTipData(
+  opts: ChartOptions,
+  config: UChartsConfig
+): ToolTipData {
+  // 实现逻辑
+}
+
+export function buildToolTipOption(
+  opts: ChartOptions,
+  config: UChartsConfig,
+  seriesData: SeriesItem[]
+): ToolTipOption {
+  // 实现逻辑
+}
+```
+
+### 编码标准
+
+**来源**: [coding-standards.md](../../architecture/coding-standards.md)
+
+- **代码风格**: TypeScript 严格模式,一致的缩进和命名
+- **类型注解**: 必须为所有函数参数和返回值添加类型注解
+- **接口定义**: 为复杂数据结构定义 TypeScript 接口
+- **导出规范**: 使用 ES6 `export` 语法导出函数和类型
+
+### 测试策略
+
+**来源**: [testing-strategy.md](../../architecture/testing-strategy.md)
+
+**测试框架**: Jest(mini 包使用 Jest,不是 Vitest)
+
+**测试位置**: `tests/` 目录(与源码并列)
+
+**测试类型**:
+- 单元测试: 测试数据处理函数的正确性
+- **不要求**集成测试和 E2E 测试(这些在后续故事中)
+
+**测试要求**:
+1. 为每个数据处理函数编写单元测试
+2. 测试覆盖率目标: 基础测试即可,不要求高覆盖率
+3. Mock 相关依赖(如配置、工具函数等)
+
+**测试命令**:
+```bash
+# 进入包目录
+cd mini-ui-packages/mini-charts
+
+# 运行所有测试
+pnpm test
+
+# 运行特定测试
+pnpm test --testNamePattern "数据处理函数测试"
+
+# 类型检查
+pnpm typecheck
+```
+
+### 构建和发布规范
+
+**来源**: [ui-package-standards.md](../../architecture/ui-package-standards.md#构建和发布规范)
+
+mini-charts 包在 PNPM 工作空间中:
+- **开发模式**: 直接使用 TypeScript 源码
+- **构建**: 使用 `tsc` 编译到 `dist/` 目录
+- **类型检查**: 使用 `tsc --noEmit` 验证类型
+- **发布**: 本故事不要求发布,仅验证本地构建成功
+
+**重要**: 本故事完成后,应该可以:
+1. ✅ 运行 `pnpm build` 成功生成 `dist/` 目录
+2. ✅ 运行 `pnpm typecheck` 无类型错误
+3. ✅ 所有新模块正确导出,可以被主入口文件引用
+
+### 开发流程
+
+**来源**: [development-workflow.md](../../architecture/development-workflow.md)
+
+**开发命令**:
+```bash
+# 进入包目录
+cd mini-ui-packages/mini-charts
+
+# 安装依赖(在根目录)
+pnpm install
+
+# 开发模式(监听文件变化)
+pnpm dev
+
+# 类型检查
+pnpm typecheck
+
+# 运行测试
+pnpm test
+
+# 构建
+pnpm build
+```
+
+### 环境配置
+
+**来源**: [CLAUDE.md](../../CLAUDE.md)
+
+- **Node.js**: 20.19.2
+- **包管理器**: pnpm
+- **测试调试**: 使用 `pnpm test --testNamePattern "测试名称"` 运行特定测试
+- **Mini 测试**: 需要 Jest,不是 Vitest
+- **类型检查**: 使用 `pnpm typecheck` 加 grep 来过滤要检查的指定文件
+
+### 文件位置规范
+
+**来源**: [source-tree.md](../../architecture/source-tree.md)
+
+所有新文件应创建在:
+- 数据处理模块目录: `mini-ui-packages/mini-charts/src/lib/data-processing/`
+- 数据处理文件:
+  - `series-calculator.ts`: 系列数据处理
+  - `axis-calculator.ts`: 坐标轴计算
+  - `categories-calculator.ts`: 分类数据处理
+  - `tooltip-calculator.ts`: 提示框数据计算
+  - `index.ts`: 数据处理模块统一导出
+- 主入口: `mini-ui-packages/mini-charts/src/index.ts`(需要更新导出)
+- 测试文件: `mini-ui-packages/mini-charts/tests/`(可选,本故事不强制要求)
+
+### 技术约束
+
+1. **搬迁原则**: 保持代码逻辑完全不变,只改变文件组织方式
+2. **类型注解**: 只在搬迁过程中添加 TypeScript 类型注解,不修改代码的实现逻辑
+3. **文件大小**: 每个文件控制在 500 行以内
+4. **类型安全**: 避免使用 `any` 类型(除非必要)
+5. **向后兼容**: 保持与原始 u-charts.ts 的功能兼容性
+
+### 验证标准
+
+完成本故事后,应该满足:
+1. ✅ `src/lib/data-processing/` 目录下所有文件存在
+2. ✅ 所有数据处理函数都有完整类型注解
+3. ✅ 运行 `pnpm typecheck` 无类型错误
+4. ✅ 每个文件控制在 500 行以内
+5. ✅ 代码逻辑与原始 u-charts.ts 完全一致
+6. ✅ 所有新模块正确导出,可以被主入口文件引用
+
+### 不包含在本故事中的工作
+
+**来源**: [epic-016 故事列表](../../prd/epic-016-mini-charts-package.md#故事列表)
+
+以下工作**不在**本故事范围内:
+- ❌ 图表数据点计算函数模块化(故事 016.004)
+- ❌ 绘制函数模块化(故事 016.005)
+- ❌ 核心类模块化(故事 016.006)
+- ❌ React 组件封装(故事 016.007)
+
+### Testing
+
+**测试框架**: Jest(不是 Vitest)
+
+**测试位置**: `tests/` 目录(与源码并列)
+
+**测试要求**:
+1. 创建基础测试验证数据处理函数的正确导入和导出
+2. 测试数据处理函数的基本功能(可选,本故事不强制要求)
+3. Mock 相关依赖(如配置、工具函数等)
+4. 测试覆盖率目标: 基础测试即可,不要求高覆盖率
+
+**测试命令**:
+```bash
+# 运行所有测试
+pnpm test
+
+# 运行特定测试
+pnpm test --testNamePattern "数据处理函数测试"
+```
+
+**参考**: [testing-strategy.md](../../architecture/testing-strategy.md)
+
+## Change Log
+
+| Date | Version | Description | Author |
+|------|---------|-------------|--------|
+| 2025-12-24 | 1.0 | 创建故事文档 | Bob (Scrum Master) |
+| 2025-12-24 | 1.1 | 更新状态为 Approved | Bob (Scrum Master) |
+
+## Dev Agent Record
+
+*此部分由开发代理在实施过程中填写*
+
+### Agent Model Used
+
+(待开发代理填写)
+
+### Debug Log References
+
+(待开发代理填写)
+
+### Completion Notes List
+
+(待开发代理填写)
+
+### File List
+
+(待开发代理填写)
+
+## QA Results
+
+*此部分由 QA 代理在审查完成后填写*