sa2kit 3.2.0 → 3.2.2

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 (227) 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/common/auth/components/index.js +18 -0
  166. package/dist/common/auth/components/index.js.map +1 -1
  167. package/dist/common/auth/components/index.mjs +18 -0
  168. package/dist/common/auth/components/index.mjs.map +1 -1
  169. package/dist/common/auth/server/index.d.mts +86 -3
  170. package/dist/common/auth/server/index.d.ts +86 -3
  171. package/dist/common/auth/server/index.js +614 -1
  172. package/dist/common/auth/server/index.js.map +1 -1
  173. package/dist/common/auth/server/index.mjs +599 -3
  174. package/dist/common/auth/server/index.mjs.map +1 -1
  175. package/dist/config-BQp3qLAL.d.mts +22 -0
  176. package/dist/config-BQp3qLAL.d.ts +22 -0
  177. package/dist/drizzle-schema-BNhqj2AZ.d.mts +1114 -0
  178. package/dist/drizzle-schema-BNhqj2AZ.d.ts +1114 -0
  179. package/dist/festivalCardService-D60G-sgr.d.mts +13 -0
  180. package/dist/festivalCardService-DnLyJpRh.d.ts +13 -0
  181. package/dist/index-BMgdH5dL.d.mts +1716 -0
  182. package/dist/index-BO9_Do5y.d.mts +93 -0
  183. package/dist/index-BO9_Do5y.d.ts +93 -0
  184. package/dist/index-BSmd4ikf.d.ts +76 -0
  185. package/dist/index-BSwvWYp2.d.mts +2632 -0
  186. package/dist/index-Bo_fW3Tl.d.mts +105 -0
  187. package/dist/index-Bo_fW3Tl.d.ts +105 -0
  188. package/dist/index-BrKazb8M.d.mts +148 -0
  189. package/dist/index-BrKazb8M.d.ts +148 -0
  190. package/dist/index-Bzh6QE4P.d.ts +25 -0
  191. package/dist/index-C5Ic6eSR.d.mts +25 -0
  192. package/dist/index-C8i9SIxk.d.ts +2632 -0
  193. package/dist/index-C_GhVhOT.d.mts +109 -0
  194. package/dist/index-C_GhVhOT.d.ts +109 -0
  195. package/dist/index-Cb3UEpG4.d.mts +101 -0
  196. package/dist/index-CjlkUj01.d.mts +103 -0
  197. package/dist/index-CucXCBNR.d.mts +302 -0
  198. package/dist/index-CucXCBNR.d.ts +302 -0
  199. package/dist/index-DLLPTprx.d.mts +1522 -0
  200. package/dist/index-DRiZy0dv.d.mts +525 -0
  201. package/dist/index-DRiZy0dv.d.ts +525 -0
  202. package/dist/index-Dc_I2t0P.d.mts +103 -0
  203. package/dist/index-DowAHRIP.d.mts +250 -0
  204. package/dist/index-DowAHRIP.d.ts +250 -0
  205. package/dist/index-Dpq_5H2n.d.ts +103 -0
  206. package/dist/index-Ds2M_9zb.d.ts +101 -0
  207. package/dist/index-IXMAeTtN.d.ts +1716 -0
  208. package/dist/index-VFDbZxVM.d.ts +1522 -0
  209. package/dist/index-jadkp96n.d.ts +103 -0
  210. package/dist/index-r2-zE3iC.d.mts +76 -0
  211. package/dist/index.d.mts +10682 -0
  212. package/dist/index.d.ts +10682 -0
  213. package/dist/index.js +38233 -0
  214. package/dist/index.js.map +1 -0
  215. package/dist/index.mjs +37959 -0
  216. package/dist/index.mjs.map +1 -0
  217. package/dist/types-B6B210gX.d.mts +270 -0
  218. package/dist/types-B6B210gX.d.ts +270 -0
  219. package/dist/types-B7voqjjA.d.mts +51 -0
  220. package/dist/types-B7voqjjA.d.ts +51 -0
  221. package/dist/types-Bdnte5EN.d.mts +292 -0
  222. package/dist/types-C2z_QQPI.d.mts +70 -0
  223. package/dist/types-C2z_QQPI.d.ts +70 -0
  224. package/dist/types-HorDyIRv.d.mts +303 -0
  225. package/dist/types-HorDyIRv.d.ts +303 -0
  226. package/dist/types-_rFX1atk.d.ts +292 -0
  227. package/package.json +10 -2
