- Add the event results page with schedule, rankings, Battle bracket, athletes, records, bilingual labels, and navigation entry. - Add the read/write competition data service, a complete Excel example, empty public state, and validation smoke tests. - Handle Furion statusCode/data responses from the production API and retain static fallback for the public page. - Document Docker sidecar deployment beside test_eventapi, persistent storage, private admin access, Nginx routing, and OSS asset rewriting. Verification: - node server/competition-api.smoke.mjs - node scripts/competition-response-test.mjs - node scripts/battle-layout-test.mjs - npm run build -- --base=https://assets.example.test/static/test/ - npm run rewrite:oss -- https://assets.example.test/static/test/ - Production /api/competition/state returned HTTP 200 after the sidecar started. Deployment note: publish the updated YD-WEB static build before public results can consume the unwrapped API response. The event remains unpublished until an administrator saves and publishes data.
35 lines
1.4 KiB
JavaScript
35 lines
1.4 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import { buildBattleLayout } from '../src/data/battle-layout.js';
|
|
|
|
const battle = {
|
|
rounds: [
|
|
{ matches: [
|
|
{ id: 'R1A', aPlayer: 'A', bPlayer: 'B', winner: 'A' },
|
|
{ id: 'R1B', aPlayer: 'C', bPlayer: 'D', winner: 'C' },
|
|
{ id: 'R1C', aPlayer: 'E', bPlayer: 'F', winner: 'E' },
|
|
{ id: 'R1D', aPlayer: 'G', bPlayer: 'H', winner: 'G' },
|
|
] },
|
|
{ matches: [
|
|
{ id: 'R2A', aPlayer: 'A', bPlayer: 'E', winner: 'A' },
|
|
{ id: 'R2B', aPlayer: 'C', bPlayer: 'G', winner: 'G' },
|
|
] },
|
|
{ matches: [{ id: 'FINAL', aPlayer: 'A', bPlayer: 'G', winner: 'A' }] },
|
|
],
|
|
};
|
|
|
|
const layout = buildBattleLayout(battle);
|
|
assert.equal(layout.lastRoundIndex, 2);
|
|
assert.deepEqual(layout.sources.get('FINAL'), { aFrom: 'R2A', bFrom: 'R2B' });
|
|
assert.deepEqual(layout.sources.get('R2A'), { aFrom: 'R1A', bFrom: 'R1C' });
|
|
assert.deepEqual([...layout.sides.left].sort(), ['R1A', 'R1C', 'R2A']);
|
|
assert.deepEqual([...layout.sides.right].sort(), ['R1B', 'R1D', 'R2B']);
|
|
|
|
const explicit = buildBattleLayout({ rounds: [
|
|
{ matches: [{ id: 'A', winner: '' }, { id: 'B', winner: '' }] },
|
|
{ matches: [{ id: 'F', aFrom: 'A', bFrom: 'B' }] },
|
|
] });
|
|
assert.deepEqual(explicit.sources.get('F'), { aFrom: 'A', bFrom: 'B' });
|
|
assert.equal(buildBattleLayout({ rounds: [{ matches: [{ id: 'ONLY' }] }] }).lastRoundIndex, 0);
|
|
|
|
console.log('Battle 轮次和晋级来源解析通过');
|