Files
chinese-family-tree-2/.kiro/specs/founder-parent-warning/design.md
T
freedakgmail 5c8c70097c 0.8.0.0
2025-12-21 17:32:33 +08:00

11 KiB

Design Document: 为始祖添加父母时的代数重新计算提醒

Overview

本设计文档描述了在家族树应用中,当用户尝试给始祖(第1代成员)添加父母时,显示确认对话框的功能实现。该功能旨在提醒用户此操作将导致全族代数重新计算,确保用户了解操作的影响后再执行。

设计目标

  1. 在所有添加父母的入口点(成员页面、族谱页面、添加关系对话框)统一实现确认提醒
  2. 提供清晰的信息说明代数变化的影响
  3. 保持与现有 UI 组件风格一致
  4. 不影响非始祖成员的正常添加父母操作

Architecture

组件架构

┌─────────────────────────────────────────────────────────────┐
│                      用户界面层                              │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │ MemberCard  │  │ D3OrgChart  │  │ AddRelationDialog   │  │
│  │ (成员页面)   │  │ (族谱页面)   │  │ (添加关系对话框)     │  │
│  └──────┬──────┘  └──────┬──────┘  └──────────┬──────────┘  │
│         │                │                     │             │
│         └────────────────┼─────────────────────┘             │
│                          │                                   │
│                          ▼                                   │
│  ┌───────────────────────────────────────────────────────┐  │
│  │         GenerationWarningDialog (新组件)               │  │
│  │  - 显示代数重新计算警告                                 │  │
│  │  - 提供确认/取消操作                                    │  │
│  └───────────────────────────────────────────────────────┘  │
├─────────────────────────────────────────────────────────────┤
│                      工具函数层                              │
├─────────────────────────────────────────────────────────────┤
│  ┌───────────────────────────────────────────────────────┐  │
│  │         isFirstGenerationMember() (新函数)             │  │
│  │  - 检查成员是否为第1代                                  │  │
│  │  - 判断是否需要显示警告                                 │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

数据流

sequenceDiagram
    participant User as 用户
    participant UI as UI组件
    participant Check as 检查函数
    participant Dialog as 警告对话框
    participant Nav as 导航

    User->>UI: 右键点击成员 → 添加父母
    UI->>Check: isFirstGenerationMember(member)
    Check-->>UI: true/false
    
    alt 是第1代成员
        UI->>Dialog: 显示警告对话框
        Dialog-->>User: 展示代数变化说明
        
        alt 用户确认
            User->>Dialog: 点击"确认添加"
            Dialog->>Nav: 跳转到新增成员页面
        else 用户取消
            User->>Dialog: 点击"取消"
            Dialog->>UI: 关闭对话框
        end
    else 不是第1代成员
        UI->>Nav: 直接跳转到新增成员页面
    end

Components and Interfaces

1. GenerationWarningDialog 组件

新建确认对话框组件,用于显示代数重新计算警告。

// components/tree/generation-warning-dialog.tsx

interface GenerationWarningDialogProps {
  open: boolean
  onOpenChange: (open: boolean) => void
  memberName: string
  relationType: 'father' | 'mother'
  onConfirm: () => void
}

export function GenerationWarningDialog({
  open,
  onOpenChange,
  memberName,
  relationType,
  onConfirm,
}: GenerationWarningDialogProps) {
  // 实现对话框内容
}

2. isFirstGenerationMember 工具函数

检查成员是否为第1代成员的工具函数。

// lib/generation-utils.ts (扩展现有文件)

/**
 * 检查成员是否为第1代成员(需要显示代数重新计算警告)
 * @param member 家族成员对象
 * @returns 是否为第1代成员
 */
export function isFirstGenerationMember(member: FamilyMember): boolean {
  return member.generation === 1
}

/**
 * 检查添加父母操作是否需要显示警告
 * @param member 目标成员
 * @param relationType 关系类型
 * @returns 是否需要显示警告
 */
export function shouldShowGenerationWarning(
  member: FamilyMember,
  relationType: 'father' | 'mother'
): boolean {
  return isFirstGenerationMember(member)
}

3. 组件集成接口

MemberCard 组件修改

// 在 MemberCard 组件中添加状态管理
const [showWarningDialog, setShowWarningDialog] = useState(false)
const [pendingRelationType, setPendingRelationType] = useState<'father' | 'mother' | null>(null)

// 修改 handleAddMember 函数
const handleAddMember = (type: RelationType) => {
  if ((type === 'father' || type === 'mother') && isFirstGenerationMember(member)) {
    setPendingRelationType(type)
    setShowWarningDialog(true)
  } else {
    onOpenAddDialog(member, type)
  }
}