@@ -0,0 +1,2 @@
1
+ export { B as MikuContestAdminPage, A as MikuContestArtistPage, z as MikuContestAudiencePage, x as MikuContestDashboard, y as MikuContestPage } from '../../../../index-DowAHRIP.mjs';
2
+ import 'react';
@@ -0,0 +1,2 @@
1
+ export { B as MikuContestAdminPage, A as MikuContestArtistPage, z as MikuContestAudiencePage, x as MikuContestDashboard, y as MikuContestPage } from '../../../../index-DowAHRIP.js';
2
+ import 'react';
@@ -0,0 +1,353 @@
1
+ 'use strict';
2
+
3
+ var React4 = require('react');
4
+
5
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
6
+
7
+ var React4__default = /*#__PURE__*/_interopDefault(React4);
8
+
9
+ // src/business/mikuContest/ui/web/components/MikuContestDashboard.tsx
10
+ var MikuContestDashboard = ({ snapshot }) => {
11
+ return /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("h2", null, snapshot.contest.name), /* @__PURE__ */ React4__default.default.createElement("p", null, snapshot.contest.theme), /* @__PURE__ */ React4__default.default.createElement("p", null, "\u6295\u7A3F\u6570\uFF1A", snapshot.submissions.length), /* @__PURE__ */ React4__default.default.createElement("p", null, "\u516C\u544A\u6570\uFF1A", snapshot.announcements.length), /* @__PURE__ */ React4__default.default.createElement("ul", null, snapshot.leaderboard.map((item) => /* @__PURE__ */ React4__default.default.createElement("li", { key: item.submissionId }, "#", item.rank, " ", item.title, " - ", item.voteCount, "\u7968"))));
12
+ };
13
+ var MikuContestDashboard_default = MikuContestDashboard;
14
+
15
+ // src/business/mikuContest/service/api/client.ts
16
+ var toQueryString = (filter) => {
17
+ if (!filter) return "";
18
+ const params = new URLSearchParams();
19
+ if (filter.status) params.set("status", filter.status);
20
+ if (filter.type) params.set("type", filter.type);
21
+ if (filter.authorId) params.set("authorId", filter.authorId);
22
+ if (filter.authorKeyword) params.set("authorKeyword", filter.authorKeyword);
23
+ if (filter.titleKeyword) params.set("titleKeyword", filter.titleKeyword);
24
+ const query = params.toString();
25
+ return query ? `?${query}` : "";
26
+ };
27
+ var unwrap = (result) => {
28
+ if (!result.success || result.data === void 0) {
29
+ throw new Error(result.error || "\u8BF7\u6C42\u5931\u8D25");
30
+ }
31
+ return result.data;
32
+ };
33
+ var createMikuContestApiClient = (basePath, requester) => {
34
+ return {
35
+ async getSnapshot() {
36
+ const result = await requester(`${basePath}/contest`, { method: "GET" });
37
+ return unwrap(result);
38
+ },
39
+ async updateContestConfig(patch) {
40
+ const result = await requester(`${basePath}/contest`, {
41
+ method: "PATCH",
42
+ body: patch
43
+ });
44
+ return unwrap(result);
45
+ },
46
+ async createSubmission(input, mode = "web") {
47
+ const result = await requester(`${basePath}/submissions`, {
48
+ method: "POST",
49
+ body: { payload: input, mode }
50
+ });
51
+ return unwrap(result);
52
+ },
53
+ async listSubmissions(filter) {
54
+ const result = await requester(
55
+ `${basePath}/submissions${toQueryString(filter)}`,
56
+ { method: "GET" }
57
+ );
58
+ return unwrap(result);
59
+ },
60
+ async reviewSubmission(input) {
61
+ const result = await requester(`${basePath}/submissions/review`, {
62
+ method: "POST",
63
+ body: input
64
+ });
65
+ return unwrap(result);
66
+ },
67
+ async vote(input) {
68
+ const result = await requester(`${basePath}/votes`, {
69
+ method: "POST",
70
+ body: input
71
+ });
72
+ return unwrap(result);
73
+ },
74
+ async setVoterRestriction(input) {
75
+ const result = await requester(`${basePath}/admin/voter-restrictions`, {
76
+ method: "POST",
77
+ body: input
78
+ });
79
+ return unwrap(result);
80
+ },
81
+ async resetVotes(input) {
82
+ const result = await requester(
83
+ `${basePath}/admin/votes/reset`,
84
+ {
85
+ method: "POST",
86
+ body: input
87
+ }
88
+ );
89
+ return unwrap(result);
90
+ },
91
+ async exportSubmissions(filter) {
92
+ const response = await fetch(`${basePath}/admin/submissions/export${toQueryString(filter)}`);
93
+ if (!response.ok) {
94
+ throw new Error(`\u5BFC\u51FA\u5931\u8D25: ${response.status}`);
95
+ }
96
+ return response.arrayBuffer();
97
+ }
98
+ };
99
+ };
100
+
101
+ // src/business/mikuContest/service/web/client.ts
102
+ var defaultRequester = (options) => {
103
+ const baseUrl = options.baseUrl || "";
104
+ const commonHeaders = options.headers || {};
105
+ return async (url, requestOptions) => {
106
+ const response = await fetch(`${baseUrl}${url}`, {
107
+ method: requestOptions?.method || "GET",
108
+ headers: {
109
+ "Content-Type": "application/json",
110
+ ...commonHeaders
111
+ },
112
+ body: requestOptions?.body ? JSON.stringify(requestOptions.body) : void 0
113
+ });
114
+ const json = await response.json();
115
+ return json;
116
+ };
117
+ };
118
+ var createMikuContestWebClient = (options = {}) => {
119
+ const basePath = options.basePath || "/api/miku-contest";
120
+ return createMikuContestApiClient(basePath, defaultRequester(options));
121
+ };
122
+
123
+ // src/business/mikuContest/ui/web/pages/MikuContestAudiencePage.tsx
124
+ var MikuContestAudiencePage = ({
125
+ client,
126
+ voterId,
127
+ title = "\u89C2\u4F17\u6295\u7968\u533A"
128
+ }) => {
129
+ const api = React4.useMemo(() => client || createMikuContestWebClient(), [client]);
130
+ const [snapshot, setSnapshot] = React4.useState(null);
131
+ const [loading, setLoading] = React4.useState(false);
132
+ const [error, setError] = React4.useState(null);
133
+ const approvedWorks = React4.useMemo(() => {
134
+ if (!snapshot) return [];
135
+ return snapshot.submissions.filter((item) => item.status === "approved");
136
+ }, [snapshot]);
137
+ const loadSnapshot = async () => {
138
+ setLoading(true);
139
+ setError(null);
140
+ try {
141
+ const data = await api.getSnapshot();
142
+ setSnapshot(data);
143
+ } catch (e) {
144
+ setError(e.message);
145
+ } finally {
146
+ setLoading(false);
147
+ }
148
+ };
149
+ React4.useEffect(() => {
150
+ void loadSnapshot();
151
+ }, []);
152
+ const handleVote = async (submission) => {
153
+ if (!snapshot) return;
154
+ try {
155
+ await api.vote({
156
+ contestId: snapshot.contest.id,
157
+ submissionId: submission.id,
158
+ voterId
159
+ });
160
+ await loadSnapshot();
161
+ } catch (e) {
162
+ setError(e.message);
163
+ }
164
+ };
165
+ return /* @__PURE__ */ React4__default.default.createElement("section", null, /* @__PURE__ */ React4__default.default.createElement("h2", null, title), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void loadSnapshot(), disabled: loading }, loading ? "\u5237\u65B0\u4E2D..." : "\u5237\u65B0\u6570\u636E"), error ? /* @__PURE__ */ React4__default.default.createElement("p", { style: { color: "crimson" } }, "\u9519\u8BEF\uFF1A", error) : null, !snapshot ? null : /* @__PURE__ */ React4__default.default.createElement(React4__default.default.Fragment, null, /* @__PURE__ */ React4__default.default.createElement("p", null, "\u8D5B\u4E8B\uFF1A", snapshot.contest.name, "\uFF5C\u4E3B\u9898\uFF1A", snapshot.contest.theme), /* @__PURE__ */ React4__default.default.createElement("p", null, "\u5DF2\u8FC7\u5BA1\u4F5C\u54C1\uFF1A", approvedWorks.length, "\uFF5C\u6BCF\u65E5\u4E0A\u9650\uFF1A", snapshot.contest.votingRules.maxVotesPerDay), /* @__PURE__ */ React4__default.default.createElement("ul", null, approvedWorks.map((work) => /* @__PURE__ */ React4__default.default.createElement("li", { key: work.id }, /* @__PURE__ */ React4__default.default.createElement("strong", null, work.title), "\uFF08", work.authorNickname, "\uFF09- \u5F53\u524D ", work.voteCount, " \u7968", " ", /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void handleVote(work) }, "\u6295\u7968"))))));
166
+ };
167
+ var MikuContestAudiencePage_default = MikuContestAudiencePage;
168
+ var workTypes = ["visual", "video", "text", "audio"];
169
+ var MikuContestArtistPage = ({
170
+ client,
171
+ authorId,
172
+ authorNickname,
173
+ title = "\u753B\u5E08\u6295\u7A3F\u533A"
174
+ }) => {
175
+ const api = React4.useMemo(() => client || createMikuContestWebClient(), [client]);
176
+ const [snapshot, setSnapshot] = React4.useState(null);
177
+ const [mySubmissions, setMySubmissions] = React4.useState([]);
178
+ const [submitting, setSubmitting] = React4.useState(false);
179
+ const [loading, setLoading] = React4.useState(false);
180
+ const [error, setError] = React4.useState(null);
181
+ const [titleInput, setTitleInput] = React4.useState("");
182
+ const [descInput, setDescInput] = React4.useState("");
183
+ const [coverImage, setCoverImage] = React4.useState("");
184
+ const [workType, setWorkType] = React4.useState("visual");
185
+ const loadData = async () => {
186
+ setLoading(true);
187
+ setError(null);
188
+ try {
189
+ const [contest, mine] = await Promise.all([
190
+ api.getSnapshot(),
191
+ api.listSubmissions({ authorId })
192
+ ]);
193
+ setSnapshot(contest);
194
+ setMySubmissions(mine);
195
+ } catch (e) {
196
+ setError(e.message);
197
+ } finally {
198
+ setLoading(false);
199
+ }
200
+ };
201
+ React4.useEffect(() => {
202
+ void loadData();
203
+ }, []);
204
+ const submitWork = async () => {
205
+ if (!snapshot) return;
206
+ const payload = {
207
+ contestId: snapshot.contest.id,
208
+ authorId,
209
+ authorNickname,
210
+ title: titleInput,
211
+ description: descInput,
212
+ type: workType,
213
+ tags: ["web"],
214
+ content: {
215
+ coverImage,
216
+ images: coverImage ? [coverImage] : void 0
217
+ }
218
+ };
219
+ setSubmitting(true);
220
+ setError(null);
221
+ try {
222
+ await api.createSubmission(payload, "web");
223
+ setTitleInput("");
224
+ setDescInput("");
225
+ setCoverImage("");
226
+ await loadData();
227
+ } catch (e) {
228
+ setError(e.message);
229
+ } finally {
230
+ setSubmitting(false);
231
+ }
232
+ };
233
+ return /* @__PURE__ */ React4__default.default.createElement("section", null, /* @__PURE__ */ React4__default.default.createElement("h2", null, title), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void loadData(), disabled: loading }, loading ? "\u5237\u65B0\u4E2D..." : "\u5237\u65B0\u6570\u636E"), error ? /* @__PURE__ */ React4__default.default.createElement("p", { style: { color: "crimson" } }, "\u9519\u8BEF\uFF1A", error) : null, /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("h3", null, "\u65B0\u5EFA\u6295\u7A3F"), /* @__PURE__ */ React4__default.default.createElement("input", { value: titleInput, onChange: (e) => setTitleInput(e.target.value), placeholder: "\u4F5C\u54C1\u6807\u9898" }), /* @__PURE__ */ React4__default.default.createElement("br", null), /* @__PURE__ */ React4__default.default.createElement("textarea", { value: descInput, onChange: (e) => setDescInput(e.target.value), placeholder: "\u4F5C\u54C1\u7B80\u4ECB" }), /* @__PURE__ */ React4__default.default.createElement("br", null), /* @__PURE__ */ React4__default.default.createElement("input", { value: coverImage, onChange: (e) => setCoverImage(e.target.value), placeholder: "\u5C01\u9762 URL" }), /* @__PURE__ */ React4__default.default.createElement("br", null), /* @__PURE__ */ React4__default.default.createElement("select", { value: workType, onChange: (e) => setWorkType(e.target.value) }, workTypes.map((item) => /* @__PURE__ */ React4__default.default.createElement("option", { value: item, key: item }, item))), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void submitWork(), disabled: submitting || !snapshot }, submitting ? "\u63D0\u4EA4\u4E2D..." : "\u63D0\u4EA4\u7A3F\u4EF6")), /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("h3", null, "\u6211\u7684\u6295\u7A3F\uFF08", mySubmissions.length, "\uFF09"), /* @__PURE__ */ React4__default.default.createElement("ul", null, mySubmissions.map((item) => /* @__PURE__ */ React4__default.default.createElement("li", { key: item.id }, item.title, "\uFF5C\u72B6\u6001\uFF1A", item.status, "\uFF5C\u7968\u6570\uFF1A", item.voteCount, item.rejectReason ? `\uFF5C\u9A73\u56DE\uFF1A${item.rejectReason}` : "")))));
234
+ };
235
+ var MikuContestArtistPage_default = MikuContestArtistPage;
236
+ var MikuContestAdminPage = ({
237
+ client,
238
+ adminId,
239
+ title = "\u7BA1\u7406\u5458\u9762\u677F"
240
+ }) => {
241
+ const api = React4.useMemo(() => client || createMikuContestWebClient(), [client]);
242
+ const [snapshot, setSnapshot] = React4.useState(null);
243
+ const [submissions, setSubmissions] = React4.useState([]);
244
+ const [loading, setLoading] = React4.useState(false);
245
+ const [error, setError] = React4.useState(null);
246
+ const [voterId, setVoterId] = React4.useState("");
247
+ const loadData = async () => {
248
+ setLoading(true);
249
+ setError(null);
250
+ try {
251
+ const [contest, list] = await Promise.all([api.getSnapshot(), api.listSubmissions()]);
252
+ setSnapshot(contest);
253
+ setSubmissions(list);
254
+ } catch (e) {
255
+ setError(e.message);
256
+ } finally {
257
+ setLoading(false);
258
+ }
259
+ };
260
+ React4.useEffect(() => {
261
+ void loadData();
262
+ }, []);
263
+ const review = async (item, action) => {
264
+ try {
265
+ await api.reviewSubmission({
266
+ submissionId: item.id,
267
+ reviewerId: adminId,
268
+ action,
269
+ rejectReason: action === "reject" ? "\u7BA1\u7406\u5458\u9A73\u56DE" : void 0
270
+ });
271
+ await loadData();
272
+ } catch (e) {
273
+ setError(e.message);
274
+ }
275
+ };
276
+ const toggleVoting = async (enabled) => {
277
+ if (!snapshot) return;
278
+ try {
279
+ await api.updateContestConfig({
280
+ toggles: {
281
+ ...snapshot.contest.toggles,
282
+ votingEnabled: enabled
283
+ }
284
+ });
285
+ await loadData();
286
+ } catch (e) {
287
+ setError(e.message);
288
+ }
289
+ };
290
+ const setRestriction = async (banned) => {
291
+ if (!snapshot || !voterId.trim()) return;
292
+ try {
293
+ await api.setVoterRestriction({
294
+ voterId: voterId.trim(),
295
+ banned,
296
+ reason: banned ? "\u7BA1\u7406\u5458\u624B\u52A8\u5C01\u7981" : "\u7BA1\u7406\u5458\u89E3\u9664\u5C01\u7981",
297
+ operatorId: adminId
298
+ });
299
+ setVoterId("");
300
+ } catch (e) {
301
+ setError(e.message);
302
+ }
303
+ };
304
+ const resetVotesByVoter = async () => {
305
+ if (!voterId.trim()) return;
306
+ try {
307
+ await api.resetVotes({ voterId: voterId.trim() });
308
+ setVoterId("");
309
+ await loadData();
310
+ } catch (e) {
311
+ setError(e.message);
312
+ }
313
+ };
314
+ const exportExcel = async () => {
315
+ try {
316
+ const data = await api.exportSubmissions();
317
+ const blob = new Blob([data], {
318
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
319
+ });
320
+ const url = URL.createObjectURL(blob);
321
+ const a = document.createElement("a");
322
+ a.href = url;
323
+ a.download = "miku-submissions.xlsx";
324
+ a.click();
325
+ URL.revokeObjectURL(url);
326
+ } catch (e) {
327
+ setError(e.message);
328
+ }
329
+ };
330
+ return /* @__PURE__ */ React4__default.default.createElement("section", null, /* @__PURE__ */ React4__default.default.createElement("h2", null, title), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void loadData(), disabled: loading }, loading ? "\u5237\u65B0\u4E2D..." : "\u5237\u65B0\u6570\u636E"), error ? /* @__PURE__ */ React4__default.default.createElement("p", { style: { color: "crimson" } }, "\u9519\u8BEF\uFF1A", error) : null, /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("h3", null, "\u8D5B\u4E8B\u5F00\u5173"), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void toggleVoting(true), disabled: !snapshot }, "\u5F00\u542F\u6295\u7968"), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void toggleVoting(false), disabled: !snapshot }, "\u5173\u95ED\u6295\u7968")), /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("h3", null, "\u6295\u7A3F\u5BA1\u6838\uFF08", submissions.length, "\uFF09"), /* @__PURE__ */ React4__default.default.createElement("ul", null, submissions.map((item) => /* @__PURE__ */ React4__default.default.createElement("li", { key: item.id }, /* @__PURE__ */ React4__default.default.createElement("strong", null, item.title), "\uFF5C\u4F5C\u8005\uFF1A", item.authorNickname, "\uFF5C\u72B6\u6001\uFF1A", item.status, "\uFF5C\u7968\u6570\uFF1A", item.voteCount, item.status === "pending" ? /* @__PURE__ */ React4__default.default.createElement(React4__default.default.Fragment, null, " ", /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void review(item, "approve") }, "\u901A\u8FC7"), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void review(item, "reject") }, "\u9A73\u56DE")) : null)))), /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("h3", null, "\u6295\u7968\u98CE\u63A7"), /* @__PURE__ */ React4__default.default.createElement("input", { value: voterId, onChange: (e) => setVoterId(e.target.value), placeholder: "voterId" }), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void setRestriction(true), disabled: !snapshot }, "\u5C01\u7981\u6295\u7968"), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void setRestriction(false), disabled: !snapshot }, "\u89E3\u9664\u5C01\u7981"), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void resetVotesByVoter() }, "\u6E05\u96F6\u8BE5\u7528\u6237\u7968\u6570")), /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("h3", null, "\u5BFC\u51FA"), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => void exportExcel() }, "\u5BFC\u51FA\u6295\u7A3F Excel")));
331
+ };
332
+ var MikuContestAdminPage_default = MikuContestAdminPage;
333
+
334
+ // src/business/mikuContest/ui/web/pages/MikuContestPage.tsx
335
+ var MikuContestPage = ({
336
+ defaultView = "audience",
337
+ viewerVoterId = "viewer-demo",
338
+ artistId = "artist-demo",
339
+ artistNickname = "Demo \u753B\u5E08",
340
+ adminId = "admin-demo"
341
+ }) => {
342
+ const [view, setView] = React4.useState(defaultView);
343
+ return /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("h1", null, "Miku Contest"), /* @__PURE__ */ React4__default.default.createElement("div", null, /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => setView("audience") }, "\u89C2\u4F17\u7AEF"), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => setView("artist") }, "\u753B\u5E08\u7AEF"), /* @__PURE__ */ React4__default.default.createElement("button", { onClick: () => setView("admin") }, "\u7BA1\u7406\u5458\u7AEF")), view === "audience" ? /* @__PURE__ */ React4__default.default.createElement(MikuContestAudiencePage_default, { voterId: viewerVoterId }) : null, view === "artist" ? /* @__PURE__ */ React4__default.default.createElement(MikuContestArtistPage_default, { authorId: artistId, authorNickname: artistNickname }) : null, view === "admin" ? /* @__PURE__ */ React4__default.default.createElement(MikuContestAdminPage_default, { adminId }) : null);
344
+ };
345
+ var MikuContestPage_default = MikuContestPage;
346
+
347
+ exports.MikuContestAdminPage = MikuContestAdminPage_default;
348
+ exports.MikuContestArtistPage = MikuContestArtistPage_default;
349
+ exports.MikuContestAudiencePage = MikuContestAudiencePage_default;
350
+ exports.MikuContestDashboard = MikuContestDashboard_default;
351
+ exports.MikuContestPage = MikuContestPage_default;
352
+ //# sourceMappingURL=index.js.map
353
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../src/business/mikuContest/ui/web/components/MikuContestDashboard.tsx","../../../../../src/business/mikuContest/service/api/client.ts","../../../../../src/business/mikuContest/service/web/client.ts","../../../../../src/business/mikuContest/ui/web/pages/MikuContestAudiencePage.tsx","../../../../../src/business/mikuContest/ui/web/pages/MikuContestArtistPage.tsx","../../../../../src/business/mikuContest/ui/web/pages/MikuContestAdminPage.tsx","../../../../../src/business/mikuContest/ui/web/pages/MikuContestPage.tsx"],"names":["React","useMemo","useState","useEffect"],"mappings":"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","file":"index.js","sourcesContent":["import React from 'react';\nimport type { MikuContestStateSnapshot } from '../../../types';\n\nexport interface MikuContestDashboardProps {\n snapshot: MikuContestStateSnapshot;\n}\n\nconst MikuContestDashboard: React.FC<MikuContestDashboardProps> = ({ snapshot }) => {\n return (\n <div>\n <h2>{snapshot.contest.name}</h2>\n <p>{snapshot.contest.theme}</p>\n <p>投稿数:{snapshot.submissions.length}</p>\n <p>公告数:{snapshot.announcements.length}</p>\n <ul>\n {snapshot.leaderboard.map((item) => (\n <li key={item.submissionId}>\n #{item.rank} {item.title} - {item.voteCount}票\n </li>\n ))}\n </ul>\n </div>\n );\n};\n\nexport default MikuContestDashboard;\n","import type {\n CreateMikuSubmissionInput,\n MikuContestConfig,\n MikuContestStateSnapshot,\n MikuSubmission,\n MikuSubmissionFilter,\n MikuVoterRestriction,\n ResetMikuVotesInput,\n ReviewMikuSubmissionInput,\n SetMikuVoterRestrictionInput,\n VoteMikuSubmissionInput,\n} from '../../types';\n\nexport interface MikuContestApiClient {\n getSnapshot(): Promise<MikuContestStateSnapshot>;\n updateContestConfig(patch: Partial<MikuContestConfig>): Promise<MikuContestConfig>;\n createSubmission(input: CreateMikuSubmissionInput, mode?: 'web' | 'miniapp'): Promise<MikuSubmission>;\n listSubmissions(filter?: MikuSubmissionFilter): Promise<MikuSubmission[]>;\n reviewSubmission(input: ReviewMikuSubmissionInput): Promise<MikuSubmission>;\n vote(input: VoteMikuSubmissionInput): Promise<MikuSubmission>;\n setVoterRestriction(input: SetMikuVoterRestrictionInput): Promise<MikuVoterRestriction>;\n resetVotes(input: ResetMikuVotesInput): Promise<{ removedVotes: number; affectedSubmissions: string[] }>;\n exportSubmissions(filter?: MikuSubmissionFilter): Promise<ArrayBuffer>;\n}\n\nexport type HttpMethod = 'GET' | 'POST' | 'PATCH';\n\nexport interface Requester {\n <T>(url: string, options?: { method?: HttpMethod; body?: unknown }): Promise<T>;\n}\n\nconst toQueryString = (filter?: MikuSubmissionFilter): string => {\n if (!filter) return '';\n const params = new URLSearchParams();\n if (filter.status) params.set('status', filter.status);\n if (filter.type) params.set('type', filter.type);\n if (filter.authorId) params.set('authorId', filter.authorId);\n if (filter.authorKeyword) params.set('authorKeyword', filter.authorKeyword);\n if (filter.titleKeyword) params.set('titleKeyword', filter.titleKeyword);\n const query = params.toString();\n return query ? `?${query}` : '';\n};\n\ninterface ApiEnvelope<T> {\n success: boolean;\n data?: T;\n error?: string;\n}\n\nconst unwrap = <T>(result: ApiEnvelope<T>): T => {\n if (!result.success || result.data === undefined) {\n throw new Error(result.error || '请求失败');\n }\n return result.data;\n};\n\nexport const createMikuContestApiClient = (\n basePath: string,\n requester: Requester,\n): MikuContestApiClient => {\n return {\n async getSnapshot() {\n const result = await requester<ApiEnvelope<MikuContestStateSnapshot>>(`${basePath}/contest`, { method: 'GET' });\n return unwrap(result);\n },\n async updateContestConfig(patch) {\n const result = await requester<ApiEnvelope<MikuContestConfig>>(`${basePath}/contest`, {\n method: 'PATCH',\n body: patch,\n });\n return unwrap(result);\n },\n async createSubmission(input, mode = 'web') {\n const result = await requester<ApiEnvelope<MikuSubmission>>(`${basePath}/submissions`, {\n method: 'POST',\n body: { payload: input, mode },\n });\n return unwrap(result);\n },\n async listSubmissions(filter) {\n const result = await requester<ApiEnvelope<MikuSubmission[]>>(\n `${basePath}/submissions${toQueryString(filter)}`,\n { method: 'GET' },\n );\n return unwrap(result);\n },\n async reviewSubmission(input) {\n const result = await requester<ApiEnvelope<MikuSubmission>>(`${basePath}/submissions/review`, {\n method: 'POST',\n body: input,\n });\n return unwrap(result);\n },\n async vote(input) {\n const result = await requester<ApiEnvelope<MikuSubmission>>(`${basePath}/votes`, {\n method: 'POST',\n body: input,\n });\n return unwrap(result);\n },\n async setVoterRestriction(input) {\n const result = await requester<ApiEnvelope<MikuVoterRestriction>>(`${basePath}/admin/voter-restrictions`, {\n method: 'POST',\n body: input,\n });\n return unwrap(result);\n },\n async resetVotes(input) {\n const result = await requester<ApiEnvelope<{ removedVotes: number; affectedSubmissions: string[] }>>(\n `${basePath}/admin/votes/reset`,\n {\n method: 'POST',\n body: input,\n },\n );\n return unwrap(result);\n },\n async exportSubmissions(filter) {\n const response = await fetch(`${basePath}/admin/submissions/export${toQueryString(filter)}`);\n if (!response.ok) {\n throw new Error(`导出失败: ${response.status}`);\n }\n return response.arrayBuffer();\n },\n };\n};\n","import { createMikuContestApiClient, type Requester } from '../api';\n\nexport interface MikuContestWebClientOptions {\n baseUrl?: string;\n basePath?: string;\n headers?: Record<string, string>;\n}\n\nconst defaultRequester = (options: MikuContestWebClientOptions): Requester => {\n const baseUrl = options.baseUrl || '';\n const commonHeaders = options.headers || {};\n\n return async <T>(url: string, requestOptions?: { method?: 'GET' | 'POST' | 'PATCH'; body?: unknown }): Promise<T> => {\n const response = await fetch(`${baseUrl}${url}`, {\n method: requestOptions?.method || 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...commonHeaders,\n },\n body: requestOptions?.body ? JSON.stringify(requestOptions.body) : undefined,\n });\n\n const json = (await response.json()) as T;\n return json;\n };\n};\n\nexport const createMikuContestWebClient = (options: MikuContestWebClientOptions = {}) => {\n const basePath = options.basePath || '/api/miku-contest';\n return createMikuContestApiClient(basePath, defaultRequester(options));\n};\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { createMikuContestWebClient } from '../../../service/web';\nimport type { MikuContestApiClient } from '../../../service/api';\nimport type { MikuContestStateSnapshot, MikuSubmission } from '../../../types';\n\nexport interface MikuContestAudiencePageProps {\n client?: Pick<MikuContestApiClient, 'getSnapshot' | 'vote'>;\n voterId: string;\n title?: string;\n}\n\nconst MikuContestAudiencePage: React.FC<MikuContestAudiencePageProps> = ({\n client,\n voterId,\n title = '观众投票区',\n}) => {\n const api = useMemo(() => client || createMikuContestWebClient(), [client]);\n\n const [snapshot, setSnapshot] = useState<MikuContestStateSnapshot | null>(null);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const approvedWorks = useMemo(() => {\n if (!snapshot) return [];\n return snapshot.submissions.filter((item) => item.status === 'approved');\n }, [snapshot]);\n\n const loadSnapshot = async () => {\n setLoading(true);\n setError(null);\n try {\n const data = await api.getSnapshot();\n setSnapshot(data);\n } catch (e) {\n setError((e as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void loadSnapshot();\n }, []);\n\n const handleVote = async (submission: MikuSubmission) => {\n if (!snapshot) return;\n try {\n await api.vote({\n contestId: snapshot.contest.id,\n submissionId: submission.id,\n voterId,\n });\n await loadSnapshot();\n } catch (e) {\n setError((e as Error).message);\n }\n };\n\n return (\n <section>\n <h2>{title}</h2>\n <button onClick={() => void loadSnapshot()} disabled={loading}>\n {loading ? '刷新中...' : '刷新数据'}\n </button>\n {error ? <p style={{ color: 'crimson' }}>错误:{error}</p> : null}\n\n {!snapshot ? null : (\n <>\n <p>\n 赛事:{snapshot.contest.name}|主题:{snapshot.contest.theme}\n </p>\n <p>\n 已过审作品:{approvedWorks.length}|每日上限:{snapshot.contest.votingRules.maxVotesPerDay}\n </p>\n <ul>\n {approvedWorks.map((work) => (\n <li key={work.id}>\n <strong>{work.title}</strong>({work.authorNickname})- 当前 {work.voteCount} 票{' '}\n <button onClick={() => void handleVote(work)}>投票</button>\n </li>\n ))}\n </ul>\n </>\n )}\n </section>\n );\n};\n\nexport default MikuContestAudiencePage;\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { createMikuContestWebClient } from '../../../service/web';\nimport type { MikuContestApiClient } from '../../../service/api';\nimport type { CreateMikuSubmissionInput, MikuContestStateSnapshot, MikuSubmission, MikuWorkType } from '../../../types';\n\nexport interface MikuContestArtistPageProps {\n client?: Pick<MikuContestApiClient, 'getSnapshot' | 'createSubmission' | 'listSubmissions'>;\n authorId: string;\n authorNickname: string;\n title?: string;\n}\n\nconst workTypes: MikuWorkType[] = ['visual', 'video', 'text', 'audio'];\n\nconst MikuContestArtistPage: React.FC<MikuContestArtistPageProps> = ({\n client,\n authorId,\n authorNickname,\n title = '画师投稿区',\n}) => {\n const api = useMemo(() => client || createMikuContestWebClient(), [client]);\n\n const [snapshot, setSnapshot] = useState<MikuContestStateSnapshot | null>(null);\n const [mySubmissions, setMySubmissions] = useState<MikuSubmission[]>([]);\n const [submitting, setSubmitting] = useState(false);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const [titleInput, setTitleInput] = useState('');\n const [descInput, setDescInput] = useState('');\n const [coverImage, setCoverImage] = useState('');\n const [workType, setWorkType] = useState<MikuWorkType>('visual');\n\n const loadData = async () => {\n setLoading(true);\n setError(null);\n try {\n const [contest, mine] = await Promise.all([\n api.getSnapshot(),\n api.listSubmissions({ authorId }),\n ]);\n setSnapshot(contest);\n setMySubmissions(mine);\n } catch (e) {\n setError((e as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void loadData();\n }, []);\n\n const submitWork = async () => {\n if (!snapshot) return;\n const payload: CreateMikuSubmissionInput = {\n contestId: snapshot.contest.id,\n authorId,\n authorNickname,\n title: titleInput,\n description: descInput,\n type: workType,\n tags: ['web'],\n content: {\n coverImage,\n images: coverImage ? [coverImage] : undefined,\n },\n };\n\n setSubmitting(true);\n setError(null);\n try {\n await api.createSubmission(payload, 'web');\n setTitleInput('');\n setDescInput('');\n setCoverImage('');\n await loadData();\n } catch (e) {\n setError((e as Error).message);\n } finally {\n setSubmitting(false);\n }\n };\n\n return (\n <section>\n <h2>{title}</h2>\n <button onClick={() => void loadData()} disabled={loading}>\n {loading ? '刷新中...' : '刷新数据'}\n </button>\n {error ? <p style={{ color: 'crimson' }}>错误:{error}</p> : null}\n\n <div>\n <h3>新建投稿</h3>\n <input value={titleInput} onChange={(e) => setTitleInput(e.target.value)} placeholder=\"作品标题\" />\n <br />\n <textarea value={descInput} onChange={(e) => setDescInput(e.target.value)} placeholder=\"作品简介\" />\n <br />\n <input value={coverImage} onChange={(e) => setCoverImage(e.target.value)} placeholder=\"封面 URL\" />\n <br />\n <select value={workType} onChange={(e) => setWorkType(e.target.value as MikuWorkType)}>\n {workTypes.map((item) => (\n <option value={item} key={item}>\n {item}\n </option>\n ))}\n </select>\n <button onClick={() => void submitWork()} disabled={submitting || !snapshot}>\n {submitting ? '提交中...' : '提交稿件'}\n </button>\n </div>\n\n <div>\n <h3>我的投稿({mySubmissions.length})</h3>\n <ul>\n {mySubmissions.map((item) => (\n <li key={item.id}>\n {item.title}|状态:{item.status}|票数:{item.voteCount}\n {item.rejectReason ? `|驳回:${item.rejectReason}` : ''}\n </li>\n ))}\n </ul>\n </div>\n </section>\n );\n};\n\nexport default MikuContestArtistPage;\n","import React, { useEffect, useMemo, useState } from 'react';\nimport { createMikuContestWebClient } from '../../../service/web';\nimport type { MikuContestApiClient } from '../../../service/api';\nimport type { MikuContestStateSnapshot, MikuSubmission } from '../../../types';\n\nexport interface MikuContestAdminPageProps {\n client?: Pick<\n MikuContestApiClient,\n | 'getSnapshot'\n | 'listSubmissions'\n | 'reviewSubmission'\n | 'setVoterRestriction'\n | 'resetVotes'\n | 'exportSubmissions'\n | 'updateContestConfig'\n >;\n adminId: string;\n title?: string;\n}\n\nconst MikuContestAdminPage: React.FC<MikuContestAdminPageProps> = ({\n client,\n adminId,\n title = '管理员面板',\n}) => {\n const api = useMemo(() => client || createMikuContestWebClient(), [client]);\n\n const [snapshot, setSnapshot] = useState<MikuContestStateSnapshot | null>(null);\n const [submissions, setSubmissions] = useState<MikuSubmission[]>([]);\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [voterId, setVoterId] = useState('');\n\n const loadData = async () => {\n setLoading(true);\n setError(null);\n try {\n const [contest, list] = await Promise.all([api.getSnapshot(), api.listSubmissions()]);\n setSnapshot(contest);\n setSubmissions(list);\n } catch (e) {\n setError((e as Error).message);\n } finally {\n setLoading(false);\n }\n };\n\n useEffect(() => {\n void loadData();\n }, []);\n\n const review = async (item: MikuSubmission, action: 'approve' | 'reject') => {\n try {\n await api.reviewSubmission({\n submissionId: item.id,\n reviewerId: adminId,\n action,\n rejectReason: action === 'reject' ? '管理员驳回' : undefined,\n });\n await loadData();\n } catch (e) {\n setError((e as Error).message);\n }\n };\n\n const toggleVoting = async (enabled: boolean) => {\n if (!snapshot) return;\n try {\n await api.updateContestConfig({\n toggles: {\n ...snapshot.contest.toggles,\n votingEnabled: enabled,\n },\n });\n await loadData();\n } catch (e) {\n setError((e as Error).message);\n }\n };\n\n const setRestriction = async (banned: boolean) => {\n if (!snapshot || !voterId.trim()) return;\n try {\n await api.setVoterRestriction({\n voterId: voterId.trim(),\n banned,\n reason: banned ? '管理员手动封禁' : '管理员解除封禁',\n operatorId: adminId,\n });\n setVoterId('');\n } catch (e) {\n setError((e as Error).message);\n }\n };\n\n const resetVotesByVoter = async () => {\n if (!voterId.trim()) return;\n try {\n await api.resetVotes({ voterId: voterId.trim() });\n setVoterId('');\n await loadData();\n } catch (e) {\n setError((e as Error).message);\n }\n };\n\n const exportExcel = async () => {\n try {\n const data = await api.exportSubmissions();\n const blob = new Blob([data], {\n type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n });\n const url = URL.createObjectURL(blob);\n const a = document.createElement('a');\n a.href = url;\n a.download = 'miku-submissions.xlsx';\n a.click();\n URL.revokeObjectURL(url);\n } catch (e) {\n setError((e as Error).message);\n }\n };\n\n return (\n <section>\n <h2>{title}</h2>\n <button onClick={() => void loadData()} disabled={loading}>\n {loading ? '刷新中...' : '刷新数据'}\n </button>\n {error ? <p style={{ color: 'crimson' }}>错误:{error}</p> : null}\n\n <div>\n <h3>赛事开关</h3>\n <button onClick={() => void toggleVoting(true)} disabled={!snapshot}>\n 开启投票\n </button>\n <button onClick={() => void toggleVoting(false)} disabled={!snapshot}>\n 关闭投票\n </button>\n </div>\n\n <div>\n <h3>投稿审核({submissions.length})</h3>\n <ul>\n {submissions.map((item) => (\n <li key={item.id}>\n <strong>{item.title}</strong>|作者:{item.authorNickname}|状态:{item.status}|票数:{item.voteCount}\n {item.status === 'pending' ? (\n <>\n {' '}\n <button onClick={() => void review(item, 'approve')}>通过</button>\n <button onClick={() => void review(item, 'reject')}>驳回</button>\n </>\n ) : null}\n </li>\n ))}\n </ul>\n </div>\n\n <div>\n <h3>投票风控</h3>\n <input value={voterId} onChange={(e) => setVoterId(e.target.value)} placeholder=\"voterId\" />\n <button onClick={() => void setRestriction(true)} disabled={!snapshot}>\n 封禁投票\n </button>\n <button onClick={() => void setRestriction(false)} disabled={!snapshot}>\n 解除封禁\n </button>\n <button onClick={() => void resetVotesByVoter()}>清零该用户票数</button>\n </div>\n\n <div>\n <h3>导出</h3>\n <button onClick={() => void exportExcel()}>导出投稿 Excel</button>\n </div>\n </section>\n );\n};\n\nexport default MikuContestAdminPage;\n","import React, { useState } from 'react';\nimport MikuContestAudiencePage from './MikuContestAudiencePage';\nimport MikuContestArtistPage from './MikuContestArtistPage';\nimport MikuContestAdminPage from './MikuContestAdminPage';\n\ntype MikuContestView = 'audience' | 'artist' | 'admin';\n\nexport interface MikuContestPageProps {\n defaultView?: MikuContestView;\n viewerVoterId?: string;\n artistId?: string;\n artistNickname?: string;\n adminId?: string;\n}\n\nconst MikuContestPage: React.FC<MikuContestPageProps> = ({\n defaultView = 'audience',\n viewerVoterId = 'viewer-demo',\n artistId = 'artist-demo',\n artistNickname = 'Demo 画师',\n adminId = 'admin-demo',\n}) => {\n const [view, setView] = useState<MikuContestView>(defaultView);\n\n return (\n <div>\n <h1>Miku Contest</h1>\n <div>\n <button onClick={() => setView('audience')}>观众端</button>\n <button onClick={() => setView('artist')}>画师端</button>\n <button onClick={() => setView('admin')}>管理员端</button>\n </div>\n\n {view === 'audience' ? <MikuContestAudiencePage voterId={viewerVoterId} /> : null}\n {view === 'artist' ? <MikuContestArtistPage authorId={artistId} authorNickname={artistNickname} /> : null}\n {view === 'admin' ? <MikuContestAdminPage adminId={adminId} /> : null}\n </div>\n );\n};\n\nexport default MikuContestPage;\n"]}