MagicalGirlCard.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. import React, { useRef } from 'react';
  2. import { snapdom } from '@zumer/snapdom';
  3. interface MagicalGirlCardProps {
  4. magicalGirl: {
  5. codename: string;
  6. appearance: {
  7. outfit: string;
  8. accessories: string;
  9. colorScheme: string;
  10. overallLook: string;
  11. };
  12. magicConstruct: {
  13. name: string;
  14. form: string;
  15. basicAbilities: string[];
  16. description: string;
  17. };
  18. wonderlandRule: {
  19. name: string;
  20. description: string;
  21. tendency: string;
  22. activation: string;
  23. };
  24. blooming: {
  25. name: string;
  26. evolvedAbilities: string[];
  27. evolvedForm: string;
  28. evolvedOutfit: string;
  29. powerLevel: string;
  30. };
  31. analysis: {
  32. personalityAnalysis: string;
  33. abilityReasoning: string;
  34. coreTraits: string[];
  35. predictionBasis: string;
  36. };
  37. };
  38. gradientStyle: string;
  39. onSaveImage?: (imageUrl: string) => void;
  40. }
  41. const MagicalGirlCard: React.FC<MagicalGirlCardProps> = ({
  42. magicalGirl,
  43. gradientStyle,
  44. onSaveImage
  45. }) => {
  46. const resultRef = useRef<HTMLDivElement>(null);
  47. const handleSaveImage = async () => {
  48. if (!resultRef.current) return;
  49. try {
  50. const saveButton = resultRef.current.querySelector('.save-button') as HTMLElement;
  51. const logoPlaceholder = resultRef.current.querySelector('.logo-placeholder') as HTMLElement;
  52. if (saveButton) saveButton.style.display = 'none';
  53. if (logoPlaceholder) logoPlaceholder.style.display = 'flex';
  54. const result = await snapdom(resultRef.current, {
  55. scale: 1,
  56. });
  57. if (saveButton) saveButton.style.display = 'block';
  58. if (logoPlaceholder) logoPlaceholder.style.display = 'none';
  59. const imgElement = await result.toPng();
  60. const imageUrl = imgElement.src;
  61. if (onSaveImage) {
  62. onSaveImage(imageUrl);
  63. }
  64. } catch {
  65. alert('生成图片失败,请重试');
  66. const saveButton = resultRef.current?.querySelector('.save-button') as HTMLElement;
  67. const logoPlaceholder = resultRef.current?.querySelector('.logo-placeholder') as HTMLElement;
  68. if (saveButton) saveButton.style.display = 'block';
  69. if (logoPlaceholder) logoPlaceholder.style.display = 'none';
  70. }
  71. };
  72. return (
  73. <div
  74. ref={resultRef}
  75. className="result-card"
  76. style={{ background: gradientStyle }}
  77. >
  78. <div className="result-content">
  79. <div className="flex justify-center items-center" style={{ marginBottom: '1rem', background: 'transparent' }}>
  80. <img src="/questionnaire-title.svg" width={300} height={70} alt="Logo" style={{ display: 'block', background: 'transparent' }} />
  81. </div>
  82. {/* 基本信息 */}
  83. <div className="result-item">
  84. <div className="result-label">💝 魔法少女代号</div>
  85. <div className="result-value">{magicalGirl.codename}</div>
  86. </div>
  87. {/* 外观描述 */}
  88. <div className="result-item">
  89. <div className="result-label">👗 魔法少女外观</div>
  90. <div className="result-value">
  91. <div><strong>服装:</strong>{magicalGirl.appearance.outfit}</div>
  92. <div><strong>饰品:</strong>{magicalGirl.appearance.accessories}</div>
  93. <div><strong>配色:</strong>{magicalGirl.appearance.colorScheme}</div>
  94. <div><strong>整体风格:</strong>{magicalGirl.appearance.overallLook}</div>
  95. </div>
  96. </div>
  97. {/* 魔力构装 */}
  98. <div className="result-item">
  99. <div className="result-label">⚔️ 魔力构装</div>
  100. <div className="result-value">
  101. <div><strong>名称:</strong>{magicalGirl.magicConstruct.name}</div>
  102. <div><strong>形态:</strong>{magicalGirl.magicConstruct.form}</div>
  103. <div><strong>基本能力:</strong></div>
  104. <ul style={{ marginLeft: '1rem', marginTop: '0.5rem' }}>
  105. {magicalGirl.magicConstruct.basicAbilities.map((ability: string, index: number) => (
  106. <li key={index}>• {ability}</li>
  107. ))}
  108. </ul>
  109. <div style={{ marginTop: '0.5rem' }}><strong>详细描述:</strong>{magicalGirl.magicConstruct.description}</div>
  110. </div>
  111. </div>
  112. {/* 奇境规则 */}
  113. <div className="result-item">
  114. <div className="result-label">🌟 奇境规则</div>
  115. <div className="result-value">
  116. <div><strong>规则名称:</strong>{magicalGirl.wonderlandRule.name}</div>
  117. <div><strong>规则描述:</strong>{magicalGirl.wonderlandRule.description}</div>
  118. <div><strong>规则倾向:</strong>{magicalGirl.wonderlandRule.tendency}</div>
  119. <div><strong>激活条件:</strong>{magicalGirl.wonderlandRule.activation}</div>
  120. </div>
  121. </div>
  122. {/* 繁开状态 */}
  123. <div className="result-item">
  124. <div className="result-label">🌸 繁开状态</div>
  125. <div className="result-value">
  126. <div><strong>繁开魔装名:</strong>{magicalGirl.blooming.name}</div>
  127. <div><strong>进化能力:</strong></div>
  128. <ul style={{ marginLeft: '1rem', marginTop: '0.5rem' }}>
  129. {magicalGirl.blooming.evolvedAbilities.map((ability: string, index: number) => (
  130. <li key={index}>• {ability}</li>
  131. ))}
  132. </ul>
  133. <div><strong>进化形态:</strong>{magicalGirl.blooming.evolvedForm}</div>
  134. <div><strong>进化衣装:</strong>{magicalGirl.blooming.evolvedOutfit}</div>
  135. <div><strong>力量等级:</strong>{magicalGirl.blooming.powerLevel}</div>
  136. </div>
  137. </div>
  138. {/* 性格分析 */}
  139. <div className="result-item">
  140. <div className="result-label">🔮 性格分析</div>
  141. <div className="result-value">
  142. <div><strong>性格分析:</strong>{magicalGirl.analysis.personalityAnalysis}</div>
  143. <div><strong>能力推理:</strong>{magicalGirl.analysis.abilityReasoning}</div>
  144. <div><strong>核心特征:</strong>{magicalGirl.analysis.coreTraits.join('、')}</div>
  145. <div><strong>预测依据:</strong>{magicalGirl.analysis.predictionBasis}</div>
  146. </div>
  147. </div>
  148. <button onClick={handleSaveImage} className="save-button">
  149. 📱 保存为图片
  150. </button>
  151. <div className="logo-placeholder" style={{ display: 'none', justifyContent: 'center', marginTop: '1rem' }}>
  152. <img
  153. src="/logo-white-qrcode.svg"
  154. width={320}
  155. height={80}
  156. alt="Logo"
  157. style={{
  158. display: 'block',
  159. maxWidth: '100%',
  160. height: 'auto'
  161. }}
  162. />
  163. </div>
  164. </div>
  165. </div>
  166. );
  167. };
  168. export default MagicalGirlCard;