sa2kit 3.2.0 → 3.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/CollisionBalls-DgKtscU2.d.mts +41 -0
  2. package/dist/CollisionBalls-DgKtscU2.d.ts +41 -0
  3. package/dist/ConfigService-Oga_zFRS.d.mts +262 -0
  4. package/dist/ConfigService-Oga_zFRS.d.ts +262 -0
  5. package/dist/UniversalFileService-CC4d3wkc.d.ts +139 -0
  6. package/dist/UniversalFileService-CzAE_G4V.d.mts +139 -0
  7. package/dist/boothVaultService-lKcnyA-u.d.mts +83 -0
  8. package/dist/boothVaultService-lKcnyA-u.d.ts +83 -0
  9. package/dist/business/audioDetection/index.d.mts +2 -0
  10. package/dist/business/audioDetection/index.d.ts +2 -0
  11. package/dist/business/audioDetection/index.js +1244 -0
  12. package/dist/business/audioDetection/index.js.map +1 -0
  13. package/dist/business/audioDetection/index.mjs +1227 -0
  14. package/dist/business/audioDetection/index.mjs.map +1 -0
  15. package/dist/business/calendar/index.d.mts +6 -0
  16. package/dist/business/calendar/index.d.ts +6 -0
  17. package/dist/business/calendar/index.js +7433 -0
  18. package/dist/business/calendar/index.js.map +1 -0
  19. package/dist/business/calendar/index.mjs +7257 -0
  20. package/dist/business/calendar/index.mjs.map +1 -0
  21. package/dist/business/calendar/routes/index.d.mts +191 -0
  22. package/dist/business/calendar/routes/index.d.ts +191 -0
  23. package/dist/business/calendar/routes/index.js +844 -0
  24. package/dist/business/calendar/routes/index.js.map +1 -0
  25. package/dist/business/calendar/routes/index.mjs +826 -0
  26. package/dist/business/calendar/routes/index.mjs.map +1 -0
  27. package/dist/business/festivalCard/index.d.mts +4 -0
  28. package/dist/business/festivalCard/index.d.ts +4 -0
  29. package/dist/business/festivalCard/index.js +1492 -0
  30. package/dist/business/festivalCard/index.js.map +1 -0
  31. package/dist/business/festivalCard/index.mjs +1475 -0
  32. package/dist/business/festivalCard/index.mjs.map +1 -0
  33. package/dist/business/festivalCard/routes/index.d.mts +42 -0
  34. package/dist/business/festivalCard/routes/index.d.ts +42 -0
  35. package/dist/business/festivalCard/routes/index.js +361 -0
  36. package/dist/business/festivalCard/routes/index.js.map +1 -0
  37. package/dist/business/festivalCard/routes/index.mjs +356 -0
  38. package/dist/business/festivalCard/routes/index.mjs.map +1 -0
  39. package/dist/business/festivalCard/server/index.d.mts +120 -0
  40. package/dist/business/festivalCard/server/index.d.ts +120 -0
  41. package/dist/business/festivalCard/server/index.js +272 -0
  42. package/dist/business/festivalCard/server/index.js.map +1 -0
  43. package/dist/business/festivalCard/server/index.mjs +265 -0
  44. package/dist/business/festivalCard/server/index.mjs.map +1 -0
  45. package/dist/business/index.d.mts +34 -0
  46. package/dist/business/index.d.ts +34 -0
  47. package/dist/business/index.js +29282 -0
  48. package/dist/business/index.js.map +1 -0
  49. package/dist/business/index.mjs +29237 -0
  50. package/dist/business/index.mjs.map +1 -0
  51. package/dist/business/mikuContest/ui/web/index.d.mts +2 -0
  52. package/dist/business/mikuContest/ui/web/index.d.ts +2 -0
  53. package/dist/business/mikuContest/ui/web/index.js +353 -0
  54. package/dist/business/mikuContest/ui/web/index.js.map +1 -0
  55. package/dist/business/mikuContest/ui/web/index.mjs +343 -0
  56. package/dist/business/mikuContest/ui/web/index.mjs.map +1 -0
  57. package/dist/business/mikuFireworks3D/index.d.mts +2 -0
  58. package/dist/business/mikuFireworks3D/index.d.ts +2 -0
  59. package/dist/business/mikuFireworks3D/index.js +1267 -0
  60. package/dist/business/mikuFireworks3D/index.js.map +1 -0
  61. package/dist/business/mikuFireworks3D/index.mjs +1228 -0
  62. package/dist/business/mikuFireworks3D/index.mjs.map +1 -0
  63. package/dist/business/mikuFusionGame/index.d.mts +2 -0
  64. package/dist/business/mikuFusionGame/index.d.ts +2 -0
  65. package/dist/business/mikuFusionGame/index.js +1208 -0
  66. package/dist/business/mikuFusionGame/index.js.map +1 -0
  67. package/dist/business/mikuFusionGame/index.mjs +1195 -0
  68. package/dist/business/mikuFusionGame/index.mjs.map +1 -0
  69. package/dist/business/mmd/admin/index.d.mts +487 -0
  70. package/dist/business/mmd/admin/index.d.ts +487 -0
  71. package/dist/business/mmd/admin/index.js +1058 -0
  72. package/dist/business/mmd/admin/index.js.map +1 -0
  73. package/dist/business/mmd/admin/index.mjs +1027 -0
  74. package/dist/business/mmd/admin/index.mjs.map +1 -0
  75. package/dist/business/mmd/index.d.mts +5 -0
  76. package/dist/business/mmd/index.d.ts +5 -0
  77. package/dist/business/mmd/index.js +10119 -0
  78. package/dist/business/mmd/index.js.map +1 -0
  79. package/dist/business/mmd/index.mjs +10028 -0
  80. package/dist/business/mmd/index.mjs.map +1 -0
  81. package/dist/business/mmd/server/index.d.mts +139 -0
  82. package/dist/business/mmd/server/index.d.ts +139 -0
  83. package/dist/business/mmd/server/index.js +424 -0
  84. package/dist/business/mmd/server/index.js.map +1 -0
  85. package/dist/business/mmd/server/index.mjs +404 -0
  86. package/dist/business/mmd/server/index.mjs.map +1 -0
  87. package/dist/business/music/index.d.mts +3 -0
  88. package/dist/business/music/index.d.ts +3 -0
  89. package/dist/business/music/index.js +830 -0
  90. package/dist/business/music/index.js.map +1 -0
  91. package/dist/business/music/index.mjs +809 -0
  92. package/dist/business/music/index.mjs.map +1 -0
  93. package/dist/business/music/server/index.d.mts +1 -0
  94. package/dist/business/music/server/index.d.ts +1 -0
  95. package/dist/business/music/server/index.js +194 -0
  96. package/dist/business/music/server/index.js.map +1 -0
  97. package/dist/business/music/server/index.mjs +182 -0
  98. package/dist/business/music/server/index.mjs.map +1 -0
  99. package/dist/business/navigation/index.d.mts +2 -0
  100. package/dist/business/navigation/index.d.ts +2 -0
  101. package/dist/business/navigation/index.js +453 -0
  102. package/dist/business/navigation/index.js.map +1 -0
  103. package/dist/business/navigation/index.mjs +443 -0
  104. package/dist/business/navigation/index.mjs.map +1 -0
  105. package/dist/business/portfolio/index.d.mts +3 -0
  106. package/dist/business/portfolio/index.d.ts +3 -0
  107. package/dist/business/portfolio/index.js +736 -0
  108. package/dist/business/portfolio/index.js.map +1 -0
  109. package/dist/business/portfolio/index.mjs +724 -0
  110. package/dist/business/portfolio/index.mjs.map +1 -0
  111. package/dist/business/qqbot/server/index.d.mts +167 -0
  112. package/dist/business/qqbot/server/index.d.ts +167 -0
  113. package/dist/business/qqbot/server/index.js +394 -0
  114. package/dist/business/qqbot/server/index.js.map +1 -0
  115. package/dist/business/qqbot/server/index.mjs +385 -0
  116. package/dist/business/qqbot/server/index.mjs.map +1 -0
  117. package/dist/business/qqbot/ui/web/index.d.mts +10 -0
  118. package/dist/business/qqbot/ui/web/index.d.ts +10 -0
  119. package/dist/business/qqbot/ui/web/index.js +105 -0
  120. package/dist/business/qqbot/ui/web/index.js.map +1 -0
  121. package/dist/business/qqbot/ui/web/index.mjs +99 -0
  122. package/dist/business/qqbot/ui/web/index.mjs.map +1 -0
  123. package/dist/business/screenReceiver/index.d.mts +2 -0
  124. package/dist/business/screenReceiver/index.d.ts +2 -0
  125. package/dist/business/screenReceiver/index.js +281 -0
  126. package/dist/business/screenReceiver/index.js.map +1 -0
  127. package/dist/business/screenReceiver/index.mjs +273 -0
  128. package/dist/business/screenReceiver/index.mjs.map +1 -0
  129. package/dist/business/testYourself/admin/index.d.mts +58 -0
  130. package/dist/business/testYourself/admin/index.d.ts +58 -0
  131. package/dist/business/testYourself/admin/index.js +1009 -0
  132. package/dist/business/testYourself/admin/index.js.map +1 -0
  133. package/dist/business/testYourself/admin/index.mjs +1002 -0
  134. package/dist/business/testYourself/admin/index.mjs.map +1 -0
  135. package/dist/business/testYourself/index.d.mts +6 -0
  136. package/dist/business/testYourself/index.d.ts +6 -0
  137. package/dist/business/testYourself/index.js +2551 -0
  138. package/dist/business/testYourself/index.js.map +1 -0
  139. package/dist/business/testYourself/index.mjs +2531 -0
  140. package/dist/business/testYourself/index.mjs.map +1 -0
  141. package/dist/business/testYourself/server/index.d.mts +1029 -0
  142. package/dist/business/testYourself/server/index.d.ts +1029 -0
  143. package/dist/business/testYourself/server/index.js +825 -0
  144. package/dist/business/testYourself/server/index.js.map +1 -0
  145. package/dist/business/testYourself/server/index.mjs +816 -0
  146. package/dist/business/testYourself/server/index.mjs.map +1 -0
  147. package/dist/business/vocaloidBooth/index.d.mts +2 -0
  148. package/dist/business/vocaloidBooth/index.d.ts +2 -0
  149. package/dist/business/vocaloidBooth/index.js +172 -0
  150. package/dist/business/vocaloidBooth/index.js.map +1 -0
  151. package/dist/business/vocaloidBooth/index.mjs +166 -0
  152. package/dist/business/vocaloidBooth/index.mjs.map +1 -0
  153. package/dist/business/vocaloidBooth/server/index.d.mts +111 -0
  154. package/dist/business/vocaloidBooth/server/index.d.ts +111 -0
  155. package/dist/business/vocaloidBooth/server/index.js +247 -0
  156. package/dist/business/vocaloidBooth/server/index.js.map +1 -0
  157. package/dist/business/vocaloidBooth/server/index.mjs +237 -0
  158. package/dist/business/vocaloidBooth/server/index.mjs.map +1 -0
  159. package/dist/business/vocaloidBooth/web/index.d.mts +45 -0
  160. package/dist/business/vocaloidBooth/web/index.d.ts +45 -0
  161. package/dist/business/vocaloidBooth/web/index.js +376 -0
  162. package/dist/business/vocaloidBooth/web/index.js.map +1 -0
  163. package/dist/business/vocaloidBooth/web/index.mjs +362 -0
  164. package/dist/business/vocaloidBooth/web/index.mjs.map +1 -0
  165. package/dist/config-BQp3qLAL.d.mts +22 -0
  166. package/dist/config-BQp3qLAL.d.ts +22 -0
  167. package/dist/drizzle-schema-BNhqj2AZ.d.mts +1114 -0
  168. package/dist/drizzle-schema-BNhqj2AZ.d.ts +1114 -0
  169. package/dist/festivalCardService-D60G-sgr.d.mts +13 -0
  170. package/dist/festivalCardService-DnLyJpRh.d.ts +13 -0
  171. package/dist/index-BMgdH5dL.d.mts +1716 -0
  172. package/dist/index-BO9_Do5y.d.mts +93 -0
  173. package/dist/index-BO9_Do5y.d.ts +93 -0
  174. package/dist/index-BSmd4ikf.d.ts +76 -0
  175. package/dist/index-BSwvWYp2.d.mts +2632 -0
  176. package/dist/index-Bo_fW3Tl.d.mts +105 -0
  177. package/dist/index-Bo_fW3Tl.d.ts +105 -0
  178. package/dist/index-BrKazb8M.d.mts +148 -0
  179. package/dist/index-BrKazb8M.d.ts +148 -0
  180. package/dist/index-Bzh6QE4P.d.ts +25 -0
  181. package/dist/index-C5Ic6eSR.d.mts +25 -0
  182. package/dist/index-C8i9SIxk.d.ts +2632 -0
  183. package/dist/index-C_GhVhOT.d.mts +109 -0
  184. package/dist/index-C_GhVhOT.d.ts +109 -0
  185. package/dist/index-Cb3UEpG4.d.mts +101 -0
  186. package/dist/index-CjlkUj01.d.mts +103 -0
  187. package/dist/index-CucXCBNR.d.mts +302 -0
  188. package/dist/index-CucXCBNR.d.ts +302 -0
  189. package/dist/index-DLLPTprx.d.mts +1522 -0
  190. package/dist/index-DRiZy0dv.d.mts +525 -0
  191. package/dist/index-DRiZy0dv.d.ts +525 -0
  192. package/dist/index-Dc_I2t0P.d.mts +103 -0
  193. package/dist/index-DowAHRIP.d.mts +250 -0
  194. package/dist/index-DowAHRIP.d.ts +250 -0
  195. package/dist/index-Dpq_5H2n.d.ts +103 -0
  196. package/dist/index-Ds2M_9zb.d.ts +101 -0
  197. package/dist/index-IXMAeTtN.d.ts +1716 -0
  198. package/dist/index-VFDbZxVM.d.ts +1522 -0
  199. package/dist/index-jadkp96n.d.ts +103 -0
  200. package/dist/index-r2-zE3iC.d.mts +76 -0
  201. package/dist/index.d.mts +10682 -0
  202. package/dist/index.d.ts +10682 -0
  203. package/dist/index.js +38233 -0
  204. package/dist/index.js.map +1 -0
  205. package/dist/index.mjs +37959 -0
  206. package/dist/index.mjs.map +1 -0
  207. package/dist/types-B6B210gX.d.mts +270 -0
  208. package/dist/types-B6B210gX.d.ts +270 -0
  209. package/dist/types-B7voqjjA.d.mts +51 -0
  210. package/dist/types-B7voqjjA.d.ts +51 -0
  211. package/dist/types-Bdnte5EN.d.mts +292 -0
  212. package/dist/types-C2z_QQPI.d.mts +70 -0
  213. package/dist/types-C2z_QQPI.d.ts +70 -0
  214. package/dist/types-HorDyIRv.d.mts +303 -0
  215. package/dist/types-HorDyIRv.d.ts +303 -0
  216. package/dist/types-_rFX1atk.d.ts +292 -0
  217. package/package.json +3 -2
