@xcpcio/core 0.14.0 → 0.15.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.
package/dist/index.cjs CHANGED
@@ -285,13 +285,59 @@ class CodeforcesGymGhostDATConverter {
285
285
  }
286
286
  }
287
287
 
288
+ var MedalType = /* @__PURE__ */ ((MedalType2) => {
289
+ MedalType2["UNKNOWN"] = "Unknown";
290
+ MedalType2["GOLD"] = "Gold";
291
+ MedalType2["SILVER"] = "Silver";
292
+ MedalType2["BRONZE"] = "Bronze";
293
+ MedalType2["HONORABLE"] = "Honorable";
294
+ return MedalType2;
295
+ })(MedalType || {});
296
+ class Award {
297
+ constructor() {
298
+ this.medalType = "Unknown" /* UNKNOWN */;
299
+ this.minRank = 0;
300
+ this.maxRank = 0;
301
+ }
302
+ }
303
+ function isValidMedalType(medal) {
304
+ const validMedalType = [
305
+ "Gold" /* GOLD */,
306
+ "Silver" /* SILVER */,
307
+ "Bronze" /* BRONZE */,
308
+ "Honorable" /* HONORABLE */
309
+ ];
310
+ return validMedalType.includes(medal);
311
+ }
312
+
288
313
  class GeneralExcelConverter {
289
314
  constructor() {
290
315
  }
291
- convert(rank) {
316
+ convert(oriRank) {
317
+ const rank = ___default.cloneDeep(oriRank);
318
+ rank.options.disableFilterTeamsByGroup();
319
+ rank.options.disableFilterSubmissionByTimestamp();
292
320
  const workbook = XLSX__namespace.utils.book_new();
321
+ for (const [k, v] of rank.contest.group) {
322
+ rank.options.setGroup(k);
323
+ rank.buildRank();
324
+ const sheet = this.convertToSheet(rank);
325
+ XLSX__namespace.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang));
326
+ }
327
+ return workbook;
328
+ }
329
+ convertAndWrite(rank, filename) {
330
+ return XLSX__namespace.writeFile(
331
+ this.convert(rank),
332
+ filename,
333
+ {
334
+ compression: true
335
+ }
336
+ );
337
+ }
338
+ convertToSheet(rank) {
293
339
  const aoa = this.convertToAoa(rank);
294
- const mainWorksheet = XLSX__namespace.utils.aoa_to_sheet(aoa);
340
+ const sheet = XLSX__namespace.utils.aoa_to_sheet(aoa);
295
341
  const cols = [];
296
342
  const head = aoa[1];
297
343
  for (let j = 0; j < head.length; j++) {
@@ -303,11 +349,11 @@ class GeneralExcelConverter {
303
349
  wch
304
350
  });
305
351
  }
306
- mainWorksheet["!cols"] = cols;
352
+ sheet["!cols"] = cols;
307
353
  {
308
354
  const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
309
355
  const merges = [{ s: mergeRange.s, e: mergeRange.e }];
310
- mainWorksheet["!merges"] = merges;
356
+ sheet["!merges"] = merges;
311
357
  }
