uni-answer-sheet 1.0.5 → 2.0.0

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.
@@ -0,0 +1,1081 @@
1
+ var ye = Object.defineProperty;
2
+ var Ee = (e, t, o) => t in e ? ye(e, t, { enumerable: !0, configurable: !0, writable: !0, value: o }) : e[t] = o;
3
+ var re = (e, t, o) => Ee(e, typeof t != "symbol" ? t + "" : t, o);
4
+ const be = ["pagination", "content-identity", "choice-fill", "answer-regions", "html-codec", "status"];
5
+ function Se(e) {
6
+ const t = e.filter((n) => n?.kind === "answer-sheet-editor");
7
+ if (t.length !== 1) throw new Error("请显式注册一个富文本插件:plugins: [createEditorPlugin()]");
8
+ const o = t[0];
9
+ if (o.apiVersion !== 1 || o.documentVersion !== 1 || be.some((n) => !o.capabilities?.includes(n)) || typeof o.prepare != "function" || typeof o.create != "function" || typeof o.validateDocument != "function" || typeof o.html?.parse != "function" || typeof o.html?.serialize != "function") throw new Error("富文本插件协议不兼容,需要支持制卡协议 v1 的 uni-editor/plugin");
10
+ return o;
11
+ }
12
+ function le(e) {
13
+ const t = [], o = (n) => {
14
+ if (n.type === "choiceGroup") {
15
+ typeof n.attrs?.id == "string" && t.push({
16
+ id: n.attrs.id,
17
+ label: n.attrs.label || String(t.length + 1),
18
+ options: (n.content || []).map((r, i) => ({ id: r.attrs?.id, label: String.fromCharCode(65 + i) })).filter((r) => typeof r.id == "string")
19
+ });
20
+ return;
21
+ }
22
+ n.content?.forEach(o);
23
+ };
24
+ return o(e.content), t;
25
+ }
26
+ class ee extends Error {
27
+ constructor(t, o) {
28
+ super(o), this.path = t;
29
+ }
30
+ }
31
+ const M = (e, t) => {
32
+ throw new ee(e, t);
33
+ }, z = {
34
+ 语文: "CHINESE",
35
+ 数学: "MATHS",
36
+ 英语: "ENGLISH",
37
+ 科学: "SCIENCE",
38
+ 物理: "PHYSICAL",
39
+ 化学: "CHEMICAL",
40
+ 生物: "BIOLOGICAL",
41
+ 地理: "GEOGRAPHIC",
42
+ 历史: "HISTORY",
43
+ 政治: "POLITICAL",
44
+ 思想政治: "POLITICAL",
45
+ 道德与法治: "POLITICAL",
46
+ 信息科技: "IT",
47
+ 信息技术: "IT",
48
+ 日语: "JAPANESE"
49
+ }, Oe = {
50
+ P: ["语文", "数学", "英语", "科学", "道德与法治"],
51
+ J: ["语文", "数学", "英语", "物理", "化学", "生物", "地理", "历史", "道德与法治", "信息科技"],
52
+ S: ["语文", "数学", "英语", "物理", "化学", "生物", "政治", "历史", "地理", "信息技术", "日语"]
53
+ }, Te = ["一年级", "二年级", "三年级", "四年级", "五年级", "六年级", "初一", "初二", "初三", "高一", "高二", "高三"], Ne = Te.map((e, t) => {
54
+ const o = t < 6 ? "P" : t < 9 ? "J" : "S";
55
+ return { label: e, value: `${o}0${t < 6 ? t + 1 : (t - 6) % 3 + 1}`, classify: o };
56
+ }), x = (e, t) => typeof e == "string" && e.trim() ? e.trim() : M(t, "字典编码和名称必须是非空字符串"), k = (e, t) => e && typeof e == "object" && !Array.isArray(e) ? e : M(t, "字典必须是对象"), de = (e) => e.classify || (/^[PJS]/.test(e.value) ? e.value[0] : void 0);
57
+ function ue(e = {}) {
58
+ const t = k(e, "dictionaries"), o = (s, c) => {
59
+ if (!Array.isArray(s)) return M(c, "字典选项必须是数组");
60
+ const l = /* @__PURE__ */ new Set();
61
+ return s.map((E, p) => {
62
+ const C = k(E, `${c}.${p}`), d = x(C.value, `${c}.${p}.value`), g = x(C.label, `${c}.${p}.label`);
63
+ return l.has(d) && M(`${c}.${p}.value`, "字典编码重复"), l.add(d), { ...C, value: d, label: g };
64
+ });
65
+ }, n = o(t.grades === void 0 ? Ne : t.grades, "dictionaries.grades").map((s, c) => (s.classify !== void 0 && !["P", "J", "S"].includes(String(s.classify)) && M(`dictionaries.grades.${c}.classify`, "学段为 P、J 或 S"), { value: s.value, label: s.label, classify: s.classify })), r = t.gradeCourseMap === void 0 ? void 0 : k(t.gradeCourseMap, "dictionaries.gradeCourseMap"), i = t.courseCodeToSubjectCode === void 0 ? {} : k(t.courseCodeToSubjectCode, "dictionaries.courseCodeToSubjectCode");
66
+ for (const [s, c] of Object.entries(i)) x(c, `dictionaries.courseCodeToSubjectCode.${s}`);
67
+ const f = /* @__PURE__ */ new Map(), a = Object.fromEntries(n.map((s) => {
68
+ const c = de(s), l = (c ? Oe[c] : []).map((C) => ({ value: z[C], label: C, subjectCode: z[C] })), E = `dictionaries.gradeCourseMap.${s.value}`, p = o(r ? r[s.value] ?? [] : l, E).map((C, d) => {
69
+ const g = i[C.value];
70
+ C.subjectCode !== void 0 && g !== void 0 && C.subjectCode !== g && M(`${E}.${d}.subjectCode`, "课程对应的学科编码冲突");
71
+ const S = x(C.subjectCode ?? g ?? (Object.values(z).includes(C.value) ? C.value : void 0), `${E}.${d}.subjectCode`);
72
+ return f.has(C.value) && f.get(C.value) !== S && M(`${E}.${d}.subjectCode`, "同一课程不能对应不同学科"), f.set(C.value, S), C.custom !== void 0 && typeof C.custom != "boolean" && M(`${E}.${d}.custom`, "custom 必须是布尔值"), { value: C.value, label: C.label, subjectCode: S, ...C.custom === void 0 ? {} : { custom: C.custom } };
73
+ });
74
+ return [s.value, p];
75
+ })), u = n.filter((s) => a[s.value].length), y = t.defaultGradeCode === void 0 ? void 0 : x(t.defaultGradeCode, "dictionaries.defaultGradeCode"), I = u.find((s) => s.value === y)?.value || u[0]?.value || "", b = t.defaultCourseCode === void 0 ? void 0 : x(t.defaultCourseCode, "dictionaries.defaultCourseCode"), m = a[I] || [], h = m.find((s) => s.value === b)?.value || m[0]?.value || "";
76
+ return { grades: u, gradeCourseMap: a, defaultGradeCode: I, defaultCourseCode: h };
77
+ }
78
+ function Q(e, t, o) {
79
+ const n = e.grades.find((i) => i.value === t);
80
+ if (!n) return M("initialization.gradeCode", "年级不在可用字典中");
81
+ const r = e.gradeCourseMap[t]?.find((i) => i.value === o);
82
+ return r ? { grade: n.label, subject: r.label, gradeCode: t, courseCode: o, subjectCode: r.subjectCode, phaseCode: de(n) } : M("initialization.courseCode", "当前年级没有此课程");
83
+ }
84
+ function nt(e, t = {}) {
85
+ const n = e.grades.find((f) => f.value === t.gradeCode || !t.gradeCode && f.label === t.grade)?.value || e.defaultGradeCode, r = e.gradeCourseMap[n] || [], i = r.find((f) => f.value === t.courseCode || !t.courseCode && f.label === t.subject)?.value || (n === e.defaultGradeCode ? e.defaultCourseCode : r[0]?.value) || "";
86
+ return n && i ? Q(e, n, i) : { grade: "", subject: "", gradeCode: "", courseCode: "" };
87
+ }
88
+ function fe(e) {
89
+ return e?.subjectCode || z[e?.subject || ""];
90
+ }
91
+ const R = { questions: 200, options: 12, score: 15 }, ot = (e) => e.multiple ? e.indefinite ? "indefinite" : "multiple" : "single", D = (e) => Number.isFinite(e) && Number.isInteger(e * 2), Z = (e) => !!(fe(e) === "MATHS" && (e?.phaseCode ? e.phaseCode === "S" : e?.gradeCode ? e.gradeCode.startsWith("S") : /^高[一二三]/.test(e?.grade || "")));
92
+ function $e(e) {
93
+ const t = typeof e.score == "number" && D(e.score) && e.score >= 0.5 && e.score <= R.score ? e.score : null, o = [...new Set(e.correctIds)].filter((n) => e.options.some((r) => r.id === n));
94
+ return {
95
+ ...e,
96
+ indefinite: !!(e.multiple && e.indefinite),
97
+ score: t,
98
+ scoreType: e.multiple && e.scoreType === "ITEM_SCORE" ? "ITEM_SCORE" : "LESS_SCORE",
99
+ lessScore: e.multiple && t !== null && D(e.lessScore ?? 0) ? Math.max(0, Math.min(t, e.lessScore ?? 0)) : 0,
100
+ correctIds: e.multiple ? o : o.slice(0, 1)
101
+ };
102
+ }
103
+ function ie(e, t, o) {
104
+ let n = { ...e };
105
+ if (t.kind !== void 0) {
106
+ const r = t.kind !== "single";
107
+ r && !e.multiple && (n.scoreType = Z(o) ? "ITEM_SCORE" : "LESS_SCORE", typeof n.score != "number" && Z(o) && (n.score = 6)), n.multiple = r, n.indefinite = t.kind === "indefinite";
108
+ }
109
+ if (t.optionCount !== void 0) {
110
+ const r = Math.max(2, Math.min(R.options, Math.round(t.optionCount)));
111
+ n.options = Array.from({ length: r }, (i, f) => e.options[f] || { id: crypto.randomUUID(), label: String.fromCharCode(65 + f) });
112
+ }
113
+ return t.score !== void 0 && (n.score = t.score), t.scoreType !== void 0 && (n.scoreType = t.scoreType), t.lessScore !== void 0 && (n.lessScore = t.lessScore), $e(n);
114
+ }
115
+ function pe(e) {
116
+ return typeof e.score == "number" && (!D(e.score) || e.score < 0.5 || e.score > R.score) ? "每题分值须为 0.5–15 分,按 0.5 分递增" : e.multiple && e.scoreType === "LESS_SCORE" && typeof e.score == "number" && (!D(e.lessScore ?? 0) || (e.lessScore ?? 0) < 0 || (e.lessScore ?? 0) > e.score) ? "少选得分须为 0.5 的倍数,且不能超过本题分值" : e.multiple && e.scoreType === "ITEM_SCORE" && typeof e.score == "number" && e.correctIds.length && !D(e.score / e.correctIds.length) ? "答案个数与分值不匹配,每个正确选项的得分须为 0.5 的倍数" : null;
117
+ }
118
+ function rt(e) {
119
+ return e.multiple && e.scoreType === "ITEM_SCORE" && typeof e.score == "number" && e.correctIds.length && !pe(e) ? e.score / e.correctIds.length : null;
120
+ }
121
+ function it(e) {
122
+ const t = e.map((r) => Number(r.label)).filter((r) => Number.isSafeInteger(r) && r > 0 && r < 1e5);
123
+ let o = String(Math.max(0, ...t) + 1);
124
+ const n = new Set(e.map((r) => r.label));
125
+ for (; n.has(o); ) o = String(Number(o) + 1);
126
+ return o;
127
+ }
128
+ function st(e, t) {
129
+ const o = new Map(e.options.map((n) => [n.id, crypto.randomUUID()]));
130
+ return {
131
+ ...e,
132
+ id: crypto.randomUUID(),
133
+ label: t,
134
+ breakBefore: !1,
135
+ contentTarget: null,
136
+ options: e.options.map((n) => ({ ...n, id: o.get(n.id) })),
137
+ correctIds: e.correctIds.map((n) => o.get(n)).filter(Boolean)
138
+ };
139
+ }
140
+ function we(e, t, o) {
141
+ return o.trim() ? e.some((n) => n.id !== t && n.label.trim() === o.trim()) ? "题组内题号不能重复" : null : "题号不能为空";
142
+ }
143
+ function ct(e, t, o, n) {
144
+ const r = e.questions.filter((u) => t.includes(u.id));
145
+ if (!r.length) return { error: "请选择要修改的题目" };
146
+ let i;
147
+ if (o.type === "settings") {
148
+ if (!Object.keys(o.patch).length) return { error: "请设置需要修改的属性" };
149
+ const { optionCount: u, score: y, lessScore: I } = o.patch;
150
+ if (u !== void 0 && (!Number.isInteger(u) || u < 2 || u > R.options)) return { error: "选项个数须为 2–12 的整数" };
151
+ if (typeof y == "number" && (!D(y) || y < 0.5 || y > R.score)) return { error: "每题分值须为 0.5–15 分,按 0.5 分递增" };
152
+ if (I !== void 0 && (!D(I) || I < 0)) return { error: "少选得分须为非负的 0.5 倍数" };
153
+ if (i = r.map((b) => ie(b, o.patch, n)), I !== void 0 && i.some((b) => b.multiple && b.scoreType !== "ITEM_SCORE" && I > (b.score ?? 0))) return { error: "少选得分不能超过所选题目的分值" };
154
+ } else if (o.type === "numbering") {
155
+ if (!Number.isInteger(o.start) || o.start < 1 || o.start + r.length - 1 > 1e3) return { error: "连续题号须在 1–1000 内" };
156
+ i = r.map((u, y) => ({ ...u, label: String(o.start + y) }));
157
+ } else if (o.type === "average") {
158
+ const u = o.total / r.length;
159
+ if (!D(u) || u < 0.5 || u > R.score) return { error: "总分无法平均分配,每题须为 0.5–15 分且为 0.5 的倍数" };
160
+ i = r.map((y) => ie(y, { score: u }));
161
+ } else {
162
+ const u = o.text.toUpperCase().trim().split(/[\s,,;;]+/).filter(Boolean);
163
+ if (u.length !== r.length) return { error: `需要 ${r.length} 组答案,当前为 ${u.length} 组` };
164
+ i = [];
165
+ for (let y = 0; y < r.length; y++) {
166
+ const I = r[y], b = u[y];
167
+ if (b !== "-" && (!/^[A-T]+$/.test(b) || new Set(b).size !== b.length || [...b].some((h) => !I.options.some((s) => s.label === h)))) return { error: `第 ${I.label} 题包含无效或重复选项` };
168
+ const m = b === "-" ? [] : [...b].map((h) => I.options.find((s) => s.label === h).id);
169
+ if (!I.multiple && m.length > 1) return { error: `第 ${I.label} 题为单选,只能设置一个答案` };
170
+ i.push({ ...I, correctIds: m });
171
+ }
172
+ }
173
+ const f = new Map(i.map((u) => [u.id, u])), a = e.questions.map((u) => f.get(u.id) || u);
174
+ for (const u of i) {
175
+ const y = we(a, u.id, u.label) || pe(u);
176
+ if (y) return { error: `第 ${u.label} 题:${y}` };
177
+ }
178
+ return { value: { ...e, questions: a } };
179
+ }
180
+ const Ae = { layout: "natural", columns: 2, indent: !1, rowGap: 0, columnGap: 32, marker: "letter" }, se = (e) => `question:${e}`, Me = (e) => e.presentation === "stem" ? "stem" : ["option", "distributed"].includes(e.presentation) ? "option" : "concentrated";
181
+ function at(e, t, o) {
182
+ const n = le(t), r = /* @__PURE__ */ new Map(), i = (a, u) => {
183
+ const y = a.attrs?.contentId || u;
184
+ a.type === "choiceGroup" && y && r.set(a.attrs.id, y), a.content?.forEach((I) => i(I, y));
185
+ };
186
+ i(t.content);
187
+ const f = new Set(e.questions.map((a) => a.contentTarget?.groupId));
188
+ return { ...e, presentation: o, questions: e.questions.map((a, u) => {
189
+ const y = n.find((I) => r.get(I.id) === a.id) || (r.size ? void 0 : n[u]);
190
+ return o === "concentrated" || a.contentTarget !== void 0 || !y || f.has(y.id) ? a : (f.add(y.id), { ...a, contentTarget: { groupId: y.id, optionIds: y.options.map((I) => I.id) } });
191
+ }) };
192
+ }
193
+ function Le(e, t, o) {
194
+ const n = Me(e), r = new Map(le(t).map((m) => [m.id, m])), i = /* @__PURE__ */ new Set(), f = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), u = (m, h) => {
195
+ const s = m.attrs?.contentId || h;
196
+ m.type === "choiceGroup" && s && (f.set(s, [...f.get(s) || [], m.attrs.id]), a.set(m.attrs.id, s)), m.type === "choiceStemAnchor" && typeof m.attrs?.groupId == "string" && i.add(m.attrs.groupId), m.content?.forEach((c) => u(c, s));
197
+ };
198
+ u(t.content);
199
+ const y = [], I = /* @__PURE__ */ new Set(), b = e.questions.filter((m) => {
200
+ if (!o || n === "concentrated") return !0;
201
+ if (n === "stem" && i.has(se(m.id)))
202
+ return y.push({ groupId: se(m.id), questionId: m.id, options: m.options.map((p) => ({ ...p, contentOptionId: p.id })) }), !1;
203
+ const h = f.get(m.id), s = h?.length === 1 ? r.get(h[0]) : void 0, c = s ? { groupId: s.id, optionIds: s.options.map((p) => p.id) } : m.contentTarget, l = c && r.get(c.groupId);
204
+ if (!c || !l || I.has(l.id) || n === "stem" && !i.has(l.id) || a.has(l.id) && a.get(l.id) !== m.id) return !0;
205
+ const E = c.optionIds.slice(0, m.options.length);
206
+ return E.length !== m.options.length || new Set(E).size !== E.length || E.some((p) => !l.options.some((C) => C.id === p)) ? !0 : (I.add(l.id), y.push({ groupId: l.id, questionId: m.id, options: m.options.map((p, C) => ({ ...p, contentOptionId: E[C] })) }), !1);
207
+ });
208
+ return { position: n === "concentrated" ? void 0 : n, bindings: y, concentrated: { ...e, questions: b } };
209
+ }
210
+ function V(e, t = 4) {
211
+ return {
212
+ id: crypto.randomUUID(),
213
+ label: String(e + 1),
214
+ multiple: !1,
215
+ indefinite: !1,
216
+ score: null,
217
+ scoreType: "LESS_SCORE",
218
+ lessScore: 0,
219
+ correctIds: [],
220
+ breakBefore: !1,
221
+ options: Array.from({ length: t }, (o, n) => ({ id: crypto.randomUUID(), label: String.fromCharCode(65 + n) }))
222
+ };
223
+ }
224
+ function De(e = 8) {
225
+ return {
226
+ source: "manual",
227
+ presentation: "concentrated",
228
+ direction: "row",
229
+ rowsPerColumn: 5,
230
+ marker: "box",
231
+ rowGap: 0,
232
+ columnGap: 0,
233
+ questions: Array.from({ length: e }, (t, o) => V(o))
234
+ };
235
+ }
236
+ function lt(e) {
237
+ return new Set(e.questions.map((t) => t.options.length)).size > 1 ? "column" : e.direction;
238
+ }
239
+ function He(e) {
240
+ const t = [];
241
+ for (const o of e.questions) {
242
+ const n = t.at(-1);
243
+ (!n || n.length >= e.rowsPerColumn || o.breakBefore || n[0].options.length !== o.options.length) && t.push([]), t[t.length - 1].push(o);
244
+ }
245
+ return t;
246
+ }
247
+ function dt(e) {
248
+ const t = [];
249
+ for (const o of He(e))
250
+ (!t.length || o[0].breakBefore) && t.push([]), t[t.length - 1].push(o);
251
+ return t;
252
+ }
253
+ const xe = {
254
+ judge: "判断题",
255
+ fill: "填空题",
256
+ answer: "解答题",
257
+ calculation: "计算/证明",
258
+ matching: "信息匹配/连线",
259
+ ordering: "排序/分类",
260
+ correction: "改错题",
261
+ drawing: "作图题",
262
+ table: "表格填答",
263
+ writing: "语文作文",
264
+ english: "外语写作",
265
+ reading: "阅读理解",
266
+ cloze: "完形填空",
267
+ completion: "语法填空",
268
+ chunk: "断句题",
269
+ composite: "材料/复合题",
270
+ optional: "选做题组",
271
+ practice: "实践评价"
272
+ }, ut = { choice: "选择", judge: "判断", fill: "填空", answer: "简答", calculation: "计算/证明", correction: "改错", drawing: "作图", table: "表格", writing: "作文", english: "外语写作" }, ft = ["reading", "cloze", "completion", "composite", "optional"], L = () => ({ version: 1, content: { type: "doc", content: [{ type: "paragraph" }] } }), pt = { symbols: ["√", "×"], letters: ["T", "F"], words: ["正确", "错误"] }, Re = (e) => ["writing", "english"].includes(e) ? 70 : ["answer", "calculation", "drawing", "table", "correction"].includes(e) ? 60 : 15, ht = (e) => e === "judge" ? 200 : e === "fill" ? 50 : ["reading", "cloze", "completion"].includes(e) ? 20 : e === "matching" ? 9 : 100;
273
+ function _e(e = 0) {
274
+ return { id: crypto.randomUUID(), label: String(e + 1), width: 50, style: "line", characters: 6, score: null, answers: [], prefix: "", suffix: "", breakAfter: !1 };
275
+ }
276
+ function Pe(e, t = "1") {
277
+ const o = crypto.randomUUID();
278
+ return {
279
+ id: o,
280
+ label: t,
281
+ kind: e,
282
+ document: L(),
283
+ reference: L(),
284
+ explanation: L(),
285
+ score: null,
286
+ choice: { ...V(0, e === "judge" ? 2 : 4), id: o, label: t },
287
+ presentation: "concentrated",
288
+ blanks: [_e()],
289
+ steps: [],
290
+ needsReason: !1,
291
+ judgment: null,
292
+ targets: [],
293
+ area: { style: e === "writing" ? "characters" : e === "english" ? "lines" : e === "drawing" ? "grid" : "blank", rows: e === "writing" ? 20 : 6, columns: 20, rowHeight: e === "writing" ? 40 : 28, wordMark: 100, title: !1, backgroundUrl: "" }
294
+ };
295
+ }
296
+ function je(e) {
297
+ return ["reading", "cloze", "chunk"].includes(e) ? "choice" : ["matching", "completion"].includes(e) ? "fill" : ["ordering", "composite", "optional", "practice"].includes(e) ? "answer" : e;
298
+ }
299
+ function mt(e) {
300
+ return {
301
+ items: [Pe(je(e))],
302
+ judgeLabels: "symbols",
303
+ fillNewLine: !0,
304
+ pool: [],
305
+ relation: "one",
306
+ reuseOptions: !0,
307
+ matchingDisplay: "letters",
308
+ ordering: "sequence",
309
+ sequence: [],
310
+ categories: [],
311
+ assignments: {},
312
+ chooseCount: 1,
313
+ groupScore: null,
314
+ chunkText: "",
315
+ chunkPoints: [],
316
+ chunkCorrect: [],
317
+ chunkMax: 3,
318
+ chunkScore: null,
319
+ attachmentUrl: ""
320
+ };
321
+ }
322
+ function gt(e) {
323
+ return String(Math.max(0, ...e.map((t) => /^\d+$/.test(t.label) ? Number(t.label) : 0)) + 1);
324
+ }
325
+ function he(e) {
326
+ const t = structuredClone(e), o = /* @__PURE__ */ new Map(), n = (i) => {
327
+ !i || typeof i != "object" || Object.entries(i).forEach(([f, a]) => {
328
+ ["id", "answerId"].includes(f) && typeof a == "string" ? o.set(a, crypto.randomUUID()) : n(a);
329
+ });
330
+ };
331
+ n(t);
332
+ const r = (i) => typeof i == "string" ? o.get(i) || i : Array.isArray(i) ? i.map(r) : i && typeof i == "object" ? Object.fromEntries(Object.entries(i).map(([f, a]) => [o.get(f) || f, r(a)])) : i;
333
+ return r(t);
334
+ }
335
+ function It(e, t) {
336
+ const o = he(e);
337
+ return { ...o, label: t, choice: { ...o.choice, label: t } };
338
+ }
339
+ function Ct(e, t, o) {
340
+ const n = e.findIndex((f) => f.id === t), r = n + o;
341
+ if (n < 0 || r < 0 || r >= e.length) return e;
342
+ const i = [...e];
343
+ return i.splice(r, 0, ...i.splice(n, 1)), i;
344
+ }
345
+ function yt(e, t) {
346
+ return { ...e, pool: e.pool.filter((o) => o.id !== t), sequence: e.sequence.filter((o) => o !== t), assignments: Object.fromEntries(Object.entries(e.assignments).filter(([o]) => o !== t)), items: e.items.map((o) => ({ ...o, targets: o.targets.filter((n) => n !== t) })) };
347
+ }
348
+ function Et(e, t, o) {
349
+ const n = [...new Set(o)].filter((i) => e.pool.some((f) => f.id === i)), r = e.relation === "one" ? n.slice(-1) : n;
350
+ return { ...e, items: e.items.map((i) => i.id === t ? { ...i, targets: r } : e.reuseOptions ? i : { ...i, targets: i.targets.filter((f) => !r.includes(f)) }) };
351
+ }
352
+ function bt(e, t) {
353
+ let o = 0;
354
+ for (; o < t.length && o < e.chunkText.length && t[o] === e.chunkText[o]; ) o++;
355
+ let n = 0;
356
+ for (; n < t.length - o && n < e.chunkText.length - o && t[t.length - 1 - n] === e.chunkText[e.chunkText.length - 1 - n]; ) n++;
357
+ const r = e.chunkText.length - n, i = /* @__PURE__ */ new Set(), f = e.chunkPoints.filter((a) => a.offset <= o || a.offset >= r).map((a) => ({ ...a, offset: a.offset <= o ? a.offset : a.offset + t.length - e.chunkText.length })).filter((a) => a.offset <= 0 || a.offset >= t.length || i.has(a.offset) ? !1 : (i.add(a.offset), !0));
358
+ return { ...e, chunkText: t, chunkPoints: f, chunkCorrect: e.chunkCorrect.filter((a) => f.some((u) => u.id === a)) };
359
+ }
360
+ function St(e, t) {
361
+ const o = [], n = e.items.map((r) => r.label.trim());
362
+ (n.some((r) => !r) || new Set(n).size !== n.length) && o.push("题号不能为空或重复");
363
+ for (const r of e.items) {
364
+ r.score !== null && (!Number.isFinite(r.score) || r.score < 0.5 || r.score > Re(r.kind) || !Number.isInteger(r.score * 2)) && o.push(`${r.label} 题分值超出范围或不是 0.5 的倍数`);
365
+ const f = (r.kind === "fill" ? r.blanks : r.steps).map((a) => a.score);
366
+ f.length && r.score !== null && f.every((a) => a !== null) && f.reduce((a, u) => a + (u || 0), 0) !== r.score && o.push(`${r.label} 题分项分值之和与题分不一致`);
367
+ }
368
+ if (["matching", "ordering"].includes(t)) {
369
+ const r = e.pool.map((i) => i.label.trim());
370
+ (r.some((i) => !i) || new Set(r).size !== r.length) && o.push("共享选项编号不能为空或重复");
371
+ }
372
+ return t === "optional" && e.chooseCount > e.items.length && o.push("选做数量不能超过题目数量"), t === "chunk" && e.chunkCorrect.length > e.chunkMax && o.push("正确断点数不能超过最多选择数"), o;
373
+ }
374
+ function Ot(e = 3, t = 3) {
375
+ return { version: 1, content: { type: "doc", content: [{ type: "table", content: Array.from({ length: e }, () => ({ type: "tableRow", content: Array.from({ length: t }, () => ({ type: "tableCell", content: [{ type: "paragraph" }] })) })) }] } };
376
+ }
377
+ function P(e) {
378
+ const t = (o) => !!(o.text || o.type && !["doc", "paragraph", "choiceStemAnchor"].includes(o.type) || o.content?.some(t));
379
+ return !t(e.content);
380
+ }
381
+ const Tt = { choice: "选择题", ...xe };
382
+ function Ge() {
383
+ return { version: 1, title: "", questionCard: !1, preset: "a3-two", margin: 15, gap: 10, blocks: [] };
384
+ }
385
+ function ke(e = "") {
386
+ return {
387
+ // 22px title + the configured 9mm line spacing + 10px bottom inset.
388
+ id: crypto.randomUUID(),
389
+ height: 70,
390
+ document: { version: 1, content: { type: "doc", content: [{
391
+ type: "paragraph",
392
+ attrs: { textAlign: "center", lineSpacing: 9 },
393
+ ...e ? { content: [{ type: "text", text: e, marks: [{ type: "textStyle", attrs: { fontFamily: "SimSun, 宋体, serif", fontSize: "22px" } }] }] } : {}
394
+ }] } }
395
+ };
396
+ }
397
+ function Ue(e) {
398
+ return {
399
+ ...Ge(),
400
+ title: e.name,
401
+ creation: e,
402
+ paperTitle: ke(e.name),
403
+ header: { focusText: !0, writeKaohao: !1, missExam: !1, mifeng: !1, kaohao: "school", weishu: 8 }
404
+ };
405
+ }
406
+ function _(e, t = 96) {
407
+ return e * t / 25.4;
408
+ }
409
+ const ze = {
410
+ a4: { label: "A4 单栏", width: 210, height: 297, columns: 1 },
411
+ "a3-two": { label: "A3 双栏", width: 420, height: 297, columns: 2 },
412
+ "a3-three": { label: "A3 三栏", width: 420, height: 297, columns: 3 }
413
+ }, U = 44, B = 16;
414
+ function te(e, t) {
415
+ const o = ze[e.preset], n = _(o.width), r = _(o.height), i = _(e.margin), f = _(e.gap), a = e.header?.mifeng ? _(e.header.kaohao === "code" ? 26 : 14) : 0, u = n - i * 2 - a, y = (u - f * (o.columns - 1)) / o.columns, I = r - i * 2, b = I - B, m = e.header ? y : u, h = t && t.id === e.paperTitle?.id && Math.abs(t.width - m) < 1 ? t : void 0, s = e.paperTitle ? Math.min(I, h?.height ?? e.paperTitle.height + (e.header ? 260 : B)) : 0, c = (C, d = 0) => !!e.paperTitle && (e.header ? C % 2 === 0 && d === 0 : C === 0), l = (C, d = 0) => c(C, d) ? s : 0;
416
+ return { ...o, width: n, height: r, margin: i, gap: f, sealWidth: a, contentWidth: u, contentHeight: I, columnWidth: y, columnX: (C, d) => i + (C % 2 === 0 ? a : 0) + d * (y + f), titleWidth: m, titleMaxHeight: b, hasHeader: c, headerHeight: l, capacity: (C, d = 0) => I - l(C, d) };
417
+ }
418
+ function Nt(e, t, o) {
419
+ const n = te(e, o);
420
+ let r = 0, i = 0, f = 0;
421
+ const a = () => {
422
+ i++, i === n.columns && (i = 0, r++), f = 0;
423
+ }, u = e.blocks.map((I) => {
424
+ const b = t[I.id], m = b && Math.abs(b.width - n.columnWidth) < 1 ? b.height : 100 + I.answerHeight, h = b && Math.abs(b.width - n.columnWidth) < 1 ? [...new Set([...b.breaks || [], m].filter((d) => Number.isFinite(d) && d > 0 && d <= m))].sort((d, g) => d - g) : [], s = I.reference?.type === "CCOMPOSITION", c = (d) => s && d > 0 ? Math.max(0, 6 - Math.max(0, (b?.compositionStart || 0) - d)) : 0;
425
+ if (h.length > 1 && h.every((d, g) => {
426
+ const S = h[g - 1] || 0;
427
+ return d - S + c(S) <= n.capacity(1) + 0.5;
428
+ })) {
429
+ const d = [];
430
+ let g = 0;
431
+ for (; g < m - 0.5; ) {
432
+ const O = n.capacity(r, i) - f, N = g, T = c(g), $ = h.filter((H) => H > N + 0.5 && H <= N + O - T + 0.5).at(-1);
433
+ if ($ === void 0) {
434
+ a();
435
+ continue;
436
+ }
437
+ const A = s && $ < m - 0.5 ? Math.max(0, O - T - ($ - g)) : 0;
438
+ d.push({ page: r, column: i, x: n.columnX(r, i), y: r * (n.height + U) + n.margin + n.headerHeight(r, i) + f, from: g, to: $, ...T ? { topPadding: T } : {}, ...A ? { bottomPadding: A } : {} }), f += $ - g + T, g = $, g < m - 0.5 && a();
439
+ }
440
+ f += B;
441
+ const S = d[0];
442
+ return { id: I.id, ...S, height: m, available: n.capacity(S.page, S.column), overflowing: !1, fragments: d };
443
+ }
444
+ for (; f + m > n.capacity(r, i) + 0.5 && (f > 0 || n.headerHeight(r, i) > 0); ) a();
445
+ const E = n.capacity(r, i), p = m > E + 0.5, C = {
446
+ id: I.id,
447
+ page: r,
448
+ column: i,
449
+ x: n.columnX(r, i),
450
+ y: r * (n.height + U) + n.margin + n.headerHeight(r, i) + f,
451
+ height: m,
452
+ available: E,
453
+ overflowing: p,
454
+ fragments: [{ page: r, column: i, x: n.columnX(r, i), y: r * (n.height + U) + n.margin + n.headerHeight(r, i) + f, from: 0, to: Math.min(m, E) }]
455
+ };
456
+ return f += Math.min(m, E) + B, C;
457
+ }), y = /* @__PURE__ */ new Map();
458
+ return u.forEach((I, b) => I.fragments.forEach((m) => {
459
+ const h = `${m.page}/${m.column}`, s = y.get(h) || [];
460
+ s.push({ fragment: m, placement: I, blockIndex: b }), y.set(h, s);
461
+ })), y.forEach((I) => {
462
+ const b = I.filter((c) => ["answer", "writing", "english", "composite"].includes(e.blocks[c.blockIndex].kind)).at(-1);
463
+ if (!b || e.blocks[b.blockIndex].reference?.type !== "CCOMPOSITION") return;
464
+ const m = I.at(-1).fragment, s = m.page * (n.height + U) + n.height - n.margin - m.y - (m.to - m.from) - (m.topPadding || 0) - (m.bottomPadding || 0);
465
+ s <= 0 || s > 30 || (b.fragment.bottomPadding = (b.fragment.bottomPadding || 0) + s, I.slice(I.indexOf(b) + 1).forEach(({ fragment: c, placement: l }) => {
466
+ c.y += s, l.fragments[0] === c && (l.y = c.y);
467
+ }));
468
+ }), { geometry: n, placements: u, pageCount: r + 1 };
469
+ }
470
+ function Y(e, t) {
471
+ return { version: 1, content: { type: "doc", content: [{ type: "paragraph", content: [
472
+ { type: "text", text: `${e}.`, marks: [{ type: "documentLabel", attrs: { kind: "number" } }] },
473
+ ...t === null ? [] : [{ type: "text", text: `(${t}分)`, marks: [{ type: "documentLabel", attrs: { kind: "score" } }] }]
474
+ ] }] } };
475
+ }
476
+ function W(e, t, o) {
477
+ const n = (r) => {
478
+ if (!r.content) return r;
479
+ let i;
480
+ const f = r.content.flatMap((a) => {
481
+ const u = a.type === "text" && a.marks?.find((b) => b.type === "documentLabel")?.attrs?.kind, y = u && u === i;
482
+ if (i = u, y) return [];
483
+ if (!u) return [n(a)];
484
+ const I = u === "number" ? `${t}.` : o === null ? "" : `(${o}分)`;
485
+ return I ? [{ ...a, text: I }] : [];
486
+ });
487
+ return { ...r, content: f };
488
+ };
489
+ return { ...e, content: n(e.content) };
490
+ }
491
+ const ne = {
492
+ SCHOICE: "单选题",
493
+ MCHOICE: "多选题",
494
+ JUDGE: "判断题",
495
+ FILLBLANK: "填空题",
496
+ SHORTANSWER: "解答题",
497
+ MIXED: "复合题",
498
+ CLOZE: "完形填空",
499
+ READTHENANSWER: "阅读理解",
500
+ INFO_MATCHING: "信息匹配",
501
+ TEXT_COMPLETION: "语法填空",
502
+ ECOMPOSITION: "英语作文",
503
+ CCOMPOSITION: "语文作文",
504
+ CHUNK_CHOICE: "断句题"
505
+ }, ce = ["SCHOICE", "MCHOICE", "JUDGE", "FILLBLANK", "SHORTANSWER", "MIXED"];
506
+ function $t(e, t = !1) {
507
+ const o = fe(e), n = t ? ce.filter((r) => r !== "MIXED") : ce;
508
+ return t ? ["CHINESE", "JAPANESE"].includes(o || "") ? [...n, "CHUNK_CHOICE"] : n : o === "CHINESE" ? [...n, "CCOMPOSITION", "CHUNK_CHOICE"] : o === "ENGLISH" ? [...n, "CLOZE", "READTHENANSWER", "INFO_MATCHING", "TEXT_COMPLETION", "ECOMPOSITION"] : o === "JAPANESE" ? Object.keys(ne) : ["POLITICAL", "HISTORY"].includes(o || "") ? [...n, "CCOMPOSITION"] : n;
509
+ }
510
+ const Fe = (e) => ["CLOZE", "READTHENANSWER", "INFO_MATCHING", "TEXT_COMPLETION"].includes(e), Be = (e) => ["SCHOICE", "MCHOICE", "CLOZE", "READTHENANSWER", "INFO_MATCHING", "JUDGE"].includes(e), G = (e) => ({ version: 1, content: { type: "doc", content: e.length ? e : [{ type: "paragraph" }] } });
511
+ function me(e, t, o = !1) {
512
+ return {
513
+ content: L(),
514
+ numbered: !o,
515
+ groupId: `options:${t.id}`,
516
+ layout: { ...Ae, columns: e === "CLOZE" ? 4 : 2, ...e === "READTHENANSWER" ? { layout: "fixed", columnGap: 0 } : {} },
517
+ itemsContent: !o && Be(e) ? t.options.map((n) => ({ id: n.id, key: n.label, content: L() })) : []
518
+ };
519
+ }
520
+ const K = (e) => {
521
+ if (e.type === "choiceStemAnchor" || e.type === "text" && e.marks?.some((n) => n.type === "documentLabel" && n.attrs?.kind === "number")) return null;
522
+ const { contentId: t, ...o } = e.attrs || {};
523
+ return { ...e, ...e.attrs ? { attrs: o } : {}, ...e.content ? { content: e.content.map(K).filter((n) => n !== null) } : {} };
524
+ };
525
+ function ae(e, t, o) {
526
+ const r = (e.content.content.content || [{ type: "paragraph" }]).map((i) => ({ ...i, attrs: { ...i.attrs, contentId: t } }));
527
+ if (e.numbered) {
528
+ const i = { type: "text", text: `${o}.`, marks: [{ type: "documentLabel", attrs: { kind: "number" } }] };
529
+ ["paragraph", "heading"].includes(r[0]?.type || "") || r.unshift({ type: "paragraph", attrs: { contentId: t }, content: [] }), r[0] = { ...r[0], content: [i, ...r[0].content || []] };
530
+ }
531
+ return e.itemsContent.length && r.push({ type: "choiceGroup", attrs: { id: e.groupId, contentId: t, ...e.layout }, content: e.itemsContent.map((i) => ({
532
+ type: "choiceOption",
533
+ attrs: { id: i.id, label: i.key, sourceKey: i.key, marker: "letter" },
534
+ content: i.content.content.content || [{ type: "paragraph" }]
535
+ })) }), r;
536
+ }
537
+ function We(e, t) {
538
+ const o = t.filter((a) => a.type === "choiceGroup"), n = o.find((a) => a.attrs?.id === e.groupId) || (o.length === 1 ? o[0] : void 0), r = t.filter((a) => a !== n);
539
+ let i = !1;
540
+ const f = (a) => {
541
+ a.marks?.some((u) => u.type === "documentLabel" && u.attrs?.kind === "number") && (i = !0), a.content?.forEach(f);
542
+ };
543
+ return r.forEach(f), {
544
+ ...e,
545
+ numbered: i,
546
+ content: G(r.map(K).filter((a) => a !== null)),
547
+ groupId: n?.attrs?.id || e.groupId,
548
+ layout: n ? Object.fromEntries(Object.entries(e.layout).map(([a, u]) => [a, n.attrs?.[a] ?? u])) : e.layout,
549
+ itemsContent: (n?.content || []).map((a, u) => ({ id: a.attrs?.id || e.itemsContent[u]?.id || crypto.randomUUID(), key: a.attrs?.label || String.fromCharCode(65 + u), content: G((a.content || []).map(K).filter((y) => y !== null)) }))
550
+ };
551
+ }
552
+ function Ke(e, t, o, n) {
553
+ const r = /* @__PURE__ */ new Map();
554
+ t.content.content?.forEach((a) => {
555
+ a.attrs?.contentId && r.set(a.attrs.contentId, [...r.get(a.attrs.contentId) || [], a]);
556
+ });
557
+ const i = new Set(n?.content.content?.map((a) => a.attrs?.contentId).filter(Boolean)), f = (a, u) => u && (r.has(a) || i.has(a)) ? We(u, r.get(a) || []) : u;
558
+ return {
559
+ ...e,
560
+ ...r.has(o) ? { material: G(r.get(o).map((a) => K(a))) } : {},
561
+ questions: e.questions.map((a) => ({ ...a, text: f(a.id, a.text), parts: a.parts.map((u) => ({ ...u, text: f(u.id, u.text) })) }))
562
+ };
563
+ }
564
+ function Ve(e) {
565
+ const t = e.reference, o = [];
566
+ t.type === "MIXED" && o.push(...(t.material || L()).content.content.map((r) => ({ ...r, attrs: { ...r.attrs, contentId: e.id } }))), t.questions.forEach((r) => {
567
+ r.text && o.push(...ae(r.text, r.id, r.label)), Fe(r.type) && r.parts.forEach((i) => {
568
+ i.text && o.push(...ae(i.text, i.id, i.label));
569
+ });
570
+ });
571
+ const n = (e.document.content.content || []).filter((r) => !r.attrs?.contentId);
572
+ return P(G(n)) || o.push(...n), G(o);
573
+ }
574
+ function Xe(e, t) {
575
+ const o = (n, r, i) => !n || !i || r.options.map((f) => f.id).join() === i.options.map((f) => f.id).join() ? n : { ...n, itemsContent: r.options.map((f) => ({ ...n.itemsContent.find((a) => a.id === f.id), id: f.id, key: f.label, content: n.itemsContent.find((a) => a.id === f.id)?.content || L() })) };
576
+ return { ...e, questions: e.questions.map((n) => {
577
+ const r = t.questions.find((i) => i.id === n.id);
578
+ return { ...n, text: o(n.text, n.choice, r?.choice), parts: n.parts.map((i) => ({ ...i, text: o(i.text, i.choice, r?.parts.find((f) => f.id === i.id)?.choice) })) };
579
+ }) };
580
+ }
581
+ function wt(e, t, o) {
582
+ if (e.reference?.textVersion !== 1) return e;
583
+ let n = e.reference;
584
+ if (!t && !P(e.document) && !e.document.content.content?.some((i) => i.attrs?.contentId)) return { ...e, reference: { ...n, textVersion: void 0 } };
585
+ if (t?.reference === n && t.document === e.document && !P(e.document)) return e;
586
+ if (e.document !== t?.document && (!P(e.document) || t) && (n = Ke(n, e.document, e.id, t?.document), t && e.reference === t.reference))
587
+ return { ...e, reference: n };
588
+ t?.reference && e.reference !== t.reference && (n = Xe(n, t.reference));
589
+ const r = { ...e, reference: n };
590
+ return o || !P(e.document) ? { ...r, document: Ve(r) } : r;
591
+ }
592
+ const X = {
593
+ SCHOICE: { count: 200, options: [2, 12], parts: 1, score: 15 },
594
+ MCHOICE: { count: 200, options: [2, 12], parts: 1, score: 15 },
595
+ JUDGE: { count: 200, options: [2, 2], parts: 1, score: 15 },
596
+ CHUNK_CHOICE: { count: 100, options: [2, 26], parts: 1, score: 10 },
597
+ FILLBLANK: { count: 50, options: [0, 0], parts: 20, score: 15 },
598
+ SHORTANSWER: { count: 100, options: [0, 0], parts: 10, score: 60 },
599
+ CLOZE: { count: 20, options: [4, 4], parts: 20, score: 15 },
600
+ READTHENANSWER: { count: 20, options: [2, 12], parts: 20, score: 15 },
601
+ INFO_MATCHING: { count: 20, options: [1, 9], parts: 9, score: 15 },
602
+ TEXT_COMPLETION: { count: 20, options: [0, 0], parts: 20, score: 15 },
603
+ CCOMPOSITION: { count: 1, options: [0, 0], parts: 1, score: 70 },
604
+ ECOMPOSITION: { count: 1, options: [0, 0], parts: 1, score: 70 }
605
+ }, j = (e) => ["SCHOICE", "MCHOICE", "JUDGE", "CHUNK_CHOICE", "CLOZE", "READTHENANSWER", "INFO_MATCHING"].includes(e), w = (e) => ["CLOZE", "READTHENANSWER", "INFO_MATCHING", "TEXT_COMPLETION"].includes(e), At = (e) => e === "FILLBLANK" || e === "TEXT_COMPLETION", ge = (e) => e === "CCOMPOSITION" || e === "ECOMPOSITION", ve = { SCHOICE: "choice", MCHOICE: "choice", JUDGE: "judge", FILLBLANK: "fill", SHORTANSWER: "answer", MIXED: "composite", CLOZE: "cloze", READTHENANSWER: "reading", INFO_MATCHING: "matching", TEXT_COMPLETION: "completion", ECOMPOSITION: "english", CCOMPOSITION: "writing", CHUNK_CHOICE: "chunk" };
606
+ function Je(e) {
607
+ return { type: e, textVersion: 1, questions: [], layout: De(0), fillNewLine: !1, optional: !1, choose: 1, optionalHeight: 200, scoreType: "LESS_SCORE" };
608
+ }
609
+ function Mt(e) {
610
+ return { id: crypto.randomUUID(), kind: ve[e], title: ne[e], answerHeight: 0, document: L(), reference: Je(e) };
611
+ }
612
+ function Lt(e, t = 1, o) {
613
+ const n = e === "MCHOICE" && Z(o);
614
+ return {
615
+ type: e,
616
+ start: t,
617
+ end: t,
618
+ optionCount: e === "INFO_MATCHING" ? null : e === "CHUNK_CHOICE" ? 12 : e === "JUDGE" ? 2 : 4,
619
+ partCount: w(e) ? null : 1,
620
+ score: n ? 6 : null,
621
+ scoreType: n ? "ITEM_SCORE" : "LESS_SCORE",
622
+ lessScore: 0,
623
+ characters: 1e3,
624
+ lines: 10,
625
+ rightAnswers: null,
626
+ singleScore: 1
627
+ };
628
+ }
629
+ function Ie(e, t, o) {
630
+ const n = Array.from({ length: o }, (r, i) => ({ ...e.options[i] || { id: crypto.randomUUID() }, label: t === "JUDGE" ? ["T", "F"][i] : String.fromCharCode(65 + i) }));
631
+ return { ...e, options: n, multiple: t === "MCHOICE" || t === "CHUNK_CHOICE", indefinite: !1, correctIds: e.correctIds.filter((r) => n.some((i) => i.id === r)).slice(0, t === "MCHOICE" || t === "CHUNK_CHOICE" ? o : 1) };
632
+ }
633
+ function Qe(e, t, o, n = 4) {
634
+ const r = crypto.randomUUID(), i = { ...Ie(V(0), o, n), id: r, label: e, score: t };
635
+ return {
636
+ id: r,
637
+ label: e,
638
+ score: t,
639
+ width: 25,
640
+ breakAfter: !1,
641
+ height: 100,
642
+ document: o === "SHORTANSWER" ? Y(e, t) : L(),
643
+ choice: i,
644
+ ...w(o) && o !== "TEXT_COMPLETION" ? { text: me(o, i) } : {}
645
+ };
646
+ }
647
+ function Ze(e, t) {
648
+ const o = crypto.randomUUID(), { type: n, score: r } = e, i = String(t), f = e.partCount || 1, a = Array.from({ length: w(n) || ["FILLBLANK", "SHORTANSWER"].includes(n) ? f : 0 }, (y, I) => Qe(w(n) ? String(t + I) : f === 1 ? i : `${i}.${I + 1}`, r, n, e.optionCount || 4)), u = { ...Ie(V(0), n, e.optionCount || 4), id: o, label: i, score: r, scoreType: e.scoreType, lessScore: e.lessScore };
649
+ return {
650
+ id: o,
651
+ type: n,
652
+ label: i,
653
+ score: a.length ? Ce(a) : r,
654
+ choice: u,
655
+ text: me(n, u, w(n)),
656
+ parts: a,
657
+ document: n === "ECOMPOSITION" ? { version: 1, content: { type: "doc", content: [...Y(i, r).content.content, ...Ye(e.lines, e.paperWidth || 600).content.content] } } : n === "CCOMPOSITION" ? Y(i, r) : L(),
658
+ height: n === "ECOMPOSITION" ? 50 * e.lines + 40 : 100,
659
+ contentHeight: 38,
660
+ characters: e.characters,
661
+ lines: e.lines,
662
+ halfPoint: !1,
663
+ rightAnswers: e.rightAnswers,
664
+ singleScore: e.singleScore
665
+ };
666
+ }
667
+ const Ce = (e) => e.some((t) => t.score === null) ? null : e.reduce((t, o) => t + (o.score || 0), 0);
668
+ function oe(e) {
669
+ return e.questions.flatMap((t) => w(t.type) ? t.parts.map((o) => o.label) : [t.label]);
670
+ }
671
+ function Dt(e) {
672
+ return Math.max(0, ...oe(e).map(Number).filter(Number.isFinite)) + 1;
673
+ }
674
+ function Ht(e, t, o = !1) {
675
+ const n = X[t.type], r = ge(t.type) ? 1 : t.end - t.start + 1;
676
+ if (!Number.isInteger(t.start) || t.start < 1 || t.end > 1e3 || !Number.isInteger(r) || r < 1 || r > n.count) return `题号须为 1–1000,单次题数为 1–${n.count}`;
677
+ if (e.type === "CCOMPOSITION" && e.questions.length) return "语文作文每组只能有一道题";
678
+ if (e.optional) return "选做题组不能追加题目";
679
+ const i = oe(e);
680
+ if (Array.from({ length: r }, (f, a) => String(t.start + a)).some((f) => i.includes(f))) return "同一分组内,题号不能重复";
681
+ if (j(t.type) && (t.optionCount === null || !Number.isInteger(t.optionCount) || t.optionCount < n.options[0] || t.optionCount > n.options[1])) return `选项个数须为 ${n.options[0]}–${n.options[1]}`;
682
+ if ((w(t.type) || ["FILLBLANK", "SHORTANSWER"].includes(t.type)) && (!t.partCount || !Number.isInteger(t.partCount) || t.partCount < 1 || t.partCount > n.parts)) return `子题/空数须为 1–${n.parts}`;
683
+ if (w(t.type) && r % t.partCount !== 0) return "题目数量无法按子题数量均分,请重新设置";
684
+ if (t.type === "INFO_MATCHING" && t.partCount > t.optionCount) return "选项个数需大于等于子题数量";
685
+ if (t.type === "SHORTANSWER" && (o || e.optional) && t.partCount !== 1) return "网阅或选做题不支持小题";
686
+ if (t.score !== null && (!Number.isFinite(t.score) || t.score < 0.5 || t.score > n.score || !Number.isInteger(t.score * 2))) return `分值须为 0.5–${n.score} 分,按 0.5 分递增`;
687
+ if (t.type === "MCHOICE" && (t.lessScore < 0 || !Number.isInteger(t.lessScore * 2) || t.lessScore > (t.score || 0))) return "少选得分不能超过本题分值";
688
+ if (t.type === "CHUNK_CHOICE") {
689
+ if (!t.rightAnswers || !Number.isInteger(t.rightAnswers) || t.rightAnswers >= t.optionCount) return "正确答案个数需小于选项个数";
690
+ if (t.singleScore === null || t.singleScore < 0.5 || !Number.isInteger(t.singleScore * 2) || t.score !== null && t.singleScore * t.rightAnswers > t.score) return "每处得分乘以正确答案个数不可大于每题分数";
691
+ }
692
+ return t.type === "CCOMPOSITION" && (!Number.isInteger(t.characters) || t.characters < 1 || t.characters > 1200) ? "作文格数须为 1–1200" : t.type === "ECOMPOSITION" && (!Number.isInteger(t.lines) || t.lines < 1 || t.lines > 100) ? "作文行数须为 1–100" : t.score === null ? "请输入分值" : null;
693
+ }
694
+ function xt(e, t, o) {
695
+ const n = w(t.type) ? t.partCount : 1, r = [];
696
+ for (let a = t.start; a <= (ge(t.type) ? t.start : t.end); a += n) r.push(Ze(t, a));
697
+ const i = [...e.questions], f = i.findIndex((a) => a.id === o || a.parts.some((u) => u.id === o));
698
+ return i.splice(f < 0 ? i.length : f + 1, 0, ...r), { ...e, questions: i };
699
+ }
700
+ function Rt(e) {
701
+ return e.questions.flatMap((t) => [t, ...t.parts]);
702
+ }
703
+ function _t(e) {
704
+ return e.questions.filter((t) => j(t.type)).flatMap((t) => w(t.type) ? t.parts.map((o) => ({ ...o.choice, label: o.label, score: o.score })) : [{ ...t.choice, label: t.label, score: t.score }]);
705
+ }
706
+ function Pt(e, t) {
707
+ const o = he(e);
708
+ return o.referenceData && (o.referenceData = { ...o.referenceData, questionId: o.id }), o.text && (o.text.groupId = `options:${o.id}`), o.label = String(t), o.choice.label = o.label, o.choice.contentTarget = null, o.choice.breakBefore = !1, o.parts.forEach((n, r) => {
709
+ n.label = w(o.type) ? String(t + r) : o.parts.length === 1 ? o.label : `${t}.${r + 1}`, n.choice.label = n.label, n.choice.contentTarget = null, n.choice.breakBefore = !1;
710
+ }), o.parts.forEach((n) => {
711
+ n.text && (n.text.groupId = `options:${n.id}`), n.referenceData && (n.referenceData = { ...n.referenceData, questionId: n.id, questionPid: o.id });
712
+ }), o.document = W(o.document, o.label, o.score), o.parts = o.parts.map((n) => ({ ...n, document: W(n.document, n.label, n.score) })), o;
713
+ }
714
+ function jt(e) {
715
+ return Math.max(1, Math.floor((e - 6) / 31));
716
+ }
717
+ function Ye(e, t) {
718
+ return { version: 1, content: { type: "doc", content: Array.from({ length: e }, () => ({ type: "paragraph", attrs: { fixedLineHeight: 1152 / 25.4 }, content: [{ type: "text", text: " ".repeat(Math.max(1, Math.floor((t - 24) / 3))), marks: [{ type: "underline" }, { type: "textStyle", attrs: { fontFamily: "Times New Roman, serif", fontSize: "12px" } }] }] })) } };
719
+ }
720
+ function Gt(e, t) {
721
+ const o = e.questions.reduce((r, i) => r + (i.parts.length || 1), 0), n = t / o;
722
+ return !o || !Number.isFinite(n) || n < 0.5 || !Number.isInteger(n * 2) || e.questions.some((r) => n > X[r.type].score || r.type === "CHUNK_CHOICE" && (r.rightAnswers || 0) * (r.singleScore || 0) > n) ? null : { ...e, questions: e.questions.map((r) => ({ ...r, score: n * (r.parts.length || 1), document: W(r.document, r.label, n * (r.parts.length || 1)), choice: { ...r.choice, score: n, lessScore: Math.min(r.choice.lessScore || 0, n) }, parts: r.parts.map((i) => ({ ...i, score: n, document: W(i.document, i.label, n), choice: { ...i.choice, score: n } })) })) };
723
+ }
724
+ function kt(e, t) {
725
+ return [...e <= 17 ? Array.from({ length: 18 }, (o, n) => 17 - n <= e ? String(17 - n) : "") : [...Array.from({ length: 7 }, (o, n) => 7 - n <= Math.floor(e / 10) ? `${7 - n}0` : ""), "", ...Array.from({ length: 10 }, (o, n) => String(9 - n))], t ? "0.5" : ""];
726
+ }
727
+ class v extends Error {
728
+ constructor(o) {
729
+ super(o[0]?.message || "题卡数据无效");
730
+ re(this, "issues");
731
+ this.name = "AnswerSheetDataError", this.issues = o;
732
+ }
733
+ }
734
+ function qe(e, t) {
735
+ const o = (s, c = "题卡数据结构无效") => {
736
+ throw new v([{ code: "INVALID_DATA", path: s, message: c }]);
737
+ }, n = (s, c) => !s || typeof s != "object" || Array.isArray(s) ? o(c) : s, r = (s, c) => Array.isArray(s) ? s : o(c), i = (s, c) => {
738
+ typeof s != "string" && o(c);
739
+ }, f = (s, c, l = 0, E = 1e5) => {
740
+ (typeof s != "number" || !Number.isFinite(s) || s < l || s > E) && o(c);
741
+ }, a = (s, c) => {
742
+ n(s, c);
743
+ const l = t.validateDocument(s);
744
+ l.length && o(c, l[0]);
745
+ }, u = (s, c) => {
746
+ const l = n(s, c);
747
+ if (i(l.id, `${c}.id`), i(l.label, `${c}.label`), (typeof l.multiple != "boolean" || typeof l.breakBefore != "boolean") && o(c), l.contentTarget !== void 0 && l.contentTarget !== null) {
748
+ const E = n(l.contentTarget, `${c}.contentTarget`);
749
+ i(E.groupId, `${c}.contentTarget.groupId`), r(E.optionIds, `${c}.contentTarget.optionIds`).forEach((p, C) => i(p, `${c}.contentTarget.optionIds.${C}`));
750
+ }
751
+ r(l.options, `${c}.options`).forEach((E, p) => {
752
+ const C = n(E, `${c}.options.${p}`);
753
+ i(C.id, `${c}.options.${p}.id`), i(C.label, `${c}.options.${p}.label`);
754
+ }), r(l.correctIds, `${c}.correctIds`).forEach((E, p) => i(E, `${c}.correctIds.${p}`));
755
+ }, y = (s, c) => {
756
+ const l = n(s, c);
757
+ (!["row", "column"].includes(String(l.direction)) || !["concentrated", "distributed", "stem", "option"].includes(String(l.presentation)) || !["box", "check", "bubble"].includes(String(l.marker))) && o(c), f(l.rowsPerColumn, `${c}.rowsPerColumn`, 1, 5), f(l.rowGap, `${c}.rowGap`, 0, 64), f(l.columnGap, `${c}.columnGap`, 0, 64), r(l.questions, `${c}.questions`).forEach((E, p) => u(E, `${c}.questions.${p}`));
758
+ }, I = /* @__PURE__ */ new WeakSet(), b = (s, c) => {
759
+ if (!(!s || typeof s != "object")) {
760
+ if (I.has(s)) return o(c, "题卡必须是无循环引用的 JSON 数据");
761
+ I.add(s), Object.entries(s).forEach(([l, E]) => b(E, `${c}.${l}`)), I.delete(s);
762
+ }
763
+ }, m = n(e, "");
764
+ if (m.version !== 1 && o("version", "不支持的题卡数据版本"), i(m.title, "title"), ["questionCard", "scanMarking", "halfPoint", "mergeObjective"].forEach((s) => {
765
+ m[s] !== void 0 && typeof m[s] != "boolean" && o(s);
766
+ }), ["a4", "a3-two", "a3-three"].includes(String(m.preset)) || o("preset"), f(m.margin, "margin", 0, 100), f(m.gap, "gap", 0, 100), m.creation) {
767
+ const s = n(m.creation, "creation");
768
+ ["template", "exam"].includes(String(s.mode)) || o("creation.mode"), ["name", "grade", "subject"].forEach((c) => i(s[c], `creation.${c}`));
769
+ for (const c of ["gradeCode", "courseCode", "subjectCode"]) s[c] !== void 0 && (typeof s[c] != "string" || !s[c].trim()) && o(`creation.${c}`);
770
+ s.phaseCode !== void 0 && !["P", "J", "S"].includes(String(s.phaseCode)) && o("creation.phaseCode"), s.createMode !== void 0 && !["MANUALLY", "IMPORTED", "THIRD"].includes(String(s.createMode)) && o("creation.createMode");
771
+ for (const c of ["id", "exampaperId"]) if (s[c] !== void 0) {
772
+ const l = s[c];
773
+ typeof l == "string" && l.trim() || typeof l == "number" && Number.isSafeInteger(l) && l >= 0 || o(`creation.${c}`);
774
+ }
775
+ }
776
+ if (m.paperTitle) {
777
+ const s = n(m.paperTitle, "paperTitle");
778
+ i(s.id, "paperTitle.id"), f(s.height, "paperTitle.height", 1, 1e3), a(s.document, "paperTitle.document");
779
+ }
780
+ if (m.header) {
781
+ const s = n(m.header, "header");
782
+ ["code", "school"].includes(String(s.kaohao)) || o("header.kaohao"), f(s.weishu, "header.weishu", 1, 20);
783
+ }
784
+ r(m.blocks, "blocks").forEach((s, c) => {
785
+ const l = `blocks.${c}`, E = n(s, l);
786
+ if (i(E.id, `${l}.id`), i(E.title, `${l}.title`), f(E.answerHeight, `${l}.answerHeight`), a(E.document, `${l}.document`), !E.reference) {
787
+ if (E.choices) {
788
+ y(E.choices, `${l}.choices`);
789
+ return;
790
+ }
791
+ o(`${l}.reference`, "请使用包含 reference 题目结构的制卡数据");
792
+ }
793
+ const p = n(E.reference, `${l}.reference`);
794
+ p.material !== void 0 && a(p.material, `${l}.reference.material`), p.textVersion !== void 0 && p.textVersion !== 1 && o(`${l}.reference.textVersion`), Object.hasOwn(ne, String(p.type)) || o(`${l}.reference.type`), y(p.layout, `${l}.reference.layout`), f(p.optionalHeight, `${l}.reference.optionalHeight`), r(p.questions, `${l}.reference.questions`).forEach((C, d) => {
795
+ const g = `${l}.reference.questions.${d}`, S = n(C, g);
796
+ Object.hasOwn(X, String(S.type)) || o(`${g}.type`), i(S.id, `${g}.id`), i(S.label, `${g}.label`), u(S.choice, `${g}.choice`), ["height", "contentHeight", "characters", "lines"].forEach((N) => f(S[N], `${g}.${N}`)), a(S.document, `${g}.document`);
797
+ const O = (N, T) => {
798
+ if (!N) return;
799
+ const $ = n(N, T);
800
+ a($.content, `${T}.content`), n($.layout, `${T}.layout`), i($.groupId, `${T}.groupId`), r($.itemsContent, `${T}.itemsContent`).forEach((A, H) => {
801
+ const J = n(A, `${T}.itemsContent.${H}`);
802
+ i(J.id, `${T}.itemsContent.${H}.id`), i(J.key, `${T}.itemsContent.${H}.key`), a(J.content, `${T}.itemsContent.${H}.content`);
803
+ });
804
+ };
805
+ O(S.text, `${g}.text`), r(S.parts, `${g}.parts`).forEach((N, T) => {
806
+ const $ = `${g}.parts.${T}`, A = n(N, $);
807
+ i(A.id, `${$}.id`), i(A.label, `${$}.label`), f(A.width, `${$}.width`), f(A.height, `${$}.height`), a(A.document, `${$}.document`), u(A.choice, `${$}.choice`), O(A.text, `${$}.text`);
808
+ });
809
+ });
810
+ }), b(e, "");
811
+ const h = te(e);
812
+ (h.columnWidth < 100 || h.contentHeight < 100) && o("margin", "边距或栏间距过大,纸张没有足够的作答区域");
813
+ }
814
+ function F(e) {
815
+ return !e || e.marks?.some((t) => t.type === "documentLabel") ? !1 : e.type === "text" ? !!e.text?.trim() : e.type === "image" ? !!e.attrs?.src : e.type === "formula" || e.type === "blockFormula" ? !!e.attrs?.latex?.trim() : !!e.content?.some(F);
816
+ }
817
+ function Ut(e, t) {
818
+ try {
819
+ qe(e, t);
820
+ } catch (h) {
821
+ return { valid: !1, issues: h instanceof v ? h.issues : [{ code: "INVALID_DATA", path: "", message: "题卡数据无法读取" }] };
822
+ }
823
+ const o = [];
824
+ let n = {};
825
+ const r = (h, s, c) => o.push({ code: h, path: s, message: c, ...n }), i = /* @__PURE__ */ new Set(), f = (h, s) => {
826
+ (!h.trim() || i.has(h)) && r("DUPLICATE_ID", s, "题块、题目和选项 ID 必须非空且唯一"), i.add(h);
827
+ }, a = (h, s, c) => {
828
+ (h === null || !Number.isFinite(h) || h < 0.5 || h > s || !Number.isInteger(h * 2)) && r("INVALID_SCORE", c, `分值须为 0.5–${s} 分,按 0.5 分递增`);
829
+ }, u = (h, s, c) => {
830
+ (h.options.length < s[0] || h.options.length > s[1]) && r("INVALID_OPTIONS", `${c}.options`, `选项个数须为 ${s[0]}–${s[1]}`), h.options.forEach((l, E) => f(l.id, `${c}.options.${E}.id`)), (new Set(h.correctIds).size !== h.correctIds.length || h.correctIds.some((l) => !h.options.some((E) => E.id === l))) && r("INVALID_ANSWER_REFERENCE", `${c}.correctIds`, "答案引用了不存在或重复的选项");
831
+ }, y = (h, s, c, l = 0, E = !0) => {
832
+ E && !F(h?.content.content) && r("MISSING_CONTENT", `${s}.content`, "请填写题干或材料"), c && (h?.itemsContent.length !== l || h.itemsContent.some((p) => !F(p.content.content))) && r("MISSING_OPTION_CONTENT", `${s}.itemsContent`, "请补全每个选项的内容");
833
+ };
834
+ e.title.trim() || r("MISSING_TITLE", "title", "请填写题卡名称"), (!e.creation?.grade.trim() || !e.creation.subject.trim()) && r("MISSING_CREATION", "creation", "请选择年级和学科"), (!e.paperTitle || !F(e.paperTitle.document.content)) && r("MISSING_PAPER_TITLE", "paperTitle", "请填写纸面标题"), e.blocks.length || r("EMPTY_CARD", "blocks", "请至少添加一个题块和一道题目"), e.paperTitle && f(e.paperTitle.id, "paperTitle.id"), e.blocks.forEach((h, s) => {
835
+ n = { blockId: h.id };
836
+ const c = `blocks.${s}`;
837
+ f(h.id, `${c}.id`), h.title.trim() || r("MISSING_BLOCK_TITLE", `${c}.title`, "请填写题块标题"), h.id === "reference-merged-objective" && r("RESERVED_ID", `${c}.id`, "题块使用了系统保留 ID");
838
+ const l = h.reference;
839
+ if (!l) {
840
+ h.choices?.questions.length || r("EMPTY_BLOCK", c, "题块中没有题目"), h.choices?.questions.forEach((p, C) => {
841
+ n = { blockId: h.id, questionId: p.id }, f(p.id, `${c}.choices.questions.${C}.id`), u(p, [2, 12], `${c}.choices.questions.${C}`), a(p.score ?? null, 15, `${c}.choices.questions.${C}.score`);
842
+ });
843
+ return;
844
+ }
845
+ l.questions.length || r("EMPTY_BLOCK", `${c}.reference.questions`, "题块中没有题目");
846
+ const E = oe(l);
847
+ if ((E.some((p) => !p.trim()) || new Set(E).size !== E.length) && r("INVALID_QUESTION_NUMBER", `${c}.reference.questions`, "同一题块内的题号须非空且不能重复"), l.optional && (l.type !== "SHORTANSWER" || !Number.isInteger(l.choose) || l.choose < 1 || l.choose >= l.questions.length) && r("INVALID_OPTIONAL", `${c}.reference.choose`, "选做题须为解答题,且选做数量小于总题数"), l.type === "CCOMPOSITION" && l.questions.length > 1 && r("INVALID_COUNT", `${c}.reference.questions`, "语文作文每组只能有一道题"), l.questions.forEach((p, C) => {
848
+ n = { blockId: h.id, questionId: p.id };
849
+ const d = `${c}.reference.questions.${C}`, g = X[p.type];
850
+ f(p.id, `${d}.id`), l.type !== "MIXED" && l.type !== p.type && r("TYPE_MISMATCH", `${d}.type`, "题目类型与题块不一致"), p.choice.id !== p.id && r("INVALID_BINDING", `${d}.choice.id`, "题目与填涂项 ID 不一致");
851
+ const S = w(p.type) || ["FILLBLANK", "SHORTANSWER"].includes(p.type);
852
+ (S && (p.parts.length < 1 || p.parts.length > g.parts) || !S && p.parts.length) && r("INVALID_PARTS", `${d}.parts`, `子题/空数须为 ${S ? `1–${g.parts}` : "0"}`), p.parts.length ? p.score !== Ce(p.parts) && r("SCORE_MISMATCH", `${d}.score`, "总分与子题分值之和不一致") : a(p.score, g.score, `${d}.score`), j(p.type) && !w(p.type) && u(p.choice, g.options, `${d}.choice`), p.type === "INFO_MATCHING" && (u(p.choice, g.options, `${d}.choice`), p.parts.length > p.choice.options.length && r("INVALID_OPTIONS", `${d}.choice.options`, "信息匹配的选项数不能少于子题数")), p.type === "MCHOICE" && (!Number.isFinite(p.choice.lessScore) || p.choice.lessScore < 0 || p.choice.lessScore > (p.score || 0) || !Number.isInteger(p.choice.lessScore * 2)) && r("INVALID_LESS_SCORE", `${d}.choice.lessScore`, "少选得分须按 0.5 分递增且不能超过本题分值"), p.type === "CHUNK_CHOICE" && (!p.rightAnswers || !Number.isInteger(p.rightAnswers) || p.rightAnswers >= p.choice.options.length || !p.singleScore || p.singleScore < 0.5 || !Number.isInteger(p.singleScore * 2) || p.singleScore * p.rightAnswers > (p.score || 0)) && r("INVALID_CHUNK_SCORE", d, "请检查正确答案个数及每处得分"), p.type === "CCOMPOSITION" && (!Number.isInteger(p.characters) || p.characters < 1 || p.characters > 1200) && r("INVALID_GRID_COUNT", `${d}.characters`, "作文格数须为 1–1200"), p.type === "ECOMPOSITION" && (!Number.isInteger(p.lines) || p.lines < 1 || p.lines > 100) && r("INVALID_LINE_COUNT", `${d}.lines`, "作文行数须为 1–100"), e.questionCard && y(p.text, `${d}.text`, ["SCHOICE", "MCHOICE"].includes(p.type), p.choice.options.length), p.parts.forEach((O, N) => {
853
+ const T = `${d}.parts.${N}`;
854
+ n = { blockId: h.id, questionId: O.id }, f(O.id, `${T}.id`), a(O.score, g.score, `${T}.score`), w(p.type) && j(p.type) && (u(O.choice, g.options, `${T}.choice`), O.choice.id !== O.id && r("INVALID_BINDING", `${T}.choice.id`, "子题与填涂项 ID 不一致")), e.questionCard && ["CLOZE", "READTHENANSWER"].includes(p.type) && y(O.text, `${T}.text`, !0, O.choice.options.length, p.type === "READTHENANSWER");
855
+ });
856
+ }), n = { blockId: h.id }, e.questionCard && l.layout.presentation !== "concentrated") {
857
+ const p = l.questions.filter((d) => j(d.type)).flatMap((d) => w(d.type) ? d.parts.map((g) => g.choice) : [d.choice]);
858
+ Le({ ...l.layout, questions: p }, h.document, !0).concentrated.questions.length && r("MISSING_FILL_TARGET", `${c}.reference.layout.presentation`, "部分填涂框没有对应的题干或选项位置");
859
+ }
860
+ }), n = {};
861
+ const I = (h, s) => {
862
+ h.type === "image" && (!h.attrs?.src || /^blob:/i.test(h.attrs.src)) && r("INVALID_IMAGE_URL", s, "图片缺少可保存的地址,请上传后使用持久 URL 或内嵌图片"), ["formula", "blockFormula"].includes(h.type || "") && !String(h.attrs?.latex || "").trim() && r("EMPTY_FORMULA", s, "请填写公式或删除空公式"), h.content?.forEach((c, l) => I(c, `${s}.content.${l}`));
863
+ }, b = (h, s) => {
864
+ h && I(h.content, `${s}.content`);
865
+ }, m = (h, s) => {
866
+ b(h?.content, `${s}.content`), h?.itemsContent.forEach((c, l) => b(c.content, `${s}.itemsContent.${l}.content`));
867
+ };
868
+ return b(e.paperTitle?.document, "paperTitle.document"), e.blocks.forEach((h, s) => {
869
+ n = { blockId: h.id };
870
+ const c = `blocks.${s}`;
871
+ b(h.document, `${c}.document`), b(h.reference?.material, `${c}.reference.material`), h.reference?.questions.forEach((l, E) => {
872
+ n = { blockId: h.id, questionId: l.id };
873
+ const p = `blocks.${s}.reference.questions.${E}`;
874
+ b(l.document, `${p}.document`), m(l.text, `${p}.text`), l.parts.forEach((C, d) => {
875
+ n = { blockId: h.id, questionId: C.id }, b(C.document, `${p}.parts.${d}.document`), m(C.text, `${p}.parts.${d}.text`);
876
+ });
877
+ });
878
+ }), { valid: o.length === 0, issues: o };
879
+ }
880
+ function q(e) {
881
+ if (e !== void 0)
882
+ try {
883
+ const t = ue(e);
884
+ return { grades: t.grades, gradeCourseMap: t.gradeCourseMap, defaultGradeCode: t.defaultGradeCode || void 0, defaultCourseCode: t.defaultCourseCode || void 0 };
885
+ } catch (t) {
886
+ throw t instanceof ee ? new v([{ code: "INVALID_DICTIONARIES", path: t.path, message: t.message }]) : t;
887
+ }
888
+ }
889
+ function et(e, t) {
890
+ const o = (d, g) => {
891
+ throw new v([{ code: "INVALID_INITIALIZATION", path: d, message: g }]);
892
+ }, n = (d, g, S) => {
893
+ if (!d || typeof d != "object" || Array.isArray(d)) return o(g, "初始化配置必须是对象");
894
+ const O = Object.entries(d);
895
+ for (const [N] of O) S.includes(N) || o(`${g}.${N}`, "不支持的初始化字段");
896
+ return Object.fromEntries(O.filter(([, N]) => N !== void 0));
897
+ }, r = (d, g) => typeof d != "string" || !d.trim() ? o(g, "请提供非空的试卷名称、年级和学科") : d.trim(), i = (d, g, S) => {
898
+ d !== void 0 && !S.includes(d) && o(g, `可选值为 ${S.join("、")}`);
899
+ }, f = (d, g) => {
900
+ d !== void 0 && typeof d != "boolean" && o(g, "请使用布尔值");
901
+ }, a = (d, g, S, O) => {
902
+ d !== void 0 && (typeof d != "number" || !Number.isFinite(d) || d < S || d > O) && o(g, `数值必须在 ${S}–${O} 之间`);
903
+ }, u = n(e, "initialization", ["name", "grade", "subject", "gradeCode", "courseCode", "subjectCode", "mode", "id", "exampaperId", "createMode", "layout", "header"]), y = r(u.name, "initialization.name");
904
+ y.length > 30 && o("initialization.name", "试卷名称最多 30 个字符");
905
+ const I = ue(q(t)), b = u.gradeCode !== void 0 || u.courseCode !== void 0 || u.subjectCode !== void 0;
906
+ let m;
907
+ if (b) {
908
+ try {
909
+ m = Q(I, r(u.gradeCode, "initialization.gradeCode"), r(u.courseCode, "initialization.courseCode"));
910
+ } catch (d) {
911
+ if (d instanceof ee) return o(d.path, d.message);
912
+ throw d;
913
+ }
914
+ for (const d of ["grade", "subject", "subjectCode"]) u[d] !== void 0 && r(u[d], `initialization.${d}`) !== m[d] && o(`initialization.${d}`, "名称或学科编码与课程字典不一致");
915
+ } else {
916
+ const d = r(u.grade, "initialization.grade"), g = r(u.subject, "initialization.subject"), S = I.grades.filter((T) => T.label === d);
917
+ S.length > 1 && o("initialization.grade", "同名年级不唯一,请使用 gradeCode");
918
+ const O = S[0], N = O ? I.gradeCourseMap[O.value].filter((T) => T.label === g) : [];
919
+ N.length > 1 && o("initialization.subject", "同名课程不唯一,请使用 courseCode"), t && (!O || !N.length) && o(O ? "initialization.subject" : "initialization.grade", "名称不在可用字典中,请使用年级和课程编码"), m = O && N.length ? Q(I, O.value, N[0].value) : { grade: d, subject: g };
920
+ }
921
+ i(u.mode, "initialization.mode", ["template", "exam"]), i(u.createMode, "initialization.createMode", ["MANUALLY", "IMPORTED", "THIRD"]);
922
+ const h = {};
923
+ for (const d of ["id", "exampaperId"]) if (u[d] !== void 0) {
924
+ const g = u[d];
925
+ typeof g == "string" ? h[d] = r(g, `initialization.${d}`) : typeof g == "number" && Number.isSafeInteger(g) && g >= 0 ? h[d] = g : o(`initialization.${d}`, "ID 必须是非空字符串或非负安全整数");
926
+ }
927
+ u.createMode !== void 0 && (h.createMode = u.createMode);
928
+ const s = u.layout === void 0 ? {} : n(u.layout, "initialization.layout", ["preset", "margin", "gap", "questionCard", "scanMarking", "halfPoint", "choiceDirection", "mergeObjective", "pageNum", "quesCard", "scoreType", "choiceType", "mixOb"]), c = (d, g, S) => {
929
+ s[d] !== void 0 && (s[g] !== void 0 && s[g] !== S && o(`initialization.layout.${d}`, `与 ${g} 设置冲突`), s[g] = S, delete s[d]);
930
+ };
931
+ s.pageNum !== void 0 && ![1, 2, 3].includes(s.pageNum) && o("initialization.layout.pageNum", "分栏数为 1、2 或 3"), c("pageNum", "preset", { 1: "a4", 2: "a3-two", 3: "a3-three" }[s.pageNum]);
932
+ for (const [d, g] of [["quesCard", "questionCard"], ["scoreType", "halfPoint"], ["mixOb", "mergeObjective"], ["choiceType", "choiceDirection"]])
933
+ f(s[d], `initialization.layout.${d}`), c(d, g, d === "choiceType" ? s[d] ? "column" : "row" : s[d]);
934
+ i(s.preset, "initialization.layout.preset", ["a4", "a3-two", "a3-three"]), i(s.choiceDirection, "initialization.layout.choiceDirection", ["row", "column"]), a(s.margin, "initialization.layout.margin", 0, 100), a(s.gap, "initialization.layout.gap", 0, 100);
935
+ for (const d of ["questionCard", "scanMarking", "halfPoint", "mergeObjective"]) f(s[d], `initialization.layout.${d}`);
936
+ const l = u.header === void 0 ? {} : n(u.header, "initialization.header", ["focusText", "writeKaohao", "missExam", "mifeng", "kaohao", "weishu"]);
937
+ for (const d of ["focusText", "writeKaohao", "missExam", "mifeng"]) f(l[d], `initialization.header.${d}`);
938
+ i(l.kaohao, "initialization.header.kaohao", ["school", "code"]), a(l.weishu, "initialization.header.weishu", 4, 12), l.weishu !== void 0 && !Number.isInteger(l.weishu) && o("initialization.header.weishu", "考号位数必须是整数");
939
+ const E = Ue({ name: y, ...m, ...h, mode: u.mode ?? "template" }), p = { ...E, ...s, header: { ...E.header, ...l } }, C = te(p);
940
+ return (C.columnWidth < 100 || C.contentHeight < 100) && o("initialization.layout", "边距或栏间距过大,纸张没有足够的作答区域"), p;
941
+ }
942
+ function zt(e, t) {
943
+ if (typeof document > "u") throw new Error("请在浏览器挂载后创建制卡实例");
944
+ const o = Se(t?.plugins || []), n = q(t.dictionaries), r = typeof e == "string" ? document.querySelector(e) : e;
945
+ if (!(r instanceof HTMLElement) || r.ownerDocument !== document || /^(INPUT|TEXTAREA|SELECT|BUTTON|IMG|CANVAS|IFRAME)$/.test(r.tagName)) throw new Error("制卡需要一个空的 HTML 容器,例如 div");
946
+ if (document.querySelector("[data-uni-answer-sheet-mount], #uni-answer-sheet")) throw new Error("当前文档已挂载制卡工作区;切换容器前请先 destroy()");
947
+ if (r.textContent?.trim() || r.children.length) throw new Error("请提供空容器,已有题卡请通过 initialValue 传入");
948
+ const i = document.createElement("div");
949
+ i.className = "uni-answer-sheet-host", i.dataset.uniAnswerSheetMount = "", i.style.height = "100%", r.append(i);
950
+ let f = !1, a = { ...t, dictionaries: n }, u, y, I;
951
+ const b = new Promise((c, l) => {
952
+ y = c, I = l;
953
+ });
954
+ b.catch(() => {
955
+ });
956
+ const m = () => {
957
+ if (f) throw new Error("制卡实例已销毁");
958
+ if (!u?.isReady()) throw new Error("请先等待 sheet.ready");
959
+ return u;
960
+ }, h = async () => (await b, m()), s = {
961
+ ready: b,
962
+ async initialize(c) {
963
+ if (f) throw new Error("制卡实例已销毁");
964
+ const l = et(c, a.dictionaries);
965
+ u || (a = { ...a, initialValue: l }), await (await h()).setDocument(l);
966
+ },
967
+ getDocument: () => m().getDocument(),
968
+ load: async (c) => (await h()).setDocument(c),
969
+ setDocument: async (c) => (await h()).setDocument(c),
970
+ newDocument: async (c) => (await h()).newDocument(c),
971
+ getReferenceData: () => m().getReferenceData(),
972
+ setReferenceData: async (c) => (await h()).setReferenceData(c),
973
+ validate: async () => (await h()).validate(),
974
+ save: async () => (await h()).save(),
975
+ focusIssue: (c) => m().focusIssue(c),
976
+ setOptions(c) {
977
+ if (f) throw new Error("制卡实例已销毁");
978
+ const l = Object.hasOwn(c, "dictionaries") ? q(c.dictionaries) : a.dictionaries;
979
+ a = { ...a, ...c, dictionaries: l }, u?.update(a);
980
+ },
981
+ destroy() {
982
+ f || (f = !0, u?.destroy(), i.remove(), I(new DOMException("制卡实例已销毁", "AbortError")));
983
+ }
984
+ };
985
+ return Promise.all([o.prepare(), import("./runtime-DFHaUhsH.js")]).then(([, { mountAnswerSheet: c }]) => {
986
+ f || (u = c(i, o, a, y, (l) => {
987
+ I(l), s.destroy(), a.onError?.(l instanceof Error ? l : new Error(String(l)));
988
+ }));
989
+ }).catch((c) => {
990
+ I(c), s.destroy(), a.onError?.(c instanceof Error ? c : new Error(String(c)));
991
+ }), s;
992
+ }
993
+ export {
994
+ Et as $,
995
+ Ge as A,
996
+ wt as B,
997
+ Nt as C,
998
+ U as D,
999
+ Rt as E,
1000
+ Ue as F,
1001
+ $t as G,
1002
+ D as H,
1003
+ R as I,
1004
+ ct as J,
1005
+ lt as K,
1006
+ Me as L,
1007
+ le as M,
1008
+ we as N,
1009
+ pe as O,
1010
+ at as P,
1011
+ it as Q,
1012
+ V as R,
1013
+ ot as S,
1014
+ rt as T,
1015
+ ie as U,
1016
+ st as V,
1017
+ Ct as W,
1018
+ gt as X,
1019
+ _e as Y,
1020
+ bt as Z,
1021
+ yt as _,
1022
+ Ze as a,
1023
+ St as a0,
1024
+ ht as a1,
1025
+ Re as a2,
1026
+ Pe as a3,
1027
+ je as a4,
1028
+ ut as a5,
1029
+ pt as a6,
1030
+ De as a7,
1031
+ Ot as a8,
1032
+ It as a9,
1033
+ ft as aa,
1034
+ X as ab,
1035
+ ge as ac,
1036
+ Ht as ad,
1037
+ Pt as ae,
1038
+ Dt as af,
1039
+ xt as ag,
1040
+ Gt as ah,
1041
+ Z as ai,
1042
+ Tt as aj,
1043
+ mt as ak,
1044
+ nt as al,
1045
+ Q as am,
1046
+ ze as an,
1047
+ dt as ao,
1048
+ We as ap,
1049
+ jt as aq,
1050
+ kt as ar,
1051
+ B as as,
1052
+ qe as at,
1053
+ Ut as au,
1054
+ v as av,
1055
+ zt as aw,
1056
+ Lt as b,
1057
+ Je as c,
1058
+ Ie as d,
1059
+ Qe as e,
1060
+ Y as f,
1061
+ j as g,
1062
+ _t as h,
1063
+ w as i,
1064
+ L as j,
1065
+ At as k,
1066
+ he as l,
1067
+ _ as m,
1068
+ se as n,
1069
+ Mt as o,
1070
+ Ve as p,
1071
+ ne as q,
1072
+ Le as r,
1073
+ Ce as s,
1074
+ P as t,
1075
+ W as u,
1076
+ me as v,
1077
+ Ke as w,
1078
+ ae as x,
1079
+ G as y,
1080
+ ue as z
1081
+ };