@@ -0,0 +1,1002 @@
1
+ import React, { useState, useCallback, useEffect } from 'react';
2
+ import { clsx } from 'clsx';
3
+ import { AlertCircle, X, CheckCircle2, Upload, Plus, RefreshCw, Star, ExternalLink, Edit, Copy, Download, Trash2, Save, Image } from 'lucide-react';
4
+
5
+ // src/business/testYourself/admin/ConfigManager.tsx
6
+
7
+ // src/business/testYourself/data/defaultResults.ts
8
+ var DEFAULT_RESULTS = [
9
+ // 动物系列 (1-15)
10
+ {
11
+ id: "animal-cat",
12
+ title: "\u6175\u61D2\u7684\u732B\u54AA \u{1F431}",
13
+ description: "\u4F60\u5C31\u50CF\u4E00\u53EA\u4F18\u96C5\u7684\u732B\uFF0C\u72EC\u7ACB\u81EA\u4E3B\uFF0C\u559C\u6B22\u6309\u7167\u81EA\u5DF1\u7684\u8282\u594F\u751F\u6D3B\u3002\u6709\u65F6\u9AD8\u51B7\uFF0C\u6709\u65F6\u7C98\u4EBA\uFF0C\u5145\u6EE1\u795E\u79D8\u9B45\u529B\u3002",
14
+ image: "\u{1F431}",
15
+ imageType: "emoji"
16
+ },
17
+ {
18
+ id: "animal-dog",
19
+ title: "\u5FE0\u8BDA\u7684\u72D7\u72D7 \u{1F415}",
20
+ description: "\u4F60\u50CF\u4E00\u53EA\u70ED\u60C5\u7684\u72D7\u72D7\uFF0C\u5BF9\u670B\u53CB\u5FE0\u8BDA\uFF0C\u5145\u6EE1\u6D3B\u529B\u3002\u603B\u662F\u80FD\u7ED9\u5468\u56F4\u7684\u4EBA\u5E26\u6765\u6B22\u4E50\u548C\u6E29\u6696\u3002",
21
+ image: "\u{1F415}",
22
+ imageType: "emoji"
23
+ },
24
+ {
25
+ id: "animal-panda",
26
+ title: "\u53EF\u7231\u7684\u718A\u732B \u{1F43C}",
27
+ description: "\u4F60\u5C31\u50CF\u56FD\u5B9D\u718A\u732B\u4E00\u6837\uFF0C\u5446\u840C\u53EF\u7231\uFF0C\u4EBA\u89C1\u4EBA\u7231\u3002\u6162\u8282\u594F\u7684\u751F\u6D3B\u65B9\u5F0F\u8BA9\u4F60\u5145\u6EE1\u6CBB\u6108\u529B\u3002",
28
+ image: "\u{1F43C}",
29
+ imageType: "emoji"
30
+ },
31
+ {
32
+ id: "animal-fox",
33
+ title: "\u673A\u667A\u7684\u72D0\u72F8 \u{1F98A}",
34
+ description: "\u806A\u660E\u4F36\u4FD0\uFF0C\u53CD\u5E94\u654F\u6377\u3002\u4F60\u603B\u80FD\u7528\u667A\u6167\u89E3\u51B3\u95EE\u9898\uFF0C\u662F\u56E2\u961F\u4E2D\u7684\u667A\u56CA\u62C5\u5F53\u3002",
35
+ image: "\u{1F98A}",
36
+ imageType: "emoji"
37
+ },
38
+ {
39
+ id: "animal-owl",
40
+ title: "\u777F\u667A\u7684\u732B\u5934\u9E70 \u{1F989}",
41
+ description: "\u4F60\u50CF\u732B\u5934\u9E70\u4E00\u6837\u5145\u6EE1\u667A\u6167\uFF0C\u559C\u6B22\u5728\u591C\u6DF1\u4EBA\u9759\u65F6\u601D\u8003\u3002\u7406\u6027\u3001\u6C89\u7A33\u662F\u4F60\u7684\u6807\u7B7E\u3002",
42
+ image: "\u{1F989}",
43
+ imageType: "emoji"
44
+ },
45
+ {
46
+ id: "animal-dolphin",
47
+ title: "\u5FEB\u4E50\u7684\u6D77\u8C5A \u{1F42C}",
48
+ description: "\u6D3B\u6CFC\u5F00\u6717\uFF0C\u793E\u4EA4\u8FBE\u4EBA\u3002\u4F60\u7684\u7B11\u5BB9\u80FD\u591F\u611F\u67D3\u8EAB\u8FB9\u7684\u6BCF\u4E00\u4E2A\u4EBA\u3002",
49
+ image: "\u{1F42C}",
50
+ imageType: "emoji"
51
+ },
52
+ {
53
+ id: "animal-butterfly",
54
+ title: "\u81EA\u7531\u7684\u8774\u8776 \u{1F98B}",
55
+ description: "\u8FFD\u6C42\u81EA\u7531\uFF0C\u70ED\u7231\u7F8E\u597D\u4E8B\u7269\u3002\u4F60\u7684\u4EBA\u751F\u5145\u6EE1\u8272\u5F69\uFF0C\u4ECE\u4E0D\u88AB\u675F\u7F1A\u3002",
56
+ image: "\u{1F98B}",
57
+ imageType: "emoji"
58
+ },
59
+ {
60
+ id: "animal-lion",
61
+ title: "\u52C7\u6562\u7684\u72EE\u5B50 \u{1F981}",
62
+ description: "\u5929\u751F\u7684\u9886\u5BFC\u8005\uFF0C\u52C7\u6562\u679C\u65AD\u3002\u4F60\u7684\u6C14\u573A\u5F3A\u5927\uFF0C\u603B\u80FD\u6FC0\u52B1\u4ED6\u4EBA\u3002",
63
+ image: "\u{1F981}",
64
+ imageType: "emoji"
65
+ },
66
+ {
67
+ id: "animal-rabbit",
68
+ title: "\u6E29\u67D4\u7684\u5154\u5B50 \u{1F430}",
69
+ description: "\u5FC3\u5730\u5584\u826F\uFF0C\u6E29\u67D4\u4F53\u8D34\u3002\u4F60\u7684\u5B58\u5728\u5C31\u50CF\u6625\u5929\u7684\u5FAE\u98CE\uFF0C\u8BA9\u4EBA\u611F\u5230\u6E29\u6696\u3002",
70
+ image: "\u{1F430}",
71
+ imageType: "emoji"
72
+ },
73
+ {
74
+ id: "animal-penguin",
75
+ title: "\u5446\u840C\u7684\u4F01\u9E45 \u{1F427}",
76
+ description: "\u61A8\u6001\u53EF\u63AC\uFF0C\u8BA4\u771F\u6267\u7740\u3002\u867D\u7136\u770B\u8D77\u6765\u7B28\u62D9\uFF0C\u4F46\u505A\u4E8B\u4E00\u4E1D\u4E0D\u82DF\u3002",
77
+ image: "\u{1F427}",
78
+ imageType: "emoji"
79
+ },
80
+ {
81
+ id: "animal-eagle",
82
+ title: "\u7FF1\u7FD4\u7684\u96C4\u9E70 \u{1F985}",
83
+ description: "\u76EE\u5149\u8FDC\u5927\uFF0C\u5FD7\u5411\u9AD8\u8FDC\u3002\u4F60\u603B\u662F\u80FD\u770B\u5230\u522B\u4EBA\u770B\u4E0D\u5230\u7684\u673A\u4F1A\u3002",
84
+ image: "\u{1F985}",
85
+ imageType: "emoji"
86
+ },
87
+ {
88
+ id: "animal-koala",
89
+ title: "\u6175\u61D2\u7684\u8003\u62C9 \u{1F428}",
90
+ description: "\u4F5B\u7CFB\u751F\u6D3B\uFF0C\u77E5\u8DB3\u5E38\u4E50\u3002\u4F60\u61C2\u5F97\u4EAB\u53D7\u5F53\u4E0B\uFF0C\u6D3B\u5728\u81EA\u5DF1\u7684\u8282\u594F\u91CC\u3002",
91
+ image: "\u{1F428}",
92
+ imageType: "emoji"
93
+ },
94
+ {
95
+ id: "animal-sloth",
96
+ title: "\u60A0\u95F2\u7684\u6811\u61D2 \u{1F9A5}",
97
+ description: "\u6162\u6162\u6765\uFF0C\u6BD4\u8F83\u5FEB\u3002\u4F60\u76F8\u4FE1\u6025\u4E0D\u6765\u7684\u4E8B\u5C31\u4E0D\u8981\u6025\uFF0C\u4FDD\u6301\u81EA\u5DF1\u7684pace\u3002",
98
+ image: "\u{1F9A5}",
99
+ imageType: "emoji"
100
+ },
101
+ {
102
+ id: "animal-unicorn",
103
+ title: "\u68A6\u5E7B\u7684\u72EC\u89D2\u517D \u{1F984}",
104
+ description: "\u5145\u6EE1\u5E7B\u60F3\uFF0C\u8FFD\u6C42\u5B8C\u7F8E\u3002\u4F60\u7684\u4E16\u754C\u4E94\u5F69\u6591\u6593\uFF0C\u603B\u6709\u72EC\u7279\u7684\u60F3\u6CD5\u3002",
105
+ image: "\u{1F984}",
106
+ imageType: "emoji"
107
+ },
108
+ {
109
+ id: "animal-dragon",
110
+ title: "\u795E\u79D8\u7684\u9F99 \u{1F409}",
111
+ description: "\u5F3A\u5927\u800C\u795E\u79D8\uFF0C\u5145\u6EE1\u9B45\u529B\u3002\u4F60\u662F\u4F20\u8BF4\u4E2D\u7684\u5B58\u5728\uFF0C\u4EE4\u4EBA\u5411\u5F80\u3002",
112
+ image: "\u{1F409}",
113
+ imageType: "emoji"
114
+ },
115
+ // 星球系列 (16-25)
116
+ {
117
+ id: "planet-sun",
118
+ title: "\u6E29\u6696\u7684\u592A\u9633 \u2600\uFE0F",
119
+ description: "\u4F60\u5C31\u50CF\u592A\u9633\u4E00\u6837\uFF0C\u662F\u56E2\u961F\u7684\u80FD\u91CF\u6765\u6E90\uFF0C\u6E29\u6696\u7740\u5468\u56F4\u7684\u6BCF\u4E2A\u4EBA\u3002",
120
+ image: "\u2600\uFE0F",
121
+ imageType: "emoji"
122
+ },
123
+ {
124
+ id: "planet-moon",
125
+ title: "\u6E29\u67D4\u7684\u6708\u4EAE \u{1F319}",
126
+ description: "\u5B89\u9759\u800C\u6E29\u67D4\uFF0C\u5728\u9ED1\u6697\u4E2D\u7ED9\u4EBA\u5149\u660E\u3002\u4F60\u662F\u591C\u665A\u6700\u7F8E\u7684\u966A\u4F34\u3002",
127
+ image: "\u{1F319}",
128
+ imageType: "emoji"
129
+ },
130
+ {
131
+ id: "planet-star",
132
+ title: "\u95EA\u8000\u7684\u661F\u661F \u2B50",
133
+ description: "\u867D\u7136\u6E3A\u5C0F\uFF0C\u4F46\u59CB\u7EC8\u95EA\u8000\u3002\u4F60\u7528\u81EA\u5DF1\u7684\u65B9\u5F0F\u53D1\u5149\u53D1\u70ED\u3002",
134
+ image: "\u2B50",
135
+ imageType: "emoji"
136
+ },
137
+ {
138
+ id: "planet-earth",
139
+ title: "\u5305\u5BB9\u7684\u5730\u7403 \u{1F30D}",
140
+ description: "\u5305\u5BB9\u4E07\u7269\uFF0C\u751F\u673A\u52C3\u52C3\u3002\u4F60\u6709\u7740\u5BBD\u5E7F\u7684\u80F8\u6000\u548C\u65E0\u9650\u7684\u53EF\u80FD\u3002",
141
+ image: "\u{1F30D}",
142
+ imageType: "emoji"
143
+ },
144
+ {
145
+ id: "planet-saturn",
146
+ title: "\u72EC\u7279\u7684\u571F\u661F \u{1FA90}",
147
+ description: "\u4E0E\u4F17\u4E0D\u540C\uFF0C\u81EA\u6210\u4E00\u683C\u3002\u4F60\u7684\u4E2A\u6027\u5C31\u50CF\u571F\u661F\u73AF\u4E00\u6837\u4EE4\u4EBA\u7740\u8FF7\u3002",
148
+ image: "\u{1FA90}",
149
+ imageType: "emoji"
150
+ },
151
+ {
152
+ id: "weather-rainbow",
153
+ title: "\u7EDA\u4E3D\u7684\u5F69\u8679 \u{1F308}",
154
+ description: "\u98CE\u96E8\u8FC7\u540E\u89C1\u5F69\u8679\uFF0C\u4F60\u603B\u80FD\u5728\u56F0\u96BE\u540E\u770B\u5230\u5E0C\u671B\u548C\u7F8E\u597D\u3002",
155
+ image: "\u{1F308}",
156
+ imageType: "emoji"
157
+ },
158
+ {
159
+ id: "weather-cloud",
160
+ title: "\u98D8\u9038\u7684\u4E91\u6735 \u2601\uFE0F",
161
+ description: "\u81EA\u7531\u81EA\u5728\uFF0C\u968F\u98CE\u98D8\u8361\u3002\u4F60\u4E0D\u88AB\u5B9A\u4E49\uFF0C\u6C38\u8FDC\u5145\u6EE1\u53EF\u80FD\u3002",
162
+ image: "\u2601\uFE0F",
163
+ imageType: "emoji"
164
+ },
165
+ {
166
+ id: "weather-lightning",
167
+ title: "\u95EA\u7535 \u26A1",
168
+ description: "\u7206\u53D1\u529B\u5F3A\uFF0C\u884C\u52A8\u8FC5\u901F\u3002\u4F60\u7684\u80FD\u91CF\u5C31\u50CF\u95EA\u7535\u4E00\u6837\u4EE4\u4EBA\u9707\u64BC\u3002",
169
+ image: "\u26A1",
170
+ imageType: "emoji"
171
+ },
172
+ {
173
+ id: "weather-snowflake",
174
+ title: "\u72EC\u7279\u7684\u96EA\u82B1 \u2744\uFE0F",
175
+ description: "\u4E16\u754C\u4E0A\u6CA1\u6709\u4E24\u7247\u76F8\u540C\u7684\u96EA\u82B1\uFF0C\u4F60\u4E5F\u662F\u72EC\u4E00\u65E0\u4E8C\u7684\u5B58\u5728\u3002",
176
+ image: "\u2744\uFE0F",
177
+ imageType: "emoji"
178
+ },
179
+ {
180
+ id: "weather-fire",
181
+ title: "\u70ED\u60C5\u7684\u706B\u7130 \u{1F525}",
182
+ description: "\u70ED\u60C5\u4F3C\u706B\uFF0C\u5145\u6EE1\u6FC0\u60C5\u3002\u4F60\u7684\u5B58\u5728\u80FD\u70B9\u71C3\u5468\u56F4\u7684\u6C14\u6C1B\u3002",
183
+ image: "\u{1F525}",
184
+ imageType: "emoji"
185
+ },
186
+ // 植物系列 (26-35)
187
+ {
188
+ id: "plant-tree",
189
+ title: "\u575A\u97E7\u7684\u5927\u6811 \u{1F333}",
190
+ description: "\u7A33\u91CD\u53EF\u9760\uFF0C\u6839\u57FA\u6DF1\u539A\u3002\u4F60\u662F\u5927\u5BB6\u53EF\u4EE5\u4F9D\u9760\u7684\u5B58\u5728\u3002",
191
+ image: "\u{1F333}",
192
+ imageType: "emoji"
193
+ },
194
+ {
195
+ id: "plant-flower",
196
+ title: "\u7F8E\u4E3D\u7684\u82B1\u6735 \u{1F338}",
197
+ description: "\u7EFD\u653E\u81EA\u6211\uFF0C\u7F8E\u4E3D\u52A8\u4EBA\u3002\u4F60\u7684\u5B58\u5728\u5C31\u662F\u4E00\u9053\u9753\u4E3D\u7684\u98CE\u666F\u3002",
198
+ image: "\u{1F338}",
199
+ imageType: "emoji"
200
+ },
201
+ {
202
+ id: "plant-sunflower",
203
+ title: "\u5411\u9633\u7684\u5411\u65E5\u8475 \u{1F33B}",
204
+ description: "\u6C38\u8FDC\u5411\u7740\u9633\u5149\uFF0C\u79EF\u6781\u5411\u4E0A\u3002\u4F60\u7684\u4E50\u89C2\u611F\u67D3\u7740\u6BCF\u4E2A\u4EBA\u3002",
205
+ image: "\u{1F33B}",
206
+ imageType: "emoji"
207
+ },
208
+ {
209
+ id: "plant-rose",
210
+ title: "\u4F18\u96C5\u7684\u73AB\u7470 \u{1F339}",
211
+ description: "\u9AD8\u8D35\u4F18\u96C5\uFF0C\u5145\u6EE1\u9B45\u529B\u3002\u867D\u6709\u523A\u4F46\u66F4\u6709\u7F8E\u4E3D\u3002",
212
+ image: "\u{1F339}",
213
+ imageType: "emoji"
214
+ },
215
+ {
216
+ id: "plant-cactus",
217
+ title: "\u575A\u5F3A\u7684\u4ED9\u4EBA\u638C \u{1F335}",
218
+ description: "\u5728\u8270\u96BE\u73AF\u5883\u4E2D\u4F9D\u7136\u575A\u5F3A\u3002\u4F60\u7684\u97E7\u6027\u4EE4\u4EBA\u656C\u4F69\u3002",
219
+ image: "\u{1F335}",
220
+ imageType: "emoji"
221
+ },
222
+ {
223
+ id: "plant-clover",
224
+ title: "\u5E78\u8FD0\u7684\u56DB\u53F6\u8349 \u{1F340}",
225
+ description: "\u5E78\u8FD0\u7684\u8C61\u5F81\uFF0C\u603B\u80FD\u7ED9\u4EBA\u5E26\u6765\u597D\u8FD0\u548C\u5E0C\u671B\u3002",
226
+ image: "\u{1F340}",
227
+ imageType: "emoji"
228
+ },
229
+ {
230
+ id: "plant-maple",
231
+ title: "\u6D6A\u6F2B\u7684\u67AB\u53F6 \u{1F341}",
232
+ description: "\u6D6A\u6F2B\u800C\u8BD7\u610F\uFF0C\u4F60\u7684\u4E16\u754C\u5145\u6EE1\u827A\u672F\u6C14\u606F\u3002",
233
+ image: "\u{1F341}",
234
+ imageType: "emoji"
235
+ },
236
+ {
237
+ id: "plant-mushroom",
238
+ title: "\u795E\u79D8\u7684\u8611\u83C7 \u{1F344}",
239
+ description: "\u4F4E\u8C03\u795E\u79D8\uFF0C\u603B\u6709\u610F\u60F3\u4E0D\u5230\u7684\u60CA\u559C\u3002",
240
+ image: "\u{1F344}",
241
+ imageType: "emoji"
242
+ },
243
+ {
244
+ id: "plant-cherry",
245
+ title: "\u6D6A\u6F2B\u7684\u6A31\u82B1 \u{1F338}",
246
+ description: "\u77ED\u6682\u800C\u7F8E\u597D\uFF0C\u4F60\u73CD\u60DC\u6BCF\u4E00\u4E2A\u77AC\u95F4\u7684\u7F8E\u4E3D\u3002",
247
+ image: "\u{1F338}",
248
+ imageType: "emoji"
249
+ },
250
+ {
251
+ id: "plant-bamboo",
252
+ title: "\u575A\u97E7\u7684\u7AF9\u5B50 \u{1F38B}",
253
+ description: "\u865A\u5FC3\u6709\u8282\uFF0C\u6108\u632B\u6108\u52C7\u3002\u4F60\u7684\u7CBE\u795E\u503C\u5F97\u5B66\u4E60\u3002",
254
+ image: "\u{1F38B}",
255
+ imageType: "emoji"
256
+ },
257
+ // 食物系列 (36-45)
258
+ {
259
+ id: "food-coffee",
260
+ title: "\u63D0\u795E\u7684\u5496\u5561 \u2615",
261
+ description: "\u4F60\u5C31\u50CF\u5496\u5561\uFF0C\u662F\u5927\u5BB6\u7684\u80FD\u91CF\u6765\u6E90\uFF0C\u5E2E\u52A9\u4ED6\u4EBA\u4FDD\u6301\u6D3B\u529B\u3002",
262
+ image: "\u2615",
263
+ imageType: "emoji"
264
+ },
265
+ {
266
+ id: "food-pizza",
267
+ title: "\u5FEB\u4E50\u7684\u62AB\u8428 \u{1F355}",
268
+ description: "\u4EBA\u89C1\u4EBA\u7231\uFF0C\u603B\u80FD\u5E26\u6765\u5FEB\u4E50\u3002\u4F60\u662F\u805A\u4F1A\u7684\u7075\u9B42\u3002",
269
+ image: "\u{1F355}",
270
+ imageType: "emoji"
271
+ },
272
+ {
273
+ id: "food-cookie",
274
+ title: "\u751C\u871C\u7684\u997C\u5E72 \u{1F36A}",
275
+ description: "\u6E29\u6696\u751C\u871C\uFF0C\u7ED9\u4EBAcomfort\u3002\u4F60\u662F\u6700\u597D\u7684\u6CBB\u6108\u7CFB\u5B58\u5728\u3002",
276
+ image: "\u{1F36A}",
277
+ imageType: "emoji"
278
+ },
279
+ {
280
+ id: "food-icecream",
281
+ title: "\u6E05\u51C9\u7684\u51B0\u6DC7\u6DCB \u{1F366}",
282
+ description: "\u751C\u7F8E\u53EF\u7231\uFF0C\u5728\u708E\u70ED\u65F6\u7ED9\u4EBA\u6E05\u51C9\u3002\u4F60\u603B\u80FD\u5728\u5173\u952E\u65F6\u523B\u51FA\u73B0\u3002",
283
+ image: "\u{1F366}",
284
+ imageType: "emoji"
285
+ },
286
+ {
287
+ id: "food-honey",
288
+ title: "\u751C\u871C\u7684\u8702\u871C \u{1F36F}",
289
+ description: "\u5929\u7136\u751C\u7F8E\uFF0C\u7EAF\u7CB9\u53EF\u7231\u3002\u4F60\u7684\u5B58\u5728\u5C31\u662F\u5E78\u798F\u7684\u5473\u9053\u3002",
290
+ image: "\u{1F36F}",
291
+ imageType: "emoji"
292
+ },
293
+ {
294
+ id: "food-sushi",
295
+ title: "\u7CBE\u81F4\u7684\u5BFF\u53F8 \u{1F363}",
296
+ description: "\u7CBE\u81F4\u4F18\u96C5\uFF0C\u6CE8\u91CD\u7EC6\u8282\u3002\u4F60\u5BF9\u751F\u6D3B\u6709\u7740\u72EC\u7279\u7684\u54C1\u5473\u3002",
297
+ image: "\u{1F363}",
298
+ imageType: "emoji"
299
+ },
300
+ {
301
+ id: "food-cake",
302
+ title: "\u751C\u7F8E\u7684\u86CB\u7CD5 \u{1F382}",
303
+ description: "\u751C\u871C\u7F8E\u597D\uFF0C\u662F\u5E86\u795D\u7684\u8C61\u5F81\u3002\u4F60\u603B\u80FD\u7ED9\u4EBA\u5E26\u6765\u60CA\u559C\u3002",
304
+ image: "\u{1F382}",
305
+ imageType: "emoji"
306
+ },
307
+ {
308
+ id: "food-donut",
309
+ title: "\u53EF\u7231\u7684\u751C\u751C\u5708 \u{1F369}",
310
+ description: "\u5706\u5706\u6EE1\u6EE1\uFF0C\u751C\u871C\u53EF\u7231\u3002\u4F60\u7684\u5B58\u5728\u8BA9\u751F\u6D3B\u66F4\u7F8E\u597D\u3002",
311
+ image: "\u{1F369}",
312
+ imageType: "emoji"
313
+ },
314
+ {
315
+ id: "food-lollipop",
316
+ title: "\u7AE5\u771F\u7684\u68D2\u68D2\u7CD6 \u{1F36D}",
317
+ description: "\u4FDD\u6301\u7AE5\u5FC3\uFF0C\u6C38\u8FDC\u5E74\u8F7B\u3002\u4F60\u7684\u7EAF\u771F\u4EE4\u4EBA\u7FA1\u6155\u3002",
318
+ image: "\u{1F36D}",
319
+ imageType: "emoji"
320
+ },
321
+ {
322
+ id: "food-watermelon",
323
+ title: "\u6E05\u723D\u7684\u897F\u74DC \u{1F349}",
324
+ description: "\u6E05\u723D\u89E3\u6E34\uFF0C\u590F\u65E5\u5FC5\u5907\u3002\u4F60\u603B\u80FD\u5E26\u6765\u6E05\u65B0\u7684\u611F\u89C9\u3002",
325
+ image: "\u{1F349}",
326
+ imageType: "emoji"
327
+ }
328
+ ];
329
+ if (DEFAULT_RESULTS.length !== 45) {
330
+ console.warn("\u7ED3\u679C\u6570\u636E\u96C6\u5E94\u5305\u542B45\u9879\uFF0C\u5F53\u524D: " + DEFAULT_RESULTS.length);
331
+ }
332
+
333
+ // src/business/testYourself/admin/ConfigManager.tsx
334
+ var ConfigManager = ({
335
+ configService,
336
+ onConfigChange,
337
+ className = "",
338
+ onImageUpload
339
+ }) => {
340
+ const [configs, setConfigs] = useState([]);
341
+ const [selectedConfig, setSelectedConfig] = useState(null);
342
+ const [isEditing, setIsEditing] = useState(false);
343
+ const [isCreating, setIsCreating] = useState(false);
344
+ const [loading, setLoading] = useState(true);
345
+ const [error, setError] = useState(null);
346
+ const [success, setSuccess] = useState(null);
347
+ const [editForm, setEditForm] = useState({
348
+ name: "",
349
+ description: "",
350
+ gameTitle: "",
351
+ gameDescription: "",
352
+ buttonText: "\u957F\u6309\u5F00\u59CB\u6D4B\u8BD5",
353
+ longPressDuration: 2e3,
354
+ results: []
355
+ });
356
+ const loadConfigs = useCallback(async () => {
357
+ try {
358
+ setLoading(true);
359
+ const allConfigs = await configService.getAllConfigs();
360
+ setConfigs(allConfigs);
361
+ onConfigChange?.(allConfigs);
362
+ } catch (err) {
363
+ setError("\u52A0\u8F7D\u914D\u7F6E\u5931\u8D25: " + err.message);
364
+ } finally {
365
+ setLoading(false);
366
+ }
367
+ }, [configService, onConfigChange]);
368
+ useEffect(() => {
369
+ loadConfigs();
370
+ }, [loadConfigs]);
371
+ const handleStartCreate = () => {
372
+ setEditForm({
373
+ name: "\u65B0\u914D\u7F6E",
374
+ description: "",
375
+ gameTitle: "\u6D4B\u6D4B\u4F60\u662F\u4EC0\u4E48",
376
+ gameDescription: "\u957F\u6309\u6309\u94AE\uFF0C\u53D1\u73B0\u4F60\u7684\u4E13\u5C5E\u5C5E\u6027",
377
+ buttonText: "\u957F\u6309\u5F00\u59CB\u6D4B\u8BD5",
378
+ longPressDuration: 2e3,
379
+ results: []
380
+ });
381
+ setIsCreating(true);
382
+ setIsEditing(true);
383
+ setSelectedConfig(null);
384
+ };
385
+ const handleStartEdit = (config) => {
386
+ setEditForm({
387
+ name: config.name,
388
+ description: config.description || "",
389
+ gameTitle: config.config.gameTitle,
390
+ gameDescription: config.config.gameDescription || "",
391
+ buttonText: config.config.buttonText || "\u957F\u6309\u5F00\u59CB\u6D4B\u8BD5",
392
+ longPressDuration: config.config.longPressDuration || 2e3,
393
+ results: config.config.results
394
+ });
395
+ setIsCreating(false);
396
+ setIsEditing(true);
397
+ setSelectedConfig(config);
398
+ };
399
+ const handleCancelEdit = () => {
400
+ setIsEditing(false);
401
+ setIsCreating(false);
402
+ setSelectedConfig(null);
403
+ setError(null);
404
+ };
405
+ const handleSave = async () => {
406
+ try {
407
+ setError(null);
408
+ if (!editForm.name.trim()) {
409
+ setError("\u8BF7\u8F93\u5165\u914D\u7F6E\u540D\u79F0");
410
+ return;
411
+ }
412
+ if (!editForm.gameTitle.trim()) {
413
+ setError("\u8BF7\u8F93\u5165\u6E38\u620F\u6807\u9898");
414
+ return;
415
+ }
416
+ if (editForm.results.length === 0) {
417
+ setError("\u8BF7\u81F3\u5C11\u6DFB\u52A0\u4E00\u4E2A\u7ED3\u679C\u9879");
418
+ return;
419
+ }
420
+ const testConfig = {
421
+ gameTitle: editForm.gameTitle,
422
+ gameDescription: editForm.gameDescription,
423
+ buttonText: editForm.buttonText,
424
+ longPressDuration: editForm.longPressDuration,
425
+ results: editForm.results
426
+ };
427
+ if (isCreating) {
428
+ await configService.createConfig(
429
+ editForm.name,
430
+ testConfig,
431
+ editForm.description
432
+ );
433
+ setSuccess("\u521B\u5EFA\u914D\u7F6E\u6210\u529F\uFF01");
434
+ } else if (selectedConfig) {
435
+ await configService.updateConfig(selectedConfig.id, {
436
+ name: editForm.name,
437
+ description: editForm.description,
438
+ config: testConfig
439
+ });
440
+ setSuccess("\u66F4\u65B0\u914D\u7F6E\u6210\u529F\uFF01");
441
+ }
442
+ await loadConfigs();
443
+ handleCancelEdit();
444
+ setTimeout(() => setSuccess(null), 3e3);
445
+ } catch (err) {
446
+ setError("\u4FDD\u5B58\u5931\u8D25: " + err.message);
447
+ }
448
+ };
449
+ const handleDelete = async (id) => {
450
+ if (!confirm("\u786E\u5B9A\u8981\u5220\u9664\u8FD9\u4E2A\u914D\u7F6E\u5417\uFF1F")) return;
451
+ try {
452
+ await configService.deleteConfig(id);
453
+ await loadConfigs();
454
+ setSuccess("\u5220\u9664\u6210\u529F\uFF01");
455
+ setTimeout(() => setSuccess(null), 3e3);
456
+ } catch (err) {
457
+ setError("\u5220\u9664\u5931\u8D25: " + err.message);
458
+ }
459
+ };
460
+ const handleDuplicate = async (id) => {
461
+ try {
462
+ await configService.duplicateConfig(id);
463
+ await loadConfigs();
464
+ setSuccess("\u590D\u5236\u6210\u529F\uFF01");
465
+ setTimeout(() => setSuccess(null), 3e3);
466
+ } catch (err) {
467
+ setError("\u590D\u5236\u5931\u8D25: " + err.message);
468
+ }
469
+ };
470
+ const handleSetDefault = async (id) => {
471
+ try {
472
+ await configService.setDefaultConfig(id);
473
+ await loadConfigs();
474
+ setSuccess("\u8BBE\u7F6E\u9ED8\u8BA4\u914D\u7F6E\u6210\u529F\uFF01");
475
+ setTimeout(() => setSuccess(null), 3e3);
476
+ } catch (err) {
477
+ setError("\u8BBE\u7F6E\u5931\u8D25: " + err.message);
478
+ }
479
+ };
480
+ const handleExport = async (id) => {
481
+ try {
482
+ const jsonString = await configService.exportConfig(id);
483
+ const blob = new Blob([jsonString], { type: "application/json" });
484
+ const url = URL.createObjectURL(blob);
485
+ const a = document.createElement("a");
486
+ a.href = url;
487
+ a.download = "config_" + id + ".json";
488
+ document.body.appendChild(a);
489
+ a.click();
490
+ document.body.removeChild(a);
491
+ URL.revokeObjectURL(url);
492
+ setSuccess("\u5BFC\u51FA\u6210\u529F\uFF01");
493
+ setTimeout(() => setSuccess(null), 3e3);
494
+ } catch (err) {
495
+ setError("\u5BFC\u51FA\u5931\u8D25: " + err.message);
496
+ }
497
+ };
498
+ const handleImport = async () => {
499
+ const input = document.createElement("input");
500
+ input.type = "file";
501
+ input.accept = ".json";
502
+ input.onchange = async (e) => {
503
+ const file = e.target.files?.[0];
504
+ if (!file) return;
505
+ try {
506
+ const text = await file.text();
507
+ await configService.importConfig(text);
508
+ await loadConfigs();
509
+ setSuccess("\u5BFC\u5165\u6210\u529F\uFF01");
510
+ setTimeout(() => setSuccess(null), 3e3);
511
+ } catch (err) {
512
+ setError("\u5BFC\u5165\u5931\u8D25: " + err.message);
513
+ }
514
+ };
515
+ input.click();
516
+ };
517
+ const handleAddResult = () => {
518
+ const newResult = {
519
+ id: "temp_" + Date.now(),
520
+ _tempId: "temp_" + Date.now(),
521
+ title: "\u65B0\u7ED3\u679C",
522
+ description: "\u8FD9\u662F\u4E00\u4E2A\u65B0\u7684\u7ED3\u679C\u63CF\u8FF0",
523
+ image: "\u{1F389}",
524
+ imageType: "emoji"
525
+ };
526
+ setEditForm({
527
+ ...editForm,
528
+ results: [...editForm.results, newResult]
529
+ });
530
+ };
531
+ const handleDeleteResult = (index) => {
532
+ const newResults = [...editForm.results];
533
+ newResults.splice(index, 1);
534
+ setEditForm({ ...editForm, results: newResults });
535
+ };
536
+ const handleUpdateResult = (index, updates) => {
537
+ const newResults = [...editForm.results];
538
+ newResults[index] = { ...newResults[index], ...updates };
539
+ setEditForm({ ...editForm, results: newResults });
540
+ };
541
+ const handleResultImageUpload = async (index, file) => {
542
+ try {
543
+ if (!onImageUpload) {
544
+ const reader = new FileReader();
545
+ reader.onload = (e) => {
546
+ const base64 = e.target?.result;
547
+ handleUpdateResult(index, {
548
+ image: base64,
549
+ imageType: "url"
550
+ });
551
+ };
552
+ reader.readAsDataURL(file);
553
+ } else {
554
+ const url = await onImageUpload(file);
555
+ handleUpdateResult(index, {
556
+ image: url,
557
+ imageType: "url"
558
+ });
559
+ }
560
+ } catch (err) {
561
+ setError("\u4E0A\u4F20\u56FE\u7247\u5931\u8D25: " + err.message);
562
+ }
563
+ };
564
+ const handleUseDefaultResults = () => {
565
+ if (confirm("\u786E\u5B9A\u8981\u4F7F\u7528\u9ED8\u8BA4\u768445\u4E2A\u7ED3\u679C\u5417\uFF1F\u8FD9\u5C06\u66FF\u6362\u5F53\u524D\u7684\u6240\u6709\u7ED3\u679C\u3002")) {
566
+ setEditForm({ ...editForm, results: DEFAULT_RESULTS });
567
+ }
568
+ };
569
+ const renderConfigList = () => /* @__PURE__ */ React.createElement("div", { className: "space-y-4" }, configs.map((config) => /* @__PURE__ */ React.createElement(
570
+ "div",
571
+ {
572
+ key: config.id,
573
+ className: "bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4 border border-gray-200 dark:border-gray-700 hover:shadow-md transition-shadow"
574
+ },
575
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-start justify-between" }, /* @__PURE__ */ React.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React.createElement("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white" }, config.name), config.isDefault && /* @__PURE__ */ React.createElement("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200" }, /* @__PURE__ */ React.createElement(Star, { className: "w-3 h-3" }), "\u9ED8\u8BA4")), config.description && /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-2" }, config.description), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-4 text-xs text-gray-500 dark:text-gray-400" }, /* @__PURE__ */ React.createElement("span", null, "\u7ED3\u679C\u6570: ", config.config.results.length), /* @__PURE__ */ React.createElement("span", null, "\u521B\u5EFA: ", new Date(config.createdAt).toLocaleDateString()))), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement(
576
+ "button",
577
+ {
578
+ onClick: () => handleSetDefault(config.id),
579
+ disabled: config.isDefault,
580
+ className: "p-2 text-gray-600 hover:text-yellow-600 disabled:opacity-50 disabled:cursor-not-allowed",
581
+ title: "\u8BBE\u4E3A\u9ED8\u8BA4"
582
+ },
583
+ /* @__PURE__ */ React.createElement(Star, { className: "w-5 h-5" })
584
+ ), /* @__PURE__ */ React.createElement(
585
+ "button",
586
+ {
587
+ onClick: () => handleStartEdit(config),
588
+ className: "p-2 text-gray-600 hover:text-blue-600",
589
+ title: "\u7F16\u8F91"
590
+ },
591
+ /* @__PURE__ */ React.createElement(Edit, { className: "w-5 h-5" })
592
+ ), /* @__PURE__ */ React.createElement(
593
+ "button",
594
+ {
595
+ onClick: () => handleDuplicate(config.id),
596
+ className: "p-2 text-gray-600 hover:text-green-600",
597
+ title: "\u590D\u5236"
598
+ },
599
+ /* @__PURE__ */ React.createElement(Copy, { className: "w-5 h-5" })
600
+ ), /* @__PURE__ */ React.createElement(
601
+ "button",
602
+ {
603
+ onClick: () => handleExport(config.id),
604
+ className: "p-2 text-gray-600 hover:text-purple-600",
605
+ title: "\u5BFC\u51FA"
606
+ },
607
+ /* @__PURE__ */ React.createElement(Download, { className: "w-5 h-5" })
608
+ ), /* @__PURE__ */ React.createElement(
609
+ "button",
610
+ {
611
+ onClick: () => handleDelete(config.id),
612
+ className: "p-2 text-gray-600 hover:text-red-600",
613
+ title: "\u5220\u9664"
614
+ },
615
+ /* @__PURE__ */ React.createElement(Trash2, { className: "w-5 h-5" })
616
+ )))
617
+ )));
618
+ const renderResultEditor = (result, index) => /* @__PURE__ */ React.createElement(
619
+ "div",
620
+ {
621
+ key: result._tempId || result.id,
622
+ className: "bg-gray-50 dark:bg-gray-700 rounded-lg p-4 space-y-3"
623
+ },
624
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-start justify-between" }, /* @__PURE__ */ React.createElement("h4", { className: "text-sm font-medium text-gray-700 dark:text-gray-300" }, "\u7ED3\u679C #", index + 1), /* @__PURE__ */ React.createElement(
625
+ "button",
626
+ {
627
+ onClick: () => handleDeleteResult(index),
628
+ className: "text-red-600 hover:text-red-700"
629
+ },
630
+ /* @__PURE__ */ React.createElement(Trash2, { className: "w-4 h-4" })
631
+ )),
632
+ /* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" }, "\u6807\u9898"), /* @__PURE__ */ React.createElement(
633
+ "input",
634
+ {
635
+ type: "text",
636
+ value: result.title,
637
+ onChange: (e) => handleUpdateResult(index, { title: e.target.value }),
638
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white",
639
+ placeholder: "\u4F8B\u5982: \u53EF\u7231\u7684\u732B\u54AA"
640
+ }
641
+ )), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" }, "\u56FE\u7247/Emoji"), /* @__PURE__ */ React.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React.createElement(
642
+ "input",
643
+ {
644
+ type: "text",
645
+ value: result.image,
646
+ onChange: (e) => handleUpdateResult(index, { image: e.target.value }),
647
+ className: "flex-1 px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white",
648
+ placeholder: "\u{1F389} \u6216 URL"
649
+ }
650
+ ), /* @__PURE__ */ React.createElement("label", { className: "cursor-pointer inline-flex items-center justify-center px-3 py-2 bg-blue-50 dark:bg-blue-900 text-blue-600 dark:text-blue-200 rounded-lg hover:bg-blue-100 dark:hover:bg-blue-800" }, /* @__PURE__ */ React.createElement(Image, { className: "w-5 h-5" }), /* @__PURE__ */ React.createElement(
651
+ "input",
652
+ {
653
+ type: "file",
654
+ accept: "image/*",
655
+ className: "hidden",
656
+ onChange: (e) => {
657
+ const file = e.target.files?.[0];
658
+ if (file) handleResultImageUpload(index, file);
659
+ }
660
+ }
661
+ ))))),
662
+ /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1" }, "\u63CF\u8FF0"), /* @__PURE__ */ React.createElement(
663
+ "textarea",
664
+ {
665
+ value: result.description,
666
+ onChange: (e) => handleUpdateResult(index, { description: e.target.value }),
667
+ rows: 2,
668
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white",
669
+ placeholder: "\u8FD9\u4E2A\u7ED3\u679C\u7684\u8BE6\u7EC6\u63CF\u8FF0..."
670
+ }
671
+ )),
672
+ result.image && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 p-2 bg-white dark:bg-gray-600 rounded border border-gray-200 dark:border-gray-500" }, /* @__PURE__ */ React.createElement("span", { className: "text-sm text-gray-500 dark:text-gray-400" }, "\u9884\u89C8:"), result.imageType === "emoji" ? /* @__PURE__ */ React.createElement("span", { className: "text-2xl" }, result.image) : /* @__PURE__ */ React.createElement("img", { src: result.image, alt: result.title, className: "w-8 h-8 object-cover rounded" }), /* @__PURE__ */ React.createElement("span", { className: "text-sm font-medium text-gray-700 dark:text-gray-300" }, result.title))
673
+ );
674
+ const renderEditForm = () => /* @__PURE__ */ React.createElement("div", { className: "space-y-6" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between" }, /* @__PURE__ */ React.createElement("h2", { className: "text-2xl font-bold text-gray-900 dark:text-white" }, isCreating ? "\u521B\u5EFA\u65B0\u914D\u7F6E" : "\u7F16\u8F91\u914D\u7F6E"), /* @__PURE__ */ React.createElement(
675
+ "button",
676
+ {
677
+ onClick: handleCancelEdit,
678
+ className: "p-2 text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200"
679
+ },
680
+ /* @__PURE__ */ React.createElement(X, { className: "w-6 h-6" })
681
+ )), /* @__PURE__ */ React.createElement("div", { className: "space-y-4 bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm border border-gray-200 dark:border-gray-700" }, /* @__PURE__ */ React.createElement("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white mb-4" }, "\u57FA\u672C\u4FE1\u606F"), /* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" }, "\u914D\u7F6E\u540D\u79F0 *"), /* @__PURE__ */ React.createElement(
682
+ "input",
683
+ {
684
+ type: "text",
685
+ value: editForm.name,
686
+ onChange: (e) => setEditForm({ ...editForm, name: e.target.value }),
687
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white",
688
+ placeholder: "\u4F8B\u5982: \u52A8\u7269\u4E3B\u9898\u6D4B\u8BD5"
689
+ }
690
+ )), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" }, "\u6E38\u620F\u6807\u9898 *"), /* @__PURE__ */ React.createElement(
691
+ "input",
692
+ {
693
+ type: "text",
694
+ value: editForm.gameTitle,
695
+ onChange: (e) => setEditForm({ ...editForm, gameTitle: e.target.value }),
696
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white",
697
+ placeholder: "\u4F8B\u5982: \u6D4B\u6D4B\u4F60\u662F\u4EC0\u4E48\u52A8\u7269"
698
+ }
699
+ ))), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" }, "\u914D\u7F6E\u63CF\u8FF0"), /* @__PURE__ */ React.createElement(
700
+ "textarea",
701
+ {
702
+ value: editForm.description,
703
+ onChange: (e) => setEditForm({ ...editForm, description: e.target.value }),
704
+ rows: 2,
705
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white",
706
+ placeholder: "\u7B80\u8981\u63CF\u8FF0\u8FD9\u4E2A\u914D\u7F6E\u7684\u7528\u9014..."
707
+ }
708
+ )), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" }, "\u6E38\u620F\u63CF\u8FF0"), /* @__PURE__ */ React.createElement(
709
+ "input",
710
+ {
711
+ type: "text",
712
+ value: editForm.gameDescription,
713
+ onChange: (e) => setEditForm({ ...editForm, gameDescription: e.target.value }),
714
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white",
715
+ placeholder: "\u4F8B\u5982: \u957F\u6309\u6309\u94AE\uFF0C\u53D1\u73B0\u4F60\u7684\u4E13\u5C5E\u5C5E\u6027"
716
+ }
717
+ )), /* @__PURE__ */ React.createElement("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4" }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" }, "\u6309\u94AE\u6587\u672C"), /* @__PURE__ */ React.createElement(
718
+ "input",
719
+ {
720
+ type: "text",
721
+ value: editForm.buttonText,
722
+ onChange: (e) => setEditForm({ ...editForm, buttonText: e.target.value }),
723
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white"
724
+ }
725
+ )), /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("label", { className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2" }, "\u957F\u6309\u65F6\u95F4 (\u6BEB\u79D2)"), /* @__PURE__ */ React.createElement(
726
+ "input",
727
+ {
728
+ type: "number",
729
+ value: editForm.longPressDuration,
730
+ onChange: (e) => setEditForm({ ...editForm, longPressDuration: parseInt(e.target.value) || 2e3 }),
731
+ className: "w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:text-white",
732
+ min: "500",
733
+ step: "100"
734
+ }
735
+ )))), /* @__PURE__ */ React.createElement("div", { className: "bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm border border-gray-200 dark:border-gray-700" }, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between mb-4" }, /* @__PURE__ */ React.createElement("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white" }, "\u7ED3\u679C\u5217\u8868 (", editForm.results.length, ")"), /* @__PURE__ */ React.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React.createElement(
736
+ "button",
737
+ {
738
+ onClick: handleUseDefaultResults,
739
+ className: "inline-flex items-center gap-2 px-3 py-1.5 text-sm bg-purple-50 dark:bg-purple-900 text-purple-600 dark:text-purple-200 rounded-lg hover:bg-purple-100 dark:hover:bg-purple-800"
740
+ },
741
+ "\u4F7F\u7528\u9ED8\u8BA4\u7ED3\u679C"
742
+ ), /* @__PURE__ */ React.createElement(
743
+ "button",
744
+ {
745
+ onClick: handleAddResult,
746
+ className: "inline-flex items-center gap-2 px-3 py-1.5 text-sm bg-blue-50 dark:bg-blue-900 text-blue-600 dark:text-blue-200 rounded-lg hover:bg-blue-100 dark:hover:bg-blue-800"
747
+ },
748
+ /* @__PURE__ */ React.createElement(Plus, { className: "w-4 h-4" }),
749
+ "\u6DFB\u52A0\u7ED3\u679C"
750
+ ))), /* @__PURE__ */ React.createElement("div", { className: "space-y-3 max-h-[500px] overflow-y-auto" }, editForm.results.length === 0 ? /* @__PURE__ */ React.createElement("div", { className: "text-center py-8 text-gray-500 dark:text-gray-400" }, /* @__PURE__ */ React.createElement("p", null, "\u8FD8\u6CA1\u6709\u6DFB\u52A0\u4EFB\u4F55\u7ED3\u679C"), /* @__PURE__ */ React.createElement("p", { className: "text-sm mt-2" }, '\u70B9\u51FB"\u6DFB\u52A0\u7ED3\u679C"\u6216"\u4F7F\u7528\u9ED8\u8BA4\u7ED3\u679C"\u5F00\u59CB')) : editForm.results.map((result, index) => renderResultEditor(result, index)))), /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-end gap-3" }, /* @__PURE__ */ React.createElement(
751
+ "button",
752
+ {
753
+ onClick: handleCancelEdit,
754
+ className: "px-6 py-2 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700"
755
+ },
756
+ "\u53D6\u6D88"
757
+ ), /* @__PURE__ */ React.createElement(
758
+ "button",
759
+ {
760
+ onClick: handleSave,
761
+ className: "inline-flex items-center gap-2 px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
762
+ },
763
+ /* @__PURE__ */ React.createElement(Save, { className: "w-5 h-5" }),
764
+ "\u4FDD\u5B58\u914D\u7F6E"
765
+ )));
766
+ if (loading) {
767
+ return /* @__PURE__ */ React.createElement("div", { className: clsx("p-8", className) }, /* @__PURE__ */ React.createElement("div", { className: "text-center" }, /* @__PURE__ */ React.createElement("div", { className: "inline-block w-8 h-8 border-4 border-blue-600 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-gray-600 dark:text-gray-400" }, "\u52A0\u8F7D\u4E2D...")));
768
+ }
769
+ return /* @__PURE__ */ React.createElement("div", { className: clsx("p-6", className) }, error && /* @__PURE__ */ React.createElement("div", { className: "mb-4 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg flex items-center gap-2 text-red-800 dark:text-red-200" }, /* @__PURE__ */ React.createElement(AlertCircle, { className: "w-5 h-5 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", null, error), /* @__PURE__ */ React.createElement("button", { onClick: () => setError(null), className: "ml-auto" }, /* @__PURE__ */ React.createElement(X, { className: "w-5 h-5" }))), success && /* @__PURE__ */ React.createElement("div", { className: "mb-4 p-4 bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-lg flex items-center gap-2 text-green-800 dark:text-green-200" }, /* @__PURE__ */ React.createElement(CheckCircle2, { className: "w-5 h-5 flex-shrink-0" }), /* @__PURE__ */ React.createElement("span", null, success), /* @__PURE__ */ React.createElement("button", { onClick: () => setSuccess(null), className: "ml-auto" }, /* @__PURE__ */ React.createElement(X, { className: "w-5 h-5" }))), isEditing ? renderEditForm() : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement("div", { className: "flex items-center justify-between mb-6" }, /* @__PURE__ */ React.createElement("h1", { className: "text-3xl font-bold text-gray-900 dark:text-white" }, "\u914D\u7F6E\u7BA1\u7406"), /* @__PURE__ */ React.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React.createElement(
770
+ "button",
771
+ {
772
+ onClick: handleImport,
773
+ className: "inline-flex items-center gap-2 px-4 py-2 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700"
774
+ },
775
+ /* @__PURE__ */ React.createElement(Upload, { className: "w-5 h-5" }),
776
+ "\u5BFC\u5165"
777
+ ), /* @__PURE__ */ React.createElement(
778
+ "button",
779
+ {
780
+ onClick: handleStartCreate,
781
+ className: "inline-flex items-center gap-2 px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
782
+ },
783
+ /* @__PURE__ */ React.createElement(Plus, { className: "w-5 h-5" }),
784
+ "\u521B\u5EFA\u914D\u7F6E"
785
+ ))), configs.length === 0 ? /* @__PURE__ */ React.createElement("div", { className: "text-center py-12 bg-white dark:bg-gray-800 rounded-lg border-2 border-dashed border-gray-300 dark:border-gray-700" }, /* @__PURE__ */ React.createElement("p", { className: "text-gray-600 dark:text-gray-400 mb-4" }, "\u8FD8\u6CA1\u6709\u4EFB\u4F55\u914D\u7F6E"), /* @__PURE__ */ React.createElement(
786
+ "button",
787
+ {
788
+ onClick: handleStartCreate,
789
+ className: "inline-flex items-center gap-2 px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700"
790
+ },
791
+ /* @__PURE__ */ React.createElement(Plus, { className: "w-5 h-5" }),
792
+ "\u521B\u5EFA\u7B2C\u4E00\u4E2A\u914D\u7F6E"
793
+ )) : renderConfigList()));
794
+ };
795
+ var ConfigList = ({
796
+ configService,
797
+ onSelect,
798
+ onEdit,
799
+ onDelete,
800
+ showActions = true,
801
+ showPreviewLink = false,
802
+ previewBaseUrl = "/test-yourself",
803
+ className = "",
804
+ pageSize = 10
805
+ }) => {
806
+ const [configs, setConfigs] = useState([]);
807
+ const [loading, setLoading] = useState(true);
808
+ const [currentPage, setCurrentPage] = useState(1);
809
+ const [searchTerm, setSearchTerm] = useState("");
810
+ const loadConfigs = useCallback(async () => {
811
+ try {
812
+ setLoading(true);
813
+ const list = await configService.getConfigList();
814
+ setConfigs(list);
815
+ } catch (error) {
816
+ console.error("\u52A0\u8F7D\u914D\u7F6E\u5217\u8868\u5931\u8D25:", error);
817
+ } finally {
818
+ setLoading(false);
819
+ }
820
+ }, [configService]);
821
+ useEffect(() => {
822
+ loadConfigs();
823
+ }, [loadConfigs]);
824
+ const handleRefresh = () => {
825
+ loadConfigs();
826
+ };
827
+ const handleSelect = (id) => {
828
+ onSelect?.(id);
829
+ };
830
+ const handleEdit = (id) => {
831
+ onEdit?.(id);
832
+ };
833
+ const handleDelete = async (id) => {
834
+ if (!confirm("\u786E\u5B9A\u8981\u5220\u9664\u8FD9\u4E2A\u914D\u7F6E\u5417\uFF1F")) return;
835
+ try {
836
+ await configService.deleteConfig(id);
837
+ await loadConfigs();
838
+ onDelete?.(id);
839
+ } catch (error) {
840
+ console.error("\u5220\u9664\u914D\u7F6E\u5931\u8D25:", error);
841
+ alert("\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
842
+ }
843
+ };
844
+ const handleDuplicate = async (id) => {
845
+ try {
846
+ await configService.duplicateConfig(id);
847
+ await loadConfigs();
848
+ } catch (error) {
849
+ console.error("\u590D\u5236\u914D\u7F6E\u5931\u8D25:", error);
850
+ alert("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
851
+ }
852
+ };
853
+ const handleSetDefault = async (id) => {
854
+ try {
855
+ await configService.setDefaultConfig(id);
856
+ await loadConfigs();
857
+ } catch (error) {
858
+ console.error("\u8BBE\u7F6E\u9ED8\u8BA4\u914D\u7F6E\u5931\u8D25:", error);
859
+ alert("\u8BBE\u7F6E\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
860
+ }
861
+ };
862
+ const handleExport = async (id) => {
863
+ try {
864
+ const jsonString = await configService.exportConfig(id);
865
+ const blob = new Blob([jsonString], { type: "application/json" });
866
+ const url = URL.createObjectURL(blob);
867
+ const a = document.createElement("a");
868
+ a.href = url;
869
+ a.download = "config_" + id + ".json";
870
+ document.body.appendChild(a);
871
+ a.click();
872
+ document.body.removeChild(a);
873
+ URL.revokeObjectURL(url);
874
+ } catch (error) {
875
+ console.error("\u5BFC\u51FA\u914D\u7F6E\u5931\u8D25:", error);
876
+ alert("\u5BFC\u51FA\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5");
877
+ }
878
+ };
879
+ const getPreviewUrl = (id) => {
880
+ return previewBaseUrl + "?configId=" + id;
881
+ };
882
+ const filteredConfigs = configs.filter((config) => {
883
+ if (!searchTerm) return true;
884
+ const term = searchTerm.toLowerCase();
885
+ return config.name.toLowerCase().includes(term) || config.description?.toLowerCase().includes(term);
886
+ });
887
+ const totalPages = Math.ceil(filteredConfigs.length / pageSize);
888
+ const startIndex = (currentPage - 1) * pageSize;
889
+ const endIndex = startIndex + pageSize;
890
+ const currentConfigs = filteredConfigs.slice(startIndex, endIndex);
891
+ if (loading) {
892
+ return /* @__PURE__ */ React.createElement("div", { className: clsx("p-8", className) }, /* @__PURE__ */ React.createElement("div", { className: "text-center" }, /* @__PURE__ */ React.createElement("div", { className: "inline-block w-8 h-8 border-4 border-blue-600 border-t-transparent rounded-full animate-spin" }), /* @__PURE__ */ React.createElement("p", { className: "mt-2 text-gray-600 dark:text-gray-400" }, "\u52A0\u8F7D\u4E2D...")));
893
+ }
894
+ return /* @__PURE__ */ React.createElement("div", { className }, /* @__PURE__ */ React.createElement("div", { className: "mb-4 flex items-center justify-between gap-4" }, /* @__PURE__ */ React.createElement("div", { className: "flex-1" }, /* @__PURE__ */ React.createElement(
895
+ "input",
896
+ {
897
+ type: "text",
898
+ placeholder: "\u641C\u7D22\u914D\u7F6E...",
899
+ value: searchTerm,
900
+ onChange: (e) => {
901
+ setSearchTerm(e.target.value);
902
+ setCurrentPage(1);
903
+ },
904
+ className: "w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 dark:bg-gray-800 dark:text-white"
905
+ }
906
+ )), /* @__PURE__ */ React.createElement(
907
+ "button",
908
+ {
909
+ onClick: handleRefresh,
910
+ className: "p-2 text-gray-600 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-200",
911
+ title: "\u5237\u65B0"
912
+ },
913
+ /* @__PURE__ */ React.createElement(RefreshCw, { className: "w-5 h-5" })
914
+ )), currentConfigs.length === 0 ? /* @__PURE__ */ React.createElement("div", { className: "text-center py-12 bg-gray-50 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700" }, /* @__PURE__ */ React.createElement("p", { className: "text-gray-600 dark:text-gray-400" }, searchTerm ? "\u6CA1\u6709\u627E\u5230\u5339\u914D\u7684\u914D\u7F6E" : "\u8FD8\u6CA1\u6709\u4EFB\u4F55\u914D\u7F6E")) : /* @__PURE__ */ React.createElement("div", { className: "space-y-3" }, currentConfigs.map((config) => /* @__PURE__ */ React.createElement(
915
+ "div",
916
+ {
917
+ key: config.id,
918
+ className: "bg-white dark:bg-gray-800 rounded-lg shadow-sm p-4 border border-gray-200 dark:border-gray-700 hover:shadow-md transition-shadow"
919
+ },
920
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-start justify-between gap-4" }, /* @__PURE__ */ React.createElement(
921
+ "div",
922
+ {
923
+ className: "flex-1 cursor-pointer",
924
+ onClick: () => handleSelect(config.id)
925
+ },
926
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2 mb-1" }, /* @__PURE__ */ React.createElement("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white" }, config.name), config.isDefault && /* @__PURE__ */ React.createElement("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200" }, /* @__PURE__ */ React.createElement(Star, { className: "w-3 h-3" }), "\u9ED8\u8BA4")),
927
+ config.description && /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-600 dark:text-gray-400 mb-2" }, config.description),
928
+ /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-4 text-xs text-gray-500 dark:text-gray-400" }, /* @__PURE__ */ React.createElement("span", null, "\u7ED3\u679C\u6570: ", config.resultCount), /* @__PURE__ */ React.createElement("span", null, "\u521B\u5EFA: ", new Date(config.createdAt).toLocaleDateString()), config.updatedAt !== config.createdAt && /* @__PURE__ */ React.createElement("span", null, "\u66F4\u65B0: ", new Date(config.updatedAt).toLocaleDateString()))
929
+ ), showActions && /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-1" }, showPreviewLink && /* @__PURE__ */ React.createElement(
930
+ "a",
931
+ {
932
+ href: getPreviewUrl(config.id),
933
+ target: "_blank",
934
+ rel: "noopener noreferrer",
935
+ className: "p-2 text-gray-600 hover:text-blue-600 dark:text-gray-400 dark:hover:text-blue-400",
936
+ title: "\u9884\u89C8"
937
+ },
938
+ /* @__PURE__ */ React.createElement(ExternalLink, { className: "w-4 h-4" })
939
+ ), /* @__PURE__ */ React.createElement(
940
+ "button",
941
+ {
942
+ onClick: () => handleSetDefault(config.id),
943
+ disabled: config.isDefault,
944
+ className: "p-2 text-gray-600 hover:text-yellow-600 disabled:opacity-50 disabled:cursor-not-allowed",
945
+ title: "\u8BBE\u4E3A\u9ED8\u8BA4"
946
+ },
947
+ /* @__PURE__ */ React.createElement(Star, { className: "w-4 h-4" })
948
+ ), /* @__PURE__ */ React.createElement(
949
+ "button",
950
+ {
951
+ onClick: () => handleEdit(config.id),
952
+ className: "p-2 text-gray-600 hover:text-blue-600",
953
+ title: "\u7F16\u8F91"
954
+ },
955
+ /* @__PURE__ */ React.createElement(Edit, { className: "w-4 h-4" })
956
+ ), /* @__PURE__ */ React.createElement(
957
+ "button",
958
+ {
959
+ onClick: () => handleDuplicate(config.id),
960
+ className: "p-2 text-gray-600 hover:text-green-600",
961
+ title: "\u590D\u5236"
962
+ },
963
+ /* @__PURE__ */ React.createElement(Copy, { className: "w-4 h-4" })
964
+ ), /* @__PURE__ */ React.createElement(
965
+ "button",
966
+ {
967
+ onClick: () => handleExport(config.id),
968
+ className: "p-2 text-gray-600 hover:text-purple-600",
969
+ title: "\u5BFC\u51FA"
970
+ },
971
+ /* @__PURE__ */ React.createElement(Download, { className: "w-4 h-4" })
972
+ ), /* @__PURE__ */ React.createElement(
973
+ "button",
974
+ {
975
+ onClick: () => handleDelete(config.id),
976
+ className: "p-2 text-gray-600 hover:text-red-600",
977
+ title: "\u5220\u9664"
978
+ },
979
+ /* @__PURE__ */ React.createElement(Trash2, { className: "w-4 h-4" })
980
+ )))
981
+ ))), totalPages > 1 && /* @__PURE__ */ React.createElement("div", { className: "mt-4 flex items-center justify-between" }, /* @__PURE__ */ React.createElement("p", { className: "text-sm text-gray-600 dark:text-gray-400" }, "\u663E\u793A ", startIndex + 1, " - ", Math.min(endIndex, filteredConfigs.length), " \u5171", " ", filteredConfigs.length, " \u4E2A\u914D\u7F6E"), /* @__PURE__ */ React.createElement("div", { className: "flex items-center gap-2" }, /* @__PURE__ */ React.createElement(
982
+ "button",
983
+ {
984
+ onClick: () => setCurrentPage((p) => Math.max(1, p - 1)),
985
+ disabled: currentPage === 1,
986
+ className: "px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-50 dark:hover:bg-gray-700"
987
+ },
988
+ "\u4E0A\u4E00\u9875"
989
+ ), /* @__PURE__ */ React.createElement("span", { className: "text-sm text-gray-600 dark:text-gray-400" }, currentPage, " / ", totalPages), /* @__PURE__ */ React.createElement(
990
+ "button",
991
+ {
992
+ onClick: () => setCurrentPage((p) => Math.min(totalPages, p + 1)),
993
+ disabled: currentPage === totalPages,
994
+ className: "px-3 py-1 border border-gray-300 dark:border-gray-600 rounded-lg disabled:opacity-50 disabled:cursor-not-allowed hover:bg-gray-50 dark:hover:bg-gray-700"
995
+ },
996
+ "\u4E0B\u4E00\u9875"
997
+ ))));
998
+ };
999
+
1000
+ export { ConfigList, ConfigManager };
1001
+ //# sourceMappingURL=index.mjs.map
1002
+ //# sourceMappingURL=index.mjs.map