312
358
  const font = {
313
359
  name: "Arial Unicode MS",
@@ -334,32 +380,23 @@ class GeneralExcelConverter {
334
380
  for (let i = 1; i < aoa.length; i++) {
335
381
  for (let j = 0; j < aoa[i].length; j++) {
336
382
  const cellAddress = XLSX__namespace.utils.encode_cell({ r: i, c: j });
337
- const cell = mainWorksheet[cellAddress];
383
+ const cell = sheet[cellAddress];
338
384
  cell.s = cellStyle;
339
385
  }
340
386
  }
341
387
  {
342
388
  const cellAddress = XLSX__namespace.utils.encode_cell({ r: 0, c: 0 });
343
- const cell = mainWorksheet[cellAddress];
389
+ const cell = sheet[cellAddress];
344
390
  const titleStyle = ___default.cloneDeep(cellStyle);
345
391
  titleStyle.font.sz = 28;
346
392
  titleStyle.font.bold = true;
347
393
  cell.s = titleStyle;
348
394
  }
349
- XLSX__namespace.utils.book_append_sheet(workbook, mainWorksheet, "Scoreboard");
350
- return workbook;
351
- }
352
- convertAndWrite(rank, filename) {
353
- return XLSX__namespace.writeFile(
354
- this.convert(rank),
355
- filename,
356
- {
357
- compression: true
358
- }
359
- );
395
+ return sheet;
360
396
  }
361
397
  convertToAoa(rank) {
362
398
  const aoa = [];
399
+ const enableAwards = rank.contest.isEnableAwards(rank.options.group);
363
400
  {
364
401
  aoa.push([rank.contest.name]);
365
402
  }
@@ -371,6 +408,9 @@ class GeneralExcelConverter {
371
408
  head.push(rank.contest.organization);
372
409
  }
373
410
  head.push("Name", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dict");
411
+ if (enableAwards) {
412
+ head.push("Medal");
413
+ }
374
414
  aoa.push(head);
375
415
  }
376
416
  for (const team of rank.teams) {
@@ -400,28 +440,16 @@ class GeneralExcelConverter {
400
440
  }
401
441
  }
402
442
  arr.push(`${team.dict}%`);
443
+ if (enableAwards) {
444
+ const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
445
+ arr.push(medals.join(", "));
446
+ }
403
447
  aoa.push(arr);
404
448
  }
405
449
  return aoa;
406
450
  }
407
451
  }
408
452
 