D3OrgChartFlow 组件修改

// 在 D3OrgChartFlow 组件中添加状态管理
const [showWarningDialog, setShowWarningDialog] = useState(false)
const [pendingAction, setPendingAction] = useState<{
  type: 'father' | 'mother'
  member: FamilyMember
} | null>(null)

// 修改 handleAddMember 函数
const handleAddMember = (type: 'father' | 'mother' | 'spouse' | 'child', member: FamilyMember) => {
  if ((type === 'father' || type === 'mother') && isFirstGenerationMember(member)) {
    setPendingAction({ type, member })
    setShowWarningDialog(true)
  } else {
    // 原有逻辑
    const url = buildAddUrl(type, member)
    window.location.href = url
  }
}

Data Models

本功能不需要新增数据模型,使用现有的 FamilyMember 类型:

interface FamilyMember {
  id: string
  generation: number  // 用于判断是否为第1代
  fullName: string
  fatherId?: string
  motherId?: string
  // ... 其他字段
}

Correctness Properties

A property is a characteristic or behavior that should hold true across all valid executions of a system—essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.

Property 1: 第1代成员检测正确性

For any 家族成员,isFirstGenerationMember 函数返回 true 当且仅当该成员的 generation 值等于 1。

Validates: Requirements 1.1, 1.2, 1.3, 1.4

Property 2: 警告显示条件正确性

For any 添加父母操作,shouldShowGenerationWarning 函数返回 true 当且仅当目标成员是第1代成员且关系类型为 'father' 或 'mother'。

Validates: Requirements 1.3, 2.1

Property 3: 非第1代成员不触发警告

For any 成员,如果其 generation 值大于 1,则添加父母操作不应触发警告对话框。

Validates: Requirements 1.4

Error Handling

错误场景

  1. 成员数据缺失

    • 场景:成员对象缺少 generation 字段
    • 处理:默认不显示警告,允许操作继续
  2. 对话框状态异常

    • 场景:对话框打开时成员数据变化
    • 处理:关闭对话框,提示用户重新操作
  3. 导航失败

    • 场景:确认后跳转失败
    • 处理:显示错误提示,保持对话框打开状态

错误处理代码示例

const handleConfirm = () => {
  try {
    if (!pendingAction) {
      console.error('No pending action')
      return
    }
    
    const url = buildAddUrl(pendingAction.type, pendingAction.member)
    setShowWarningDialog(false)
    setPendingAction(null)
    
    // 使用 setTimeout 确保对话框关闭后再跳转
    setTimeout(() => {
      window.location.href = url
    }, 100)
  } catch (error) {
    console.error('Navigation failed:', error)
    toast({
      title: '操作失败',
      description: '无法跳转到新增成员页面,请重试',
      variant: 'destructive'
    })
  }
}

Testing Strategy

单元测试

  1. isFirstGenerationMember 函数测试

    • 测试 generation = 1 返回 true
    • 测试 generation > 1 返回 false
    • 测试边界值(generation = 0, 负数等)
  2. shouldShowGenerationWarning 函数测试

    • 测试第1代成员 + father/mother 返回 true
    • 测试非第1代成员返回 false
    • 测试其他关系类型(spouse, child)返回 false

属性测试

使用 fast-check 进行属性测试:

import fc from 'fast-check'

// Property 1: 第1代成员检测
fc.assert(
  fc.property(
    fc.integer({ min: 1, max: 100 }),
    (generation) => {
      const member = { generation } as FamilyMember
      return isFirstGenerationMember(member) === (generation === 1)
    }
  ),
  { numRuns: 100 }
)

// Property 2: 警告显示条件
fc.assert(
  fc.property(
    fc.integer({ min: 1, max: 100 }),
    fc.constantFrom('father', 'mother', 'spouse', 'child'),
    (generation, relationType) => {
      const member = { generation } as FamilyMember
      const shouldShow = shouldShowGenerationWarning(member, relationType as any)
      const expected = generation === 1 && (relationType === 'father' || relationType === 'mother')
      return shouldShow === expected
    }
  ),
  { numRuns: 100 }
)

集成测试

  1. 成员页面右键菜单测试

    • 验证第1代成员右键添加父母显示对话框
    • 验证非第1代成员右键添加父母直接跳转
  2. 族谱页面右键菜单测试

    • 验证第1代成员右键添加父母显示对话框
    • 验证确认后正确跳转
  3. 对话框交互测试

    • 验证对话框内容正确显示
    • 验证确认按钮触发跳转
    • 验证取消按钮关闭对话框