import assert from 'node:assert/strict'; import XLSX from 'xlsx-js-style'; import { parseCompetitionWorkbook, workbookBytes } from '../src/views/website/competition/workbook.mjs'; const parsed = parseCompetitionWorkbook(workbookBytes(), { currentId: 'M999', callingId: 'M999', upcomingCount: 1 }); assert.equal(parsed.competition.nameZh, '跃动跳绳示例赛(请替换)'); assert.equal(parsed.notice.enabled, true); assert.equal(parsed.published, false); assert.equal(parsed.schedule.items[0].id, 'M001'); assert.equal(parsed.schedule.items.length, 8); assert.equal(parsed.schedule.currentId, 'M006'); assert.equal(parsed.schedule.callingId, 'M007'); assert.equal(parsed.schedule.upcomingCount, 3); assert.equal(parsed.results.overall[0].entries[0].overallRank, 1); assert.equal(parsed.results.overall[0].entries[0].qualified, true); assert.equal(parsed.results.challenge[0].rankings[0].playerId, 'A001'); assert.equal(parsed.results.challenge[0].qualifier[0].playerId, 'A001'); assert.equal(parsed.results.battle[0].rounds[0].matches[0].winner, 'A001'); assert.deepEqual(parsed.results.battle[0].rounds.map((round) => round.matches.length), [8, 4, 2, 1]); assert.deepEqual(parsed.results.battle[0].rounds.map((round) => round.nameEn), ['Round of 16', 'Quarterfinals', 'Semifinals', 'Final']); assert.equal(parsed.results.battle[0].rounds[1].matches[0].aFrom, 'B001'); assert.equal(parsed.results.battle[0].rounds[1].matches[0].bFrom, 'B002'); assert.equal(parsed.results.battle[0].rounds[3].matches[0].winner, 'A001'); assert.equal(parsed.players.length, 16); assert.equal(parsed.records.length, 4); const winners = new Map(); for (const round of parsed.results.battle[0].rounds) for (const match of round.matches) { const a = match.aPlayer || winners.get(match.aFrom); const b = match.bPlayer || winners.get(match.bFrom); assert.ok(a && b, `${match.id} 双方选手已确定`); assert.ok([a, b].includes(match.winner), `${match.id} 获胜者来自本场`); winners.set(match.id, match.winner); } const current = parseCompetitionWorkbook(workbookBytes(parsed)); assert.deepEqual(current.competition, parsed.competition); assert.deepEqual(current.notice, parsed.notice); assert.deepEqual(current.schedule, parsed.schedule); assert.deepEqual(current.results, parsed.results); assert.deepEqual(current.players, parsed.players); assert.deepEqual(current.records, parsed.records); const edited = XLSX.read(workbookBytes(), { type: 'array' }); edited.Sheets['赛事设置'].A2.v = '我的正式赛事'; edited.Sheets['赛事设置'].M2.v = '是'; const editedParsed = parseCompetitionWorkbook(XLSX.write(edited, { bookType: 'xlsx', type: 'array' })); assert.equal(editedParsed.competition.nameZh, '我的正式赛事'); assert.equal(editedParsed.published, true); const legacy = XLSX.read(workbookBytes(), { type: 'array' }); legacy.SheetNames = legacy.SheetNames.filter((name) => name !== '赛事设置'); delete legacy.Sheets['赛事设置']; const legacyParsed = parseCompetitionWorkbook(XLSX.write(legacy, { bookType: 'xlsx', type: 'array' }), { currentId: 'M002' }); assert.equal(legacyParsed.schedule.currentId, 'M002'); assert.equal('competition' in legacyParsed, false); const excelTime = XLSX.read(workbookBytes(), { type: 'array' }); excelTime.Sheets['赛程'].B2 = { t: 'n', v: 0.375, z: 'hh:mm' }; assert.equal(parseCompetitionWorkbook(XLSX.write(excelTime, { bookType: 'xlsx', type: 'array' })).schedule.items[0].time, '09:00'); const duplicate = XLSX.read(workbookBytes(), { type: 'array' }); XLSX.utils.sheet_add_aoa(duplicate.Sheets['选手'], [['A001', '重复选手', '', 'A', '男']], { origin: -1 }); assert.throws(() => parseCompetitionWorkbook(XLSX.write(duplicate, { bookType: 'xlsx', type: 'array' })), /选手编号重复/); const broken = XLSX.read(workbookBytes(), { type: 'array' }); broken.Sheets['赛程'].A1.v = '错误表头'; assert.throws(() => parseCompetitionWorkbook(XLSX.write(broken, { bookType: 'xlsx', type: 'array' })), /表头与示例模板不一致/); console.log('官网赛事 Excel 模板生成、导入、回写与错误校验通过');