File size: 6,885 Bytes
25fe4a1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# Save Profile and Download Image Implementation Guide

## Overview

This implementation adds two new features to the results page:
1. **Save Profile Button** - Allows users to save their Bazi profile information for quick access later
2. **Download Image Button** - Enables users to download the analysis results as a PNG image using html2canvas

## Components Created

### 1. SaveProfileDialog.tsx (`/home/lifekline/components/SaveProfileDialog.tsx`)

A modal dialog component that prompts users to enter a profile name and displays the Bazi information before saving.

**Features:**
- Input field for profile name validation
- Display of four pillars (年柱, 月柱, 日柱, 时柱)
- Shows birth year
- Save/Cancel actions with loading states
- Error handling

**Props:**
```typescript
interface SaveProfileDialogProps {
  onClose: () => void;
  onSave: (profileName: string) => Promise<void>;
  baziInfo: {
    yearPillar: string;
    monthPillar: string;
    dayPillar: string;
    hourPillar: string;
    birthYear: string;
  };
  isOpen: boolean;
}
```

### 2. ResultActions.tsx (`/home/lifekline/components/ResultActions.tsx`)

A component that provides action buttons for the results page.

**Features:**
- **保存档案 (Save Profile)** - Opens SaveProfileDialog
- **下载图片 (Download Image)** - Uses html2canvas to capture and download results
- **分享 (Share)** - Triggers the share functionality
- Error handling for download failures
- Loading states during image generation

**Props:**
```typescript
interface ResultActionsProps {
  baziInfo: {
    yearPillar: string;
    monthPillar: string;
    dayPillar: string;
    hourPillar: string;
    birthYear: string;
  };
  userName?: string;
  onSaveProfile?: (profileName: string) => Promise<void>;
  onShare?: () => void;
  resultElementId?: string;
}
```

## Integration with ProgressiveAnalysisResult.tsx

The `ResultActions` component has been integrated into `ProgressiveAnalysisResult.tsx`:

### Changes Made:

1. **Import Added:**
```typescript
import ResultActions from './ResultActions';
```

2. **Props Extended:**
```typescript
interface ProgressiveAnalysisResultProps {
  // ... existing props
  userName?: string;
  onSaveProfile?: (profileName: string) => Promise<void>;
  onShare?: () => void;
}
```

3. **Component Placement:**
The ResultActions component is placed after the Agent Status section and before the Bazi Pillars display. It only appears when the analysis is complete and Bazi data is available.

4. **Result Section Wrapper:**
Added a wrapper div with `id="result-chart-section"` around the entire results area to enable html2canvas to capture the content.

## Usage Example

Here's how to use the updated ProgressiveAnalysisResult component:

```typescript
import ProgressiveAnalysisResult from './components/ProgressiveAnalysisResult';

function MyAnalysisPage() {
  // Save profile handler - integrates with existing profile management
  const handleSaveProfile = async (profileName: string) => {
    try {
      // Get current user input from state
      const profileData = {
        name: profileName,
        birthYear: currentInput.birthYear,
        yearPillar: currentInput.yearPillar,
        monthPillar: currentInput.monthPillar,
        dayPillar: currentInput.dayPillar,
        hourPillar: currentInput.hourPillar,
        startAge: currentInput.startAge,
        firstDaYun: currentInput.firstDaYun,
        birthPlace: currentInput.birthPlace,
        gender: currentInput.gender,
        // ... other required fields
      };

      // Save to localStorage or API
      const profiles = JSON.parse(localStorage.getItem('lifekline_profiles') || '[]');
      const newProfile = {
        ...profileData,
        id: Date.now().toString(),
        isDefault: profiles.length === 0,
        createdAt: new Date().toISOString(),
      };
      profiles.push(newProfile);
      localStorage.setItem('lifekline_profiles', JSON.stringify(profiles));

      // Show success message
      alert('Profile saved successfully!');
    } catch (error) {
      console.error('Failed to save profile:', error);
      throw new Error('Failed to save profile. Please try again.');
    }
  };

  // Share handler
  const handleShare = () => {
    // Open share panel or trigger share functionality
    setShowSharePanel(true);
  };

  return (
    <ProgressiveAnalysisResult
      requestData={requestData}
      userName={userName}
      onSaveProfile={handleSaveProfile}
      onShare={handleShare}
      onComplete={(result) => console.log('Analysis complete:', result)}
      onError={(error) => console.error('Analysis error:', error)}
    />
  );
}
```

## Download Image Functionality

The download image feature uses html2canvas with the following configuration:

```typescript
const canvas = await html2canvas(element, {
  scale: 2,              // High resolution (2x)
  useCORS: true,         // Handle cross-origin images
  backgroundColor: '#ffffff',
  logging: false,
  windowWidth: element.scrollWidth,
  windowHeight: element.scrollHeight,
});
```

The generated image is named: `人生K线_[UserName]_[Date].png`

## Save Profile Integration with Existing System

The save profile functionality integrates seamlessly with the existing profile management system:

1. Uses the same data structure as `CreateProfileModal`
2. Stores in localStorage under `lifekline_profiles` key
3. Compatible with `ProfileManager` component
4. Can be loaded back using the profile selector

## Styling and UX

- All buttons use consistent styling with the existing design system
- Loading states with spinners during async operations
- Error messages displayed inline with appropriate styling
- Modal dialogs use backdrop blur for better focus
- Responsive design works on mobile and desktop

## Testing Checklist

✓ Build successful with no TypeScript errors
- [ ] Save Profile Dialog opens and closes correctly
- [ ] Profile name validation works
- [ ] Bazi information displays correctly in dialog
- [ ] Profile saves to localStorage
- [ ] Saved profile can be loaded from ProfileManager
- [ ] Download Image generates PNG correctly
- [ ] Downloaded image includes all result sections
- [ ] Image filename includes username and date
- [ ] Error handling works for both features
- [ ] Responsive design on mobile devices
- [ ] Integration with share functionality

## Browser Compatibility

- html2canvas requires modern browsers
- Works with Chrome, Firefox, Safari, Edge
- May have limitations with very old browsers (IE11 not supported)

## Future Enhancements

Potential improvements for future versions:

1. Add image format options (PNG, JPEG)
2. Add image quality/resolution selector
3. Save to cloud storage instead of just localStorage
4. Batch profile management
5. Profile import/export functionality
6. Share profile as QR code
7. Print-optimized layout for PDF export