409
- var MedalType = /* @__PURE__ */ ((MedalType2) => {
410
- MedalType2[MedalType2["UNKNOWN"] = 0] = "UNKNOWN";
411
- MedalType2[MedalType2["GOLD"] = 1] = "GOLD";
412
- MedalType2[MedalType2["SILVER"] = 2] = "SILVER";
413
- MedalType2[MedalType2["BRONZE"] = 3] = "BRONZE";
414
- MedalType2[MedalType2["HONORABLE"] = 4] = "HONORABLE";
415
- return MedalType2;
416
- })(MedalType || {});
417
- class Award {
418
- constructor() {
419
- this.medalType = 0 /* UNKNOWN */;
420
- this.minRank = 0;
421
- this.maxRank = 0;
422
- }
423
- }
424
-
425
453
  function calcDict(attemptedNum, solvedNum) {
426
454
  if (solvedNum === 0) {
427
455
  return 0;
@@ -625,6 +653,15 @@ class Contest {
625
653
  const pass = baseTime.diff(this.startTime, "s");
626
654
  return Math.round(pass * 100 / total);
627
655
  }
656
+ isEnableAwards(group) {
657
+ if (!this.awards) {
658
+ return false;
659
+ }
660
+ if (!this.awards.has(group)) {
661
+ return false;
662
+ }
663
+ return true;
664
+ }
628
665
  }
629
666
  function createContest(contestJSON) {
630
667
  const c = new Contest();
@@ -851,6 +888,7 @@ class Team {
851
888
  this.problemStatisticsMap = /* @__PURE__ */ new Map();
852
889
  this.submissions = [];
853
890
  this.placeChartPoints = [];
891
+ this.awards = [];
854
892
  }
855
893
  get penaltyToMinute() {
856
894
  return Math.floor(this.penalty / 60);
@@ -1427,4 +1465,5 @@ exports.isAccepted = isAccepted;
1427
1465
  exports.isNotCalculatedPenaltyStatus = isNotCalculatedPenaltyStatus;
1428
1466
  exports.isPending = isPending;
1429
1467
  exports.isRejected = isRejected;
1468
+ exports.isValidMedalType = isValidMedalType;
1430
1469
  exports.stringToSubmissionStatus = stringToSubmissionStatus;
package/dist/index.d.ts CHANGED
@@ -88,11 +88,11 @@ declare class Group {
88
88
  }
89
89
 
90
90
  declare enum MedalType {
91
- UNKNOWN = 0,
92
- GOLD = 1,
93
- SILVER = 2,
94
- BRONZE = 3,
95
- HONORABLE = 4
91
+ UNKNOWN = "Unknown",
92
+ GOLD = "Gold",
93
+ SILVER = "Silver",
94
+ BRONZE = "Bronze",
95
+ HONORABLE = "Honorable"
96
96
  }
97
97
  declare class Award {
98
98
  medalType: MedalType;
@@ -100,6 +100,7 @@ declare class Award {
100
100
  maxRank: number;
101
101
  constructor();
102
102
  }
103
+ declare function isValidMedalType(medal: MedalType): boolean;
103
104
  type Awards = Map<string, Award[]>;
104
105
 
105
106
  declare class Contest {
@@ -130,6 +131,7 @@ declare class Contest {
130
131
  getContestElapsedTime(nowTime?: Date): string;
131
132
  getContestRemainingTime(nowTime?: Date): string;
132
133
  getContestProgressRatio(nowTime?: Date): number;
134
+ isEnableAwards(group: string): boolean;
133
135
  }
134
136
  declare function createContest(contestJSON: Contest$1): Contest;
135
137
 
@@ -233,8 +235,9 @@ declare class CodeforcesGymGhostDATConverter {
233
235
 
234
236
  declare class GeneralExcelConverter {
235
237
  constructor();
236
- convert(rank: Rank): XLSX.WorkBook;
238
+ convert(oriRank: Rank): XLSX.WorkBook;
237
239
  convertAndWrite(rank: Rank, filename: string): any;
240
+ private convertToSheet;
238
241
  private convertToAoa;
239
242
  }
240
243
 
@@ -284,4 +287,4 @@ declare function isRejected(status: SubmissionStatus): boolean;
284
287
  declare function isPending(status: SubmissionStatus): boolean;
285
288
  declare function isNotCalculatedPenaltyStatus(status: SubmissionStatus): boolean;
286
289
 
287
- export { Award, Awards, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, stringToSubmissionStatus };
290
+ export { Award, Awards, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, ContestIndexList, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Problems, Rank, RankOptions, RankStatistics, Resolver, SelectOptionItem, Submission, Submissions, Team, TeamProblemStatistics, Teams, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
package/dist/index.mjs CHANGED
@@ -255,13 +255,59 @@ class CodeforcesGymGhostDATConverter {
255
255
  }
256
256
  }
257
257
 
258
+ var MedalType = /* @__PURE__ */ ((MedalType2) => {
259
+ MedalType2["UNKNOWN"] = "Unknown";
260
+ MedalType2["GOLD"] = "Gold";
261
+ MedalType2["SILVER"] = "Silver";
262
+ MedalType2["BRONZE"] = "Bronze";
263
+ MedalType2["HONORABLE"] = "Honorable";
264
+ return MedalType2;
265
+ })(MedalType || {});
266
+ class Award {
267
+ constructor() {
268
+ this.medalType = "Unknown" /* UNKNOWN */;
269
+ this.minRank = 0;
270
+ this.maxRank = 0;
271
+ }
272
+ }
273
+ function isValidMedalType(medal) {
274
+ const validMedalType = [
275
+ "Gold" /* GOLD */,
276
+ "Silver" /* SILVER */,
277
+ "Bronze" /* BRONZE */,
278
+ "Honorable" /* HONORABLE */
279
+ ];
280
+ return validMedalType.includes(medal);
281
+ }
282
+
258
283
  class GeneralExcelConverter {
259
284
  constructor() {
260
285
  }
261
- convert(rank) {
286
+ convert(oriRank) {
287
+ const rank = _.cloneDeep(oriRank);
288
+ rank.options.disableFilterTeamsByGroup();
289
+ rank.options.disableFilterSubmissionByTimestamp();
262
290
  const workbook = XLSX.utils.book_new();
291
+ for (const [k, v] of rank.contest.group) {
292
+ rank.options.setGroup(k);
293
+ rank.buildRank();
294
+ const sheet = this.convertToSheet(rank);
295
+ XLSX.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang));
296
+ }
297
+ return workbook;
298
+ }
299
+ convertAndWrite(rank, filename) {
300
+ return XLSX.writeFile(
301
+ this.convert(rank),
302
+ filename,
303
+ {
304
+ compression: true
305
+ }
306
+ );
307
+ }
308
+ convertToSheet(rank) {
263
309
  const aoa = this.convertToAoa(rank);
264
- const mainWorksheet = XLSX.utils.aoa_to_sheet(aoa);
310
+ const sheet = XLSX.utils.aoa_to_sheet(aoa);
265
311
  const cols = [];
266
312
  const head = aoa[1];
267
313
  for (let j = 0; j < head.length; j++) {
@@ -273,11 +319,11 @@ class GeneralExcelConverter {
273
319
  wch
274
320
  });
275
321
  }
276
- mainWorksheet["!cols"] = cols;
322
+ sheet["!cols"] = cols;
277
323
  {
278
324
  const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
279
325
  const merges = [{ s: mergeRange.s, e: mergeRange.e }];
280
- mainWorksheet["!merges"] = merges;
326
+ sheet["!merges"] = merges;
281
327
  }
282
328
  const font = {
283
329
  name: "Arial Unicode MS",
@@ -304,32 +350,23 @@ class GeneralExcelConverter {
304
350
  for (let i = 1; i < aoa.length; i++) {
305
351
  for (let j = 0; j < aoa[i].length; j++) {
306
352
  const cellAddress = XLSX.utils.encode_cell({ r: i, c: j });
307
- const cell = mainWorksheet[cellAddress];
353
+ const cell = sheet[cellAddress];
308
354
  cell.s = cellStyle;
309
355
  }
310
356
  }
311
357
  {
312
358
  const cellAddress = XLSX.utils.encode_cell({ r: 0, c: 0 });
313
- const cell = mainWorksheet[cellAddress];
359
+ const cell = sheet[cellAddress];
314
360
  const titleStyle = _.cloneDeep(cellStyle);
315
361
  titleStyle.font.sz = 28;
316
362
  titleStyle.font.bold = true;
317
363
  cell.s = titleStyle;
318
364
  }
319
- XLSX.utils.book_append_sheet(workbook, mainWorksheet, "Scoreboard");
320
- return workbook;
321
- }
322
- convertAndWrite(rank, filename) {
323
- return XLSX.writeFile(
324
- this.convert(rank),
325
- filename,
326
- {
327
- compression: true
328
- }
329
- );
365
+ return sheet;
330
366
  }
331
367
  convertToAoa(rank) {
332
368
  const aoa = [];
369
+ const enableAwards = rank.contest.isEnableAwards(rank.options.group);
333
370
  {
334
371
  aoa.push([rank.contest.name]);
335
372
  }
@@ -341,6 +378,9 @@ class GeneralExcelConverter {
341
378
  head.push(rank.contest.organization);
342
379
  }
343
380
  head.push("Name", "Solved", "Penalty", ...rank.contest.problems.map((p) => p.label), "Dict");
381
+ if (enableAwards) {
382
+ head.push("Medal");
383
+ }
344
384
  aoa.push(head);
345
385
  }
346
386
  for (const team of rank.teams) {
@@ -370,28 +410,16 @@ class GeneralExcelConverter {
370
410
  }
371
411
  }
372
412
  arr.push(`${team.dict}%`);
413
+ if (enableAwards) {
414
+ const medals = team.awards.filter((a) => isValidMedalType(a)).map((a) => a.toString());
415
+ arr.push(medals.join(", "));
416
+ }
373
417
  aoa.push(arr);
374
418
  }
375
419
  return aoa;
376
420
  }
377
421
  }
378
422
 
379
- var MedalType = /* @__PURE__ */ ((MedalType2) => {
380
- MedalType2[MedalType2["UNKNOWN"] = 0] = "UNKNOWN";
381
- MedalType2[MedalType2["GOLD"] = 1] = "GOLD";
382
- MedalType2[MedalType2["SILVER"] = 2] = "SILVER";
383
- MedalType2[MedalType2["BRONZE"] = 3] = "BRONZE";
384
- MedalType2[MedalType2["HONORABLE"] = 4] = "HONORABLE";
385
- return MedalType2;
386
- })(MedalType || {});
387
- class Award {
388
- constructor() {
389
- this.medalType = 0 /* UNKNOWN */;
390
- this.minRank = 0;
391
- this.maxRank = 0;
392
- }
393
- }
394
-
395
423
  function calcDict(attemptedNum, solvedNum) {
396
424
  if (solvedNum === 0) {
397
425
  return 0;
@@ -595,6 +623,15 @@ class Contest {
595
623
  const pass = baseTime.diff(this.startTime, "s");
596
624
  return Math.round(pass * 100 / total);
597
625
  }
626
+ isEnableAwards(group) {
627
+ if (!this.awards) {
628
+ return false;
629
+ }
630
+ if (!this.awards.has(group)) {
631
+ return false;
632
+ }
633
+ return true;
634
+ }
598
635
  }
599
636
  function createContest(contestJSON) {
600
637
  const c = new Contest();
@@ -821,6 +858,7 @@ class Team {
821
858
  this.problemStatisticsMap = /* @__PURE__ */ new Map();
822
859
  this.submissions = [];
823
860
  this.placeChartPoints = [];
861
+ this.awards = [];
824
862
  }
825
863
  get penaltyToMinute() {
826
864
  return Math.floor(this.penalty / 60);
@@ -1360,4 +1398,4 @@ class Resolver extends Rank {
1360
1398
  }
1361
1399
  }
1362
1400
 
1363
- export { Award, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, stringToSubmissionStatus };
1401
+ export { Award, CodeforcesGymGhostDATConverter, Contest, ContestIndex, ContestIndexConfig, GeneralExcelConverter, MedalType, PlaceChartPointData, Problem, ProblemStatistics, Rank, RankOptions, RankStatistics, Resolver, Submission, Team, TeamProblemStatistics, calcDict, createContest, createContestIndex, createContestIndexList, createDayJS, createProblem, createProblems, createProblemsByProblemIds, createSubmission, createSubmissions, createTeam, createTeams, getImageSource, getTimeDiff, getTimestamp, isAccepted, isNotCalculatedPenaltyStatus, isPending, isRejected, isValidMedalType, stringToSubmissionStatus };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xcpcio/core",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "XCPCIO Core",
5
5
  "author": "Dup4 <lyuzhi.pan@gmail.com>",
6
6
  "license": "MIT",
@@ -44,7 +44,7 @@
44
44
  "lodash": "^4.17.21",
45
45
  "string-width": "^6.1.0",
46
46
  "xlsx-js-style": "^1.2.0",
47
- "@xcpcio/types": "0.14.0"
47
+ "@xcpcio/types": "0.15.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@babel/types": "^7.22.4",
package/src/award.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  export enum MedalType {
2
- UNKNOWN,
3
- GOLD,
4
- SILVER,
5
- BRONZE,
6
- HONORABLE,
2
+ UNKNOWN = "Unknown",
3
+ GOLD = "Gold",
4
+ SILVER = "Silver",
5
+ BRONZE = "Bronze",
6
+ HONORABLE = "Honorable",
7
7
  }
8
8
 
9
9
  export class Award {
@@ -18,4 +18,15 @@ export class Award {
18
18
  }
19
19
  }
20
20
 
21
+ export function isValidMedalType(medal: MedalType): boolean {
22
+ const validMedalType = [
23
+ MedalType.GOLD,
24
+ MedalType.SILVER,
25
+ MedalType.BRONZE,
26
+ MedalType.HONORABLE,
27
+ ];
28
+
29
+ return validMedalType.includes(medal);
30
+ }
31
+
21
32
  export type Awards = Map<string, Award[]>;
package/src/contest.ts CHANGED
@@ -136,6 +136,18 @@ export class Contest {
136
136
 
137
137
  return Math.round((pass * 100) / total);
138
138
  }
139
+
140
+ isEnableAwards(group: string): boolean {
141
+ if (!this.awards) {
142
+ return false;
143
+ }
144
+
145
+ if (!this.awards.has(group)) {
146
+ return false;
147
+ }
148
+
149
+ return true;
150
+ }
139
151
  }
140
152
 
141
153
  export function createContest(contestJSON: IContest): Contest {
@@ -2,15 +2,43 @@ import _ from "lodash";
2
2
  import * as XLSX from "xlsx-js-style";
3
3
  import stringWidth from "string-width";
4
4
 
5
+ import { isValidMedalType } from "../award";
5
6
  import type { Rank } from "../rank";
6
7
 
7
8
  export class GeneralExcelConverter {
8
9
  constructor() {}
9
10
 
10
- public convert(rank: Rank): XLSX.WorkBook {
11
+ public convert(oriRank: Rank): XLSX.WorkBook {
12
+ const rank = _.cloneDeep(oriRank);
13
+
14
+ rank.options.disableFilterTeamsByGroup();
15
+ rank.options.disableFilterSubmissionByTimestamp();
16
+
11
17
  const workbook = XLSX.utils.book_new();
18
+
19
+ for (const [k, v] of rank.contest.group) {
20
+ rank.options.setGroup(k);
21
+ rank.buildRank();
22
+
23
+ const sheet = this.convertToSheet(rank);
24
+ XLSX.utils.book_append_sheet(workbook, sheet, v.names.get(v.defaultLang) as string);
25
+ }
26
+
27
+ return workbook;
28
+ }
29
+
30
+ public convertAndWrite(rank: Rank, filename: string): any {
31
+ return XLSX.writeFile(
32
+ this.convert(rank),
33
+ filename,
34
+ {
35
+ compression: true,
36
+ });
37
+ }
38
+
39
+ private convertToSheet(rank: Rank): XLSX.WorkSheet {
12
40
  const aoa = this.convertToAoa(rank);
13
- const mainWorksheet = XLSX.utils.aoa_to_sheet(aoa);
41
+ const sheet = XLSX.utils.aoa_to_sheet(aoa);
14
42
 
15
43
  const cols = [];
16
44
  const head = aoa[1];
@@ -25,12 +53,12 @@ export class GeneralExcelConverter {
25
53
  });
26
54
  }
27
55
 
28
- mainWorksheet["!cols"] = cols;
56
+ sheet["!cols"] = cols;
29
57
 
30
58
  {
31
59
  const mergeRange = { s: { r: 0, c: 0 }, e: { r: 0, c: head.length - 1 } };
32
60
  const merges = [{ s: mergeRange.s, e: mergeRange.e }];
33
- mainWorksheet["!merges"] = merges;
61
+ sheet["!merges"] = merges;
34
62
  }
35
63
 
36
64
  const font = {
@@ -61,37 +89,28 @@ export class GeneralExcelConverter {
61
89
  for (let i = 1; i < aoa.length; i++) {
62
90
  for (let j = 0; j < aoa[i].length; j++) {
63
91
  const cellAddress = XLSX.utils.encode_cell({ r: i, c: j });
64
- const cell = mainWorksheet[cellAddress];
92
+ const cell = sheet[cellAddress];
65
93
  cell.s = cellStyle;
66
94
  }
67
95
  }
68
96
 
69
97
  {
70
98
  const cellAddress = XLSX.utils.encode_cell({ r: 0, c: 0 });
71
- const cell = mainWorksheet[cellAddress];
99
+ const cell = sheet[cellAddress];
72
100
  const titleStyle = _.cloneDeep(cellStyle);
73
101
  titleStyle.font.sz = 28;
74
102
  titleStyle.font.bold = true;
75
103
  cell.s = titleStyle;
76
104
  }
77
105
 
78
- XLSX.utils.book_append_sheet(workbook, mainWorksheet, "Scoreboard");
79
-
80
- return workbook;
81
- }
82
-
83
- public convertAndWrite(rank: Rank, filename: string): any {
84
- return XLSX.writeFile(
85
- this.convert(rank),
86
- filename,
87
- {
88
- compression: true,
89
- });
106
+ return sheet;
90
107
  }
91
108
 
92
109
  private convertToAoa(rank: Rank): string[][] {
93
110
  const aoa: string[][] = [];
94
111
 
112
+ const enableAwards = rank.contest.isEnableAwards(rank.options.group);
113
+
95
114
  {
96
115
  aoa.push([rank.contest.name]);
97
116
  }
@@ -106,6 +125,11 @@ export class GeneralExcelConverter {
106
125
  }
107
126
 
108
127
  head.push("Name", "Solved", "Penalty", ...rank.contest.problems.map(p => p.label), "Dict");
128
+
129
+ if (enableAwards) {
130
+ head.push("Medal");
131
+ }
132
+
109
133
  aoa.push(head);
110
134
  }
111
135
 
@@ -145,6 +169,13 @@ export class GeneralExcelConverter {
145
169
 
146
170
  arr.push(`${team.dict}%`);
147
171
 
172
+ if (enableAwards) {
173
+ const medals = team.awards
174
+ .filter(a => isValidMedalType(a))
175
+ .map(a => a.toString());
176
+ arr.push(medals.join(", "));
177
+ }
178
+
148
179
  aoa.push(arr);
149
180
  }
150
181
 
package/src/team.ts CHANGED
@@ -101,6 +101,8 @@ export class Team {
101
101
  this.submissions = [];
102
102
 
103
103
  this.placeChartPoints = [];
104
+
105
+ this.awards = [];
104
106
  }
105
107
 
106
108
  get penaltyToMinute() {