Compare commits
2 Commits
448e49b9fd
...
bf377c9c5e
| Author | SHA1 | Date | |
|---|---|---|---|
| bf377c9c5e | |||
| 145d5e7ca8 |
6
pom.xml
6
pom.xml
@ -11,7 +11,7 @@
|
|||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
|
||||||
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
|
||||||
<quarkus.platform.version>3.16.4</quarkus.platform.version>
|
<quarkus.platform.version>3.30.5</quarkus.platform.version>
|
||||||
<skipITs>true</skipITs>
|
<skipITs>true</skipITs>
|
||||||
<surefire-plugin.version>3.2.3</surefire-plugin.version>
|
<surefire-plugin.version>3.2.3</surefire-plugin.version>
|
||||||
</properties>
|
</properties>
|
||||||
@ -68,7 +68,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkiverse.tika</groupId>
|
<groupId>io.quarkiverse.tika</groupId>
|
||||||
<artifactId>quarkus-tika</artifactId>
|
<artifactId>quarkus-tika</artifactId>
|
||||||
<version>2.0.4</version>
|
<version>2.3.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -127,7 +127,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.xmlgraphics</groupId>
|
<groupId>org.apache.xmlgraphics</groupId>
|
||||||
<artifactId>fop</artifactId>
|
<artifactId>fop</artifactId>
|
||||||
<version>2.6</version>
|
<version>2.11</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.quarkus</groupId>
|
<groupId>io.quarkus</groupId>
|
||||||
|
|||||||
@ -66,4 +66,13 @@ public class RegisterModel {
|
|||||||
return membre.club;
|
return membre.club;
|
||||||
return club;
|
return club;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Categorie getCategorie2() {
|
||||||
|
Categorie tmp = this.categorie;
|
||||||
|
if (tmp == null)
|
||||||
|
tmp = membre.getCategorie();
|
||||||
|
if (tmp == null)
|
||||||
|
return null;
|
||||||
|
return Categorie.values()[Math.min(tmp.ordinal() + this.overCategory, Categorie.values().length - 1)];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,6 @@ import fr.titionfire.ffsaf.rest.client.HelloAssoAuthClient;
|
|||||||
import fr.titionfire.ffsaf.rest.client.dto.TokenResponse;
|
import fr.titionfire.ffsaf.rest.client.dto.TokenResponse;
|
||||||
import io.smallrye.mutiny.Uni;
|
import io.smallrye.mutiny.Uni;
|
||||||
import jakarta.enterprise.context.ApplicationScoped;
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
import jakarta.inject.Inject;
|
|
||||||
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
import org.eclipse.microprofile.config.inject.ConfigProperty;
|
||||||
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
import org.eclipse.microprofile.rest.client.inject.RestClient;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
@ -13,7 +12,6 @@ import org.jboss.logging.Logger;
|
|||||||
public class HelloAssoTokenService {
|
public class HelloAssoTokenService {
|
||||||
private static final Logger LOG = Logger.getLogger(HelloAssoTokenService.class);
|
private static final Logger LOG = Logger.getLogger(HelloAssoTokenService.class);
|
||||||
|
|
||||||
@Inject
|
|
||||||
@RestClient
|
@RestClient
|
||||||
HelloAssoAuthClient authClient;
|
HelloAssoAuthClient authClient;
|
||||||
|
|
||||||
|
|||||||
@ -58,6 +58,8 @@ public class LoggerService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Uni<?> append() {
|
public Uni<?> append() {
|
||||||
|
if (buffer.isEmpty())
|
||||||
|
return Uni.createFrom().voidItem();
|
||||||
return Panache.withTransaction(() -> repository.persist(buffer))
|
return Panache.withTransaction(() -> repository.persist(buffer))
|
||||||
.invoke(__ -> buffer.clear());
|
.invoke(__ -> buffer.clear());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -158,7 +158,7 @@ public class MembreService {
|
|||||||
"EXISTS (SELECT 1 FROM LicenceModel l WHERE l.membre.id = m.id AND l.saison >= %s)",
|
"EXISTS (SELECT 1 FROM LicenceModel l WHERE l.membre.id = m.id AND l.saison >= %s)",
|
||||||
Utils.getSaison() - 1);
|
Utils.getSaison() - 1);
|
||||||
|
|
||||||
String clubFilter = "?3 = ?3";
|
String clubFilter = "(TRUE OR ?3 = ?3)";
|
||||||
if (club != null) {
|
if (club != null) {
|
||||||
if (club instanceof String club_) {
|
if (club instanceof String club_) {
|
||||||
if (!club_.isBlank()) {
|
if (!club_.isBlank()) {
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
package fr.titionfire.ffsaf.domain.service;
|
package fr.titionfire.ffsaf.domain.service;
|
||||||
|
|
||||||
import fr.titionfire.ffsaf.data.model.*;
|
import fr.titionfire.ffsaf.data.model.*;
|
||||||
import fr.titionfire.ffsaf.data.repository.CategoryRepository;
|
import fr.titionfire.ffsaf.data.repository.*;
|
||||||
import fr.titionfire.ffsaf.data.repository.CompetitionRepository;
|
|
||||||
import fr.titionfire.ffsaf.data.repository.MatchRepository;
|
|
||||||
import fr.titionfire.ffsaf.data.repository.RegisterRepository;
|
|
||||||
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
|
import fr.titionfire.ffsaf.rest.data.ResultCategoryData;
|
||||||
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
import fr.titionfire.ffsaf.rest.exception.DForbiddenException;
|
||||||
import fr.titionfire.ffsaf.utils.*;
|
import fr.titionfire.ffsaf.utils.*;
|
||||||
@ -19,7 +16,9 @@ import lombok.Builder;
|
|||||||
import org.hibernate.reactive.mutiny.Mutiny;
|
import org.hibernate.reactive.mutiny.Mutiny;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@WithSession
|
@WithSession
|
||||||
@ -35,6 +34,12 @@ public class ResultService {
|
|||||||
@Inject
|
@Inject
|
||||||
MembreService membreService;
|
MembreService membreService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ClubRepository clubRepository;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
CompetitionGuestRepository competitionGuestRepository;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
CategoryRepository categoryRepository;
|
CategoryRepository categoryRepository;
|
||||||
|
|
||||||
@ -53,10 +58,22 @@ public class ResultService {
|
|||||||
.collect().asList();
|
.collect().asList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Uni<HashMap<String, Long>> getCategoryList(String uuid) {
|
||||||
|
return categoryRepository.list("compet.uuid = ?1", uuid)
|
||||||
|
.map(categoryModels -> {
|
||||||
|
HashMap<String, Long> map = new HashMap<>();
|
||||||
|
categoryModels.stream()
|
||||||
|
.sorted(Comparator.comparing(CategoryModel::getName))
|
||||||
|
.forEachOrdered(categoryModel -> map.put(categoryModel.getName(), categoryModel.getId()));
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public Uni<List<ResultCategoryData>> getCategory(String uuid, SecurityCtx securityCtx) {
|
public Uni<List<ResultCategoryData>> getCategory(String uuid, SecurityCtx securityCtx) {
|
||||||
return hasAccess(uuid, securityCtx)
|
return hasAccess(uuid, securityCtx)
|
||||||
.chain(m -> categoryRepository.list("compet.uuid = ?1", uuid)
|
.chain(m -> categoryRepository.list("compet.uuid = ?1", uuid)
|
||||||
.chain(cats -> matchRepository.list("(c1_id = ?1 OR c2_id = ?1 OR True) AND category IN ?2", //TODO rm OR True
|
.chain(cats -> matchRepository.list(
|
||||||
|
"(c1_id = ?1 OR c2_id = ?1 OR True) AND category IN ?2", //TODO rm OR True
|
||||||
m.getMembre(), cats)))
|
m.getMembre(), cats)))
|
||||||
.map(matchModels -> {
|
.map(matchModels -> {
|
||||||
HashMap<Long, List<MatchModel>> map = new HashMap<>();
|
HashMap<Long, List<MatchModel>> map = new HashMap<>();
|
||||||
@ -82,6 +99,8 @@ public class ResultService {
|
|||||||
CategoryModel categoryModel = matchModels.get(0).getCategory();
|
CategoryModel categoryModel = matchModels.get(0).getCategory();
|
||||||
out.setName(categoryModel.getName());
|
out.setName(categoryModel.getName());
|
||||||
out.setType(categoryModel.getType());
|
out.setType(categoryModel.getType());
|
||||||
|
out.setLiceName(categoryModel.getLiceName() == null ? new String[]{} : categoryModel.getLiceName().split(";"));
|
||||||
|
out.setGenTime(System.currentTimeMillis());
|
||||||
|
|
||||||
getArray2(matchModels, out);
|
getArray2(matchModels, out);
|
||||||
getTree(categoryModel.getTree(), out);
|
getTree(categoryModel.getTree(), out);
|
||||||
@ -173,6 +192,12 @@ public class ResultService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Uni<ResultCategoryData> getCategoryPublic(String uuid, long poule) {
|
||||||
|
return matchRepository.list("category.compet.uuid = ?1 AND category.id = ?2", uuid, poule)
|
||||||
|
.call(list -> Mutiny.fetch(list.get(0).getCategory().getTree()))
|
||||||
|
.map(this::getData);
|
||||||
|
}
|
||||||
|
|
||||||
private void getTree(List<TreeModel> treeModels, ResultCategoryData out) {
|
private void getTree(List<TreeModel> treeModels, ResultCategoryData out) {
|
||||||
ArrayList<TreeNode<ResultCategoryData.TreeData>> trees = new ArrayList<>();
|
ArrayList<TreeNode<ResultCategoryData.TreeData>> trees = new ArrayList<>();
|
||||||
treeModels.stream().filter(t -> t.getLevel() != 0).forEach(treeModel -> {
|
treeModels.stream().filter(t -> t.getLevel() != 0).forEach(treeModel -> {
|
||||||
@ -185,7 +210,15 @@ public class ResultService {
|
|||||||
|
|
||||||
public Uni<CombsArrayData> getAllCombArray(String uuid, SecurityCtx securityCtx) {
|
public Uni<CombsArrayData> getAllCombArray(String uuid, SecurityCtx securityCtx) {
|
||||||
return hasAccess(uuid, securityCtx)
|
return hasAccess(uuid, securityCtx)
|
||||||
.chain(cm_register -> registerRepository.list("competition.uuid = ?1", uuid)
|
.chain(__ -> getAllCombArray(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uni<CombsArrayData> getAllCombArrayPublic(String uuid) {
|
||||||
|
return getAllCombArray(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uni<CombsArrayData> getAllCombArray(String uuid) {
|
||||||
|
return registerRepository.list("competition.uuid = ?1", uuid)
|
||||||
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
|
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
|
||||||
.map(matchModels -> new Pair<>(registers, matchModels)))
|
.map(matchModels -> new Pair<>(registers, matchModels)))
|
||||||
.map(pair -> {
|
.map(pair -> {
|
||||||
@ -262,10 +295,145 @@ public class ResultService {
|
|||||||
builder.combs(combs);
|
builder.combs(combs);
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uni<HashMap<String, String>> getCombList(String uuid) {
|
||||||
|
return registerRepository.list("competition.uuid = ?1", uuid)
|
||||||
|
.map(models -> {
|
||||||
|
HashMap<String, String> map = new HashMap<>();
|
||||||
|
models.forEach(registerEmbeddable -> {
|
||||||
|
map.put(Utils.getFullName(registerEmbeddable.getMembre()),
|
||||||
|
registerEmbeddable.getMembre().getFname() + "¤" + registerEmbeddable.getMembre()
|
||||||
|
.getLname());
|
||||||
|
});
|
||||||
|
return map;
|
||||||
|
})
|
||||||
|
.chain(map -> competitionGuestRepository.list("competition.uuid = ?1", uuid)
|
||||||
|
.map(models -> {
|
||||||
|
models.forEach(guestModel -> map.put(Utils.getFullName(guestModel),
|
||||||
|
guestModel.getFname() + "¤" + guestModel.getLname()));
|
||||||
|
return map;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Uni<?> getCombArrayPublic(String uuid, String fname, String lname) {
|
||||||
|
CombArrayData.CombArrayDataBuilder builder = CombArrayData.builder();
|
||||||
|
AtomicBoolean guest = new AtomicBoolean(false);
|
||||||
|
AtomicLong id = new AtomicLong(0);
|
||||||
|
|
||||||
|
|
||||||
|
return registerRepository.find("membre.fname = ?1 AND membre.lname = ?2 AND competition.uuid = ?3", fname,
|
||||||
|
lname, uuid).firstResult()
|
||||||
|
.chain(registerModel -> {
|
||||||
|
if (registerModel == null) {
|
||||||
|
return competitionGuestRepository.find("fname = ?1 AND lname = ?2 AND competition.uuid = ?3",
|
||||||
|
fname, lname, uuid).firstResult()
|
||||||
|
.chain(guestModel -> {
|
||||||
|
builder.name(Utils.getFullName(guestModel));
|
||||||
|
builder.club(guestModel.getClub());
|
||||||
|
guest.set(true);
|
||||||
|
id.set(guestModel.getId());
|
||||||
|
builder.cat((guestModel.getCategorie() == null) ? "---" : guestModel.getCategorie()
|
||||||
|
.getName(BUNDLE));
|
||||||
|
|
||||||
|
return matchRepository.list(
|
||||||
|
"category.compet.uuid = ?1 AND (c1_guest = ?2 OR c2_guest = ?2)", uuid,
|
||||||
|
guestModel);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
builder.name(Utils.getFullName(registerModel.getMembre()));
|
||||||
|
builder.club((registerModel.getClub2() == null) ? BUNDLE.getString(
|
||||||
|
"no.licence") : registerModel.getClub2().getName());
|
||||||
|
id.set(registerModel.getMembre().getId());
|
||||||
|
builder.cat((registerModel.getCategorie2() == null) ? "---" : registerModel.getCategorie2()
|
||||||
|
.getName(BUNDLE));
|
||||||
|
|
||||||
|
return matchRepository.list("category.compet.uuid = ?1 AND (c1_id = ?2 OR c2_id = ?2)", uuid,
|
||||||
|
registerModel.getMembre());
|
||||||
|
})
|
||||||
|
.invoke(matchModels -> {
|
||||||
|
List<CategoryModel> pouleModels = matchModels.stream().map(MatchModel::getCategory).distinct()
|
||||||
|
.toList();
|
||||||
|
List<CombArrayData.MatchsData> matchs = new ArrayList<>();
|
||||||
|
|
||||||
|
AtomicInteger sumW = new AtomicInteger();
|
||||||
|
AtomicInteger sumPointMake = new AtomicInteger(0);
|
||||||
|
AtomicInteger sumPointTake = new AtomicInteger(0);
|
||||||
|
|
||||||
|
for (MatchModel matchModel : matchModels) {
|
||||||
|
if ((matchModel.getC1_id() == null && matchModel.getC1_guest() == null) ||
|
||||||
|
(matchModel.getC2_id() == null && matchModel.getC2_guest() == null))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var builder2 = CombArrayData.MatchsData.builder();
|
||||||
|
builder2.date(matchModel.getDate());
|
||||||
|
builder2.poule(pouleModels.stream().filter(p -> p.equals(matchModel.getCategory()))
|
||||||
|
.map(CategoryModel::getName).findFirst().orElse(""));
|
||||||
|
|
||||||
|
AtomicInteger pointMake = new AtomicInteger();
|
||||||
|
AtomicInteger pointTake = new AtomicInteger();
|
||||||
|
|
||||||
|
if ((!guest.get() && matchModel.getC1_id() != null && matchModel.getC1_id().getId() == id.get())
|
||||||
|
|| (guest.get() && matchModel.getC1_guest() != null && matchModel.getC1_guest()
|
||||||
|
.getId() == id.get())) {
|
||||||
|
builder2.adv(Utils.getFullName(matchModel.getC2_id(), matchModel.getC2_guest()));
|
||||||
|
if (matchModel.isEnd()) {
|
||||||
|
matchModel.getScores().stream()
|
||||||
|
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||||
|
.forEach(scoreEntity -> {
|
||||||
|
pointMake.addAndGet(scoreEntity.getS1());
|
||||||
|
pointTake.addAndGet(scoreEntity.getS2());
|
||||||
|
});
|
||||||
|
builder2.score(matchModel.getScores().stream()
|
||||||
|
.map(s -> new Integer[]{s.getS1(), s.getS2()}).toList());
|
||||||
|
} else {
|
||||||
|
builder2.score(new ArrayList<>());
|
||||||
|
}
|
||||||
|
builder2.win(matchModel.win() > 0);
|
||||||
|
} else {
|
||||||
|
builder2.adv(Utils.getFullName(matchModel.getC1_id(), matchModel.getC1_guest()));
|
||||||
|
if (matchModel.isEnd()) {
|
||||||
|
matchModel.getScores().stream()
|
||||||
|
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||||
|
.forEach(scoreEntity -> {
|
||||||
|
pointMake.addAndGet(scoreEntity.getS2());
|
||||||
|
pointTake.addAndGet(scoreEntity.getS1());
|
||||||
|
});
|
||||||
|
builder2.score(matchModel.getScores().stream()
|
||||||
|
.map(s -> new Integer[]{s.getS2(), s.getS1()}).toList());
|
||||||
|
} else {
|
||||||
|
builder2.score(new ArrayList<>());
|
||||||
|
}
|
||||||
|
builder2.win(matchModel.win() < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder2.ratio(
|
||||||
|
(pointTake.get() == 0) ? pointMake.get() : (float) pointMake.get() / pointTake.get());
|
||||||
|
|
||||||
|
sumPointMake.addAndGet(pointMake.get());
|
||||||
|
sumPointTake.addAndGet(pointTake.get());
|
||||||
|
|
||||||
|
matchs.add(builder2.build());
|
||||||
|
if (builder2.win)
|
||||||
|
sumW.getAndIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.totalWin(sumW.get());
|
||||||
|
builder.pointRatio(
|
||||||
|
(sumPointTake.get() == 0) ? sumPointMake.get() : (float) sumPointMake.get() / sumPointTake.get());
|
||||||
|
builder.pointMake(sumPointMake.get());
|
||||||
|
builder.pointTake(sumPointTake.get());
|
||||||
|
|
||||||
|
matchs.sort(Comparator.comparing(CombArrayData.MatchsData::poule)
|
||||||
|
.thenComparing(CombArrayData.MatchsData::adv));
|
||||||
|
|
||||||
|
builder.matchs(matchs);
|
||||||
|
})
|
||||||
|
.map(__ -> builder.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
@RegisterForReflection
|
@RegisterForReflection
|
||||||
@ -277,13 +445,40 @@ public class ResultService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Uni<ClubArrayData> getClubArray(String uuid, SecurityCtx securityCtx) {
|
@Builder
|
||||||
ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder();
|
@RegisterForReflection
|
||||||
|
public static record CombArrayData(String name, String club, String cat, int totalWin,
|
||||||
|
float pointRatio, int pointMake, int pointTake, List<MatchsData> matchs) {
|
||||||
|
@Builder
|
||||||
|
@RegisterForReflection
|
||||||
|
public static record MatchsData(Date date, String poule, String adv, List<Integer[]> score, float ratio,
|
||||||
|
boolean win) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return hasAccess(uuid, securityCtx)
|
public Uni<HashMap<String, Long>> getClubList(String uuid) { // TODO add guest club
|
||||||
.invoke(cm_register -> builder.name(cm_register.getClub2().getName()))
|
return registerRepository.list("competition.uuid = ?1", uuid)
|
||||||
.chain(cm_register -> registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid,
|
.map(registers -> {
|
||||||
cm_register.getClub2())
|
HashMap<String, Long> registerMap = new HashMap<>();
|
||||||
|
registers.stream().map(RegisterModel::getClub2).distinct().filter(Objects::nonNull)
|
||||||
|
.forEach(registerClub -> registerMap.put(registerClub.getName(), registerClub.getId()));
|
||||||
|
return registerMap;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uni<ClubArrayData> getClubArray(String uuid, SecurityCtx securityCtx) {
|
||||||
|
return hasAccess(uuid, securityCtx).chain(cm_register -> getClubArray(uuid, cm_register.getClub2()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uni<ClubArrayData> getClubArrayPublic(String uuid, Long id) {
|
||||||
|
return clubRepository.findById(id).chain(clubModel -> getClubArray(uuid, clubModel));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Uni<ClubArrayData> getClubArray(String uuid, ClubModel clubModel) {
|
||||||
|
ClubArrayData.ClubArrayDataBuilder builder = ClubArrayData.builder();
|
||||||
|
builder.name(clubModel.getName());
|
||||||
|
|
||||||
|
return registerRepository.list("competition.uuid = ?1 AND membre.club = ?2", uuid, clubModel)
|
||||||
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
|
.chain(registers -> matchRepository.list("category.compet.uuid = ?1", uuid)
|
||||||
.map(matchModels -> new Pair<>(registers, matchModels)))
|
.map(matchModels -> new Pair<>(registers, matchModels)))
|
||||||
.map(pair -> {
|
.map(pair -> {
|
||||||
@ -295,9 +490,7 @@ public class ResultService {
|
|||||||
AtomicInteger tt_win = new AtomicInteger(0);
|
AtomicInteger tt_win = new AtomicInteger(0);
|
||||||
AtomicInteger tt_match = new AtomicInteger(0);
|
AtomicInteger tt_match = new AtomicInteger(0);
|
||||||
|
|
||||||
List<ClubArrayData.CombData> combData = registers.stream()
|
List<ClubArrayData.CombData> combData = registers.stream().map(register -> {
|
||||||
.map(register -> {
|
|
||||||
|
|
||||||
var builder2 = ClubArrayData.CombData.builder();
|
var builder2 = ClubArrayData.CombData.builder();
|
||||||
AtomicInteger w = new AtomicInteger(0);
|
AtomicInteger w = new AtomicInteger(0);
|
||||||
AtomicInteger l = new AtomicInteger(0);
|
AtomicInteger l = new AtomicInteger(0);
|
||||||
@ -309,10 +502,8 @@ public class ResultService {
|
|||||||
|| register.getMembre().equals(m.getC2_id())))
|
|| register.getMembre().equals(m.getC2_id())))
|
||||||
.forEach(matchModel -> {
|
.forEach(matchModel -> {
|
||||||
int win = matchModel.win();
|
int win = matchModel.win();
|
||||||
if ((register.getMembre()
|
if ((register.getMembre().equals(matchModel.getC1_id()) && win > 0) ||
|
||||||
.equals(matchModel.getC1_id()) && win > 0) ||
|
register.getMembre().equals(matchModel.getC2_id()) && win < 0) {
|
||||||
register.getMembre()
|
|
||||||
.equals(matchModel.getC2_id()) && win < 0) {
|
|
||||||
w.getAndIncrement();
|
w.getAndIncrement();
|
||||||
} else {
|
} else {
|
||||||
l.getAndIncrement();
|
l.getAndIncrement();
|
||||||
@ -321,8 +512,7 @@ public class ResultService {
|
|||||||
matchModel.getScores().stream()
|
matchModel.getScores().stream()
|
||||||
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
.filter(s -> s.getS1() > -900 && s.getS2() > -900)
|
||||||
.forEach(score -> {
|
.forEach(score -> {
|
||||||
if (register.getMembre()
|
if (register.getMembre().equals(matchModel.getC1_id())) {
|
||||||
.equals(matchModel.getC1_id())) {
|
|
||||||
pointMake.addAndGet(score.getS1());
|
pointMake.addAndGet(score.getS1());
|
||||||
pointTake.addAndGet(score.getS2());
|
pointTake.addAndGet(score.getS2());
|
||||||
} else {
|
} else {
|
||||||
@ -365,8 +555,7 @@ public class ResultService {
|
|||||||
builder.combs(combData);
|
builder.combs(combData);
|
||||||
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
})
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Builder
|
@Builder
|
||||||
|
|||||||
@ -0,0 +1,23 @@
|
|||||||
|
package fr.titionfire.ffsaf.domain.service;
|
||||||
|
|
||||||
|
import jakarta.enterprise.context.ApplicationScoped;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@ApplicationScoped
|
||||||
|
public class UpdateService { // For public result page
|
||||||
|
static HashMap<Long, Long> lastUpdate = new HashMap<>();
|
||||||
|
|
||||||
|
public void setNewData(long id) {
|
||||||
|
lastUpdate.put(id, System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean needUpdate(long id, long last_update) {
|
||||||
|
if (!lastUpdate.containsKey(id)) {
|
||||||
|
lastUpdate.put(id, System.currentTimeMillis() - 5000);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastUpdate.getOrDefault(id, 0L) > last_update;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,85 @@
|
|||||||
|
package fr.titionfire.ffsaf.rest;
|
||||||
|
|
||||||
|
import fr.titionfire.ffsaf.domain.service.ResultService;
|
||||||
|
import fr.titionfire.ffsaf.domain.service.UpdateService;
|
||||||
|
import io.smallrye.mutiny.Uni;
|
||||||
|
import jakarta.inject.Inject;
|
||||||
|
import jakarta.ws.rs.*;
|
||||||
|
import jakarta.ws.rs.core.MediaType;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
@Path("api/public/result/{id}")
|
||||||
|
public class ExternalResultEndpoints {
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
ResultService resultService;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
UpdateService updateService;
|
||||||
|
|
||||||
|
@PathParam("id")
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/poule/list")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Uni<HashMap<String, Long>> list() {
|
||||||
|
return resultService.getCategoryList(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/poule/data")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Uni<?> getArray(@QueryParam("poule") long poule, @DefaultValue("-1") @QueryParam("rf") long rf) {
|
||||||
|
if (poule == 0)
|
||||||
|
return Uni.createFrom().voidItem();
|
||||||
|
|
||||||
|
if (updateService.needUpdate(poule, rf)) {
|
||||||
|
return resultService.getCategoryPublic(id, poule);
|
||||||
|
} else {
|
||||||
|
return Uni.createFrom().voidItem();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/comb/list")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Uni<HashMap<String, String>> combList() {
|
||||||
|
return resultService.getCombList(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/comb/data")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Uni<?> getArray(@QueryParam("comb") String comb) {
|
||||||
|
if (comb.equals("0"))
|
||||||
|
return Uni.createFrom().item("");
|
||||||
|
return resultService.getCombArrayPublic(id, comb.substring(0, comb.indexOf('¤')), comb.substring(comb.indexOf('¤') + 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/comb/get_all")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Uni<?> getAll() {
|
||||||
|
return resultService.getAllCombArrayPublic(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/club/list")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Uni<HashMap<String, Long>> clubList() {
|
||||||
|
return resultService.getClubList(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/club/data")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
public Uni<?> getClubArray(@QueryParam("club") long club) {
|
||||||
|
if (club == 0)
|
||||||
|
return Uni.createFrom().item("");
|
||||||
|
return resultService.getClubArrayPublic(id, club);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -21,6 +21,8 @@ public class ResultCategoryData {
|
|||||||
HashMap<Character, List<PouleArrayData>> matchs = new HashMap<>();
|
HashMap<Character, List<PouleArrayData>> matchs = new HashMap<>();
|
||||||
HashMap<Character, List<RankArray>> rankArray = new HashMap<>();
|
HashMap<Character, List<RankArray>> rankArray = new HashMap<>();
|
||||||
ArrayList<TreeNode<TreeData>> trees;
|
ArrayList<TreeNode<TreeData>> trees;
|
||||||
|
String[] liceName;
|
||||||
|
long genTime;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
package fr.titionfire.ffsaf.utils;
|
package fr.titionfire.ffsaf.utils;
|
||||||
|
|
||||||
|
import fr.titionfire.ffsaf.data.model.CompetitionGuestModel;
|
||||||
|
import fr.titionfire.ffsaf.data.model.MembreModel;
|
||||||
import io.smallrye.mutiny.Uni;
|
import io.smallrye.mutiny.Uni;
|
||||||
import jakarta.ws.rs.core.HttpHeaders;
|
import jakarta.ws.rs.core.HttpHeaders;
|
||||||
import jakarta.ws.rs.core.MediaType;
|
import jakarta.ws.rs.core.MediaType;
|
||||||
@ -365,4 +367,16 @@ public class Utils {
|
|||||||
}
|
}
|
||||||
return result.toString().trim();
|
return result.toString().trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String getFullName(Object ...models) {
|
||||||
|
for (Object model : models){
|
||||||
|
if (model == null)
|
||||||
|
continue;
|
||||||
|
if (model instanceof MembreModel membreModel)
|
||||||
|
return membreModel.getFname() + " " + membreModel.getLname();
|
||||||
|
if (model instanceof CompetitionGuestModel guestModel)
|
||||||
|
return guestModel.getFname() + " " + guestModel.getLname();
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,6 +75,4 @@ helloasso.client-id=changeme
|
|||||||
helloasso.client-secret=changeme
|
helloasso.client-secret=changeme
|
||||||
|
|
||||||
quarkus.rest-client.helloasso-auth.url=${helloasso.api}/oauth2
|
quarkus.rest-client.helloasso-auth.url=${helloasso.api}/oauth2
|
||||||
quarkus.rest-client.helloasso-auth.scope=javax.inject.Singleton
|
|
||||||
|
|
||||||
quarkus.rest-client.helloasso-api.url=${helloasso.api}/v5
|
quarkus.rest-client.helloasso-api.url=${helloasso.api}/v5
|
||||||
|
|||||||
1
src/main/webapp/.gitignore
vendored
1
src/main/webapp/.gitignore
vendored
@ -22,3 +22,4 @@ dist-ssr
|
|||||||
*.njsproj
|
*.njsproj
|
||||||
*.sln
|
*.sln
|
||||||
*.sw?
|
*.sw?
|
||||||
|
/public/result_test.html
|
||||||
|
|||||||
946
src/main/webapp/public/competition.js
Normal file
946
src/main/webapp/public/competition.js
Normal file
@ -0,0 +1,946 @@
|
|||||||
|
let apiUrlRoot = "";
|
||||||
|
const rootDiv = document.getElementById("safca_api_data");
|
||||||
|
|
||||||
|
const header = `<h4>Résultat de la compétition :</h4>`
|
||||||
|
const backButton = `<a onclick="setSubPage('home')" href="javascript:void(0);">Retour</a>`
|
||||||
|
const cupImg = `<img decoding="async" loading="lazy" width="16" height="16" class="wp-image-1635"
|
||||||
|
style="width: 16px;" src="https://intra.ffsaf.fr/img/171891.png"
|
||||||
|
alt="">`
|
||||||
|
|
||||||
|
const voidFunction = () => {
|
||||||
|
}
|
||||||
|
let lastRf = 0;
|
||||||
|
let rfFonction = voidFunction;
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
rfFonction();
|
||||||
|
}, 15000);
|
||||||
|
|
||||||
|
function setSubPage(name) {
|
||||||
|
window.location.hash = name;
|
||||||
|
const location = name.split('/');
|
||||||
|
console.log(location);
|
||||||
|
|
||||||
|
switch (location[0]) {
|
||||||
|
case 'home':
|
||||||
|
homePage();
|
||||||
|
break;
|
||||||
|
case 'poule':
|
||||||
|
poulePage(location);
|
||||||
|
break;
|
||||||
|
case 'comb':
|
||||||
|
combPage(location);
|
||||||
|
break;
|
||||||
|
case 'club':
|
||||||
|
clubPage(location);
|
||||||
|
break;
|
||||||
|
case 'all':
|
||||||
|
combsPage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function homePage() {
|
||||||
|
rootDiv.innerHTML = header;
|
||||||
|
|
||||||
|
let content = document.createElement('div');
|
||||||
|
content.innerHTML = `
|
||||||
|
<ul>
|
||||||
|
<li><a onclick="setSubPage('poule')" href="javascript:void(0);">Par poule</a></li>
|
||||||
|
<li><a onclick="setSubPage('comb')" href="javascript:void(0);">Par combattant</a></li>
|
||||||
|
<li><a onclick="setSubPage('club')" href="javascript:void(0);">Par club</a></li>
|
||||||
|
<li><a onclick="setSubPage('all')" href="javascript:void(0);">Tous les combattants</a></li>
|
||||||
|
</ul>
|
||||||
|
`
|
||||||
|
rootDiv.append(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
let loadingAnimationStep = 0;
|
||||||
|
|
||||||
|
function startLoading(root) {
|
||||||
|
const id = "loading" + Math.random().toString(36);
|
||||||
|
let element = document.createElement('h2');
|
||||||
|
element.id = id;
|
||||||
|
|
||||||
|
const anim = setInterval(() => {
|
||||||
|
let str = "Chargement";
|
||||||
|
for (let i = 0; i < loadingAnimationStep; i++) {
|
||||||
|
str += ".";
|
||||||
|
}
|
||||||
|
loadingAnimationStep = (loadingAnimationStep + 1) % 4;
|
||||||
|
element.innerText = str;
|
||||||
|
}, 500);
|
||||||
|
|
||||||
|
root.append(element)
|
||||||
|
return {interval: anim, root: root, element: element};
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopLoading(loading) {
|
||||||
|
clearInterval(loading['interval']);
|
||||||
|
loading['root'].removeChild(loading['element']);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scoreToString(score) {
|
||||||
|
const scorePrint = (s1) => {
|
||||||
|
switch (s1) {
|
||||||
|
case -997:
|
||||||
|
return "disc.";
|
||||||
|
case -998:
|
||||||
|
return "abs.";
|
||||||
|
case -999:
|
||||||
|
return "for.";
|
||||||
|
case -1000:
|
||||||
|
return "";
|
||||||
|
default:
|
||||||
|
return String(s1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score.map(o => scorePrint(o.at(0)) + "-" + scorePrint(o.at(1))).join(" | ");
|
||||||
|
}
|
||||||
|
|
||||||
|
function dateToString(date) {
|
||||||
|
if (date === null || date === undefined)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
const date_ = new Date(date);
|
||||||
|
const date_2 = new Date(date);
|
||||||
|
const current = new Date();
|
||||||
|
current.setHours(0, 0, 0, 0);
|
||||||
|
date_2.setHours(0, 0, 0, 0);
|
||||||
|
|
||||||
|
let d = Math.floor((current - date_2) / (1000 * 60 * 60 * 24));
|
||||||
|
if (d === 0)
|
||||||
|
return "Aujourd'hui à " + date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"});
|
||||||
|
else if (d === 1)
|
||||||
|
return "Hier à " + date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"});
|
||||||
|
else if (d === 2)
|
||||||
|
return "Avant-hier à " + date_.toLocaleTimeString([], {hour: "2-digit", minute: "2-digit"});
|
||||||
|
else
|
||||||
|
return date_.toLocaleDateString();
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildPouleMenu(isPoule, change_view) {
|
||||||
|
const menuDiv = document.createElement('div');
|
||||||
|
menuDiv.id = 'menu';
|
||||||
|
menuDiv.style.borderBottom = '1px solid #9EA0A1';
|
||||||
|
menuDiv.style.paddingBottom = '25px';
|
||||||
|
|
||||||
|
const ul = document.createElement('ul');
|
||||||
|
ul.id = 'onglets';
|
||||||
|
ul.style.position = 'absolute';
|
||||||
|
ul.style.border = '1px solid transparent';
|
||||||
|
ul.style.padding = '0';
|
||||||
|
ul.style.font = 'bold 11px Batang, arial, serif';
|
||||||
|
ul.style.listStyleType = 'none';
|
||||||
|
ul.style.left = '50%';
|
||||||
|
ul.style.marginTop = '0';
|
||||||
|
ul.style.width = '430px';
|
||||||
|
ul.style.marginLeft = '-215px';
|
||||||
|
|
||||||
|
function createTab(text, isActive, onClickHandler) {
|
||||||
|
const li = document.createElement('li');
|
||||||
|
if (isActive) {
|
||||||
|
li.className = 'active';
|
||||||
|
li.style.borderBottom = '1px solid #fff';
|
||||||
|
li.style.backgroundColor = '#fff';
|
||||||
|
} else {
|
||||||
|
li.style.backgroundColor = '#F4F9FD';
|
||||||
|
}
|
||||||
|
li.style.float = 'left';
|
||||||
|
li.style.height = '21px';
|
||||||
|
li.style.margin = '2px 2px 0 2px !important';
|
||||||
|
li.style.margin = '1px 2px 0 2px';
|
||||||
|
li.style.border = '1px solid #9EA0A1';
|
||||||
|
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = 'javascript:void(0);';
|
||||||
|
a.onclick = onClickHandler;
|
||||||
|
a.textContent = text;
|
||||||
|
a.style.display = 'block';
|
||||||
|
a.style.color = '#666';
|
||||||
|
a.style.textDecoration = 'none';
|
||||||
|
a.style.padding = '4px';
|
||||||
|
|
||||||
|
a.addEventListener('mouseover', function () {
|
||||||
|
a.style.background = '#fff';
|
||||||
|
});
|
||||||
|
|
||||||
|
a.addEventListener('mouseout', function () {
|
||||||
|
if (!isActive)
|
||||||
|
a.style.background = '#F4F9FD';
|
||||||
|
});
|
||||||
|
|
||||||
|
li.appendChild(a);
|
||||||
|
return li;
|
||||||
|
}
|
||||||
|
|
||||||
|
const li1 = createTab('Poule', isPoule, function () {
|
||||||
|
change_view(true);
|
||||||
|
});
|
||||||
|
ul.appendChild(li1);
|
||||||
|
const li2 = createTab('Tournois', !isPoule, function () {
|
||||||
|
change_view(false);
|
||||||
|
});
|
||||||
|
ul.appendChild(li2);
|
||||||
|
|
||||||
|
menuDiv.appendChild(ul);
|
||||||
|
|
||||||
|
return menuDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildMatchArray(matchs) {
|
||||||
|
const pouleDiv = document.createElement('div');
|
||||||
|
let arrayContent = `
|
||||||
|
<figure class="wp-block-table is-style-stripes" style="font-size: 16px">
|
||||||
|
<table style="width: 800px;overflow: auto"><thead>
|
||||||
|
<tr>
|
||||||
|
<th class="has-text-align-center" data-align="center">Rouge</th>
|
||||||
|
<th class="has-text-align-center" data-align="center"></th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Scores</th>
|
||||||
|
<th class="has-text-align-center" data-align="center"></th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Bleu</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Date</th>
|
||||||
|
</tr>
|
||||||
|
</thead><tbody>`
|
||||||
|
for (const match of matchs) {
|
||||||
|
arrayContent += `
|
||||||
|
<tr>
|
||||||
|
<td class="has-text-align-right" data-align="right">${match.red}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${match.red_w ? cupImg : ""}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${scoreToString(match.score)}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${match.blue_w ? cupImg : ""}</td>
|
||||||
|
<td class="has-text-align-left" data-align="left">${match.blue}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${dateToString((match.red_w || match.blue_w) ? match.date : null)}</td>
|
||||||
|
</tr>`
|
||||||
|
}
|
||||||
|
arrayContent += `</tbody></table></figure>`
|
||||||
|
pouleDiv.innerHTML = arrayContent;
|
||||||
|
return pouleDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildRankArray(rankArray) {
|
||||||
|
const arrayDiv = document.createElement('div');
|
||||||
|
let arrayContent = `<figure class="wp-block-table is-style-stripes" style="font-size: 16px; margin-top: 2em">
|
||||||
|
<table style="width: 600px;overflow: auto">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="has-text-align-center" data-align="center">Place</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Nom</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Victoire</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Ratio</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Points marqués</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Points reçus</th>
|
||||||
|
</tr>
|
||||||
|
</thead><tbody>`
|
||||||
|
for (const row of rankArray) {
|
||||||
|
arrayContent += `
|
||||||
|
<tr>
|
||||||
|
<td class="has-text-align-center" data-align="center">${row.rank}</td>
|
||||||
|
<td class="has-text-align-left" data-align="left">${row.name}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${row.win}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${row.pointRate.toFixed(3)}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${row.pointMake}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${row.pointTake}</td>
|
||||||
|
</tr>`
|
||||||
|
|
||||||
|
}
|
||||||
|
arrayContent += `</tbody></table></figure>`
|
||||||
|
arrayDiv.innerHTML = arrayContent;
|
||||||
|
return arrayDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTree(treeData) {
|
||||||
|
return drawGraph(initTree(treeData))
|
||||||
|
}
|
||||||
|
|
||||||
|
function poulePage(location) {
|
||||||
|
rootDiv.innerHTML = header + backButton;
|
||||||
|
const content = document.createElement('div');
|
||||||
|
content.style.marginTop = '1em';
|
||||||
|
content.innerHTML = '<h4>Recherche par poule</h4>';
|
||||||
|
|
||||||
|
const dataContainer = document.createElement('div');
|
||||||
|
dataContainer.id = 'data-container';
|
||||||
|
|
||||||
|
let currentPoule = 0;
|
||||||
|
const loadPoule = () => {
|
||||||
|
const loading = startLoading(content);
|
||||||
|
fetch(`${apiUrlRoot}/poule/data?poule=${currentPoule}&rf=${lastRf}`)
|
||||||
|
.then(response => {
|
||||||
|
if (response.status === 204) // No content => no update
|
||||||
|
return;
|
||||||
|
|
||||||
|
response.json().then(poule => {
|
||||||
|
lastRf = (poule.genTime !== undefined) ? poule.genTime : 0;
|
||||||
|
// console.log(poule);
|
||||||
|
|
||||||
|
if (location.length === 3 && poule.type < 3) {
|
||||||
|
location.pop();
|
||||||
|
window.location.hash = location.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
dataContainer.replaceChildren();
|
||||||
|
|
||||||
|
if (poule.type === 1) {
|
||||||
|
for (const g in poule.matchs) {
|
||||||
|
if (Object.keys(poule.matchs).length > 1) {
|
||||||
|
const text = document.createElement('h4');
|
||||||
|
text.textContent = `Groupe ${g}`;
|
||||||
|
text.style.marginTop = '2em';
|
||||||
|
dataContainer.append(text);
|
||||||
|
}
|
||||||
|
dataContainer.append(buildMatchArray(poule.matchs[g]));
|
||||||
|
dataContainer.append(buildRankArray(poule.rankArray[g]));
|
||||||
|
}
|
||||||
|
} else if (poule.type === 2) {
|
||||||
|
dataContainer.append(buildTree(poule['trees']));
|
||||||
|
} else {
|
||||||
|
const change_view = (isPoule) => {
|
||||||
|
dataContainer.replaceChildren(buildPouleMenu(isPoule, change_view));
|
||||||
|
|
||||||
|
if (isPoule) {
|
||||||
|
for (const g in poule.matchs) {
|
||||||
|
if (Object.keys(poule.matchs).length > 1) {
|
||||||
|
const text = document.createElement('h4');
|
||||||
|
text.textContent = `Groupe ${g}`;
|
||||||
|
text.style.marginTop = '2em';
|
||||||
|
dataContainer.append(text);
|
||||||
|
}
|
||||||
|
dataContainer.append(buildMatchArray(poule.matchs[g]));
|
||||||
|
dataContainer.append(buildRankArray(poule.rankArray[g]));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dataContainer.append(buildTree(poule['trees']));
|
||||||
|
}
|
||||||
|
|
||||||
|
location[2] = isPoule ? 1 : 2;
|
||||||
|
window.location.hash = location.join('/');
|
||||||
|
}
|
||||||
|
change_view((location.length === 3) ? location[2] === '1' : true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.error(e);
|
||||||
|
dataContainer.replaceChildren(new Text("Erreur de chargement de la poule"));
|
||||||
|
})
|
||||||
|
.finally(() => stopLoading(loading));
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = startLoading(content);
|
||||||
|
fetch(`${apiUrlRoot}/poule/list`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(poule => {
|
||||||
|
const select = document.createElement('select');
|
||||||
|
select.setAttribute('id', poule.id);
|
||||||
|
select.innerHTML = `<option value="0">--Sélectionner une poule--</option>`;
|
||||||
|
for (const pouleKey of Object.keys(poule).sort()) {
|
||||||
|
select.innerHTML += `<option value="${poule[pouleKey]}">${pouleKey}</option>`;
|
||||||
|
}
|
||||||
|
select.addEventListener('change', e => {
|
||||||
|
location[1] = Object.keys(poule).find(key => poule[key] === Number(e.target.value));
|
||||||
|
location[1] = encodeURI(location[1]);
|
||||||
|
window.location.hash = location.join('/');
|
||||||
|
lastRf = 0;
|
||||||
|
currentPoule = e.target.value;
|
||||||
|
loadPoule();
|
||||||
|
})
|
||||||
|
content.append(select);
|
||||||
|
content.appendChild(dataContainer);
|
||||||
|
|
||||||
|
if (location.length > 1 && location[1] !== undefined && location[1] !== '') {
|
||||||
|
const tmp = poule[decodeURI(location[1])];
|
||||||
|
select.value = tmp;
|
||||||
|
currentPoule = tmp
|
||||||
|
loadPoule();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => rootDiv.append(new Text("Erreur de chargement des poules")))
|
||||||
|
.finally(() => stopLoading(loading));
|
||||||
|
|
||||||
|
rfFonction = () => {
|
||||||
|
if (currentPoule !== 0)
|
||||||
|
loadPoule();
|
||||||
|
}
|
||||||
|
|
||||||
|
rootDiv.append(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCombView(comb) {
|
||||||
|
const pouleDiv = document.createElement('div');
|
||||||
|
let arrayContent = `
|
||||||
|
<h3>Info :</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Nom Prénom : ${comb.name}</li>
|
||||||
|
<li>Club : ${comb.club}</li>
|
||||||
|
<li>Catégorie : ${comb.cat}</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Statistique :</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Taux de victoire : ${comb.matchs.length === 0 ? "---" : (comb.totalWin / comb.matchs.length * 100).toFixed(0)}% (${comb.totalWin} sur ${comb.matchs.length})</li>
|
||||||
|
<li>Points marqués : ${comb.pointMake}</li>
|
||||||
|
<li>Points reçus : ${comb.pointTake}</li>
|
||||||
|
<li>Ratio du score (point marqué / point reçu): ${comb.pointRatio.toFixed(3)}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Liste des matchs:</h3>
|
||||||
|
|
||||||
|
<figure class="wp-block-table is-style-stripes" style="font-size: 16px">
|
||||||
|
<table style="width: 700px;overflow: auto"><thead>
|
||||||
|
<tr>
|
||||||
|
<th class="has-text-align-center" data-align="center">Date</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Poule</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Adversaire</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Scores</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Ratio</th>
|
||||||
|
<th class="has-text-align-center" data-align="center"></th>
|
||||||
|
</tr>
|
||||||
|
</thead><tbody>`
|
||||||
|
for (const match of comb.matchs) {
|
||||||
|
arrayContent += `
|
||||||
|
<tr>
|
||||||
|
<td class="has-text-align-center" data-align="center">${dateToString(match.date)}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${match.poule}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${match.adv}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${scoreToString(match.score)}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${match.ratio.toFixed(3)}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${match.win ? cupImg : ""}</td>
|
||||||
|
</tr>`
|
||||||
|
}
|
||||||
|
arrayContent += `</tbody></table></figure>`
|
||||||
|
pouleDiv.innerHTML = arrayContent;
|
||||||
|
return pouleDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function combPage(location) {
|
||||||
|
rootDiv.innerHTML = header + backButton;
|
||||||
|
const content = document.createElement('div');
|
||||||
|
content.style.marginTop = '1em';
|
||||||
|
content.innerHTML = '<h4>Recherche par combattant</h4>';
|
||||||
|
|
||||||
|
const dataContainer = document.createElement('div');
|
||||||
|
dataContainer.id = 'data-container';
|
||||||
|
|
||||||
|
const loadComb = (id) => {
|
||||||
|
const loading = startLoading(content);
|
||||||
|
fetch(`${apiUrlRoot}/comb/data?comb=${id}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(comb => {
|
||||||
|
console.log(comb);
|
||||||
|
dataContainer.replaceChildren(buildCombView(comb));
|
||||||
|
})
|
||||||
|
.catch(() => dataContainer.replaceChildren(new Text("Erreur de chargement du combattant")))
|
||||||
|
.finally(() => stopLoading(loading));
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = startLoading(content);
|
||||||
|
fetch(`${apiUrlRoot}/comb/list`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(combs => {
|
||||||
|
const select = document.createElement('select');
|
||||||
|
select.innerHTML = `<option value="0">--Sélectionner un combattant--</option>`;
|
||||||
|
for (const comb of Object.keys(combs).sort()) {
|
||||||
|
select.innerHTML += `<option value="${combs[comb]}">${comb}</option>`;
|
||||||
|
}
|
||||||
|
select.addEventListener('change', e => {
|
||||||
|
location[1] = Object.keys(combs).find(key => combs[key] === e.target.value);
|
||||||
|
location[1] = encodeURI(location[1]);
|
||||||
|
window.location.hash = location.join('/');
|
||||||
|
loadComb(e.target.value);
|
||||||
|
})
|
||||||
|
content.append(select);
|
||||||
|
content.appendChild(dataContainer);
|
||||||
|
|
||||||
|
if (location.length > 1 && location[1] !== undefined && location[1] !== '') {
|
||||||
|
const tmp = combs[decodeURI(location[1])];
|
||||||
|
select.value = tmp;
|
||||||
|
loadComb(tmp);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => rootDiv.append(new Text("Erreur de chargement des combattants")))
|
||||||
|
.finally(() => stopLoading(loading));
|
||||||
|
|
||||||
|
rootDiv.append(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildClubView(club) {
|
||||||
|
const pouleDiv = document.createElement('div');
|
||||||
|
let arrayContent = `
|
||||||
|
<h3>Info :</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Nom : ${club.name}</li>
|
||||||
|
<li>Nombre d'inscris : ${club.nb_insc}</li>
|
||||||
|
</ul>
|
||||||
|
<h3>Statistique :</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Nombre de match disputé : ${club.nb_match}</li>
|
||||||
|
<li>Nombre de victoires : ${club.match_w}</li>
|
||||||
|
<li>Ratio de victoires moyen : ${club.ratioVictoire.toFixed(3)}</li>
|
||||||
|
<li>Points marqués : ${club.pointMake}</li>
|
||||||
|
<li>Points reçus : ${club.pointTake}</li>
|
||||||
|
<li>Ratio de points moyen : ${club.ratioPoint.toFixed(3)}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Liste des menbres :</h3>
|
||||||
|
|
||||||
|
<figure class="wp-block-table is-style-stripes" style="font-size: 16px">
|
||||||
|
<table style="width: 800px;overflow: auto"><thead>
|
||||||
|
<tr>
|
||||||
|
<th class="has-text-align-center" data-align="center">Catégorie</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Nom</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Victoires</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Défaites</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Ratio victoires</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Points marqués</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Points reçus</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Ratio points</th>
|
||||||
|
</tr>
|
||||||
|
</thead><tbody>`
|
||||||
|
for (const comb of club.combs) {
|
||||||
|
arrayContent += `
|
||||||
|
<tr>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.cat}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.name}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.w}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.l}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.ratioVictoire.toFixed(3)}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.pointMake}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.pointTake}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.ratioPoint.toFixed(3)}</td>
|
||||||
|
</tr>`
|
||||||
|
}
|
||||||
|
arrayContent += `</tbody></table></figure>`
|
||||||
|
pouleDiv.innerHTML = arrayContent;
|
||||||
|
return pouleDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clubPage(location) {
|
||||||
|
rootDiv.innerHTML = header + backButton;
|
||||||
|
const content = document.createElement('div');
|
||||||
|
content.style.marginTop = '1em';
|
||||||
|
content.innerHTML = '<h4>Recherche par club</h4>';
|
||||||
|
|
||||||
|
const dataContainer = document.createElement('div');
|
||||||
|
dataContainer.id = 'data-container';
|
||||||
|
|
||||||
|
const loadComb = (id) => {
|
||||||
|
const loading = startLoading(content);
|
||||||
|
fetch(`${apiUrlRoot}/club/data?club=${id}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(club => {
|
||||||
|
console.log(club);
|
||||||
|
dataContainer.replaceChildren(buildClubView(club));
|
||||||
|
})
|
||||||
|
.catch(() => dataContainer.replaceChildren(new Text("Erreur de chargement du club")))
|
||||||
|
.finally(() => stopLoading(loading));
|
||||||
|
}
|
||||||
|
|
||||||
|
const loading = startLoading(content);
|
||||||
|
fetch(`${apiUrlRoot}/club/list`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(clubs => {
|
||||||
|
const select = document.createElement('select');
|
||||||
|
select.innerHTML = `<option value="0">--Sélectionner un club--</option>`;
|
||||||
|
for (const club of Object.keys(clubs).sort()) {
|
||||||
|
select.innerHTML += `<option value="${clubs[club]}">${club}</option>`;
|
||||||
|
}
|
||||||
|
select.addEventListener('change', e => {
|
||||||
|
if (e.target.value === '0')
|
||||||
|
return;
|
||||||
|
location[1] = Object.keys(clubs).find(key => clubs[key] === Number(e.target.value));
|
||||||
|
location[1] = encodeURI(location[1]);
|
||||||
|
window.location.hash = location.join('/');
|
||||||
|
loadComb(e.target.value);
|
||||||
|
})
|
||||||
|
content.append(select);
|
||||||
|
content.appendChild(dataContainer);
|
||||||
|
|
||||||
|
if (location.length > 1 && location[1] !== undefined && location[1] !== '') {
|
||||||
|
const tmp = clubs[decodeURI(location[1])];
|
||||||
|
select.value = tmp;
|
||||||
|
loadComb(tmp);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => rootDiv.append(new Text("Erreur de chargement des clubs")))
|
||||||
|
.finally(() => stopLoading(loading));
|
||||||
|
|
||||||
|
rootDiv.append(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildCombsView(combs) {
|
||||||
|
const pouleDiv = document.createElement('div');
|
||||||
|
let arrayContent = `
|
||||||
|
<h3>Statistique :</h3>
|
||||||
|
<ul>
|
||||||
|
<li>Nombre d'inscris : ${combs.nb_insc}</li>
|
||||||
|
<li>Nombre de match disputé : ${combs.tt_match}</li>
|
||||||
|
<li>Points marqués : ${combs.point}</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Liste des combattants :</h3>
|
||||||
|
|
||||||
|
<figure class="wp-block-table is-style-stripes" style="font-size: 16px">
|
||||||
|
<table style="width: 1200px;overflow: auto"><thead>
|
||||||
|
<tr>
|
||||||
|
<th class="has-text-align-center" data-align="center">Catégorie</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Club</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Nom</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Victoires</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Défaites</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Ratio victoires</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Points marqués</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Points reçus</th>
|
||||||
|
<th class="has-text-align-center" data-align="center">Ratios points</th>
|
||||||
|
</tr>
|
||||||
|
</thead><tbody>`
|
||||||
|
for (const comb of combs.combs) {
|
||||||
|
arrayContent += `
|
||||||
|
<tr>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.cat}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.club}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.name}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.w}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.l}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.ratioVictoire.toFixed(3)}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.pointMake}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.pointTake}</td>
|
||||||
|
<td class="has-text-align-center" data-align="center">${comb.ratioPoint.toFixed(3)}</td>
|
||||||
|
</tr>`
|
||||||
|
}
|
||||||
|
arrayContent += `</tbody></table></figure>`
|
||||||
|
pouleDiv.innerHTML = arrayContent;
|
||||||
|
return pouleDiv;
|
||||||
|
}
|
||||||
|
|
||||||
|
function combsPage() {
|
||||||
|
rootDiv.innerHTML = header + backButton;
|
||||||
|
const content = document.createElement('div');
|
||||||
|
content.style.marginTop = '1em';
|
||||||
|
|
||||||
|
const dataContainer = document.createElement('div');
|
||||||
|
dataContainer.id = 'data-container';
|
||||||
|
|
||||||
|
const loading = startLoading(content);
|
||||||
|
fetch(`${apiUrlRoot}/comb/get_all`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(combs => {
|
||||||
|
console.log(combs);
|
||||||
|
dataContainer.replaceChildren(buildCombsView(combs));
|
||||||
|
})
|
||||||
|
.catch(() => dataContainer.replaceChildren(new Text("Erreur de chargement de la liste")))
|
||||||
|
.finally(() => stopLoading(loading));
|
||||||
|
|
||||||
|
content.append(dataContainer);
|
||||||
|
rootDiv.append(content)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("load", () => {
|
||||||
|
let path = document.getElementById('safca_api_script').src;
|
||||||
|
const urlParams = new URLSearchParams(new URL(path).search);
|
||||||
|
apiUrlRoot = path.substring(0, path.lastIndexOf('/')) + "/api/public/result/" + urlParams.get("id");
|
||||||
|
|
||||||
|
console.log("apiUrlRoot:", apiUrlRoot)
|
||||||
|
|
||||||
|
let hash = window.location.hash.substring(1);
|
||||||
|
if (hash.length === 0)
|
||||||
|
setSubPage('home');
|
||||||
|
else
|
||||||
|
setSubPage(hash);
|
||||||
|
});
|
||||||
|
|
||||||
|
class TreeNode {
|
||||||
|
constructor(data) {
|
||||||
|
this.data = data;
|
||||||
|
this.left = null;
|
||||||
|
this.right = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
death() {
|
||||||
|
let dg = 0;
|
||||||
|
let dd = 0;
|
||||||
|
|
||||||
|
if (this.right != null)
|
||||||
|
dg = this.right.death();
|
||||||
|
|
||||||
|
if (this.left != null)
|
||||||
|
dg = this.left.death();
|
||||||
|
|
||||||
|
return 1 + Math.max(dg, dd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initTree(data_in) {
|
||||||
|
out = [];
|
||||||
|
for (const din of data_in) {
|
||||||
|
out.push(parseTree(din));
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseTree(data_in) {
|
||||||
|
if (data_in?.data == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
let node = new TreeNode(data_in.data);
|
||||||
|
node.left = parseTree(data_in?.left);
|
||||||
|
node.right = parseTree(data_in?.right);
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
const max_x = 500;
|
||||||
|
const size = 24;
|
||||||
|
|
||||||
|
function getBounds(root) {
|
||||||
|
let px = max_x;
|
||||||
|
let py;
|
||||||
|
let maxx, minx, miny, maxy
|
||||||
|
|
||||||
|
function drawNode(tree, px, py) {
|
||||||
|
let death = tree.death() - 1
|
||||||
|
|
||||||
|
if (death === 0) {
|
||||||
|
if (miny > py - size - ((size * 1.5 / 2) | 0)) miny = py - size - (size * 1.5 / 2) | 0;
|
||||||
|
if (maxy < py + size + ((size * 1.5 / 2) | 0)) maxy = py + size + (size * 1.5 / 2) | 0;
|
||||||
|
} else {
|
||||||
|
if (miny > py - size * 2 * death - ((size * 1.5 / 2) | 0))
|
||||||
|
miny = py - size * 2 * death - ((size * 1.5 / 2) | 0);
|
||||||
|
if (maxy < py + size * 2 * death + ((size * 1.5 / 2) | 0))
|
||||||
|
maxy = py + size * 2 * death + ((size * 1.5 / 2) | 0);
|
||||||
|
}
|
||||||
|
if (minx > px - size * 2 - size * 8) minx = px - size * 2 - size * 8;
|
||||||
|
|
||||||
|
if (tree.left != null) drawNode(tree.left, px - size * 2 - size * 8, py - size * 2 * death);
|
||||||
|
if (tree.right != null) drawNode(tree.right, px - size * 2 - size * 8, py + size * 2 * death);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root != null) {
|
||||||
|
py = (size * 2 * root.at(0).death() + (((size * 1.5 / 2) | 0) + size) * root.at(0).death()) * 2;
|
||||||
|
|
||||||
|
maxx = px;
|
||||||
|
minx = px;
|
||||||
|
miny = py - (size * 1.5 / 2) | 0;
|
||||||
|
maxy = py + (size * 1.5 / 2) | 0;
|
||||||
|
|
||||||
|
for (const node of root) {
|
||||||
|
px = px - size * 2 - size * 8;
|
||||||
|
if (minx > px) minx = px;
|
||||||
|
|
||||||
|
drawNode(node, px, py);
|
||||||
|
//graphics2D.drawRect(minx, miny, maxx - minx, maxy - miny);
|
||||||
|
py = maxy + ((size * 2 * node.death() + ((size * 1.5 / 2) | 0)));
|
||||||
|
px = maxx;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
minx = 0;
|
||||||
|
maxx = 0;
|
||||||
|
miny = 0;
|
||||||
|
maxy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return [minx, maxx, miny, maxy];
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawGraph(root = []) {
|
||||||
|
const canvas = document.createElement('canvas');
|
||||||
|
canvas.id = "myCanvas";
|
||||||
|
canvas.style.border = "1px solid grey";
|
||||||
|
canvas.style.marginTop = "10px";
|
||||||
|
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
const [minx, maxx, miny, maxy] = getBounds(root);
|
||||||
|
canvas.width = maxx - minx;
|
||||||
|
canvas.height = maxy - miny;
|
||||||
|
ctx.translate(-minx, -miny);
|
||||||
|
|
||||||
|
|
||||||
|
ctx.fillStyle = "#000000"
|
||||||
|
ctx.lineWidth = 2
|
||||||
|
ctx.strokeStyle = "#000000"
|
||||||
|
|
||||||
|
function printText(s, x, y, width, height, lineG, lineD) {
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(x, y);
|
||||||
|
|
||||||
|
let tSize = 17;
|
||||||
|
let ratioX = height * 1. / 20.;
|
||||||
|
|
||||||
|
ctx.font = "100 " + tSize + "px Arial";
|
||||||
|
|
||||||
|
let mw = width - (ratioX * 2) | 0;
|
||||||
|
if (ctx.measureText(s).width > mw) {
|
||||||
|
let dTextSize = true;
|
||||||
|
do {
|
||||||
|
tSize--;
|
||||||
|
ctx.font = tSize + "px Arial";
|
||||||
|
} while (ctx.measureText(s).width > mw && tSize > 10)
|
||||||
|
|
||||||
|
if (!dTextSize || ctx.measureText(s).width > mw) {
|
||||||
|
let s = "";
|
||||||
|
for (const string2 in s.split(" ")) {
|
||||||
|
if (ctx.measureText(s + string2).width >= mw) {
|
||||||
|
s += "...";
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
s += string2 + " "
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const text = ctx.measureText(s)
|
||||||
|
let dx = (width - text.width) / 2;
|
||||||
|
let dy = ((height - text.actualBoundingBoxDescent) / 2) + (text.actualBoundingBoxAscent / 2);
|
||||||
|
|
||||||
|
ctx.fillText(s, dx, dy, width - dy);
|
||||||
|
ctx.restore();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
if (lineD) {
|
||||||
|
ctx.moveTo((ratioX * 2.5 + x + dx + text.width) | 0, y + height / 2);
|
||||||
|
ctx.lineTo(x + width, y + height / 2)
|
||||||
|
}
|
||||||
|
if (lineG) {
|
||||||
|
ctx.moveTo(x, y + height / 2);
|
||||||
|
ctx.lineTo((dx + x - ratioX * 2.5) | 0, y + height / 2)
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
function printScores(scores, px, py, scale) {
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
ctx.translate(px - size * 2, py - size * scale);
|
||||||
|
ctx.font = "100 " + 14 + "px Arial";
|
||||||
|
ctx.textBaseline = 'top';
|
||||||
|
|
||||||
|
for (let i = 0; i < scores.length; i++) {
|
||||||
|
const score = scores[i].s1+"-"+scores[i].s2;
|
||||||
|
const div = (scores.length <= 2) ? 2 : (scores.length >= 4) ? 4 : 3;
|
||||||
|
const text = ctx.measureText(score);
|
||||||
|
let dx = (size * 2 - text.width) / 2;
|
||||||
|
let dy = ((size * 2 / div - text.actualBoundingBoxDescent) / 2) + (text.actualBoundingBoxAscent / 2);
|
||||||
|
|
||||||
|
ctx.fillStyle = '#ffffffdd';
|
||||||
|
ctx.fillRect(dx, size * 2 * scale / div * (i) + dy, text.width, 14);
|
||||||
|
ctx.fillStyle = "#000000";
|
||||||
|
ctx.fillText(score, dx, size * 2 * scale / div * (i) + dy, size * 2);
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawNode(tree, px, py) {
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(px, py)
|
||||||
|
ctx.lineTo(px - size, py)
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
let death = tree.death() - 1
|
||||||
|
let match = tree.data
|
||||||
|
|
||||||
|
if (death === 0) {
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(px - size, py + size)
|
||||||
|
ctx.lineTo(px - size, py - size)
|
||||||
|
|
||||||
|
ctx.moveTo(px - size, py + size)
|
||||||
|
ctx.lineTo(px - size * 2, py + size)
|
||||||
|
ctx.moveTo(px - size, py - size)
|
||||||
|
ctx.lineTo(px - size * 2, py - size)
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
printScores(match.scores, px, py, 1);
|
||||||
|
|
||||||
|
ctx.fillStyle = "#FF0000";
|
||||||
|
printText((match.c1FullName == null) ? "" : match.c1FullName, px - size * 2 - size * 8, py - size - (size * 1.5 / 2) | 0,
|
||||||
|
size * 8, (size * 1.5) | 0, false, true)
|
||||||
|
|
||||||
|
ctx.fillStyle = "#0000FF";
|
||||||
|
printText((match.c2FullName == null) ? "" : match.c2FullName, px - size * 2 - size * 8, py + size - (size * 1.5 / 2) | 0,
|
||||||
|
size * 8, (size * 1.5) | 0, false, true)
|
||||||
|
|
||||||
|
if (max_y < py + size + ((size * 1.5 / 2) | 0)) max_y = py + size + (size * 1.5 / 2) | 0;
|
||||||
|
} else {
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(px - size, py)
|
||||||
|
ctx.lineTo(px - size, py + size * 2 * death)
|
||||||
|
ctx.moveTo(px - size, py)
|
||||||
|
ctx.lineTo(px - size, py - size * 2 * death)
|
||||||
|
|
||||||
|
ctx.moveTo(px - size, py + size * 2 * death)
|
||||||
|
ctx.lineTo(px - size * 2, py + size * 2 * death)
|
||||||
|
ctx.moveTo(px - size, py - size * 2 * death)
|
||||||
|
ctx.lineTo(px - size * 2, py - size * 2 * death)
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
printScores(match.scores, px, py, 1.5);
|
||||||
|
|
||||||
|
ctx.fillStyle = "#FF0000";
|
||||||
|
printText((match.c1FullName == null) ? "" : match.c1FullName, px - size * 2 - size * 8, py - size * 2 * death - (size * 1.5 / 2) | 0,
|
||||||
|
size * 8, (size * 1.5) | 0, true, true)
|
||||||
|
|
||||||
|
ctx.fillStyle = "#0000FF";
|
||||||
|
printText((match.c2FullName == null) ? "" : match.c2FullName, px - size * 2 - size * 8, py + size * 2 * death - (size * 1.5 / 2) | 0,
|
||||||
|
size * 8, (size * 1.5) | 0, true, true)
|
||||||
|
|
||||||
|
if (max_y < py + size * 2 * death + ((size * 1.5 / 2) | 0))
|
||||||
|
max_y = py + size * 2 * death + ((size * 1.5 / 2) | 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
if (tree.left != null) drawNode(tree.left, px - size * 2 - size * 8, py - size * 2 * death);
|
||||||
|
if (tree.right != null) drawNode(tree.right, px - size * 2 - size * 8, py + size * 2 * death);
|
||||||
|
}
|
||||||
|
|
||||||
|
function win(scores) {
|
||||||
|
let sum = 0;
|
||||||
|
for (const score of scores) {
|
||||||
|
if (score.s1 === -1000 || score.s2 === -1000)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (score.s1 > score.s2)
|
||||||
|
sum++;
|
||||||
|
else if (score.s1 < score.s2)
|
||||||
|
sum--;
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
let px = max_x;
|
||||||
|
let py;
|
||||||
|
let max_y
|
||||||
|
|
||||||
|
if (root != null) {
|
||||||
|
py = (size * 2 * root.at(0).death() + (((size * 1.5 / 2) | 0) + size) * root.at(0).death()) * 2;
|
||||||
|
|
||||||
|
max_y = py + (size * 1.5 / 2) | 0;
|
||||||
|
|
||||||
|
for (const node of root) {
|
||||||
|
let win_name = "";
|
||||||
|
if (node.data.end) {
|
||||||
|
if (win(node.data.scores) > 0)
|
||||||
|
win_name = (node.data.c1FullName === null) ? "???" : node.data.c1FullName;
|
||||||
|
else
|
||||||
|
win_name = (node.data.c2FullName === null) ? "???" : node.data.c2FullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ctx.fillStyle = "#18A918";
|
||||||
|
printText(win_name, px - size * 2 - size * 8, py - ((size * 1.5 / 2) | 0),
|
||||||
|
size * 8, (size * 1.5) | 0, true, false);
|
||||||
|
|
||||||
|
px = px - size * 2 - size * 8;
|
||||||
|
|
||||||
|
drawNode(node, px, py);
|
||||||
|
|
||||||
|
py = max_y + ((size * 2 * node.death() + ((size * 1.5 / 2) | 0)));
|
||||||
|
px = max_x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
@ -11,8 +11,11 @@ import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
|||||||
import {SimpleIconsOBS} from "../../../assets/SimpleIconsOBS.ts";
|
import {SimpleIconsOBS} from "../../../assets/SimpleIconsOBS.ts";
|
||||||
import JSZip from "jszip";
|
import JSZip from "jszip";
|
||||||
import {detectOptimalBackground} from "../../../components/SmartLogoBackground.jsx";
|
import {detectOptimalBackground} from "../../../components/SmartLogoBackground.jsx";
|
||||||
|
import {faGlobe} from "@fortawesome/free-solid-svg-icons";
|
||||||
|
|
||||||
export function CMAdmin() {
|
const vite_url = import.meta.env.VITE_URL;
|
||||||
|
|
||||||
|
export function CMAdmin({compUuid}) {
|
||||||
const [catId, setCatId] = useState(null);
|
const [catId, setCatId] = useState(null);
|
||||||
const [cat, setCat] = useState(null);
|
const [cat, setCat] = useState(null);
|
||||||
const menuActions = useRef({});
|
const menuActions = useRef({});
|
||||||
@ -46,7 +49,7 @@ export function CMAdmin() {
|
|||||||
</div>
|
</div>
|
||||||
</LoadingProvider>
|
</LoadingProvider>
|
||||||
</div>
|
</div>
|
||||||
<Menu menuActions={menuActions}/>
|
<Menu menuActions={menuActions} compUuid={compUuid}/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
@ -155,7 +158,7 @@ async function downloadResourcesAsZip(resourceList) {
|
|||||||
progressText.textContent = "Téléchargement terminé !";
|
progressText.textContent = "Téléchargement terminé !";
|
||||||
}
|
}
|
||||||
|
|
||||||
function Menu({menuActions}) {
|
function Menu({menuActions, compUuid}) {
|
||||||
const e = document.getElementById("actionMenu")
|
const e = document.getElementById("actionMenu")
|
||||||
const longPress = useRef({time: null, timer: null, button: null});
|
const longPress = useRef({time: null, timer: null, button: null});
|
||||||
const obsModal = useRef(null);
|
const obsModal = useRef(null);
|
||||||
@ -213,6 +216,16 @@ function Menu({menuActions}) {
|
|||||||
exportOBSConfiguration(adresse, password, assets_dir)
|
exportOBSConfiguration(adresse, password, assets_dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const copyScriptToClipboard = () => {
|
||||||
|
navigator.clipboard.writeText(`<div id='safca_api_data'></div>
|
||||||
|
<script id="safca_api_script" type="text/javascript" src="${vite_url}/competition.js?id=${compUuid}"></script>`
|
||||||
|
).then(() => {
|
||||||
|
toast.success("Texte copié dans le presse-papier ! Collez-le dans une balise HTML sur votre WordPress.");
|
||||||
|
}).catch(err => {
|
||||||
|
toast.error("Erreur lors de la copie dans le presse-papier : " + err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
return <></>;
|
return <></>;
|
||||||
return <>
|
return <>
|
||||||
@ -220,11 +233,16 @@ function Menu({menuActions}) {
|
|||||||
<>
|
<>
|
||||||
<div className="vr" style={{margin: "0 0.5em", height: "100%"}}></div>
|
<div className="vr" style={{margin: "0 0.5em", height: "100%"}}></div>
|
||||||
<FontAwesomeIcon icon={SimpleIconsOBS} size="xl"
|
<FontAwesomeIcon icon={SimpleIconsOBS} size="xl"
|
||||||
style={{color: "#6c757d", cursor: "pointer"}}
|
style={{color: "#6c757d", cursor: "pointer", marginRight: "0.25em"}}
|
||||||
onMouseDown={() => longPressDown("obs")}
|
onMouseDown={() => longPressDown("obs")}
|
||||||
onMouseUp={() => longPressUp("obs")}
|
onMouseUp={() => longPressUp("obs")}
|
||||||
data-bs-toggle="tooltip2" data-bs-placement="top"
|
data-bs-toggle="tooltip2" data-bs-placement="top"
|
||||||
data-bs-title="Clique court : Télécharger les ressources. Clique long : Créer la configuration obs"/>
|
data-bs-title="Clique court : Télécharger les ressources. Clique long : Créer la configuration obs"/>
|
||||||
|
<FontAwesomeIcon icon={faGlobe} size="xl"
|
||||||
|
style={{color: "#6c757d", cursor: "pointer"}}
|
||||||
|
onClick={() => copyScriptToClipboard()}
|
||||||
|
data-bs-toggle="tooltip2" data-bs-placement="top"
|
||||||
|
data-bs-title="Copier le scripte d'intégration"/>
|
||||||
</>, document.getElementById("actionMenu"))}
|
</>, document.getElementById("actionMenu"))}
|
||||||
|
|
||||||
<button ref={obsModal} type="button" className="btn btn-link" data-bs-toggle="modal" data-bs-target="#OBSModal" style={{display: 'none'}}>
|
<button ref={obsModal} type="button" className="btn btn-link" data-bs-toggle="modal" data-bs-target="#OBSModal" style={{display: 'none'}}>
|
||||||
|
|||||||
@ -66,7 +66,7 @@ function HomeComp() {
|
|||||||
<LoadingProvider>
|
<LoadingProvider>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/" element={<Home2 perm={perm}/>}/>
|
<Route path="/" element={<Home2 perm={perm}/>}/>
|
||||||
<Route path="/admin" element={<CMAdmin/>}/>
|
<Route path="/admin" element={<CMAdmin compUuid={compUuid}/>}/>
|
||||||
<Route path="/table" element={<CMTable/>}/>
|
<Route path="/table" element={<CMTable/>}/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</LoadingProvider>
|
</LoadingProvider>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user