sa2kit 1.6.91 → 1.6.96
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.
- package/dist/client-BlkUL2To.d.ts +26 -0
- package/dist/client-DpMIhrlS.d.mts +26 -0
- package/dist/huarongdao/index.d.mts +8 -0
- package/dist/huarongdao/index.d.ts +8 -0
- package/dist/huarongdao/index.js +360 -0
- package/dist/huarongdao/index.js.map +1 -0
- package/dist/huarongdao/index.mjs +338 -0
- package/dist/huarongdao/index.mjs.map +1 -0
- package/dist/huarongdao/logic/index.d.mts +11 -0
- package/dist/huarongdao/logic/index.d.ts +11 -0
- package/dist/huarongdao/logic/index.js +89 -0
- package/dist/huarongdao/logic/index.js.map +1 -0
- package/dist/huarongdao/logic/index.mjs +81 -0
- package/dist/huarongdao/logic/index.mjs.map +1 -0
- package/dist/huarongdao/routes/index.d.mts +38 -0
- package/dist/huarongdao/routes/index.d.ts +38 -0
- package/dist/huarongdao/routes/index.js +114 -0
- package/dist/huarongdao/routes/index.js.map +1 -0
- package/dist/huarongdao/routes/index.mjs +108 -0
- package/dist/huarongdao/routes/index.mjs.map +1 -0
- package/dist/huarongdao/server/index.d.mts +14 -0
- package/dist/huarongdao/server/index.d.ts +14 -0
- package/dist/huarongdao/server/index.js +60 -0
- package/dist/huarongdao/server/index.js.map +1 -0
- package/dist/huarongdao/server/index.mjs +57 -0
- package/dist/huarongdao/server/index.mjs.map +1 -0
- package/dist/huarongdao/service/index.d.mts +31 -0
- package/dist/huarongdao/service/index.d.ts +31 -0
- package/dist/huarongdao/service/index.js +45 -0
- package/dist/huarongdao/service/index.js.map +1 -0
- package/dist/huarongdao/service/index.mjs +42 -0
- package/dist/huarongdao/service/index.mjs.map +1 -0
- package/dist/huarongdao/types/index.d.mts +46 -0
- package/dist/huarongdao/types/index.d.ts +46 -0
- package/dist/huarongdao/types/index.js +4 -0
- package/dist/huarongdao/types/index.js.map +1 -0
- package/dist/huarongdao/types/index.mjs +3 -0
- package/dist/huarongdao/types/index.mjs.map +1 -0
- package/dist/huarongdao/ui/web/index.d.mts +3 -0
- package/dist/huarongdao/ui/web/index.d.ts +3 -0
- package/dist/huarongdao/ui/web/index.js +237 -0
- package/dist/huarongdao/ui/web/index.js.map +1 -0
- package/dist/huarongdao/ui/web/index.mjs +229 -0
- package/dist/huarongdao/ui/web/index.mjs.map +1 -0
- package/dist/index-B48rcsqv.d.ts +27 -0
- package/dist/index-BNqJdwX4.d.ts +37 -0
- package/dist/index-C7yh6b5Q.d.mts +17 -0
- package/dist/index-CDapUIT5.d.mts +51 -0
- package/dist/index-Cv9jlnNz.d.ts +17 -0
- package/dist/index-D3UbkUai.d.ts +51 -0
- package/dist/index-DOtQI_mz.d.mts +37 -0
- package/dist/index-Da2X78GE.d.mts +27 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +1707 -79
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1675 -82
- package/dist/index.mjs.map +1 -1
- package/dist/mikuContest/index.d.mts +13 -0
- package/dist/mikuContest/index.d.ts +13 -0
- package/dist/mikuContest/index.js +1310 -0
- package/dist/mikuContest/index.js.map +1 -0
- package/dist/mikuContest/index.mjs +1253 -0
- package/dist/mikuContest/index.mjs.map +1 -0
- package/dist/mikuContest/logic/index.d.mts +32 -0
- package/dist/mikuContest/logic/index.d.ts +32 -0
- package/dist/mikuContest/logic/index.js +511 -0
- package/dist/mikuContest/logic/index.js.map +1 -0
- package/dist/mikuContest/logic/index.mjs +483 -0
- package/dist/mikuContest/logic/index.mjs.map +1 -0
- package/dist/mikuContest/routes/index.d.mts +80 -0
- package/dist/mikuContest/routes/index.d.ts +80 -0
- package/dist/mikuContest/routes/index.js +821 -0
- package/dist/mikuContest/routes/index.js.map +1 -0
- package/dist/mikuContest/routes/index.mjs +791 -0
- package/dist/mikuContest/routes/index.mjs.map +1 -0
- package/dist/mikuContest/server/index.d.mts +766 -0
- package/dist/mikuContest/server/index.d.ts +766 -0
- package/dist/mikuContest/server/index.js +705 -0
- package/dist/mikuContest/server/index.js.map +1 -0
- package/dist/mikuContest/server/index.mjs +672 -0
- package/dist/mikuContest/server/index.mjs.map +1 -0
- package/dist/mikuContest/service/index.d.mts +30 -0
- package/dist/mikuContest/service/index.d.ts +30 -0
- package/dist/mikuContest/service/index.js +139 -0
- package/dist/mikuContest/service/index.js.map +1 -0
- package/dist/mikuContest/service/index.mjs +135 -0
- package/dist/mikuContest/service/index.mjs.map +1 -0
- package/dist/mikuContest/types/index.d.mts +179 -0
- package/dist/mikuContest/types/index.d.ts +179 -0
- package/dist/mikuContest/types/index.js +4 -0
- package/dist/mikuContest/types/index.js.map +1 -0
- package/dist/mikuContest/types/index.mjs +3 -0
- package/dist/mikuContest/types/index.mjs.map +1 -0
- package/dist/mikuContest/ui/miniapp/index.d.mts +3 -0
- package/dist/mikuContest/ui/miniapp/index.d.ts +3 -0
- package/dist/mikuContest/ui/miniapp/index.js +566 -0
- package/dist/mikuContest/ui/miniapp/index.js.map +1 -0
- package/dist/mikuContest/ui/miniapp/index.mjs +540 -0
- package/dist/mikuContest/ui/miniapp/index.mjs.map +1 -0
- package/dist/mikuContest/ui/web/index.d.mts +4 -0
- package/dist/mikuContest/ui/web/index.d.ts +4 -0
- package/dist/mikuContest/ui/web/index.js +353 -0
- package/dist/mikuContest/ui/web/index.js.map +1 -0
- package/dist/mikuContest/ui/web/index.mjs +343 -0
- package/dist/mikuContest/ui/web/index.mjs.map +1 -0
- package/dist/qqbot/server/index.d.mts +126 -1
- package/dist/qqbot/server/index.d.ts +126 -1
- package/dist/qqbot/server/index.js +250 -0
- package/dist/qqbot/server/index.js.map +1 -1
- package/dist/qqbot/server/index.mjs +246 -1
- package/dist/qqbot/server/index.mjs.map +1 -1
- package/dist/service-D7DM1wW-.d.ts +38 -0
- package/dist/service-DPr2rlvH.d.mts +38 -0
- package/dist/types-BS7Xz09b.d.mts +14 -0
- package/dist/types-k4koMp4m.d.ts +14 -0
- package/package.json +76 -1
package/dist/index.js
CHANGED
|
@@ -18,6 +18,8 @@ var crypto = require('crypto');
|
|
|
18
18
|
require('bcryptjs');
|
|
19
19
|
require('jsonwebtoken');
|
|
20
20
|
var THREE2 = require('three');
|
|
21
|
+
var XLSX = require('xlsx');
|
|
22
|
+
var server = require('next/server');
|
|
21
23
|
|
|
22
24
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
23
25
|
|
|
@@ -42,13 +44,19 @@ function _interopNamespace(e) {
|
|
|
42
44
|
var React69__namespace = /*#__PURE__*/_interopNamespace(React69);
|
|
43
45
|
var Link__default = /*#__PURE__*/_interopDefault(Link);
|
|
44
46
|
var THREE2__namespace = /*#__PURE__*/_interopNamespace(THREE2);
|
|
47
|
+
var XLSX__namespace = /*#__PURE__*/_interopNamespace(XLSX);
|
|
45
48
|
|
|
49
|
+
var __defProp = Object.defineProperty;
|
|
46
50
|
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
47
51
|
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
48
52
|
}) : x)(function(x) {
|
|
49
53
|
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
50
54
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
51
55
|
});
|
|
56
|
+
var __export = (target, all) => {
|
|
57
|
+
for (var name in all)
|
|
58
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
59
|
+
};
|
|
52
60
|
|
|
53
61
|
// src/logger/types.ts
|
|
54
62
|
var LogLevel = /* @__PURE__ */ ((LogLevel2) => {
|
|
@@ -76,10 +84,10 @@ var ConsoleLoggerAdapter = class {
|
|
|
76
84
|
};
|
|
77
85
|
}
|
|
78
86
|
log(entry) {
|
|
79
|
-
const { level, message, timestamp:
|
|
87
|
+
const { level, message, timestamp: timestamp6, data, context, error } = entry;
|
|
80
88
|
let logMessage = "";
|
|
81
|
-
if (
|
|
82
|
-
logMessage += "[" + this.formatTimestamp(
|
|
89
|
+
if (timestamp6) {
|
|
90
|
+
logMessage += "[" + this.formatTimestamp(timestamp6) + "] ";
|
|
83
91
|
}
|
|
84
92
|
const levelName = this.getLevelName(level);
|
|
85
93
|
logMessage += levelName + ": ";
|
|
@@ -572,7 +580,7 @@ var useSentimentAnalysis = (options = {}) => {
|
|
|
572
580
|
result: null
|
|
573
581
|
});
|
|
574
582
|
const pipelineRef = React69.useRef(null);
|
|
575
|
-
const analyze = React69.useCallback(async (
|
|
583
|
+
const analyze = React69.useCallback(async (text6) => {
|
|
576
584
|
setState((prev) => ({
|
|
577
585
|
...prev,
|
|
578
586
|
isProcessing: true,
|
|
@@ -619,12 +627,12 @@ var useSentimentAnalysis = (options = {}) => {
|
|
|
619
627
|
pipelineRef.current = await pipeline("sentiment-analysis", options.model || defaultModel);
|
|
620
628
|
}
|
|
621
629
|
setState((prev) => ({ ...prev, status: "analyzing" }));
|
|
622
|
-
const output = await pipelineRef.current(
|
|
630
|
+
const output = await pipelineRef.current(text6);
|
|
623
631
|
const resultData = output[0];
|
|
624
632
|
const label = resultData.label.toLowerCase();
|
|
625
633
|
let sentiment = "neutral";
|
|
626
634
|
const negativeKeywords = ["\u7D2F", "\u60E8", "\u7EDD\u671B", "\u96BE\u53D7", "\u4F24\u5FC3", "\u5DEE", "\u574F", "\u7CDF", "\u4E0D\u884C"];
|
|
627
|
-
const hasNegativeKeyword = negativeKeywords.some((k) =>
|
|
635
|
+
const hasNegativeKeyword = negativeKeywords.some((k) => text6.includes(k));
|
|
628
636
|
if (label.includes("positive") && !hasNegativeKeyword) {
|
|
629
637
|
sentiment = "positive";
|
|
630
638
|
} else if (label.includes("negative") || label.includes("0") || hasNegativeKeyword) {
|
|
@@ -656,12 +664,12 @@ var SentimentAnalyzer = ({
|
|
|
656
664
|
className = "",
|
|
657
665
|
placeholder = "\u8F93\u5165\u4E00\u6BB5\u4E2D\u6587\u6216\u82F1\u6587\uFF0C\u5206\u6790\u5176\u60C5\u611F\u503E\u5411..."
|
|
658
666
|
}) => {
|
|
659
|
-
const [
|
|
667
|
+
const [text6, setText] = React69.useState("");
|
|
660
668
|
const { analyze, isProcessing, status, result, error } = useSentimentAnalysis();
|
|
661
669
|
const handleAnalyze = async () => {
|
|
662
|
-
if (!
|
|
670
|
+
if (!text6.trim() || isProcessing) return;
|
|
663
671
|
try {
|
|
664
|
-
const res = await analyze(
|
|
672
|
+
const res = await analyze(text6);
|
|
665
673
|
onResult?.(res);
|
|
666
674
|
} catch (err) {
|
|
667
675
|
console.error("Sentiment Analysis Error:", err);
|
|
@@ -692,7 +700,7 @@ var SentimentAnalyzer = ({
|
|
|
692
700
|
return /* @__PURE__ */ React69__namespace.default.createElement("div", { className: clsx.clsx("p-6 border rounded-xl bg-white dark:bg-gray-800 shadow-sm", className) }, /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "flex items-center gap-2 mb-4 text-gray-700 dark:text-gray-300 font-medium" }, /* @__PURE__ */ React69__namespace.default.createElement(lucideReact.MessageSquare, { size: 20 }), /* @__PURE__ */ React69__namespace.default.createElement("span", null, "\u6587\u672C\u60C5\u611F\u5206\u6790")), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "relative" }, /* @__PURE__ */ React69__namespace.default.createElement(
|
|
693
701
|
"textarea",
|
|
694
702
|
{
|
|
695
|
-
value:
|
|
703
|
+
value: text6,
|
|
696
704
|
onChange: (e) => setText(e.target.value),
|
|
697
705
|
placeholder,
|
|
698
706
|
className: "w-full h-32 p-4 bg-gray-50 dark:bg-gray-900 border border-gray-200 dark:border-gray-700 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent transition-all outline-none resize-none text-gray-800 dark:text-gray-200",
|
|
@@ -702,7 +710,7 @@ var SentimentAnalyzer = ({
|
|
|
702
710
|
"button",
|
|
703
711
|
{
|
|
704
712
|
onClick: handleAnalyze,
|
|
705
|
-
disabled: !
|
|
713
|
+
disabled: !text6.trim() || isProcessing,
|
|
706
714
|
className: "absolute bottom-3 right-3 p-2 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white rounded-md transition-colors shadow-sm"
|
|
707
715
|
},
|
|
708
716
|
isProcessing ? /* @__PURE__ */ React69__namespace.default.createElement(lucideReact.Loader2, { className: "animate-spin", size: 18 }) : /* @__PURE__ */ React69__namespace.default.createElement(lucideReact.Send, { size: 18 })
|
|
@@ -890,13 +898,13 @@ var requestJson = async (options) => {
|
|
|
890
898
|
body: body ? JSON.stringify(body) : void 0,
|
|
891
899
|
signal: controller?.signal
|
|
892
900
|
});
|
|
893
|
-
const
|
|
901
|
+
const text6 = await response.text();
|
|
894
902
|
let data = null;
|
|
895
|
-
if (
|
|
903
|
+
if (text6) {
|
|
896
904
|
try {
|
|
897
|
-
data = JSON.parse(
|
|
905
|
+
data = JSON.parse(text6);
|
|
898
906
|
} catch {
|
|
899
|
-
data =
|
|
907
|
+
data = text6;
|
|
900
908
|
}
|
|
901
909
|
}
|
|
902
910
|
if (!response.ok) {
|
|
@@ -1357,20 +1365,20 @@ var japaneseUtils = {
|
|
|
1357
1365
|
/**
|
|
1358
1366
|
* 提取文本中的汉字
|
|
1359
1367
|
*/
|
|
1360
|
-
extractKanji(
|
|
1361
|
-
return
|
|
1368
|
+
extractKanji(text6) {
|
|
1369
|
+
return text6.match(/[\u4E00-\u9FAF]/g) || [];
|
|
1362
1370
|
},
|
|
1363
1371
|
/**
|
|
1364
1372
|
* 提取文本中的假名
|
|
1365
1373
|
*/
|
|
1366
|
-
extractKana(
|
|
1367
|
-
return
|
|
1374
|
+
extractKana(text6) {
|
|
1375
|
+
return text6.match(/[\u3040-\u309F\u30A0-\u30FF]/g) || [];
|
|
1368
1376
|
},
|
|
1369
1377
|
/**
|
|
1370
1378
|
* 清理文本,移除特殊字符但保留日语字符
|
|
1371
1379
|
*/
|
|
1372
|
-
cleanText(
|
|
1373
|
-
return
|
|
1380
|
+
cleanText(text6) {
|
|
1381
|
+
return text6.replace(/[^\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF\w\s]/g, "");
|
|
1374
1382
|
}
|
|
1375
1383
|
};
|
|
1376
1384
|
|
|
@@ -1459,11 +1467,11 @@ var fileUtils = {
|
|
|
1459
1467
|
* 生成唯一文件名
|
|
1460
1468
|
*/
|
|
1461
1469
|
generateUniqueFileName(originalName) {
|
|
1462
|
-
const
|
|
1470
|
+
const timestamp6 = Date.now();
|
|
1463
1471
|
const random = Math.random().toString(36).substring(2, 15);
|
|
1464
1472
|
const extension = this.getFileExtension(originalName);
|
|
1465
1473
|
const baseName = originalName.replace("." + extension, "");
|
|
1466
|
-
return extension ? baseName + "_" +
|
|
1474
|
+
return extension ? baseName + "_" + timestamp6 + "_" + random + "." + extension : baseName + "_" + timestamp6 + "_" + random;
|
|
1467
1475
|
},
|
|
1468
1476
|
/**
|
|
1469
1477
|
* 验证文件名是否有效
|
|
@@ -1533,28 +1541,28 @@ var stringUtils = {
|
|
|
1533
1541
|
/**
|
|
1534
1542
|
* 截断文本
|
|
1535
1543
|
*/
|
|
1536
|
-
truncate(
|
|
1537
|
-
if (
|
|
1538
|
-
return
|
|
1544
|
+
truncate(text6, length, suffix = "...") {
|
|
1545
|
+
if (text6.length <= length) return text6;
|
|
1546
|
+
return text6.substring(0, length - suffix.length) + suffix;
|
|
1539
1547
|
},
|
|
1540
1548
|
/**
|
|
1541
1549
|
* 首字母大写
|
|
1542
1550
|
*/
|
|
1543
|
-
capitalize(
|
|
1544
|
-
if (!
|
|
1545
|
-
return
|
|
1551
|
+
capitalize(text6) {
|
|
1552
|
+
if (!text6) return "";
|
|
1553
|
+
return text6.charAt(0).toUpperCase() + text6.slice(1).toLowerCase();
|
|
1546
1554
|
},
|
|
1547
1555
|
/**
|
|
1548
1556
|
* 驼峰转下划线
|
|
1549
1557
|
*/
|
|
1550
|
-
camelToSnake(
|
|
1551
|
-
return
|
|
1558
|
+
camelToSnake(text6) {
|
|
1559
|
+
return text6.replace(/[A-Z]/g, (letter) => "_" + letter.toLowerCase());
|
|
1552
1560
|
},
|
|
1553
1561
|
/**
|
|
1554
1562
|
* 下划线转驼峰
|
|
1555
1563
|
*/
|
|
1556
|
-
snakeToCamel(
|
|
1557
|
-
return
|
|
1564
|
+
snakeToCamel(text6) {
|
|
1565
|
+
return text6.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
1558
1566
|
},
|
|
1559
1567
|
/**
|
|
1560
1568
|
* 生成随机字符串
|
|
@@ -3655,7 +3663,7 @@ function ImageMappingPanel({
|
|
|
3655
3663
|
uploadLabel = "\u4E0A\u4F20\u56FE\u7247",
|
|
3656
3664
|
clearLabel = "\u6E05\u9664"
|
|
3657
3665
|
}) {
|
|
3658
|
-
const handleFileChange = (
|
|
3666
|
+
const handleFileChange = (id2, file) => {
|
|
3659
3667
|
if (!file) {
|
|
3660
3668
|
return;
|
|
3661
3669
|
}
|
|
@@ -3667,14 +3675,14 @@ function ImageMappingPanel({
|
|
|
3667
3675
|
}
|
|
3668
3676
|
onChange({
|
|
3669
3677
|
...value,
|
|
3670
|
-
[
|
|
3678
|
+
[id2]: base64
|
|
3671
3679
|
});
|
|
3672
3680
|
};
|
|
3673
3681
|
reader.readAsDataURL(file);
|
|
3674
3682
|
};
|
|
3675
|
-
const handleRemove = (
|
|
3683
|
+
const handleRemove = (id2) => {
|
|
3676
3684
|
const next = { ...value };
|
|
3677
|
-
delete next[
|
|
3685
|
+
delete next[id2];
|
|
3678
3686
|
onChange(next);
|
|
3679
3687
|
};
|
|
3680
3688
|
return /* @__PURE__ */ React69__namespace.default.createElement("details", { className: cn("rounded-lg border border-slate-200 bg-white/80 p-3", className) }, /* @__PURE__ */ React69__namespace.default.createElement("summary", { className: "cursor-pointer text-sm font-semibold text-slate-700" }, title), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "mt-3 grid grid-cols-1 gap-2 sm:grid-cols-2" }, items.map((item) => {
|
|
@@ -4814,8 +4822,8 @@ var FloatingMenuExample = () => {
|
|
|
4814
4822
|
{ id: 4, label: "\u5E2E\u52A9", icon: "\u2753" },
|
|
4815
4823
|
{ id: 5, label: "\u9000\u51FA", icon: "\u{1F6AA}" }
|
|
4816
4824
|
];
|
|
4817
|
-
const handleMenuItemClick = (
|
|
4818
|
-
console.log("\u70B9\u51FB\u4E86\u83DC\u5355\u9879: " +
|
|
4825
|
+
const handleMenuItemClick = (id2) => {
|
|
4826
|
+
console.log("\u70B9\u51FB\u4E86\u83DC\u5355\u9879: " + id2);
|
|
4819
4827
|
};
|
|
4820
4828
|
return /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "w-full h-screen bg-gray-100 relative p-8" }, /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "max-w-2xl mx-auto bg-white rounded-2xl shadow-sm p-8 mt-12" }, /* @__PURE__ */ React69__namespace.default.createElement("h1", { className: "text-3xl font-bold mb-4 text-gray-900" }, "\u60AC\u6D6E\u83DC\u5355\u793A\u4F8B"), /* @__PURE__ */ React69__namespace.default.createElement("p", { className: "text-gray-600 leading-relaxed mb-6" }, "\u8FD9\u662F\u4E00\u4E2A\u53EF\u62D6\u62FD\u7684\u60AC\u6D6E\u83DC\u5355\u7EC4\u4EF6\u793A\u4F8B\u3002\u4F60\u53EF\u4EE5\u5C1D\u8BD5\u62D6\u52A8\u4E0B\u65B9\u7684 ", /* @__PURE__ */ React69__namespace.default.createElement("span", { className: "font-bold text-blue-600" }, "\u84DD\u8272\u6309\u94AE"), " \u5230\u5904\u79FB\u52A8\u3002"), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "bg-blue-50 border-l-4 border-blue-500 p-4 mb-6" }, /* @__PURE__ */ React69__namespace.default.createElement("p", { className: "text-sm text-blue-700" }, /* @__PURE__ */ React69__namespace.default.createElement("strong", null, "\u667A\u80FD\u5B9A\u4F4D\uFF1A"), " \u83DC\u5355\u4F1A\u6839\u636E\u6309\u94AE\u5728\u5C4F\u5E55\u4E0A\u7684\u4F4D\u7F6E\u81EA\u52A8\u8C03\u6574\u5F39\u51FA\u65B9\u5411\uFF08\u5411\u5DE6\u6216\u5411\u53F3\uFF09\u3002"))), /* @__PURE__ */ React69__namespace.default.createElement(
|
|
4821
4829
|
FloatingMenu_default,
|
|
@@ -5673,9 +5681,9 @@ var UserInfoBar = ({ apiClient }) => {
|
|
|
5673
5681
|
))));
|
|
5674
5682
|
};
|
|
5675
5683
|
function DanmakuPanel({ onSend }) {
|
|
5676
|
-
const [
|
|
5684
|
+
const [text6, setText] = React69.useState("");
|
|
5677
5685
|
const emit = () => {
|
|
5678
|
-
const value =
|
|
5686
|
+
const value = text6.trim();
|
|
5679
5687
|
if (!value) {
|
|
5680
5688
|
return;
|
|
5681
5689
|
}
|
|
@@ -5686,7 +5694,7 @@ function DanmakuPanel({ onSend }) {
|
|
|
5686
5694
|
"input",
|
|
5687
5695
|
{
|
|
5688
5696
|
type: "text",
|
|
5689
|
-
value:
|
|
5697
|
+
value: text6,
|
|
5690
5698
|
onChange: (event) => setText(event.target.value),
|
|
5691
5699
|
onKeyDown: (event) => {
|
|
5692
5700
|
if (event.key === "Enter") {
|
|
@@ -5786,8 +5794,8 @@ function FireworksControlPanel({
|
|
|
5786
5794
|
function useDanmakuController(options) {
|
|
5787
5795
|
const [items, setItems] = React69.useState([]);
|
|
5788
5796
|
const cursorRef = React69.useRef(0);
|
|
5789
|
-
const removeItem = React69.useCallback((
|
|
5790
|
-
setItems((prev) => prev.filter((item) => item.id !==
|
|
5797
|
+
const removeItem = React69.useCallback((id2) => {
|
|
5798
|
+
setItems((prev) => prev.filter((item) => item.id !== id2));
|
|
5791
5799
|
}, []);
|
|
5792
5800
|
const addIncoming = React69.useCallback((message) => {
|
|
5793
5801
|
setItems((prev) => {
|
|
@@ -5802,8 +5810,8 @@ function useDanmakuController(options) {
|
|
|
5802
5810
|
cursorRef.current += 1;
|
|
5803
5811
|
}, []);
|
|
5804
5812
|
const send = React69.useCallback(
|
|
5805
|
-
(
|
|
5806
|
-
const trimmed =
|
|
5813
|
+
(text6, color, sendOptions) => {
|
|
5814
|
+
const trimmed = text6.trim();
|
|
5807
5815
|
if (!trimmed) {
|
|
5808
5816
|
return null;
|
|
5809
5817
|
}
|
|
@@ -5840,26 +5848,26 @@ function useDanmakuController(options) {
|
|
|
5840
5848
|
[addIncoming, items, removeItem, send]
|
|
5841
5849
|
);
|
|
5842
5850
|
}
|
|
5843
|
-
function parseCommand(
|
|
5844
|
-
if (
|
|
5845
|
-
return { launchKind: "miku", content:
|
|
5851
|
+
function parseCommand(text6) {
|
|
5852
|
+
if (text6.startsWith("/miku ")) {
|
|
5853
|
+
return { launchKind: "miku", content: text6.replace("/miku ", "").trim() };
|
|
5846
5854
|
}
|
|
5847
|
-
if (
|
|
5855
|
+
if (text6 === "/miku") {
|
|
5848
5856
|
return { launchKind: "miku", content: "MIKU!" };
|
|
5849
5857
|
}
|
|
5850
|
-
if (
|
|
5851
|
-
return { launchKind: "avatar", content:
|
|
5858
|
+
if (text6.startsWith("/avatar ")) {
|
|
5859
|
+
return { launchKind: "avatar", content: text6.replace("/avatar ", "").trim() };
|
|
5852
5860
|
}
|
|
5853
|
-
if (
|
|
5861
|
+
if (text6 === "/avatar") {
|
|
5854
5862
|
return { launchKind: "avatar", content: "Avatar Firework!" };
|
|
5855
5863
|
}
|
|
5856
|
-
if (
|
|
5857
|
-
return { launchKind: "normal", content:
|
|
5864
|
+
if (text6.startsWith("/normal ")) {
|
|
5865
|
+
return { launchKind: "normal", content: text6.replace("/normal ", "").trim() };
|
|
5858
5866
|
}
|
|
5859
|
-
if (
|
|
5867
|
+
if (text6 === "/normal") {
|
|
5860
5868
|
return { launchKind: "normal", content: "Fireworks!" };
|
|
5861
5869
|
}
|
|
5862
|
-
return { content:
|
|
5870
|
+
return { content: text6 };
|
|
5863
5871
|
}
|
|
5864
5872
|
function createCircularSpriteTexture() {
|
|
5865
5873
|
const size = 64;
|
|
@@ -6541,12 +6549,12 @@ var WebSocketTransport = class {
|
|
|
6541
6549
|
}
|
|
6542
6550
|
};
|
|
6543
6551
|
function parseServerMessage(raw) {
|
|
6544
|
-
const
|
|
6545
|
-
if (!
|
|
6552
|
+
const text6 = decodeMessage(raw);
|
|
6553
|
+
if (!text6) {
|
|
6546
6554
|
return null;
|
|
6547
6555
|
}
|
|
6548
6556
|
try {
|
|
6549
|
-
return JSON.parse(
|
|
6557
|
+
return JSON.parse(text6);
|
|
6550
6558
|
} catch {
|
|
6551
6559
|
return null;
|
|
6552
6560
|
}
|
|
@@ -6813,8 +6821,8 @@ function MikuFireworks3D({
|
|
|
6813
6821
|
}
|
|
6814
6822
|
launch(payload);
|
|
6815
6823
|
};
|
|
6816
|
-
const handleSendDanmaku = (
|
|
6817
|
-
const result = send(
|
|
6824
|
+
const handleSendDanmaku = (text6) => {
|
|
6825
|
+
const result = send(text6, void 0, {
|
|
6818
6826
|
optimistic: !realtimeEnabled
|
|
6819
6827
|
});
|
|
6820
6828
|
if (!result) {
|
|
@@ -6913,9 +6921,9 @@ function useScreenReceiver(options) {
|
|
|
6913
6921
|
const peerRef = React69.useRef({ pendingCandidates: [] });
|
|
6914
6922
|
const videoRef = React69.useRef(null);
|
|
6915
6923
|
const appendLog = React69.useCallback(
|
|
6916
|
-
(
|
|
6924
|
+
(text6) => {
|
|
6917
6925
|
logIdRef.current += 1;
|
|
6918
|
-
setLogs((prev) => [...prev, { id: logIdRef.current, text:
|
|
6926
|
+
setLogs((prev) => [...prev, { id: logIdRef.current, text: text6 }].slice(-maxLogs));
|
|
6919
6927
|
},
|
|
6920
6928
|
[maxLogs]
|
|
6921
6929
|
);
|
|
@@ -7641,8 +7649,8 @@ var withRoundedClip = (ctx, left, top, width, height, radius, draw) => {
|
|
|
7641
7649
|
draw();
|
|
7642
7650
|
ctx.restore();
|
|
7643
7651
|
};
|
|
7644
|
-
var drawMultilineText = (ctx,
|
|
7645
|
-
const paragraphs =
|
|
7652
|
+
var drawMultilineText = (ctx, text6, left, top, maxWidth, lineHeight) => {
|
|
7653
|
+
const paragraphs = text6.split("\n");
|
|
7646
7654
|
let currentY = top;
|
|
7647
7655
|
paragraphs.forEach((paragraph, index) => {
|
|
7648
7656
|
const words = paragraph.split("");
|
|
@@ -8307,19 +8315,19 @@ var FestivalCardConfigPage = ({
|
|
|
8307
8315
|
const createNew = async () => {
|
|
8308
8316
|
const name = window.prompt("\u8BF7\u8F93\u5165\u65B0\u5361\u7247\u540D\u79F0");
|
|
8309
8317
|
if (!name) return;
|
|
8310
|
-
const
|
|
8318
|
+
const id2 = `festival-${Date.now()}`;
|
|
8311
8319
|
const config = normalizeFestivalCardConfig({
|
|
8312
|
-
id,
|
|
8320
|
+
id: id2,
|
|
8313
8321
|
name
|
|
8314
8322
|
});
|
|
8315
8323
|
try {
|
|
8316
|
-
const response = await fetch(`${apiBase}/${encodeURIComponent(
|
|
8324
|
+
const response = await fetch(`${apiBase}/${encodeURIComponent(id2)}`, {
|
|
8317
8325
|
method: "PUT",
|
|
8318
8326
|
headers: { "Content-Type": "application/json" },
|
|
8319
8327
|
body: JSON.stringify({ config })
|
|
8320
8328
|
});
|
|
8321
8329
|
if (!response.ok) throw new Error(`\u521B\u5EFA\u5931\u8D25: ${response.status}`);
|
|
8322
|
-
setSelectedId(
|
|
8330
|
+
setSelectedId(id2);
|
|
8323
8331
|
await reloadList();
|
|
8324
8332
|
window.alert("\u65B0\u5361\u7247\u521B\u5EFA\u6210\u529F");
|
|
8325
8333
|
} catch (error) {
|
|
@@ -8424,21 +8432,21 @@ if (!memoryStore.has(defaultId)) {
|
|
|
8424
8432
|
var createInMemoryFestivalCardDb = () => ({
|
|
8425
8433
|
listConfigs() {
|
|
8426
8434
|
return Promise.resolve(
|
|
8427
|
-
Array.from(memoryStore.entries()).map(([
|
|
8428
|
-
id,
|
|
8429
|
-
name: config.name ||
|
|
8435
|
+
Array.from(memoryStore.entries()).map(([id2, config]) => ({
|
|
8436
|
+
id: id2,
|
|
8437
|
+
name: config.name || id2
|
|
8430
8438
|
}))
|
|
8431
8439
|
);
|
|
8432
8440
|
},
|
|
8433
|
-
getConfig(
|
|
8434
|
-
return Promise.resolve(memoryStore.get(
|
|
8441
|
+
getConfig(id2) {
|
|
8442
|
+
return Promise.resolve(memoryStore.get(id2) || null);
|
|
8435
8443
|
},
|
|
8436
|
-
saveConfig(
|
|
8437
|
-
memoryStore.set(
|
|
8444
|
+
saveConfig(id2, config) {
|
|
8445
|
+
memoryStore.set(id2, config);
|
|
8438
8446
|
return Promise.resolve();
|
|
8439
8447
|
},
|
|
8440
|
-
deleteConfig(
|
|
8441
|
-
memoryStore.delete(
|
|
8448
|
+
deleteConfig(id2) {
|
|
8449
|
+
memoryStore.delete(id2);
|
|
8442
8450
|
return Promise.resolve();
|
|
8443
8451
|
}
|
|
8444
8452
|
});
|
|
@@ -8799,6 +8807,1592 @@ var BoothConfigPage = ({ initialConfig, onSave }) => {
|
|
|
8799
8807
|
)), /* @__PURE__ */ React69__namespace.default.createElement("div", { className: "flex gap-2" }, /* @__PURE__ */ React69__namespace.default.createElement("button", { className: "rounded bg-indigo-600 px-3 py-2 text-white", disabled: saving, onClick: save }, saving ? "\u4FDD\u5B58\u4E2D..." : "\u4FDD\u5B58\u914D\u7F6E"), /* @__PURE__ */ React69__namespace.default.createElement("button", { className: "rounded border px-3 py-2", onClick: reset }, "\u6062\u590D\u9ED8\u8BA4")));
|
|
8800
8808
|
};
|
|
8801
8809
|
|
|
8810
|
+
// src/mikuContest/logic/shared/defaults.ts
|
|
8811
|
+
var defaultMikuVotingRules = {
|
|
8812
|
+
maxVotesPerDay: 3,
|
|
8813
|
+
forbidDuplicateVotePerWork: true,
|
|
8814
|
+
maxVotesPerDevicePerDay: 20,
|
|
8815
|
+
maxVotesPerIpPerDay: 100
|
|
8816
|
+
};
|
|
8817
|
+
var createDefaultMikuContestConfig = (overrides) => ({
|
|
8818
|
+
id: overrides?.id || "miku-contest-default",
|
|
8819
|
+
name: overrides?.name || "\u521D\u97F3\u672A\u6765\u793E\u56E2\u5F81\u7A3F\u5927\u8D5B",
|
|
8820
|
+
theme: overrides?.theme || "\u521D\u97F3\u672A\u6765\u4E3B\u9898\u521B\u4F5C\u5F81\u7A3F",
|
|
8821
|
+
organizer: overrides?.organizer || "\u521D\u97F3\u672A\u6765\u793E\u56E2",
|
|
8822
|
+
awards: overrides?.awards || ["\u4E00\u7B49\u5956", "\u4E8C\u7B49\u5956", "\u4E09\u7B49\u5956", "\u4EBA\u6C14\u5956"],
|
|
8823
|
+
rules: overrides?.rules || "\u8BF7\u786E\u4FDD\u4F5C\u54C1\u539F\u521B\u4E14\u7B26\u5408\u793E\u56E2\u89C4\u8303\u3002",
|
|
8824
|
+
copyright: overrides?.copyright || "\u6295\u7A3F\u5373\u89C6\u4E3A\u6388\u6743\u8D5B\u4E8B\u5C55\u793A\u4E0E\u516C\u793A\u3002",
|
|
8825
|
+
timeline: overrides?.timeline || {
|
|
8826
|
+
submissionStartAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8827
|
+
submissionEndAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8828
|
+
votingStartAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8829
|
+
votingEndAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
8830
|
+
publicResultAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
8831
|
+
},
|
|
8832
|
+
votingRules: {
|
|
8833
|
+
...defaultMikuVotingRules,
|
|
8834
|
+
...overrides?.votingRules || {}
|
|
8835
|
+
},
|
|
8836
|
+
toggles: {
|
|
8837
|
+
submissionEnabled: overrides?.toggles?.submissionEnabled ?? true,
|
|
8838
|
+
votingEnabled: overrides?.toggles?.votingEnabled ?? true,
|
|
8839
|
+
resultEnabled: overrides?.toggles?.resultEnabled ?? false
|
|
8840
|
+
}
|
|
8841
|
+
});
|
|
8842
|
+
|
|
8843
|
+
// src/mikuContest/logic/shared/validators.ts
|
|
8844
|
+
var DESCRIPTION_LIMIT = 500;
|
|
8845
|
+
var MINIAPP_DESCRIPTION_LIMIT = 200;
|
|
8846
|
+
var TEXT_CONTENT_LIMIT = 2e3;
|
|
8847
|
+
var MAX_TAGS = 3;
|
|
8848
|
+
var hasValue = (value) => {
|
|
8849
|
+
return typeof value === "string" ? value.trim().length > 0 : value !== null && value !== void 0;
|
|
8850
|
+
};
|
|
8851
|
+
var validateByType = (type, input) => {
|
|
8852
|
+
const errors = [];
|
|
8853
|
+
const { content } = input;
|
|
8854
|
+
switch (type) {
|
|
8855
|
+
case "visual": {
|
|
8856
|
+
const imageCount = content.images?.length || 0;
|
|
8857
|
+
if (imageCount < 1 || imageCount > 3) {
|
|
8858
|
+
errors.push("\u89C6\u89C9\u7C7B\u4F5C\u54C1\u9700\u4E0A\u4F20 1-3 \u5F20\u56FE\u7247");
|
|
8859
|
+
}
|
|
8860
|
+
break;
|
|
8861
|
+
}
|
|
8862
|
+
case "video": {
|
|
8863
|
+
if (!hasValue(content.videoLink)) {
|
|
8864
|
+
errors.push("\u89C6\u9891\u7C7B\u4F5C\u54C1\u9700\u63D0\u4F9B\u89C6\u9891\u94FE\u63A5");
|
|
8865
|
+
}
|
|
8866
|
+
if (!hasValue(content.coverImage)) {
|
|
8867
|
+
errors.push("\u89C6\u9891\u7C7B\u4F5C\u54C1\u9700\u63D0\u4F9B\u5C01\u9762\u56FE");
|
|
8868
|
+
}
|
|
8869
|
+
break;
|
|
8870
|
+
}
|
|
8871
|
+
case "text": {
|
|
8872
|
+
const text6 = content.textContent || "";
|
|
8873
|
+
if (!text6.trim()) {
|
|
8874
|
+
errors.push("\u6587\u5B57\u7C7B\u4F5C\u54C1\u9700\u586B\u5199\u6B63\u6587");
|
|
8875
|
+
}
|
|
8876
|
+
if (text6.length > TEXT_CONTENT_LIMIT) {
|
|
8877
|
+
errors.push(`\u6587\u5B57\u6B63\u6587\u4E0D\u80FD\u8D85\u8FC7 ${TEXT_CONTENT_LIMIT} \u5B57`);
|
|
8878
|
+
}
|
|
8879
|
+
break;
|
|
8880
|
+
}
|
|
8881
|
+
case "audio": {
|
|
8882
|
+
if (!hasValue(content.audioLink)) {
|
|
8883
|
+
errors.push("\u97F3\u9891\u7C7B\u4F5C\u54C1\u9700\u63D0\u4F9B\u97F3\u9891\u94FE\u63A5");
|
|
8884
|
+
}
|
|
8885
|
+
break;
|
|
8886
|
+
}
|
|
8887
|
+
}
|
|
8888
|
+
return errors;
|
|
8889
|
+
};
|
|
8890
|
+
var validateMikuSubmissionInput = (input, mode = "web") => {
|
|
8891
|
+
const errors = [];
|
|
8892
|
+
if (!input.contestId.trim()) errors.push("contestId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
8893
|
+
if (!input.authorId.trim()) errors.push("authorId \u4E0D\u80FD\u4E3A\u7A7A");
|
|
8894
|
+
if (!input.authorNickname.trim()) errors.push("\u4F5C\u8005\u6635\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
8895
|
+
if (!input.title.trim()) errors.push("\u4F5C\u54C1\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A");
|
|
8896
|
+
const descriptionLimit = mode === "miniapp" ? MINIAPP_DESCRIPTION_LIMIT : DESCRIPTION_LIMIT;
|
|
8897
|
+
if (input.description.length > descriptionLimit) {
|
|
8898
|
+
errors.push(`\u4F5C\u54C1\u7B80\u4ECB\u4E0D\u80FD\u8D85\u8FC7 ${descriptionLimit} \u5B57`);
|
|
8899
|
+
}
|
|
8900
|
+
if ((input.tags?.length || 0) > MAX_TAGS) {
|
|
8901
|
+
errors.push(`\u6807\u7B7E\u6700\u591A ${MAX_TAGS} \u4E2A`);
|
|
8902
|
+
}
|
|
8903
|
+
errors.push(...validateByType(input.type, input));
|
|
8904
|
+
return errors;
|
|
8905
|
+
};
|
|
8906
|
+
|
|
8907
|
+
// src/mikuContest/logic/shared/voting.ts
|
|
8908
|
+
var toVoteDayKey = (date = /* @__PURE__ */ new Date()) => {
|
|
8909
|
+
const y = date.getUTCFullYear();
|
|
8910
|
+
const m = String(date.getUTCMonth() + 1).padStart(2, "0");
|
|
8911
|
+
const d = String(date.getUTCDate()).padStart(2, "0");
|
|
8912
|
+
return `${y}-${m}-${d}`;
|
|
8913
|
+
};
|
|
8914
|
+
var checkVoteEligibility = (context) => {
|
|
8915
|
+
const { existingVotes, submissionId, voterId, dayKey, rules } = context;
|
|
8916
|
+
const userTodayVotes = existingVotes.filter((vote) => vote.voterId === voterId && vote.dayKey === dayKey);
|
|
8917
|
+
if (userTodayVotes.length >= rules.maxVotesPerDay) {
|
|
8918
|
+
return { ok: false, reason: "\u5DF2\u8FBE\u5230\u4ECA\u65E5\u6295\u7968\u4E0A\u9650" };
|
|
8919
|
+
}
|
|
8920
|
+
if (rules.forbidDuplicateVotePerWork) {
|
|
8921
|
+
const duplicated = userTodayVotes.some((vote) => vote.submissionId === submissionId);
|
|
8922
|
+
if (duplicated) return { ok: false, reason: "\u4E0D\u53EF\u91CD\u590D\u6295\u540C\u4E00\u4F5C\u54C1" };
|
|
8923
|
+
}
|
|
8924
|
+
return { ok: true };
|
|
8925
|
+
};
|
|
8926
|
+
var sortByVotesDesc = (items) => {
|
|
8927
|
+
return [...items].sort((a, b) => {
|
|
8928
|
+
if (b.voteCount === a.voteCount) {
|
|
8929
|
+
return (a.createdAt || "").localeCompare(b.createdAt || "");
|
|
8930
|
+
}
|
|
8931
|
+
return b.voteCount - a.voteCount;
|
|
8932
|
+
});
|
|
8933
|
+
};
|
|
8934
|
+
var randomId = (prefix) => {
|
|
8935
|
+
return `${prefix}_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
8936
|
+
};
|
|
8937
|
+
var serialNo = () => {
|
|
8938
|
+
const now = /* @__PURE__ */ new Date();
|
|
8939
|
+
const y = now.getFullYear();
|
|
8940
|
+
const m = String(now.getMonth() + 1).padStart(2, "0");
|
|
8941
|
+
const d = String(now.getDate()).padStart(2, "0");
|
|
8942
|
+
const seq = Math.floor(Math.random() * 9e3 + 1e3);
|
|
8943
|
+
return `MIKU-${y}${m}${d}-${seq}`;
|
|
8944
|
+
};
|
|
8945
|
+
var MikuContestService = class {
|
|
8946
|
+
constructor(options = {}) {
|
|
8947
|
+
this.submissions = /* @__PURE__ */ new Map();
|
|
8948
|
+
this.votes = [];
|
|
8949
|
+
this.announcements = /* @__PURE__ */ new Map();
|
|
8950
|
+
this.voterRestrictions = /* @__PURE__ */ new Map();
|
|
8951
|
+
this.contest = createDefaultMikuContestConfig(options.contestConfig);
|
|
8952
|
+
}
|
|
8953
|
+
getContestConfig() {
|
|
8954
|
+
return this.contest;
|
|
8955
|
+
}
|
|
8956
|
+
updateContestConfig(patch) {
|
|
8957
|
+
this.contest = {
|
|
8958
|
+
...this.contest,
|
|
8959
|
+
...patch,
|
|
8960
|
+
votingRules: {
|
|
8961
|
+
...this.contest.votingRules,
|
|
8962
|
+
...patch.votingRules || {}
|
|
8963
|
+
},
|
|
8964
|
+
toggles: {
|
|
8965
|
+
...this.contest.toggles,
|
|
8966
|
+
...patch.toggles || {}
|
|
8967
|
+
},
|
|
8968
|
+
timeline: {
|
|
8969
|
+
...this.contest.timeline,
|
|
8970
|
+
...patch.timeline || {}
|
|
8971
|
+
}
|
|
8972
|
+
};
|
|
8973
|
+
return this.contest;
|
|
8974
|
+
}
|
|
8975
|
+
createSubmission(input, mode = "web") {
|
|
8976
|
+
if (!this.contest.toggles.submissionEnabled) {
|
|
8977
|
+
throw new Error("\u5F53\u524D\u672A\u5F00\u653E\u6295\u7A3F");
|
|
8978
|
+
}
|
|
8979
|
+
const errors = validateMikuSubmissionInput(input, mode);
|
|
8980
|
+
if (errors.length > 0) {
|
|
8981
|
+
throw new Error(errors.join("\uFF1B"));
|
|
8982
|
+
}
|
|
8983
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8984
|
+
const next = {
|
|
8985
|
+
id: randomId("submission"),
|
|
8986
|
+
serialNo: serialNo(),
|
|
8987
|
+
contestId: input.contestId,
|
|
8988
|
+
authorId: input.authorId,
|
|
8989
|
+
authorNickname: input.authorNickname,
|
|
8990
|
+
title: input.title,
|
|
8991
|
+
type: input.type,
|
|
8992
|
+
description: input.description,
|
|
8993
|
+
tags: input.tags || [],
|
|
8994
|
+
content: input.content,
|
|
8995
|
+
voteCount: 0,
|
|
8996
|
+
status: "pending",
|
|
8997
|
+
createdAt: now,
|
|
8998
|
+
updatedAt: now
|
|
8999
|
+
};
|
|
9000
|
+
this.submissions.set(next.id, next);
|
|
9001
|
+
return next;
|
|
9002
|
+
}
|
|
9003
|
+
listSubmissions(filter) {
|
|
9004
|
+
const authorKeyword = filter?.authorKeyword?.trim().toLowerCase();
|
|
9005
|
+
const titleKeyword = filter?.titleKeyword?.trim().toLowerCase();
|
|
9006
|
+
return [...this.submissions.values()].filter((item) => {
|
|
9007
|
+
if (filter?.status && item.status !== filter.status) return false;
|
|
9008
|
+
if (filter?.type && item.type !== filter.type) return false;
|
|
9009
|
+
if (filter?.authorId && item.authorId !== filter.authorId) return false;
|
|
9010
|
+
if (authorKeyword && !item.authorNickname.toLowerCase().includes(authorKeyword)) return false;
|
|
9011
|
+
if (titleKeyword && !item.title.toLowerCase().includes(titleKeyword)) return false;
|
|
9012
|
+
return true;
|
|
9013
|
+
});
|
|
9014
|
+
}
|
|
9015
|
+
getSubmission(submissionId) {
|
|
9016
|
+
return this.submissions.get(submissionId) || null;
|
|
9017
|
+
}
|
|
9018
|
+
reviewSubmission(input) {
|
|
9019
|
+
const current = this.submissions.get(input.submissionId);
|
|
9020
|
+
if (!current) throw new Error("\u6295\u7A3F\u4E0D\u5B58\u5728");
|
|
9021
|
+
if (input.action === "reject" && !input.rejectReason?.trim()) {
|
|
9022
|
+
throw new Error("\u9A73\u56DE\u9700\u586B\u5199\u539F\u56E0");
|
|
9023
|
+
}
|
|
9024
|
+
const reviewed = {
|
|
9025
|
+
...current,
|
|
9026
|
+
status: input.action === "approve" ? "approved" : "rejected",
|
|
9027
|
+
rejectReason: input.action === "reject" ? input.rejectReason?.trim() : void 0,
|
|
9028
|
+
reviewedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9029
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9030
|
+
};
|
|
9031
|
+
this.submissions.set(reviewed.id, reviewed);
|
|
9032
|
+
return reviewed;
|
|
9033
|
+
}
|
|
9034
|
+
vote(input) {
|
|
9035
|
+
if (!this.contest.toggles.votingEnabled) {
|
|
9036
|
+
throw new Error("\u5F53\u524D\u672A\u5F00\u653E\u6295\u7968");
|
|
9037
|
+
}
|
|
9038
|
+
const restriction = this.voterRestrictions.get(input.voterId);
|
|
9039
|
+
if (restriction?.banned) {
|
|
9040
|
+
throw new Error("\u5F53\u524D\u8D26\u53F7\u5DF2\u88AB\u9650\u5236\u6295\u7968");
|
|
9041
|
+
}
|
|
9042
|
+
const target = this.submissions.get(input.submissionId);
|
|
9043
|
+
if (!target) throw new Error("\u4F5C\u54C1\u4E0D\u5B58\u5728");
|
|
9044
|
+
if (target.status !== "approved") throw new Error("\u4EC5\u53EF\u5BF9\u5DF2\u8FC7\u5BA1\u4F5C\u54C1\u6295\u7968");
|
|
9045
|
+
const dayKey = toVoteDayKey();
|
|
9046
|
+
const eligible = checkVoteEligibility({
|
|
9047
|
+
existingVotes: this.votes,
|
|
9048
|
+
submissionId: input.submissionId,
|
|
9049
|
+
voterId: input.voterId,
|
|
9050
|
+
dayKey,
|
|
9051
|
+
rules: this.contest.votingRules
|
|
9052
|
+
});
|
|
9053
|
+
if (!eligible.ok) {
|
|
9054
|
+
throw new Error(eligible.reason || "\u6295\u7968\u5931\u8D25");
|
|
9055
|
+
}
|
|
9056
|
+
const vote = {
|
|
9057
|
+
id: randomId("vote"),
|
|
9058
|
+
contestId: input.contestId,
|
|
9059
|
+
submissionId: input.submissionId,
|
|
9060
|
+
voterId: input.voterId,
|
|
9061
|
+
votedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9062
|
+
dayKey,
|
|
9063
|
+
deviceId: input.deviceId,
|
|
9064
|
+
ip: input.ip
|
|
9065
|
+
};
|
|
9066
|
+
this.votes.push(vote);
|
|
9067
|
+
const updated = {
|
|
9068
|
+
...target,
|
|
9069
|
+
voteCount: target.voteCount + 1,
|
|
9070
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9071
|
+
};
|
|
9072
|
+
this.submissions.set(updated.id, updated);
|
|
9073
|
+
return updated;
|
|
9074
|
+
}
|
|
9075
|
+
getVoterRestriction(voterId) {
|
|
9076
|
+
return this.voterRestrictions.get(voterId) || null;
|
|
9077
|
+
}
|
|
9078
|
+
setVoterRestriction(input) {
|
|
9079
|
+
const next = {
|
|
9080
|
+
voterId: input.voterId,
|
|
9081
|
+
banned: input.banned,
|
|
9082
|
+
reason: input.reason,
|
|
9083
|
+
operatorId: input.operatorId,
|
|
9084
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9085
|
+
};
|
|
9086
|
+
this.voterRestrictions.set(input.voterId, next);
|
|
9087
|
+
return next;
|
|
9088
|
+
}
|
|
9089
|
+
resetVotes(input) {
|
|
9090
|
+
if (!input.submissionId && !input.voterId) {
|
|
9091
|
+
throw new Error("submissionId \u4E0E voterId \u81F3\u5C11\u63D0\u4F9B\u4E00\u4E2A");
|
|
9092
|
+
}
|
|
9093
|
+
const before = this.votes.length;
|
|
9094
|
+
const affected = /* @__PURE__ */ new Set();
|
|
9095
|
+
const remained = this.votes.filter((vote) => {
|
|
9096
|
+
const matchSubmission = input.submissionId ? vote.submissionId === input.submissionId : true;
|
|
9097
|
+
const matchVoter = input.voterId ? vote.voterId === input.voterId : true;
|
|
9098
|
+
const shouldRemove = matchSubmission && matchVoter;
|
|
9099
|
+
if (shouldRemove) affected.add(vote.submissionId);
|
|
9100
|
+
return !shouldRemove;
|
|
9101
|
+
});
|
|
9102
|
+
this.votes.length = 0;
|
|
9103
|
+
this.votes.push(...remained);
|
|
9104
|
+
this.recalculateVoteCounts();
|
|
9105
|
+
return {
|
|
9106
|
+
removedVotes: before - remained.length,
|
|
9107
|
+
affectedSubmissions: [...affected]
|
|
9108
|
+
};
|
|
9109
|
+
}
|
|
9110
|
+
listAnnouncements(contestId) {
|
|
9111
|
+
const all = [...this.announcements.values()];
|
|
9112
|
+
return contestId ? all.filter((item) => item.contestId === contestId) : all;
|
|
9113
|
+
}
|
|
9114
|
+
publishAnnouncement(input) {
|
|
9115
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
9116
|
+
const announcement = {
|
|
9117
|
+
id: randomId("notice"),
|
|
9118
|
+
contestId: input.contestId,
|
|
9119
|
+
title: input.title,
|
|
9120
|
+
content: input.content,
|
|
9121
|
+
type: input.type,
|
|
9122
|
+
createdBy: input.createdBy,
|
|
9123
|
+
createdAt: now,
|
|
9124
|
+
updatedAt: now
|
|
9125
|
+
};
|
|
9126
|
+
this.announcements.set(announcement.id, announcement);
|
|
9127
|
+
return announcement;
|
|
9128
|
+
}
|
|
9129
|
+
getLeaderboard(limit = 10) {
|
|
9130
|
+
const ranked = sortByVotesDesc(this.listSubmissions({ status: "approved" })).slice(0, limit);
|
|
9131
|
+
return ranked.map((item, index) => ({
|
|
9132
|
+
submissionId: item.id,
|
|
9133
|
+
title: item.title,
|
|
9134
|
+
authorNickname: item.authorNickname,
|
|
9135
|
+
voteCount: item.voteCount,
|
|
9136
|
+
rank: index + 1
|
|
9137
|
+
}));
|
|
9138
|
+
}
|
|
9139
|
+
getSnapshot() {
|
|
9140
|
+
return {
|
|
9141
|
+
contest: this.contest,
|
|
9142
|
+
submissions: this.listSubmissions(),
|
|
9143
|
+
announcements: this.listAnnouncements(),
|
|
9144
|
+
leaderboard: this.getLeaderboard()
|
|
9145
|
+
};
|
|
9146
|
+
}
|
|
9147
|
+
getSubmissionExportRows(filter) {
|
|
9148
|
+
return this.listSubmissions(filter).map((item) => ({
|
|
9149
|
+
\u6295\u7A3F\u7F16\u53F7: item.serialNo,
|
|
9150
|
+
\u6295\u7A3FID: item.id,
|
|
9151
|
+
\u8D5B\u4E8BID: item.contestId,
|
|
9152
|
+
\u4F5C\u8005ID: item.authorId,
|
|
9153
|
+
\u4F5C\u8005\u6635\u79F0: item.authorNickname,
|
|
9154
|
+
\u4F5C\u54C1\u540D\u79F0: item.title,
|
|
9155
|
+
\u4F5C\u54C1\u7C7B\u578B: item.type,
|
|
9156
|
+
\u7B80\u4ECB: item.description,
|
|
9157
|
+
\u6807\u7B7E: item.tags.join(","),
|
|
9158
|
+
\u5BA1\u6838\u72B6\u6001: item.status,
|
|
9159
|
+
\u9A73\u56DE\u539F\u56E0: item.rejectReason || "",
|
|
9160
|
+
\u7968\u6570: item.voteCount,
|
|
9161
|
+
\u63D0\u4EA4\u65F6\u95F4: item.createdAt,
|
|
9162
|
+
\u66F4\u65B0\u65F6\u95F4: item.updatedAt
|
|
9163
|
+
}));
|
|
9164
|
+
}
|
|
9165
|
+
exportSubmissionExcel(filter) {
|
|
9166
|
+
const rows = this.getSubmissionExportRows(filter);
|
|
9167
|
+
const workbook = XLSX__namespace.utils.book_new();
|
|
9168
|
+
const worksheet = XLSX__namespace.utils.json_to_sheet(rows);
|
|
9169
|
+
XLSX__namespace.utils.book_append_sheet(workbook, worksheet, "submissions");
|
|
9170
|
+
return XLSX__namespace.write(workbook, { bookType: "xlsx", type: "buffer" });
|
|
9171
|
+
}
|
|
9172
|
+
recalculateVoteCounts() {
|
|
9173
|
+
const counts = /* @__PURE__ */ new Map();
|
|
9174
|
+
for (const vote of this.votes) {
|
|
9175
|
+
counts.set(vote.submissionId, (counts.get(vote.submissionId) || 0) + 1);
|
|
9176
|
+
}
|
|
9177
|
+
for (const [id2, submission] of this.submissions.entries()) {
|
|
9178
|
+
const nextCount = counts.get(id2) || 0;
|
|
9179
|
+
if (submission.voteCount === nextCount) continue;
|
|
9180
|
+
this.submissions.set(id2, {
|
|
9181
|
+
...submission,
|
|
9182
|
+
voteCount: nextCount,
|
|
9183
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9184
|
+
});
|
|
9185
|
+
}
|
|
9186
|
+
}
|
|
9187
|
+
exportPersistenceState() {
|
|
9188
|
+
return {
|
|
9189
|
+
contest: this.contest,
|
|
9190
|
+
submissions: [...this.submissions.values()],
|
|
9191
|
+
votes: [...this.votes],
|
|
9192
|
+
announcements: [...this.announcements.values()],
|
|
9193
|
+
voterRestrictions: [...this.voterRestrictions.values()],
|
|
9194
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9195
|
+
};
|
|
9196
|
+
}
|
|
9197
|
+
importPersistenceState(state) {
|
|
9198
|
+
this.contest = state.contest;
|
|
9199
|
+
this.submissions.clear();
|
|
9200
|
+
this.announcements.clear();
|
|
9201
|
+
this.voterRestrictions.clear();
|
|
9202
|
+
this.votes.length = 0;
|
|
9203
|
+
for (const item of state.submissions) {
|
|
9204
|
+
this.submissions.set(item.id, item);
|
|
9205
|
+
}
|
|
9206
|
+
for (const item of state.announcements) {
|
|
9207
|
+
this.announcements.set(item.id, item);
|
|
9208
|
+
}
|
|
9209
|
+
for (const item of state.voterRestrictions) {
|
|
9210
|
+
this.voterRestrictions.set(item.voterId, item);
|
|
9211
|
+
}
|
|
9212
|
+
this.votes.push(...state.votes);
|
|
9213
|
+
}
|
|
9214
|
+
};
|
|
9215
|
+
var createMikuContestService = (options) => {
|
|
9216
|
+
return new MikuContestService(options);
|
|
9217
|
+
};
|
|
9218
|
+
var mikuContestConfigs = pgCore.pgTable("miku_contest_configs", {
|
|
9219
|
+
contestId: pgCore.text("contest_id").primaryKey(),
|
|
9220
|
+
config: pgCore.jsonb("config").$type().notNull(),
|
|
9221
|
+
createdAt: pgCore.timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
|
|
9222
|
+
updatedAt: pgCore.timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
|
|
9223
|
+
});
|
|
9224
|
+
var mikuContestSubmissions = pgCore.pgTable("miku_contest_submissions", {
|
|
9225
|
+
id: pgCore.text("id").primaryKey(),
|
|
9226
|
+
contestId: pgCore.text("contest_id").notNull(),
|
|
9227
|
+
serialNo: pgCore.text("serial_no").notNull(),
|
|
9228
|
+
authorId: pgCore.text("author_id").notNull(),
|
|
9229
|
+
authorNickname: pgCore.text("author_nickname").notNull(),
|
|
9230
|
+
title: pgCore.text("title").notNull(),
|
|
9231
|
+
type: pgCore.text("type").notNull(),
|
|
9232
|
+
description: pgCore.text("description").notNull(),
|
|
9233
|
+
tags: pgCore.jsonb("tags").$type().notNull(),
|
|
9234
|
+
content: pgCore.jsonb("content").$type().notNull(),
|
|
9235
|
+
voteCount: pgCore.integer("vote_count").notNull().default(0),
|
|
9236
|
+
status: pgCore.text("status").notNull(),
|
|
9237
|
+
rejectReason: pgCore.text("reject_reason"),
|
|
9238
|
+
createdAt: pgCore.timestamp("created_at", { withTimezone: true }).notNull(),
|
|
9239
|
+
reviewedAt: pgCore.timestamp("reviewed_at", { withTimezone: true }),
|
|
9240
|
+
updatedAt: pgCore.timestamp("updated_at", { withTimezone: true }).notNull()
|
|
9241
|
+
});
|
|
9242
|
+
var mikuContestVotes = pgCore.pgTable("miku_contest_votes", {
|
|
9243
|
+
id: pgCore.text("id").primaryKey(),
|
|
9244
|
+
contestId: pgCore.text("contest_id").notNull(),
|
|
9245
|
+
submissionId: pgCore.text("submission_id").notNull(),
|
|
9246
|
+
voterId: pgCore.text("voter_id").notNull(),
|
|
9247
|
+
votedAt: pgCore.text("voted_at").notNull(),
|
|
9248
|
+
dayKey: pgCore.text("day_key").notNull(),
|
|
9249
|
+
deviceId: pgCore.text("device_id"),
|
|
9250
|
+
ip: pgCore.text("ip")
|
|
9251
|
+
});
|
|
9252
|
+
var mikuContestNotices = pgCore.pgTable("miku_contest_notices", {
|
|
9253
|
+
id: pgCore.text("id").primaryKey(),
|
|
9254
|
+
contestId: pgCore.text("contest_id").notNull(),
|
|
9255
|
+
title: pgCore.text("title").notNull(),
|
|
9256
|
+
content: pgCore.text("content").notNull(),
|
|
9257
|
+
type: pgCore.text("type").notNull(),
|
|
9258
|
+
createdBy: pgCore.text("created_by").notNull(),
|
|
9259
|
+
createdAt: pgCore.text("created_at").notNull(),
|
|
9260
|
+
updatedAt: pgCore.text("updated_at").notNull()
|
|
9261
|
+
});
|
|
9262
|
+
var mikuContestVoterRestrictions = pgCore.pgTable("miku_contest_voter_restrictions", {
|
|
9263
|
+
id: pgCore.text("id").primaryKey(),
|
|
9264
|
+
contestId: pgCore.text("contest_id").notNull(),
|
|
9265
|
+
data: pgCore.jsonb("data").$type().notNull()
|
|
9266
|
+
});
|
|
9267
|
+
var MikuContestStateDbService = class {
|
|
9268
|
+
constructor(db) {
|
|
9269
|
+
this.db = db;
|
|
9270
|
+
}
|
|
9271
|
+
async loadState(contestId) {
|
|
9272
|
+
const configRows = await this.db.select({ config: mikuContestConfigs.config }).from(mikuContestConfigs).where(drizzleOrm.eq(mikuContestConfigs.contestId, contestId)).limit(1);
|
|
9273
|
+
const config = configRows[0]?.config;
|
|
9274
|
+
if (!config) return null;
|
|
9275
|
+
const [submissions, votes, announcements, restrictions] = await Promise.all([
|
|
9276
|
+
this.db.select().from(mikuContestSubmissions).where(drizzleOrm.eq(mikuContestSubmissions.contestId, contestId)),
|
|
9277
|
+
this.db.select().from(mikuContestVotes).where(drizzleOrm.eq(mikuContestVotes.contestId, contestId)),
|
|
9278
|
+
this.db.select().from(mikuContestNotices).where(drizzleOrm.eq(mikuContestNotices.contestId, contestId)),
|
|
9279
|
+
this.db.select({ data: mikuContestVoterRestrictions.data }).from(mikuContestVoterRestrictions).where(drizzleOrm.eq(mikuContestVoterRestrictions.contestId, contestId))
|
|
9280
|
+
]);
|
|
9281
|
+
return {
|
|
9282
|
+
contest: config,
|
|
9283
|
+
submissions,
|
|
9284
|
+
votes,
|
|
9285
|
+
announcements,
|
|
9286
|
+
voterRestrictions: restrictions.map((item) => item.data),
|
|
9287
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
9288
|
+
};
|
|
9289
|
+
}
|
|
9290
|
+
async saveState(state) {
|
|
9291
|
+
const contestId = state.contest.id;
|
|
9292
|
+
const exists = await this.db.select({ contestId: mikuContestConfigs.contestId }).from(mikuContestConfigs).where(drizzleOrm.eq(mikuContestConfigs.contestId, contestId)).limit(1);
|
|
9293
|
+
if (exists[0]) {
|
|
9294
|
+
await this.db.update(mikuContestConfigs).set({
|
|
9295
|
+
config: state.contest,
|
|
9296
|
+
updatedAt: /* @__PURE__ */ new Date()
|
|
9297
|
+
}).where(drizzleOrm.eq(mikuContestConfigs.contestId, contestId));
|
|
9298
|
+
} else {
|
|
9299
|
+
await this.db.insert(mikuContestConfigs).values({
|
|
9300
|
+
contestId,
|
|
9301
|
+
config: state.contest
|
|
9302
|
+
});
|
|
9303
|
+
}
|
|
9304
|
+
await this.db.delete(mikuContestSubmissions).where(drizzleOrm.eq(mikuContestSubmissions.contestId, contestId));
|
|
9305
|
+
await this.db.delete(mikuContestVotes).where(drizzleOrm.eq(mikuContestVotes.contestId, contestId));
|
|
9306
|
+
await this.db.delete(mikuContestNotices).where(drizzleOrm.eq(mikuContestNotices.contestId, contestId));
|
|
9307
|
+
await this.db.delete(mikuContestVoterRestrictions).where(drizzleOrm.eq(mikuContestVoterRestrictions.contestId, contestId));
|
|
9308
|
+
if (state.submissions.length > 0) {
|
|
9309
|
+
await this.db.insert(mikuContestSubmissions).values(
|
|
9310
|
+
state.submissions.map((item) => ({
|
|
9311
|
+
...item,
|
|
9312
|
+
contestId,
|
|
9313
|
+
createdAt: new Date(item.createdAt),
|
|
9314
|
+
reviewedAt: item.reviewedAt ? new Date(item.reviewedAt) : null,
|
|
9315
|
+
updatedAt: new Date(item.updatedAt)
|
|
9316
|
+
}))
|
|
9317
|
+
);
|
|
9318
|
+
}
|
|
9319
|
+
if (state.votes.length > 0) {
|
|
9320
|
+
await this.db.insert(mikuContestVotes).values(state.votes);
|
|
9321
|
+
}
|
|
9322
|
+
if (state.announcements.length > 0) {
|
|
9323
|
+
await this.db.insert(mikuContestNotices).values(state.announcements);
|
|
9324
|
+
}
|
|
9325
|
+
if (state.voterRestrictions.length > 0) {
|
|
9326
|
+
await this.db.insert(mikuContestVoterRestrictions).values(
|
|
9327
|
+
state.voterRestrictions.map((item) => ({
|
|
9328
|
+
id: `${contestId}:${item.voterId}`,
|
|
9329
|
+
contestId,
|
|
9330
|
+
data: item
|
|
9331
|
+
}))
|
|
9332
|
+
);
|
|
9333
|
+
}
|
|
9334
|
+
}
|
|
9335
|
+
};
|
|
9336
|
+
|
|
9337
|
+
// src/mikuContest/server/persistence/drizzle-adapter.ts
|
|
9338
|
+
var createMikuContestDrizzlePersistenceAdapter = (db) => {
|
|
9339
|
+
const service = new MikuContestStateDbService(db);
|
|
9340
|
+
return {
|
|
9341
|
+
loadState: (contestId) => service.loadState(contestId),
|
|
9342
|
+
saveState: (state) => service.saveState(state)
|
|
9343
|
+
};
|
|
9344
|
+
};
|
|
9345
|
+
|
|
9346
|
+
// src/mikuContest/server/persistence/service.ts
|
|
9347
|
+
var MikuContestPersistentService = class {
|
|
9348
|
+
constructor(options) {
|
|
9349
|
+
this.options = options;
|
|
9350
|
+
this.hydrated = false;
|
|
9351
|
+
this.hydrationPromise = null;
|
|
9352
|
+
this.engine = createMikuContestService(options);
|
|
9353
|
+
}
|
|
9354
|
+
async ensureHydrated() {
|
|
9355
|
+
if (this.hydrated) return;
|
|
9356
|
+
if (this.hydrationPromise) return this.hydrationPromise;
|
|
9357
|
+
this.hydrationPromise = (async () => {
|
|
9358
|
+
const contestId = this.engine.getContestConfig().id;
|
|
9359
|
+
const loaded = await this.options.persistenceAdapter.loadState(contestId);
|
|
9360
|
+
if (loaded) {
|
|
9361
|
+
this.engine.importPersistenceState(loaded);
|
|
9362
|
+
} else {
|
|
9363
|
+
await this.options.persistenceAdapter.saveState(this.engine.exportPersistenceState());
|
|
9364
|
+
}
|
|
9365
|
+
this.hydrated = true;
|
|
9366
|
+
})();
|
|
9367
|
+
await this.hydrationPromise;
|
|
9368
|
+
}
|
|
9369
|
+
async persist() {
|
|
9370
|
+
await this.options.persistenceAdapter.saveState(this.engine.exportPersistenceState());
|
|
9371
|
+
}
|
|
9372
|
+
async getContestConfig() {
|
|
9373
|
+
await this.ensureHydrated();
|
|
9374
|
+
return this.engine.getContestConfig();
|
|
9375
|
+
}
|
|
9376
|
+
async updateContestConfig(patch) {
|
|
9377
|
+
await this.ensureHydrated();
|
|
9378
|
+
const data = this.engine.updateContestConfig(patch);
|
|
9379
|
+
await this.persist();
|
|
9380
|
+
return data;
|
|
9381
|
+
}
|
|
9382
|
+
async createSubmission(input, mode = "web") {
|
|
9383
|
+
await this.ensureHydrated();
|
|
9384
|
+
const data = this.engine.createSubmission(input, mode);
|
|
9385
|
+
await this.persist();
|
|
9386
|
+
return data;
|
|
9387
|
+
}
|
|
9388
|
+
async listSubmissions(filter) {
|
|
9389
|
+
await this.ensureHydrated();
|
|
9390
|
+
return this.engine.listSubmissions(filter);
|
|
9391
|
+
}
|
|
9392
|
+
async getSubmission(submissionId) {
|
|
9393
|
+
await this.ensureHydrated();
|
|
9394
|
+
return this.engine.getSubmission(submissionId);
|
|
9395
|
+
}
|
|
9396
|
+
async reviewSubmission(input) {
|
|
9397
|
+
await this.ensureHydrated();
|
|
9398
|
+
const data = this.engine.reviewSubmission(input);
|
|
9399
|
+
await this.persist();
|
|
9400
|
+
return data;
|
|
9401
|
+
}
|
|
9402
|
+
async vote(input) {
|
|
9403
|
+
await this.ensureHydrated();
|
|
9404
|
+
const data = this.engine.vote(input);
|
|
9405
|
+
await this.persist();
|
|
9406
|
+
return data;
|
|
9407
|
+
}
|
|
9408
|
+
async getVoterRestriction(voterId) {
|
|
9409
|
+
await this.ensureHydrated();
|
|
9410
|
+
return this.engine.getVoterRestriction(voterId);
|
|
9411
|
+
}
|
|
9412
|
+
async setVoterRestriction(input) {
|
|
9413
|
+
await this.ensureHydrated();
|
|
9414
|
+
const data = this.engine.setVoterRestriction(input);
|
|
9415
|
+
await this.persist();
|
|
9416
|
+
return data;
|
|
9417
|
+
}
|
|
9418
|
+
async resetVotes(input) {
|
|
9419
|
+
await this.ensureHydrated();
|
|
9420
|
+
const data = this.engine.resetVotes(input);
|
|
9421
|
+
await this.persist();
|
|
9422
|
+
return data;
|
|
9423
|
+
}
|
|
9424
|
+
async listAnnouncements(contestId) {
|
|
9425
|
+
await this.ensureHydrated();
|
|
9426
|
+
return this.engine.listAnnouncements(contestId);
|
|
9427
|
+
}
|
|
9428
|
+
async publishAnnouncement(input) {
|
|
9429
|
+
await this.ensureHydrated();
|
|
9430
|
+
const data = this.engine.publishAnnouncement(input);
|
|
9431
|
+
await this.persist();
|
|
9432
|
+
return data;
|
|
9433
|
+
}
|
|
9434
|
+
async getLeaderboard(limit = 10) {
|
|
9435
|
+
await this.ensureHydrated();
|
|
9436
|
+
return this.engine.getLeaderboard(limit);
|
|
9437
|
+
}
|
|
9438
|
+
async getSnapshot() {
|
|
9439
|
+
await this.ensureHydrated();
|
|
9440
|
+
return this.engine.getSnapshot();
|
|
9441
|
+
}
|
|
9442
|
+
async getSubmissionExportRows(filter) {
|
|
9443
|
+
await this.ensureHydrated();
|
|
9444
|
+
return this.engine.getSubmissionExportRows(filter);
|
|
9445
|
+
}
|
|
9446
|
+
async exportSubmissionExcel(filter) {
|
|
9447
|
+
await this.ensureHydrated();
|
|
9448
|
+
return this.engine.exportSubmissionExcel(filter);
|
|
9449
|
+
}
|
|
9450
|
+
};
|
|
9451
|
+
var createMikuContestPersistentService = (options) => {
|
|
9452
|
+
return new MikuContestPersistentService(options);
|
|
9453
|
+
};
|
|
9454
|
+
|
|
9455
|
+
// src/mikuContest/server/db.ts
|
|
9456
|
+
var MikuContestDbService = class {
|
|
9457
|
+
constructor() {
|
|
9458
|
+
this._db = null;
|
|
9459
|
+
}
|
|
9460
|
+
setDb(db) {
|
|
9461
|
+
this._db = db;
|
|
9462
|
+
}
|
|
9463
|
+
isConfigured() {
|
|
9464
|
+
return Boolean(this._db);
|
|
9465
|
+
}
|
|
9466
|
+
get db() {
|
|
9467
|
+
if (!this._db) {
|
|
9468
|
+
throw new Error("MikuContestDbService: Database instance not set. Call setDb(db) first.");
|
|
9469
|
+
}
|
|
9470
|
+
return this._db;
|
|
9471
|
+
}
|
|
9472
|
+
};
|
|
9473
|
+
var mikuContestDbService = new MikuContestDbService();
|
|
9474
|
+
|
|
9475
|
+
// src/mikuContest/logic/hooks/useMikuContest.ts
|
|
9476
|
+
var useMikuContest = (options) => {
|
|
9477
|
+
const [service] = React69.useState(() => createMikuContestService(options));
|
|
9478
|
+
const [version, setVersion] = React69.useState(0);
|
|
9479
|
+
const refresh = () => setVersion((value) => value + 1);
|
|
9480
|
+
const snapshot = React69.useMemo(() => {
|
|
9481
|
+
return service.getSnapshot();
|
|
9482
|
+
}, [service, version]);
|
|
9483
|
+
return {
|
|
9484
|
+
service,
|
|
9485
|
+
snapshot,
|
|
9486
|
+
refresh
|
|
9487
|
+
};
|
|
9488
|
+
};
|
|
9489
|
+
|
|
9490
|
+
// src/mikuContest/service/api/client.ts
|
|
9491
|
+
var toQueryString = (filter) => {
|
|
9492
|
+
if (!filter) return "";
|
|
9493
|
+
const params = new URLSearchParams();
|
|
9494
|
+
if (filter.status) params.set("status", filter.status);
|
|
9495
|
+
if (filter.type) params.set("type", filter.type);
|
|
9496
|
+
if (filter.authorId) params.set("authorId", filter.authorId);
|
|
9497
|
+
if (filter.authorKeyword) params.set("authorKeyword", filter.authorKeyword);
|
|
9498
|
+
if (filter.titleKeyword) params.set("titleKeyword", filter.titleKeyword);
|
|
9499
|
+
const query = params.toString();
|
|
9500
|
+
return query ? `?${query}` : "";
|
|
9501
|
+
};
|
|
9502
|
+
var unwrap = (result) => {
|
|
9503
|
+
if (!result.success || result.data === void 0) {
|
|
9504
|
+
throw new Error(result.error || "\u8BF7\u6C42\u5931\u8D25");
|
|
9505
|
+
}
|
|
9506
|
+
return result.data;
|
|
9507
|
+
};
|
|
9508
|
+
var createMikuContestApiClient = (basePath, requester2) => {
|
|
9509
|
+
return {
|
|
9510
|
+
async getSnapshot() {
|
|
9511
|
+
const result = await requester2(`${basePath}/contest`, { method: "GET" });
|
|
9512
|
+
return unwrap(result);
|
|
9513
|
+
},
|
|
9514
|
+
async updateContestConfig(patch) {
|
|
9515
|
+
const result = await requester2(`${basePath}/contest`, {
|
|
9516
|
+
method: "PATCH",
|
|
9517
|
+
body: patch
|
|
9518
|
+
});
|
|
9519
|
+
return unwrap(result);
|
|
9520
|
+
},
|
|
9521
|
+
async createSubmission(input, mode = "web") {
|
|
9522
|
+
const result = await requester2(`${basePath}/submissions`, {
|
|
9523
|
+
method: "POST",
|
|
9524
|
+
body: { payload: input, mode }
|
|
9525
|
+
});
|
|
9526
|
+
return unwrap(result);
|
|
9527
|
+
},
|
|
9528
|
+
async listSubmissions(filter) {
|
|
9529
|
+
const result = await requester2(
|
|
9530
|
+
`${basePath}/submissions${toQueryString(filter)}`,
|
|
9531
|
+
{ method: "GET" }
|
|
9532
|
+
);
|
|
9533
|
+
return unwrap(result);
|
|
9534
|
+
},
|
|
9535
|
+
async reviewSubmission(input) {
|
|
9536
|
+
const result = await requester2(`${basePath}/submissions/review`, {
|
|
9537
|
+
method: "POST",
|
|
9538
|
+
body: input
|
|
9539
|
+
});
|
|
9540
|
+
return unwrap(result);
|
|
9541
|
+
},
|
|
9542
|
+
async vote(input) {
|
|
9543
|
+
const result = await requester2(`${basePath}/votes`, {
|
|
9544
|
+
method: "POST",
|
|
9545
|
+
body: input
|
|
9546
|
+
});
|
|
9547
|
+
return unwrap(result);
|
|
9548
|
+
},
|
|
9549
|
+
async setVoterRestriction(input) {
|
|
9550
|
+
const result = await requester2(`${basePath}/admin/voter-restrictions`, {
|
|
9551
|
+
method: "POST",
|
|
9552
|
+
body: input
|
|
9553
|
+
});
|
|
9554
|
+
return unwrap(result);
|
|
9555
|
+
},
|
|
9556
|
+
async resetVotes(input) {
|
|
9557
|
+
const result = await requester2(
|
|
9558
|
+
`${basePath}/admin/votes/reset`,
|
|
9559
|
+
{
|
|
9560
|
+
method: "POST",
|
|
9561
|
+
body: input
|
|
9562
|
+
}
|
|
9563
|
+
);
|
|
9564
|
+
return unwrap(result);
|
|
9565
|
+
},
|
|
9566
|
+
async exportSubmissions(filter) {
|
|
9567
|
+
const response = await fetch(`${basePath}/admin/submissions/export${toQueryString(filter)}`);
|
|
9568
|
+
if (!response.ok) {
|
|
9569
|
+
throw new Error(`\u5BFC\u51FA\u5931\u8D25: ${response.status}`);
|
|
9570
|
+
}
|
|
9571
|
+
return response.arrayBuffer();
|
|
9572
|
+
}
|
|
9573
|
+
};
|
|
9574
|
+
};
|
|
9575
|
+
|
|
9576
|
+
// src/mikuContest/service/web/index.ts
|
|
9577
|
+
var web_exports = {};
|
|
9578
|
+
__export(web_exports, {
|
|
9579
|
+
createMikuContestWebClient: () => createMikuContestWebClient
|
|
9580
|
+
});
|
|
9581
|
+
|
|
9582
|
+
// src/mikuContest/service/web/client.ts
|
|
9583
|
+
var defaultRequester = (options) => {
|
|
9584
|
+
const baseUrl = options.baseUrl || "";
|
|
9585
|
+
const commonHeaders = options.headers || {};
|
|
9586
|
+
return async (url, requestOptions) => {
|
|
9587
|
+
const response = await fetch(`${baseUrl}${url}`, {
|
|
9588
|
+
method: requestOptions?.method || "GET",
|
|
9589
|
+
headers: {
|
|
9590
|
+
"Content-Type": "application/json",
|
|
9591
|
+
...commonHeaders
|
|
9592
|
+
},
|
|
9593
|
+
body: requestOptions?.body ? JSON.stringify(requestOptions.body) : void 0
|
|
9594
|
+
});
|
|
9595
|
+
const json = await response.json();
|
|
9596
|
+
return json;
|
|
9597
|
+
};
|
|
9598
|
+
};
|
|
9599
|
+
var createMikuContestWebClient = (options = {}) => {
|
|
9600
|
+
const basePath = options.basePath || "/api/miku-contest";
|
|
9601
|
+
return createMikuContestApiClient(basePath, defaultRequester(options));
|
|
9602
|
+
};
|
|
9603
|
+
|
|
9604
|
+
// src/mikuContest/service/miniapp/index.ts
|
|
9605
|
+
var miniapp_exports = {};
|
|
9606
|
+
__export(miniapp_exports, {
|
|
9607
|
+
createMikuContestMiniappClient: () => createMikuContestMiniappClient
|
|
9608
|
+
});
|
|
9609
|
+
|
|
9610
|
+
// src/mikuContest/service/miniapp/client.ts
|
|
9611
|
+
var createMikuContestMiniappClient = (options) => {
|
|
9612
|
+
const basePath = options.basePath || "/api/miku-contest";
|
|
9613
|
+
return createMikuContestApiClient(basePath, options.requester);
|
|
9614
|
+
};
|
|
9615
|
+
var isDrizzleDb = (value) => {
|
|
9616
|
+
if (!value || typeof value !== "object") return false;
|
|
9617
|
+
const candidate = value;
|
|
9618
|
+
return typeof candidate.select === "function" && typeof candidate.insert === "function" && typeof candidate.update === "function" && typeof candidate.delete === "function";
|
|
9619
|
+
};
|
|
9620
|
+
var resolveService = (config) => {
|
|
9621
|
+
if (config?.service) return config.service;
|
|
9622
|
+
const adapter = config?.persistenceAdapter || (isDrizzleDb(config?.db) ? createMikuContestDrizzlePersistenceAdapter(config.db) : null);
|
|
9623
|
+
if (adapter) {
|
|
9624
|
+
return createMikuContestPersistentService({
|
|
9625
|
+
persistenceAdapter: adapter
|
|
9626
|
+
});
|
|
9627
|
+
}
|
|
9628
|
+
return createMikuContestService();
|
|
9629
|
+
};
|
|
9630
|
+
var createGetContestSnapshotHandler = (config) => {
|
|
9631
|
+
const service = resolveService(config);
|
|
9632
|
+
return async (_request) => {
|
|
9633
|
+
const data = await service.getSnapshot();
|
|
9634
|
+
return server.NextResponse.json({ success: true, data });
|
|
9635
|
+
};
|
|
9636
|
+
};
|
|
9637
|
+
var createUpdateContestConfigHandler = (config) => {
|
|
9638
|
+
const service = resolveService(config);
|
|
9639
|
+
return async (request) => {
|
|
9640
|
+
try {
|
|
9641
|
+
const payload = await request.json();
|
|
9642
|
+
const data = await service.updateContestConfig(payload);
|
|
9643
|
+
return server.NextResponse.json({ success: true, data });
|
|
9644
|
+
} catch (error) {
|
|
9645
|
+
return server.NextResponse.json({ success: false, error: error.message }, { status: 400 });
|
|
9646
|
+
}
|
|
9647
|
+
};
|
|
9648
|
+
};
|
|
9649
|
+
var createCreateSubmissionHandler = (config) => {
|
|
9650
|
+
const service = resolveService(config);
|
|
9651
|
+
return async (request) => {
|
|
9652
|
+
try {
|
|
9653
|
+
const body = await request.json();
|
|
9654
|
+
const mode = body.mode || "web";
|
|
9655
|
+
const payload = body.payload;
|
|
9656
|
+
if (!payload) {
|
|
9657
|
+
return server.NextResponse.json({ success: false, error: "payload \u4E0D\u80FD\u4E3A\u7A7A" }, { status: 400 });
|
|
9658
|
+
}
|
|
9659
|
+
const data = await service.createSubmission(payload, mode);
|
|
9660
|
+
return server.NextResponse.json({ success: true, data });
|
|
9661
|
+
} catch (error) {
|
|
9662
|
+
return server.NextResponse.json({ success: false, error: error.message }, { status: 400 });
|
|
9663
|
+
}
|
|
9664
|
+
};
|
|
9665
|
+
};
|
|
9666
|
+
var createVoteHandler = (config) => {
|
|
9667
|
+
const service = resolveService(config);
|
|
9668
|
+
return async (request) => {
|
|
9669
|
+
try {
|
|
9670
|
+
const payload = await request.json();
|
|
9671
|
+
const data = await service.vote(payload);
|
|
9672
|
+
return server.NextResponse.json({ success: true, data });
|
|
9673
|
+
} catch (error) {
|
|
9674
|
+
return server.NextResponse.json({ success: false, error: error.message }, { status: 400 });
|
|
9675
|
+
}
|
|
9676
|
+
};
|
|
9677
|
+
};
|
|
9678
|
+
var createReviewSubmissionHandler = (config) => {
|
|
9679
|
+
const service = resolveService(config);
|
|
9680
|
+
return async (request) => {
|
|
9681
|
+
try {
|
|
9682
|
+
const payload = await request.json();
|
|
9683
|
+
const data = await service.reviewSubmission(payload);
|
|
9684
|
+
return server.NextResponse.json({ success: true, data });
|
|
9685
|
+
} catch (error) {
|
|
9686
|
+
return server.NextResponse.json({ success: false, error: error.message }, { status: 400 });
|
|
9687
|
+
}
|
|
9688
|
+
};
|
|
9689
|
+
};
|
|
9690
|
+
var buildSubmissionFilterFromQuery = (request) => {
|
|
9691
|
+
const search = request.nextUrl.searchParams;
|
|
9692
|
+
const status = search.get("status");
|
|
9693
|
+
const type = search.get("type");
|
|
9694
|
+
return {
|
|
9695
|
+
status: status ? status : void 0,
|
|
9696
|
+
type: type ? type : void 0,
|
|
9697
|
+
authorId: search.get("authorId") || void 0,
|
|
9698
|
+
authorKeyword: search.get("authorKeyword") || void 0,
|
|
9699
|
+
titleKeyword: search.get("titleKeyword") || void 0
|
|
9700
|
+
};
|
|
9701
|
+
};
|
|
9702
|
+
var createListSubmissionsHandler = (config) => {
|
|
9703
|
+
const service = resolveService(config);
|
|
9704
|
+
return async (request) => {
|
|
9705
|
+
const filter = buildSubmissionFilterFromQuery(request);
|
|
9706
|
+
const data = await service.listSubmissions(filter);
|
|
9707
|
+
return server.NextResponse.json({ success: true, data });
|
|
9708
|
+
};
|
|
9709
|
+
};
|
|
9710
|
+
var createSetVoterRestrictionHandler = (config) => {
|
|
9711
|
+
const service = resolveService(config);
|
|
9712
|
+
return async (request) => {
|
|
9713
|
+
try {
|
|
9714
|
+
const payload = await request.json();
|
|
9715
|
+
const data = await service.setVoterRestriction(payload);
|
|
9716
|
+
return server.NextResponse.json({ success: true, data });
|
|
9717
|
+
} catch (error) {
|
|
9718
|
+
return server.NextResponse.json({ success: false, error: error.message }, { status: 400 });
|
|
9719
|
+
}
|
|
9720
|
+
};
|
|
9721
|
+
};
|
|
9722
|
+
var createResetVotesHandler = (config) => {
|
|
9723
|
+
const service = resolveService(config);
|
|
9724
|
+
return async (request) => {
|
|
9725
|
+
try {
|
|
9726
|
+
const payload = await request.json();
|
|
9727
|
+
const data = await service.resetVotes(payload);
|
|
9728
|
+
return server.NextResponse.json({ success: true, data });
|
|
9729
|
+
} catch (error) {
|
|
9730
|
+
return server.NextResponse.json({ success: false, error: error.message }, { status: 400 });
|
|
9731
|
+
}
|
|
9732
|
+
};
|
|
9733
|
+
};
|
|
9734
|
+
var createExportSubmissionsHandler = (config) => {
|
|
9735
|
+
const service = resolveService(config);
|
|
9736
|
+
return async (request) => {
|
|
9737
|
+
const filter = buildSubmissionFilterFromQuery(request);
|
|
9738
|
+
const data = await service.exportSubmissionExcel(filter);
|
|
9739
|
+
const body = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength);
|
|
9740
|
+
return new server.NextResponse(body, {
|
|
9741
|
+
status: 200,
|
|
9742
|
+
headers: {
|
|
9743
|
+
"Content-Type": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
9744
|
+
"Content-Disposition": 'attachment; filename="miku-submissions.xlsx"'
|
|
9745
|
+
}
|
|
9746
|
+
});
|
|
9747
|
+
};
|
|
9748
|
+
};
|
|
9749
|
+
|
|
9750
|
+
// src/mikuContest/ui/web/index.ts
|
|
9751
|
+
var web_exports2 = {};
|
|
9752
|
+
__export(web_exports2, {
|
|
9753
|
+
MikuContestAdminPage: () => MikuContestAdminPage_default,
|
|
9754
|
+
MikuContestArtistPage: () => MikuContestArtistPage_default,
|
|
9755
|
+
MikuContestAudiencePage: () => MikuContestAudiencePage_default,
|
|
9756
|
+
MikuContestDashboard: () => MikuContestDashboard_default,
|
|
9757
|
+
MikuContestPage: () => MikuContestPage_default
|
|
9758
|
+
});
|
|
9759
|
+
var MikuContestDashboard = ({ snapshot }) => {
|
|
9760
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h2", null, snapshot.contest.name), /* @__PURE__ */ React69__namespace.default.createElement("p", null, snapshot.contest.theme), /* @__PURE__ */ React69__namespace.default.createElement("p", null, "\u6295\u7A3F\u6570\uFF1A", snapshot.submissions.length), /* @__PURE__ */ React69__namespace.default.createElement("p", null, "\u516C\u544A\u6570\uFF1A", snapshot.announcements.length), /* @__PURE__ */ React69__namespace.default.createElement("ul", null, snapshot.leaderboard.map((item) => /* @__PURE__ */ React69__namespace.default.createElement("li", { key: item.submissionId }, "#", item.rank, " ", item.title, " - ", item.voteCount, "\u7968"))));
|
|
9761
|
+
};
|
|
9762
|
+
var MikuContestDashboard_default = MikuContestDashboard;
|
|
9763
|
+
var MikuContestAudiencePage = ({
|
|
9764
|
+
client,
|
|
9765
|
+
voterId,
|
|
9766
|
+
title = "\u89C2\u4F17\u6295\u7968\u533A"
|
|
9767
|
+
}) => {
|
|
9768
|
+
const api = React69.useMemo(() => client || createMikuContestWebClient(), [client]);
|
|
9769
|
+
const [snapshot, setSnapshot] = React69.useState(null);
|
|
9770
|
+
const [loading, setLoading] = React69.useState(false);
|
|
9771
|
+
const [error, setError] = React69.useState(null);
|
|
9772
|
+
const approvedWorks = React69.useMemo(() => {
|
|
9773
|
+
if (!snapshot) return [];
|
|
9774
|
+
return snapshot.submissions.filter((item) => item.status === "approved");
|
|
9775
|
+
}, [snapshot]);
|
|
9776
|
+
const loadSnapshot = async () => {
|
|
9777
|
+
setLoading(true);
|
|
9778
|
+
setError(null);
|
|
9779
|
+
try {
|
|
9780
|
+
const data = await api.getSnapshot();
|
|
9781
|
+
setSnapshot(data);
|
|
9782
|
+
} catch (e) {
|
|
9783
|
+
setError(e.message);
|
|
9784
|
+
} finally {
|
|
9785
|
+
setLoading(false);
|
|
9786
|
+
}
|
|
9787
|
+
};
|
|
9788
|
+
React69.useEffect(() => {
|
|
9789
|
+
void loadSnapshot();
|
|
9790
|
+
}, []);
|
|
9791
|
+
const handleVote = async (submission) => {
|
|
9792
|
+
if (!snapshot) return;
|
|
9793
|
+
try {
|
|
9794
|
+
await api.vote({
|
|
9795
|
+
contestId: snapshot.contest.id,
|
|
9796
|
+
submissionId: submission.id,
|
|
9797
|
+
voterId
|
|
9798
|
+
});
|
|
9799
|
+
await loadSnapshot();
|
|
9800
|
+
} catch (e) {
|
|
9801
|
+
setError(e.message);
|
|
9802
|
+
}
|
|
9803
|
+
};
|
|
9804
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("section", null, /* @__PURE__ */ React69__namespace.default.createElement("h2", null, title), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void loadSnapshot(), disabled: loading }, loading ? "\u5237\u65B0\u4E2D..." : "\u5237\u65B0\u6570\u636E"), error ? /* @__PURE__ */ React69__namespace.default.createElement("p", { style: { color: "crimson" } }, "\u9519\u8BEF\uFF1A", error) : null, !snapshot ? null : /* @__PURE__ */ React69__namespace.default.createElement(React69__namespace.default.Fragment, null, /* @__PURE__ */ React69__namespace.default.createElement("p", null, "\u8D5B\u4E8B\uFF1A", snapshot.contest.name, "\uFF5C\u4E3B\u9898\uFF1A", snapshot.contest.theme), /* @__PURE__ */ React69__namespace.default.createElement("p", null, "\u5DF2\u8FC7\u5BA1\u4F5C\u54C1\uFF1A", approvedWorks.length, "\uFF5C\u6BCF\u65E5\u4E0A\u9650\uFF1A", snapshot.contest.votingRules.maxVotesPerDay), /* @__PURE__ */ React69__namespace.default.createElement("ul", null, approvedWorks.map((work) => /* @__PURE__ */ React69__namespace.default.createElement("li", { key: work.id }, /* @__PURE__ */ React69__namespace.default.createElement("strong", null, work.title), "\uFF08", work.authorNickname, "\uFF09- \u5F53\u524D ", work.voteCount, " \u7968", " ", /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void handleVote(work) }, "\u6295\u7968"))))));
|
|
9805
|
+
};
|
|
9806
|
+
var MikuContestAudiencePage_default = MikuContestAudiencePage;
|
|
9807
|
+
var workTypes = ["visual", "video", "text", "audio"];
|
|
9808
|
+
var MikuContestArtistPage = ({
|
|
9809
|
+
client,
|
|
9810
|
+
authorId,
|
|
9811
|
+
authorNickname,
|
|
9812
|
+
title = "\u753B\u5E08\u6295\u7A3F\u533A"
|
|
9813
|
+
}) => {
|
|
9814
|
+
const api = React69.useMemo(() => client || createMikuContestWebClient(), [client]);
|
|
9815
|
+
const [snapshot, setSnapshot] = React69.useState(null);
|
|
9816
|
+
const [mySubmissions, setMySubmissions] = React69.useState([]);
|
|
9817
|
+
const [submitting, setSubmitting] = React69.useState(false);
|
|
9818
|
+
const [loading, setLoading] = React69.useState(false);
|
|
9819
|
+
const [error, setError] = React69.useState(null);
|
|
9820
|
+
const [titleInput, setTitleInput] = React69.useState("");
|
|
9821
|
+
const [descInput, setDescInput] = React69.useState("");
|
|
9822
|
+
const [coverImage, setCoverImage] = React69.useState("");
|
|
9823
|
+
const [workType, setWorkType] = React69.useState("visual");
|
|
9824
|
+
const loadData = async () => {
|
|
9825
|
+
setLoading(true);
|
|
9826
|
+
setError(null);
|
|
9827
|
+
try {
|
|
9828
|
+
const [contest, mine] = await Promise.all([
|
|
9829
|
+
api.getSnapshot(),
|
|
9830
|
+
api.listSubmissions({ authorId })
|
|
9831
|
+
]);
|
|
9832
|
+
setSnapshot(contest);
|
|
9833
|
+
setMySubmissions(mine);
|
|
9834
|
+
} catch (e) {
|
|
9835
|
+
setError(e.message);
|
|
9836
|
+
} finally {
|
|
9837
|
+
setLoading(false);
|
|
9838
|
+
}
|
|
9839
|
+
};
|
|
9840
|
+
React69.useEffect(() => {
|
|
9841
|
+
void loadData();
|
|
9842
|
+
}, []);
|
|
9843
|
+
const submitWork = async () => {
|
|
9844
|
+
if (!snapshot) return;
|
|
9845
|
+
const payload = {
|
|
9846
|
+
contestId: snapshot.contest.id,
|
|
9847
|
+
authorId,
|
|
9848
|
+
authorNickname,
|
|
9849
|
+
title: titleInput,
|
|
9850
|
+
description: descInput,
|
|
9851
|
+
type: workType,
|
|
9852
|
+
tags: ["web"],
|
|
9853
|
+
content: {
|
|
9854
|
+
coverImage,
|
|
9855
|
+
images: coverImage ? [coverImage] : void 0
|
|
9856
|
+
}
|
|
9857
|
+
};
|
|
9858
|
+
setSubmitting(true);
|
|
9859
|
+
setError(null);
|
|
9860
|
+
try {
|
|
9861
|
+
await api.createSubmission(payload, "web");
|
|
9862
|
+
setTitleInput("");
|
|
9863
|
+
setDescInput("");
|
|
9864
|
+
setCoverImage("");
|
|
9865
|
+
await loadData();
|
|
9866
|
+
} catch (e) {
|
|
9867
|
+
setError(e.message);
|
|
9868
|
+
} finally {
|
|
9869
|
+
setSubmitting(false);
|
|
9870
|
+
}
|
|
9871
|
+
};
|
|
9872
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("section", null, /* @__PURE__ */ React69__namespace.default.createElement("h2", null, title), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void loadData(), disabled: loading }, loading ? "\u5237\u65B0\u4E2D..." : "\u5237\u65B0\u6570\u636E"), error ? /* @__PURE__ */ React69__namespace.default.createElement("p", { style: { color: "crimson" } }, "\u9519\u8BEF\uFF1A", error) : null, /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h3", null, "\u65B0\u5EFA\u6295\u7A3F"), /* @__PURE__ */ React69__namespace.default.createElement("input", { value: titleInput, onChange: (e) => setTitleInput(e.target.value), placeholder: "\u4F5C\u54C1\u6807\u9898" }), /* @__PURE__ */ React69__namespace.default.createElement("br", null), /* @__PURE__ */ React69__namespace.default.createElement("textarea", { value: descInput, onChange: (e) => setDescInput(e.target.value), placeholder: "\u4F5C\u54C1\u7B80\u4ECB" }), /* @__PURE__ */ React69__namespace.default.createElement("br", null), /* @__PURE__ */ React69__namespace.default.createElement("input", { value: coverImage, onChange: (e) => setCoverImage(e.target.value), placeholder: "\u5C01\u9762 URL" }), /* @__PURE__ */ React69__namespace.default.createElement("br", null), /* @__PURE__ */ React69__namespace.default.createElement("select", { value: workType, onChange: (e) => setWorkType(e.target.value) }, workTypes.map((item) => /* @__PURE__ */ React69__namespace.default.createElement("option", { value: item, key: item }, item))), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void submitWork(), disabled: submitting || !snapshot }, submitting ? "\u63D0\u4EA4\u4E2D..." : "\u63D0\u4EA4\u7A3F\u4EF6")), /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h3", null, "\u6211\u7684\u6295\u7A3F\uFF08", mySubmissions.length, "\uFF09"), /* @__PURE__ */ React69__namespace.default.createElement("ul", null, mySubmissions.map((item) => /* @__PURE__ */ React69__namespace.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}` : "")))));
|
|
9873
|
+
};
|
|
9874
|
+
var MikuContestArtistPage_default = MikuContestArtistPage;
|
|
9875
|
+
var MikuContestAdminPage = ({
|
|
9876
|
+
client,
|
|
9877
|
+
adminId,
|
|
9878
|
+
title = "\u7BA1\u7406\u5458\u9762\u677F"
|
|
9879
|
+
}) => {
|
|
9880
|
+
const api = React69.useMemo(() => client || createMikuContestWebClient(), [client]);
|
|
9881
|
+
const [snapshot, setSnapshot] = React69.useState(null);
|
|
9882
|
+
const [submissions, setSubmissions] = React69.useState([]);
|
|
9883
|
+
const [loading, setLoading] = React69.useState(false);
|
|
9884
|
+
const [error, setError] = React69.useState(null);
|
|
9885
|
+
const [voterId, setVoterId] = React69.useState("");
|
|
9886
|
+
const loadData = async () => {
|
|
9887
|
+
setLoading(true);
|
|
9888
|
+
setError(null);
|
|
9889
|
+
try {
|
|
9890
|
+
const [contest, list] = await Promise.all([api.getSnapshot(), api.listSubmissions()]);
|
|
9891
|
+
setSnapshot(contest);
|
|
9892
|
+
setSubmissions(list);
|
|
9893
|
+
} catch (e) {
|
|
9894
|
+
setError(e.message);
|
|
9895
|
+
} finally {
|
|
9896
|
+
setLoading(false);
|
|
9897
|
+
}
|
|
9898
|
+
};
|
|
9899
|
+
React69.useEffect(() => {
|
|
9900
|
+
void loadData();
|
|
9901
|
+
}, []);
|
|
9902
|
+
const review = async (item, action) => {
|
|
9903
|
+
try {
|
|
9904
|
+
await api.reviewSubmission({
|
|
9905
|
+
submissionId: item.id,
|
|
9906
|
+
reviewerId: adminId,
|
|
9907
|
+
action,
|
|
9908
|
+
rejectReason: action === "reject" ? "\u7BA1\u7406\u5458\u9A73\u56DE" : void 0
|
|
9909
|
+
});
|
|
9910
|
+
await loadData();
|
|
9911
|
+
} catch (e) {
|
|
9912
|
+
setError(e.message);
|
|
9913
|
+
}
|
|
9914
|
+
};
|
|
9915
|
+
const toggleVoting = async (enabled) => {
|
|
9916
|
+
if (!snapshot) return;
|
|
9917
|
+
try {
|
|
9918
|
+
await api.updateContestConfig({
|
|
9919
|
+
toggles: {
|
|
9920
|
+
...snapshot.contest.toggles,
|
|
9921
|
+
votingEnabled: enabled
|
|
9922
|
+
}
|
|
9923
|
+
});
|
|
9924
|
+
await loadData();
|
|
9925
|
+
} catch (e) {
|
|
9926
|
+
setError(e.message);
|
|
9927
|
+
}
|
|
9928
|
+
};
|
|
9929
|
+
const setRestriction = async (banned) => {
|
|
9930
|
+
if (!snapshot || !voterId.trim()) return;
|
|
9931
|
+
try {
|
|
9932
|
+
await api.setVoterRestriction({
|
|
9933
|
+
voterId: voterId.trim(),
|
|
9934
|
+
banned,
|
|
9935
|
+
reason: banned ? "\u7BA1\u7406\u5458\u624B\u52A8\u5C01\u7981" : "\u7BA1\u7406\u5458\u89E3\u9664\u5C01\u7981",
|
|
9936
|
+
operatorId: adminId
|
|
9937
|
+
});
|
|
9938
|
+
setVoterId("");
|
|
9939
|
+
} catch (e) {
|
|
9940
|
+
setError(e.message);
|
|
9941
|
+
}
|
|
9942
|
+
};
|
|
9943
|
+
const resetVotesByVoter = async () => {
|
|
9944
|
+
if (!voterId.trim()) return;
|
|
9945
|
+
try {
|
|
9946
|
+
await api.resetVotes({ voterId: voterId.trim() });
|
|
9947
|
+
setVoterId("");
|
|
9948
|
+
await loadData();
|
|
9949
|
+
} catch (e) {
|
|
9950
|
+
setError(e.message);
|
|
9951
|
+
}
|
|
9952
|
+
};
|
|
9953
|
+
const exportExcel = async () => {
|
|
9954
|
+
try {
|
|
9955
|
+
const data = await api.exportSubmissions();
|
|
9956
|
+
const blob = new Blob([data], {
|
|
9957
|
+
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
9958
|
+
});
|
|
9959
|
+
const url = URL.createObjectURL(blob);
|
|
9960
|
+
const a = document.createElement("a");
|
|
9961
|
+
a.href = url;
|
|
9962
|
+
a.download = "miku-submissions.xlsx";
|
|
9963
|
+
a.click();
|
|
9964
|
+
URL.revokeObjectURL(url);
|
|
9965
|
+
} catch (e) {
|
|
9966
|
+
setError(e.message);
|
|
9967
|
+
}
|
|
9968
|
+
};
|
|
9969
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("section", null, /* @__PURE__ */ React69__namespace.default.createElement("h2", null, title), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void loadData(), disabled: loading }, loading ? "\u5237\u65B0\u4E2D..." : "\u5237\u65B0\u6570\u636E"), error ? /* @__PURE__ */ React69__namespace.default.createElement("p", { style: { color: "crimson" } }, "\u9519\u8BEF\uFF1A", error) : null, /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h3", null, "\u8D5B\u4E8B\u5F00\u5173"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void toggleVoting(true), disabled: !snapshot }, "\u5F00\u542F\u6295\u7968"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void toggleVoting(false), disabled: !snapshot }, "\u5173\u95ED\u6295\u7968")), /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h3", null, "\u6295\u7A3F\u5BA1\u6838\uFF08", submissions.length, "\uFF09"), /* @__PURE__ */ React69__namespace.default.createElement("ul", null, submissions.map((item) => /* @__PURE__ */ React69__namespace.default.createElement("li", { key: item.id }, /* @__PURE__ */ React69__namespace.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__ */ React69__namespace.default.createElement(React69__namespace.default.Fragment, null, " ", /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void review(item, "approve") }, "\u901A\u8FC7"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void review(item, "reject") }, "\u9A73\u56DE")) : null)))), /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h3", null, "\u6295\u7968\u98CE\u63A7"), /* @__PURE__ */ React69__namespace.default.createElement("input", { value: voterId, onChange: (e) => setVoterId(e.target.value), placeholder: "voterId" }), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void setRestriction(true), disabled: !snapshot }, "\u5C01\u7981\u6295\u7968"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void setRestriction(false), disabled: !snapshot }, "\u89E3\u9664\u5C01\u7981"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void resetVotesByVoter() }, "\u6E05\u96F6\u8BE5\u7528\u6237\u7968\u6570")), /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h3", null, "\u5BFC\u51FA"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => void exportExcel() }, "\u5BFC\u51FA\u6295\u7A3F Excel")));
|
|
9970
|
+
};
|
|
9971
|
+
var MikuContestAdminPage_default = MikuContestAdminPage;
|
|
9972
|
+
|
|
9973
|
+
// src/mikuContest/ui/web/pages/MikuContestPage.tsx
|
|
9974
|
+
var MikuContestPage = ({
|
|
9975
|
+
defaultView = "audience",
|
|
9976
|
+
viewerVoterId = "viewer-demo",
|
|
9977
|
+
artistId = "artist-demo",
|
|
9978
|
+
artistNickname = "Demo \u753B\u5E08",
|
|
9979
|
+
adminId = "admin-demo"
|
|
9980
|
+
}) => {
|
|
9981
|
+
const [view, setView] = React69.useState(defaultView);
|
|
9982
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h1", null, "Miku Contest"), /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => setView("audience") }, "\u89C2\u4F17\u7AEF"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => setView("artist") }, "\u753B\u5E08\u7AEF"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => setView("admin") }, "\u7BA1\u7406\u5458\u7AEF")), view === "audience" ? /* @__PURE__ */ React69__namespace.default.createElement(MikuContestAudiencePage_default, { voterId: viewerVoterId }) : null, view === "artist" ? /* @__PURE__ */ React69__namespace.default.createElement(MikuContestArtistPage_default, { authorId: artistId, authorNickname: artistNickname }) : null, view === "admin" ? /* @__PURE__ */ React69__namespace.default.createElement(MikuContestAdminPage_default, { adminId }) : null);
|
|
9983
|
+
};
|
|
9984
|
+
var MikuContestPage_default = MikuContestPage;
|
|
9985
|
+
|
|
9986
|
+
// src/mikuContest/ui/miniapp/index.ts
|
|
9987
|
+
var miniapp_exports2 = {};
|
|
9988
|
+
__export(miniapp_exports2, {
|
|
9989
|
+
MikuContestMiniappHome: () => MikuContestMiniappHome_default,
|
|
9990
|
+
MikuContestMiniappPage: () => MikuContestMiniappPage_default
|
|
9991
|
+
});
|
|
9992
|
+
var MikuContestMiniappHome = ({ snapshot }) => {
|
|
9993
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h3", null, snapshot.contest.name), /* @__PURE__ */ React69__namespace.default.createElement("p", null, "\u6295\u7A3F\uFF1A", snapshot.submissions.length, " | \u516C\u544A\uFF1A", snapshot.announcements.length), /* @__PURE__ */ React69__namespace.default.createElement("ol", null, snapshot.leaderboard.slice(0, 3).map((item) => /* @__PURE__ */ React69__namespace.default.createElement("li", { key: item.submissionId }, item.title, "\uFF08", item.voteCount, "\u7968\uFF09"))));
|
|
9994
|
+
};
|
|
9995
|
+
var MikuContestMiniappHome_default = MikuContestMiniappHome;
|
|
9996
|
+
var MikuContestMiniappPage = () => {
|
|
9997
|
+
const { service, snapshot, refresh } = useMikuContest();
|
|
9998
|
+
const [tab, setTab] = React69.useState("vote");
|
|
9999
|
+
const [voterId, setVoterId] = React69.useState("miniapp-voter");
|
|
10000
|
+
const [authorId, setAuthorId] = React69.useState("miniapp-author");
|
|
10001
|
+
const [authorNickname, setAuthorNickname] = React69.useState("\u5C0F\u7A0B\u5E8F\u753B\u5E08");
|
|
10002
|
+
const [title, setTitle] = React69.useState("");
|
|
10003
|
+
const [desc, setDesc] = React69.useState("");
|
|
10004
|
+
const [type, setType] = React69.useState("visual");
|
|
10005
|
+
const [error, setError] = React69.useState(null);
|
|
10006
|
+
const approvedWorks = React69.useMemo(() => {
|
|
10007
|
+
return snapshot.submissions.filter((item) => item.status === "approved");
|
|
10008
|
+
}, [snapshot.submissions]);
|
|
10009
|
+
const vote = (submissionId) => {
|
|
10010
|
+
try {
|
|
10011
|
+
service.vote({
|
|
10012
|
+
contestId: snapshot.contest.id,
|
|
10013
|
+
submissionId,
|
|
10014
|
+
voterId
|
|
10015
|
+
});
|
|
10016
|
+
refresh();
|
|
10017
|
+
setError(null);
|
|
10018
|
+
} catch (e) {
|
|
10019
|
+
setError(e.message);
|
|
10020
|
+
}
|
|
10021
|
+
};
|
|
10022
|
+
const submit = () => {
|
|
10023
|
+
try {
|
|
10024
|
+
service.createSubmission(
|
|
10025
|
+
{
|
|
10026
|
+
contestId: snapshot.contest.id,
|
|
10027
|
+
authorId,
|
|
10028
|
+
authorNickname,
|
|
10029
|
+
title,
|
|
10030
|
+
description: desc,
|
|
10031
|
+
type,
|
|
10032
|
+
content: {}
|
|
10033
|
+
},
|
|
10034
|
+
"miniapp"
|
|
10035
|
+
);
|
|
10036
|
+
setTitle("");
|
|
10037
|
+
setDesc("");
|
|
10038
|
+
refresh();
|
|
10039
|
+
setError(null);
|
|
10040
|
+
} catch (e) {
|
|
10041
|
+
setError(e.message);
|
|
10042
|
+
}
|
|
10043
|
+
};
|
|
10044
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("h3", null, snapshot.contest.name), /* @__PURE__ */ React69__namespace.default.createElement("p", null, "\u5C0F\u7A0B\u5E8F\u7AEF\u793A\u4F8B\u9875\u9762"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => setTab("vote") }, "\u89C2\u4F17\u6295\u7968"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => setTab("submit") }, "\u753B\u5E08\u6295\u7A3F"), error ? /* @__PURE__ */ React69__namespace.default.createElement("p", { style: { color: "crimson" } }, "\u9519\u8BEF\uFF1A", error) : null, tab === "vote" ? /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("input", { value: voterId, onChange: (e) => setVoterId(e.target.value), placeholder: "voterId" }), /* @__PURE__ */ React69__namespace.default.createElement("ul", null, approvedWorks.map((item) => /* @__PURE__ */ React69__namespace.default.createElement("li", { key: item.id }, item.title, "\uFF08", item.voteCount, "\u7968\uFF09", /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: () => vote(item.id) }, "\u6295\u7968"))))) : null, tab === "submit" ? /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("input", { value: authorId, onChange: (e) => setAuthorId(e.target.value), placeholder: "authorId" }), /* @__PURE__ */ React69__namespace.default.createElement("input", { value: authorNickname, onChange: (e) => setAuthorNickname(e.target.value), placeholder: "\u4F5C\u8005\u6635\u79F0" }), /* @__PURE__ */ React69__namespace.default.createElement("input", { value: title, onChange: (e) => setTitle(e.target.value), placeholder: "\u4F5C\u54C1\u6807\u9898" }), /* @__PURE__ */ React69__namespace.default.createElement("input", { value: desc, onChange: (e) => setDesc(e.target.value), placeholder: "\u4F5C\u54C1\u7B80\u4ECB" }), /* @__PURE__ */ React69__namespace.default.createElement("select", { value: type, onChange: (e) => setType(e.target.value) }, /* @__PURE__ */ React69__namespace.default.createElement("option", { value: "visual" }, "visual"), /* @__PURE__ */ React69__namespace.default.createElement("option", { value: "video" }, "video"), /* @__PURE__ */ React69__namespace.default.createElement("option", { value: "text" }, "text"), /* @__PURE__ */ React69__namespace.default.createElement("option", { value: "audio" }, "audio")), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: submit }, "\u63D0\u4EA4")) : null);
|
|
10045
|
+
};
|
|
10046
|
+
var MikuContestMiniappPage_default = MikuContestMiniappPage;
|
|
10047
|
+
|
|
10048
|
+
// src/huarongdao/index.ts
|
|
10049
|
+
var huarongdao_exports = {};
|
|
10050
|
+
__export(huarongdao_exports, {
|
|
10051
|
+
HuarongdaoService: () => HuarongdaoService,
|
|
10052
|
+
buildSolvedTiles: () => buildSolvedTiles,
|
|
10053
|
+
canMove: () => canMove,
|
|
10054
|
+
createCreateConfigHandler: () => createCreateConfigHandler,
|
|
10055
|
+
createDeleteConfigHandler: () => createDeleteConfigHandler,
|
|
10056
|
+
createGetSnapshotHandler: () => createGetSnapshotHandler,
|
|
10057
|
+
createHuarongdaoApiClient: () => createHuarongdaoApiClient,
|
|
10058
|
+
createHuarongdaoService: () => createHuarongdaoService,
|
|
10059
|
+
createHuarongdaoWebClient: () => createHuarongdaoWebClient,
|
|
10060
|
+
createListConfigsHandler: () => createListConfigsHandler,
|
|
10061
|
+
createUpdateConfigHandler: () => createUpdateConfigHandler,
|
|
10062
|
+
inversionCount: () => inversionCount,
|
|
10063
|
+
isSolvable: () => isSolvable,
|
|
10064
|
+
isSolved: () => isSolved,
|
|
10065
|
+
moveTile: () => moveTile,
|
|
10066
|
+
shuffleSolvable: () => shuffleSolvable,
|
|
10067
|
+
webUI: () => web_exports3
|
|
10068
|
+
});
|
|
10069
|
+
|
|
10070
|
+
// src/huarongdao/logic/game.ts
|
|
10071
|
+
var clone = (v) => [...v];
|
|
10072
|
+
var buildSolvedTiles = (rows, cols) => {
|
|
10073
|
+
const total = rows * cols;
|
|
10074
|
+
return Array.from({ length: total }, (_, i) => (i + 1) % total);
|
|
10075
|
+
};
|
|
10076
|
+
var isSolved = (tiles) => {
|
|
10077
|
+
return tiles.every((v, i, arr) => v === (i + 1) % arr.length);
|
|
10078
|
+
};
|
|
10079
|
+
var canMove = (tiles, rows, cols, tileIndex) => {
|
|
10080
|
+
const blank = tiles.indexOf(0);
|
|
10081
|
+
if (blank < 0 || tileIndex < 0 || tileIndex >= tiles.length) return false;
|
|
10082
|
+
const br = Math.floor(blank / cols);
|
|
10083
|
+
const bc = blank % cols;
|
|
10084
|
+
const tr = Math.floor(tileIndex / cols);
|
|
10085
|
+
const tc = tileIndex % cols;
|
|
10086
|
+
return Math.abs(br - tr) + Math.abs(bc - tc) === 1;
|
|
10087
|
+
};
|
|
10088
|
+
var moveTile = (state, tileIndex) => {
|
|
10089
|
+
if (!canMove(state.tiles, state.rows, state.cols, tileIndex)) return state;
|
|
10090
|
+
const nextTiles = clone(state.tiles);
|
|
10091
|
+
const blank = nextTiles.indexOf(0);
|
|
10092
|
+
const blankValue = nextTiles[blank];
|
|
10093
|
+
const tileValue = nextTiles[tileIndex];
|
|
10094
|
+
if (blankValue === void 0 || tileValue === void 0) return state;
|
|
10095
|
+
nextTiles[blank] = tileValue;
|
|
10096
|
+
nextTiles[tileIndex] = blankValue;
|
|
10097
|
+
const solved = isSolved(nextTiles);
|
|
10098
|
+
return {
|
|
10099
|
+
...state,
|
|
10100
|
+
tiles: nextTiles,
|
|
10101
|
+
moveCount: state.moveCount + 1,
|
|
10102
|
+
isSolved: solved,
|
|
10103
|
+
finishedAt: solved ? Date.now() : void 0
|
|
10104
|
+
};
|
|
10105
|
+
};
|
|
10106
|
+
var inversionCount = (tiles) => {
|
|
10107
|
+
const arr = tiles.filter((n) => n !== 0);
|
|
10108
|
+
let cnt = 0;
|
|
10109
|
+
for (let i = 0; i < arr.length; i += 1) {
|
|
10110
|
+
for (let j = i + 1; j < arr.length; j += 1) {
|
|
10111
|
+
if ((arr[i] ?? 0) > (arr[j] ?? 0)) cnt += 1;
|
|
10112
|
+
}
|
|
10113
|
+
}
|
|
10114
|
+
return cnt;
|
|
10115
|
+
};
|
|
10116
|
+
var isSolvable = (tiles, rows, cols) => {
|
|
10117
|
+
const inv = inversionCount(tiles);
|
|
10118
|
+
if (cols % 2 === 1) return inv % 2 === 0;
|
|
10119
|
+
const blankRowFromBottom = rows - Math.floor(tiles.indexOf(0) / cols);
|
|
10120
|
+
return blankRowFromBottom % 2 === 0 !== (inv % 2 === 0);
|
|
10121
|
+
};
|
|
10122
|
+
var shuffleSolvable = (rows, cols, steps = 80) => {
|
|
10123
|
+
let tiles = buildSolvedTiles(rows, cols);
|
|
10124
|
+
for (let i = 0; i < steps; i += 1) {
|
|
10125
|
+
const blank = tiles.indexOf(0);
|
|
10126
|
+
const br = Math.floor(blank / cols);
|
|
10127
|
+
const bc = blank % cols;
|
|
10128
|
+
const candidate = [];
|
|
10129
|
+
const dirs = [
|
|
10130
|
+
[1, 0],
|
|
10131
|
+
[-1, 0],
|
|
10132
|
+
[0, 1],
|
|
10133
|
+
[0, -1]
|
|
10134
|
+
];
|
|
10135
|
+
dirs.forEach(([dr, dc]) => {
|
|
10136
|
+
const nr = br + dr;
|
|
10137
|
+
const nc = bc + dc;
|
|
10138
|
+
if (nr >= 0 && nr < rows && nc >= 0 && nc < cols) candidate.push(nr * cols + nc);
|
|
10139
|
+
});
|
|
10140
|
+
const idx = candidate[Math.floor(Math.random() * candidate.length)] ?? blank;
|
|
10141
|
+
const next = clone(tiles);
|
|
10142
|
+
[next[blank], next[idx]] = [next[idx] ?? 0, next[blank] ?? 0];
|
|
10143
|
+
tiles = next;
|
|
10144
|
+
}
|
|
10145
|
+
return tiles;
|
|
10146
|
+
};
|
|
10147
|
+
|
|
10148
|
+
// src/huarongdao/service/api/client.ts
|
|
10149
|
+
var unwrap2 = (result) => {
|
|
10150
|
+
if (!result.success || result.data === void 0) throw new Error(result.error || "\u8BF7\u6C42\u5931\u8D25");
|
|
10151
|
+
return result.data;
|
|
10152
|
+
};
|
|
10153
|
+
var createHuarongdaoApiClient = (basePath, requester2) => ({
|
|
10154
|
+
async getSnapshot() {
|
|
10155
|
+
return unwrap2(await requester2(`${basePath}/snapshot`, { method: "GET" }));
|
|
10156
|
+
},
|
|
10157
|
+
async listConfigs() {
|
|
10158
|
+
return unwrap2(await requester2(`${basePath}/configs`, { method: "GET" }));
|
|
10159
|
+
},
|
|
10160
|
+
async createConfig(input) {
|
|
10161
|
+
return unwrap2(await requester2(`${basePath}/configs`, { method: "POST", body: input }));
|
|
10162
|
+
},
|
|
10163
|
+
async updateConfig(id2, patch) {
|
|
10164
|
+
return unwrap2(await requester2(`${basePath}/configs`, { method: "PATCH", body: { id: id2, patch } }));
|
|
10165
|
+
},
|
|
10166
|
+
async deleteConfig(id2) {
|
|
10167
|
+
return unwrap2(await requester2(`${basePath}/configs`, { method: "DELETE", body: { id: id2 } }));
|
|
10168
|
+
}
|
|
10169
|
+
});
|
|
10170
|
+
|
|
10171
|
+
// src/huarongdao/service/web/client.ts
|
|
10172
|
+
var requester = (options) => {
|
|
10173
|
+
const baseUrl = options.baseUrl || "";
|
|
10174
|
+
return async (url, req) => {
|
|
10175
|
+
const res = await fetch(`${baseUrl}${url}`, {
|
|
10176
|
+
method: req?.method || "GET",
|
|
10177
|
+
headers: { "Content-Type": "application/json", ...options.headers || {} },
|
|
10178
|
+
body: req?.body ? JSON.stringify(req.body) : void 0
|
|
10179
|
+
});
|
|
10180
|
+
return await res.json();
|
|
10181
|
+
};
|
|
10182
|
+
};
|
|
10183
|
+
var createHuarongdaoWebClient = (options = {}) => {
|
|
10184
|
+
return createHuarongdaoApiClient(options.basePath || "/api/huarongdao", requester(options));
|
|
10185
|
+
};
|
|
10186
|
+
|
|
10187
|
+
// src/huarongdao/server/service.ts
|
|
10188
|
+
var id = () => `puzzle_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
10189
|
+
var HuarongdaoService = class {
|
|
10190
|
+
constructor() {
|
|
10191
|
+
this.configs = /* @__PURE__ */ new Map();
|
|
10192
|
+
}
|
|
10193
|
+
listConfigs() {
|
|
10194
|
+
return [...this.configs.values()];
|
|
10195
|
+
}
|
|
10196
|
+
getBySlug(slug) {
|
|
10197
|
+
return [...this.configs.values()].find((c) => c.slug === slug) || null;
|
|
10198
|
+
}
|
|
10199
|
+
createConfig(input) {
|
|
10200
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10201
|
+
const next = {
|
|
10202
|
+
id: id(),
|
|
10203
|
+
slug: input.slug,
|
|
10204
|
+
name: input.name,
|
|
10205
|
+
description: input.description,
|
|
10206
|
+
status: "draft",
|
|
10207
|
+
rows: input.rows,
|
|
10208
|
+
cols: input.cols,
|
|
10209
|
+
sourceImageUrl: input.sourceImageUrl,
|
|
10210
|
+
showReference: input.showReference ?? true,
|
|
10211
|
+
shuffleSteps: input.shuffleSteps ?? 80,
|
|
10212
|
+
timeLimitSec: input.timeLimitSec,
|
|
10213
|
+
startMode: input.startMode ?? "random-solvable",
|
|
10214
|
+
initialTiles: input.initialTiles,
|
|
10215
|
+
createdAt: now,
|
|
10216
|
+
updatedAt: now
|
|
10217
|
+
};
|
|
10218
|
+
this.configs.set(next.id, next);
|
|
10219
|
+
return next;
|
|
10220
|
+
}
|
|
10221
|
+
updateConfig(id2, patch) {
|
|
10222
|
+
const cur = this.configs.get(id2);
|
|
10223
|
+
if (!cur) throw new Error("\u914D\u7F6E\u4E0D\u5B58\u5728");
|
|
10224
|
+
const next = { ...cur, ...patch, id: cur.id, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
10225
|
+
this.configs.set(id2, next);
|
|
10226
|
+
return next;
|
|
10227
|
+
}
|
|
10228
|
+
deleteConfig(id2) {
|
|
10229
|
+
this.configs.delete(id2);
|
|
10230
|
+
}
|
|
10231
|
+
getSnapshot() {
|
|
10232
|
+
const configs = this.listConfigs();
|
|
10233
|
+
return {
|
|
10234
|
+
configs,
|
|
10235
|
+
activeConfig: configs.find((c) => c.status === "active")
|
|
10236
|
+
};
|
|
10237
|
+
}
|
|
10238
|
+
};
|
|
10239
|
+
var createHuarongdaoService = () => new HuarongdaoService();
|
|
10240
|
+
var resolveService2 = (config) => config?.service || createHuarongdaoService();
|
|
10241
|
+
var createGetSnapshotHandler = (config) => {
|
|
10242
|
+
const service = resolveService2(config);
|
|
10243
|
+
return async (_req) => server.NextResponse.json({ success: true, data: service.getSnapshot() });
|
|
10244
|
+
};
|
|
10245
|
+
var createListConfigsHandler = (config) => {
|
|
10246
|
+
const service = resolveService2(config);
|
|
10247
|
+
return async (_req) => server.NextResponse.json({ success: true, data: service.listConfigs() });
|
|
10248
|
+
};
|
|
10249
|
+
var createCreateConfigHandler = (config) => {
|
|
10250
|
+
const service = resolveService2(config);
|
|
10251
|
+
return async (req) => {
|
|
10252
|
+
try {
|
|
10253
|
+
const body = await req.json();
|
|
10254
|
+
const data = service.createConfig(body);
|
|
10255
|
+
return server.NextResponse.json({ success: true, data });
|
|
10256
|
+
} catch (e) {
|
|
10257
|
+
return server.NextResponse.json({ success: false, error: e.message }, { status: 400 });
|
|
10258
|
+
}
|
|
10259
|
+
};
|
|
10260
|
+
};
|
|
10261
|
+
var createUpdateConfigHandler = (config) => {
|
|
10262
|
+
const service = resolveService2(config);
|
|
10263
|
+
return async (req) => {
|
|
10264
|
+
try {
|
|
10265
|
+
const body = await req.json();
|
|
10266
|
+
const data = service.updateConfig(body.id, body.patch || {});
|
|
10267
|
+
return server.NextResponse.json({ success: true, data });
|
|
10268
|
+
} catch (e) {
|
|
10269
|
+
return server.NextResponse.json({ success: false, error: e.message }, { status: 400 });
|
|
10270
|
+
}
|
|
10271
|
+
};
|
|
10272
|
+
};
|
|
10273
|
+
var createDeleteConfigHandler = (config) => {
|
|
10274
|
+
const service = resolveService2(config);
|
|
10275
|
+
return async (req) => {
|
|
10276
|
+
try {
|
|
10277
|
+
const body = await req.json();
|
|
10278
|
+
service.deleteConfig(body.id);
|
|
10279
|
+
return server.NextResponse.json({ success: true, data: true });
|
|
10280
|
+
} catch (e) {
|
|
10281
|
+
return server.NextResponse.json({ success: false, error: e.message }, { status: 400 });
|
|
10282
|
+
}
|
|
10283
|
+
};
|
|
10284
|
+
};
|
|
10285
|
+
|
|
10286
|
+
// src/huarongdao/ui/web/index.ts
|
|
10287
|
+
var web_exports3 = {};
|
|
10288
|
+
__export(web_exports3, {
|
|
10289
|
+
HuarongdaoBoard: () => HuarongdaoBoard_default,
|
|
10290
|
+
HuarongdaoConfigPage: () => HuarongdaoConfigPage_default,
|
|
10291
|
+
HuarongdaoGamePage: () => HuarongdaoGamePage_default
|
|
10292
|
+
});
|
|
10293
|
+
var HuarongdaoBoard = ({ tiles, rows, cols, imageUrl, onClickTile }) => {
|
|
10294
|
+
const total = rows * cols;
|
|
10295
|
+
return /* @__PURE__ */ React69__namespace.default.createElement(
|
|
10296
|
+
"div",
|
|
10297
|
+
{
|
|
10298
|
+
style: {
|
|
10299
|
+
display: "grid",
|
|
10300
|
+
gridTemplateColumns: `repeat(${cols}, 96px)`,
|
|
10301
|
+
gridTemplateRows: `repeat(${rows}, 96px)`,
|
|
10302
|
+
gap: 6
|
|
10303
|
+
}
|
|
10304
|
+
},
|
|
10305
|
+
tiles.map((tile, index) => {
|
|
10306
|
+
if (tile === 0) return /* @__PURE__ */ React69__namespace.default.createElement("div", { key: `blank-${index}`, style: { background: "#ddd" } });
|
|
10307
|
+
const pieceIndex = tile - 1;
|
|
10308
|
+
const pr = Math.floor(pieceIndex / cols);
|
|
10309
|
+
const pc = pieceIndex % cols;
|
|
10310
|
+
return /* @__PURE__ */ React69__namespace.default.createElement(
|
|
10311
|
+
"button",
|
|
10312
|
+
{
|
|
10313
|
+
key: `${tile}-${index}`,
|
|
10314
|
+
onClick: () => onClickTile(index),
|
|
10315
|
+
style: {
|
|
10316
|
+
border: "1px solid #666",
|
|
10317
|
+
cursor: "pointer",
|
|
10318
|
+
backgroundImage: `url(${imageUrl})`,
|
|
10319
|
+
backgroundSize: `${cols * 96}px ${rows * 96}px`,
|
|
10320
|
+
backgroundPosition: `${-pc * 96}px ${-pr * 96}px`
|
|
10321
|
+
}
|
|
10322
|
+
}
|
|
10323
|
+
);
|
|
10324
|
+
}),
|
|
10325
|
+
tiles.length !== total ? /* @__PURE__ */ React69__namespace.default.createElement("div", null, "tiles invalid") : null
|
|
10326
|
+
);
|
|
10327
|
+
};
|
|
10328
|
+
var HuarongdaoBoard_default = HuarongdaoBoard;
|
|
10329
|
+
var HuarongdaoGamePage = ({ config }) => {
|
|
10330
|
+
const initial = React69.useMemo(() => {
|
|
10331
|
+
const tiles = config.startMode === "custom-layout" && config.initialTiles?.length === config.rows * config.cols ? config.initialTiles : shuffleSolvable(config.rows, config.cols, config.shuffleSteps);
|
|
10332
|
+
return {
|
|
10333
|
+
tiles,
|
|
10334
|
+
rows: config.rows,
|
|
10335
|
+
cols: config.cols,
|
|
10336
|
+
moveCount: 0,
|
|
10337
|
+
startedAt: Date.now(),
|
|
10338
|
+
isSolved: false
|
|
10339
|
+
};
|
|
10340
|
+
}, [config]);
|
|
10341
|
+
const [state, setState] = React69.useState(initial);
|
|
10342
|
+
const reset = () => {
|
|
10343
|
+
setState({
|
|
10344
|
+
...state,
|
|
10345
|
+
tiles: shuffleSolvable(config.rows, config.cols, config.shuffleSteps),
|
|
10346
|
+
moveCount: 0,
|
|
10347
|
+
startedAt: Date.now(),
|
|
10348
|
+
finishedAt: void 0,
|
|
10349
|
+
isSolved: false
|
|
10350
|
+
});
|
|
10351
|
+
};
|
|
10352
|
+
const solveNow = () => {
|
|
10353
|
+
setState((prev) => ({ ...prev, tiles: buildSolvedTiles(config.rows, config.cols), isSolved: true, finishedAt: Date.now() }));
|
|
10354
|
+
};
|
|
10355
|
+
const durationSec = Math.floor(((state.finishedAt || Date.now()) - state.startedAt) / 1e3);
|
|
10356
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("section", null, /* @__PURE__ */ React69__namespace.default.createElement("h2", null, config.name), /* @__PURE__ */ React69__namespace.default.createElement("p", null, "\u6B65\u6570\uFF1A", state.moveCount, " \uFF5C \u7528\u65F6\uFF1A", durationSec, "s ", state.isSolved ? "\uFF5C\u5DF2\u901A\u5173 \u{1F389}" : ""), /* @__PURE__ */ React69__namespace.default.createElement(
|
|
10357
|
+
HuarongdaoBoard_default,
|
|
10358
|
+
{
|
|
10359
|
+
tiles: state.tiles,
|
|
10360
|
+
rows: state.rows,
|
|
10361
|
+
cols: state.cols,
|
|
10362
|
+
imageUrl: config.sourceImageUrl,
|
|
10363
|
+
onClickTile: (idx) => setState((prev) => moveTile(prev, idx))
|
|
10364
|
+
}
|
|
10365
|
+
), /* @__PURE__ */ React69__namespace.default.createElement("div", { style: { marginTop: 12 } }, /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: reset }, "\u91CD\u65B0\u6253\u4E71"), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: solveNow }, "\u4E00\u952E\u5B8C\u6210(\u6D4B\u8BD5)")), config.showReference ? /* @__PURE__ */ React69__namespace.default.createElement("div", { style: { marginTop: 12 } }, /* @__PURE__ */ React69__namespace.default.createElement("div", null, "\u53C2\u8003\u56FE\uFF1A"), /* @__PURE__ */ React69__namespace.default.createElement("img", { src: config.sourceImageUrl, alt: "reference", style: { width: 180, border: "1px solid #ccc" } })) : null);
|
|
10366
|
+
};
|
|
10367
|
+
var HuarongdaoGamePage_default = HuarongdaoGamePage;
|
|
10368
|
+
var HuarongdaoConfigPage = () => {
|
|
10369
|
+
const service = React69.useMemo(() => createHuarongdaoService(), []);
|
|
10370
|
+
const [version, setVersion] = React69.useState(0);
|
|
10371
|
+
const [name, setName] = React69.useState("\u793A\u4F8B\u534E\u5BB9\u9053");
|
|
10372
|
+
const [slug, setSlug] = React69.useState("sample-huarongdao");
|
|
10373
|
+
const [imageUrl, setImageUrl] = React69.useState("https://i.imgur.com/6z7Qw6M.png");
|
|
10374
|
+
const [rows, setRows] = React69.useState(3);
|
|
10375
|
+
const [cols, setCols] = React69.useState(3);
|
|
10376
|
+
const list = React69.useMemo(() => {
|
|
10377
|
+
return service.listConfigs();
|
|
10378
|
+
}, [service, version]);
|
|
10379
|
+
const create = () => {
|
|
10380
|
+
const input = {
|
|
10381
|
+
name,
|
|
10382
|
+
slug,
|
|
10383
|
+
sourceImageUrl: imageUrl,
|
|
10384
|
+
rows,
|
|
10385
|
+
cols,
|
|
10386
|
+
showReference: true,
|
|
10387
|
+
shuffleSteps: 80
|
|
10388
|
+
};
|
|
10389
|
+
service.createConfig(input);
|
|
10390
|
+
setVersion((v) => v + 1);
|
|
10391
|
+
};
|
|
10392
|
+
return /* @__PURE__ */ React69__namespace.default.createElement("section", null, /* @__PURE__ */ React69__namespace.default.createElement("h2", null, "\u534E\u5BB9\u9053\u540E\u53F0\u914D\u7F6E\u9875"), /* @__PURE__ */ React69__namespace.default.createElement("p", null, "\u652F\u6301\u591A\u5957\u914D\u7F6E\u521B\u5EFA\u3001\u53C2\u6570\u5316\u7BA1\u7406\uFF08V1 \u9AA8\u67B6\uFF09"), /* @__PURE__ */ React69__namespace.default.createElement("div", null, /* @__PURE__ */ React69__namespace.default.createElement("input", { value: name, onChange: (e) => setName(e.target.value), placeholder: "name" }), /* @__PURE__ */ React69__namespace.default.createElement("input", { value: slug, onChange: (e) => setSlug(e.target.value), placeholder: "slug" }), /* @__PURE__ */ React69__namespace.default.createElement("input", { value: imageUrl, onChange: (e) => setImageUrl(e.target.value), placeholder: "image url" }), /* @__PURE__ */ React69__namespace.default.createElement("input", { type: "number", value: rows, onChange: (e) => setRows(Number(e.target.value) || 3) }), /* @__PURE__ */ React69__namespace.default.createElement("input", { type: "number", value: cols, onChange: (e) => setCols(Number(e.target.value) || 3) }), /* @__PURE__ */ React69__namespace.default.createElement("button", { onClick: create }, "\u521B\u5EFA\u914D\u7F6E")), /* @__PURE__ */ React69__namespace.default.createElement("ul", null, list.map((item) => /* @__PURE__ */ React69__namespace.default.createElement("li", { key: item.id }, item.name, " (", item.slug, ") - ", item.rows, "x", item.cols, " - ", item.status))));
|
|
10393
|
+
};
|
|
10394
|
+
var HuarongdaoConfigPage_default = HuarongdaoConfigPage;
|
|
10395
|
+
|
|
8802
10396
|
// src/storage/adapters/react-native-adapter.ts
|
|
8803
10397
|
var AsyncStorage = null;
|
|
8804
10398
|
try {
|
|
@@ -9252,6 +10846,9 @@ exports.LocalImageMappingPanel = LocalImageMappingPanel;
|
|
|
9252
10846
|
exports.LogLevel = LogLevel;
|
|
9253
10847
|
exports.Logger = Logger;
|
|
9254
10848
|
exports.MIKU_PALETTE = MIKU_PALETTE;
|
|
10849
|
+
exports.MikuContestPersistentService = MikuContestPersistentService;
|
|
10850
|
+
exports.MikuContestService = MikuContestService;
|
|
10851
|
+
exports.MikuContestStateDbService = MikuContestStateDbService;
|
|
9255
10852
|
exports.MikuFireworks3D = MikuFireworks3D;
|
|
9256
10853
|
exports.Modal = Modal;
|
|
9257
10854
|
exports.NORMAL_PALETTE = NORMAL_PALETTE;
|
|
@@ -9316,14 +10913,30 @@ exports.applyPromptTemplate = applyPromptTemplate;
|
|
|
9316
10913
|
exports.arrayUtils = arrayUtils;
|
|
9317
10914
|
exports.badgeVariants = badgeVariants;
|
|
9318
10915
|
exports.buttonVariants = buttonVariants;
|
|
10916
|
+
exports.checkVoteEligibility = checkVoteEligibility;
|
|
9319
10917
|
exports.cn = cn;
|
|
9320
10918
|
exports.createAiClient = createAiClient;
|
|
9321
10919
|
exports.createChatSession = createChatSession;
|
|
10920
|
+
exports.createCreateSubmissionHandler = createCreateSubmissionHandler;
|
|
10921
|
+
exports.createDefaultMikuContestConfig = createDefaultMikuContestConfig;
|
|
10922
|
+
exports.createExportSubmissionsHandler = createExportSubmissionsHandler;
|
|
10923
|
+
exports.createGetContestSnapshotHandler = createGetContestSnapshotHandler;
|
|
9322
10924
|
exports.createInMemoryFestivalCardDb = createInMemoryFestivalCardDb;
|
|
10925
|
+
exports.createListSubmissionsHandler = createListSubmissionsHandler;
|
|
9323
10926
|
exports.createLogger = createLogger;
|
|
10927
|
+
exports.createMikuContestApiClient = createMikuContestApiClient;
|
|
10928
|
+
exports.createMikuContestDrizzlePersistenceAdapter = createMikuContestDrizzlePersistenceAdapter;
|
|
10929
|
+
exports.createMikuContestPersistentService = createMikuContestPersistentService;
|
|
10930
|
+
exports.createMikuContestService = createMikuContestService;
|
|
9324
10931
|
exports.createOpenAICompatibleProvider = createOpenAICompatibleProvider;
|
|
10932
|
+
exports.createResetVotesHandler = createResetVotesHandler;
|
|
10933
|
+
exports.createReviewSubmissionHandler = createReviewSubmissionHandler;
|
|
10934
|
+
exports.createSetVoterRestrictionHandler = createSetVoterRestrictionHandler;
|
|
9325
10935
|
exports.createSkillRegistry = createSkillRegistry;
|
|
10936
|
+
exports.createUpdateContestConfigHandler = createUpdateContestConfigHandler;
|
|
10937
|
+
exports.createVoteHandler = createVoteHandler;
|
|
9326
10938
|
exports.debugUtils = debugUtils;
|
|
10939
|
+
exports.defaultMikuVotingRules = defaultMikuVotingRules;
|
|
9327
10940
|
exports.defaultVocaloidBoothConfig = defaultVocaloidBoothConfig;
|
|
9328
10941
|
exports.errorUtils = errorUtils;
|
|
9329
10942
|
exports.fileUtils = fileUtils;
|
|
@@ -9337,8 +10950,17 @@ exports.getCompletionFilterDisplayName = getCompletionFilterDisplayName;
|
|
|
9337
10950
|
exports.getCompletionStatusColor = getCompletionStatusColor;
|
|
9338
10951
|
exports.getCompletionStatusText = getCompletionStatusText;
|
|
9339
10952
|
exports.getExperimentCounts = getExperimentCounts;
|
|
10953
|
+
exports.huarongdao = huarongdao_exports;
|
|
9340
10954
|
exports.japaneseUtils = japaneseUtils;
|
|
9341
10955
|
exports.logger = logger;
|
|
10956
|
+
exports.mikuContestConfigs = mikuContestConfigs;
|
|
10957
|
+
exports.mikuContestDbService = mikuContestDbService;
|
|
10958
|
+
exports.mikuContestNotices = mikuContestNotices;
|
|
10959
|
+
exports.mikuContestSubmissions = mikuContestSubmissions;
|
|
10960
|
+
exports.mikuContestVoterRestrictions = mikuContestVoterRestrictions;
|
|
10961
|
+
exports.mikuContestVotes = mikuContestVotes;
|
|
10962
|
+
exports.miniappService = miniapp_exports;
|
|
10963
|
+
exports.miniappUI = miniapp_exports2;
|
|
9342
10964
|
exports.normalizeFestivalCardConfig = normalizeFestivalCardConfig;
|
|
9343
10965
|
exports.normalizeMatchCode = normalizeMatchCode;
|
|
9344
10966
|
exports.normalizePromptVariables = normalizePromptVariables;
|
|
@@ -9346,8 +10968,10 @@ exports.normalizeVocaloidBoothConfig = normalizeVocaloidBoothConfig;
|
|
|
9346
10968
|
exports.resizeFestivalCardPages = resizeFestivalCardPages;
|
|
9347
10969
|
exports.resolveScreenReceiverSignalUrl = resolveScreenReceiverSignalUrl;
|
|
9348
10970
|
exports.skillToToolDefinition = skillToToolDefinition;
|
|
10971
|
+
exports.sortByVotesDesc = sortByVotesDesc;
|
|
9349
10972
|
exports.sortExperiments = sortExperiments;
|
|
9350
10973
|
exports.stringUtils = stringUtils;
|
|
10974
|
+
exports.toVoteDayKey = toVoteDayKey;
|
|
9351
10975
|
exports.useAiChat = useAiChat;
|
|
9352
10976
|
exports.useAsyncStorage = useAsyncStorage;
|
|
9353
10977
|
exports.useBackgroundRemoval = useBackgroundRemoval;
|
|
@@ -9357,6 +10981,7 @@ exports.useFestivalCardConfig = useFestivalCardConfig;
|
|
|
9357
10981
|
exports.useFireworksEngine = useFireworksEngine;
|
|
9358
10982
|
exports.useFireworksRealtime = useFireworksRealtime;
|
|
9359
10983
|
exports.useLocalStorage = useLocalStorage;
|
|
10984
|
+
exports.useMikuContest = useMikuContest;
|
|
9360
10985
|
exports.useOCR = useOCR;
|
|
9361
10986
|
exports.useScreenReceiver = useScreenReceiver;
|
|
9362
10987
|
exports.useSentimentAnalysis = useSentimentAnalysis;
|
|
@@ -9364,6 +10989,9 @@ exports.useStorage = useStorage;
|
|
|
9364
10989
|
exports.useTaroStorage = useTaroStorage;
|
|
9365
10990
|
exports.useTextGeneration = useTextGeneration;
|
|
9366
10991
|
exports.validateExperiment = validateExperiment;
|
|
10992
|
+
exports.validateMikuSubmissionInput = validateMikuSubmissionInput;
|
|
9367
10993
|
exports.validators = validators;
|
|
10994
|
+
exports.webService = web_exports;
|
|
10995
|
+
exports.webUI = web_exports2;
|
|
9368
10996
|
//# sourceMappingURL=index.js.map
|
|
9369
10997
|
//# sourceMappingURL=index.js.map
|