uni-answer-sheet 2.0.0 → 2.2.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.
@@ -1,1081 +0,0 @@
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
- };