forked from tom.biard/ScienceQuest
Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
|
1fe4450781 | 1 year ago |
@ -1,39 +0,0 @@
|
|||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: ScienceQuestFront
|
|
||||||
|
|
||||||
trigger:
|
|
||||||
branch:
|
|
||||||
- front
|
|
||||||
event:
|
|
||||||
- push
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build-container-image
|
|
||||||
image: plugins/docker
|
|
||||||
settings:
|
|
||||||
dockerfile: Dockerfile
|
|
||||||
registry: hub.codefirst.iut.uca.fr
|
|
||||||
repo: hub.codefirst.iut.uca.fr/alix.jeudi--lemoine/front
|
|
||||||
username:
|
|
||||||
from_secret: SECRET_REGISTRY_USERNAME
|
|
||||||
password:
|
|
||||||
from_secret: SECRET_REGISTRY_PASSWORD
|
|
||||||
|
|
||||||
- name: deploy-container
|
|
||||||
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
|
|
||||||
depends_on: [build-container-image]
|
|
||||||
environment:
|
|
||||||
IMAGENAME: hub.codefirst.iut.uca.fr/alix.jeudi--lemoine/front:latest
|
|
||||||
CONTAINERNAME: front
|
|
||||||
COMMAND: create
|
|
||||||
OVERWRITE: true
|
|
||||||
ADMINS: alixjeudi--lemoine,victorsoulier,gwenaelplanchon
|
|
||||||
|
|
||||||
- name: code-analysis-android
|
|
||||||
image: aosapps/drone-sonar-plugin
|
|
||||||
settings:
|
|
||||||
sonar_host:
|
|
||||||
from_secret: sonar_host
|
|
||||||
sonar_token:
|
|
||||||
from_secret: sonar_sae_token
|
|
@ -1,26 +0,0 @@
|
|||||||
# On part de l'image long term service (en alpine pour le poids)
|
|
||||||
FROM node:lts-alpine
|
|
||||||
|
|
||||||
# Installe http-server (simple serveur pour contenu statique)
|
|
||||||
RUN npm install -g http-server
|
|
||||||
|
|
||||||
# On se rends dans (et on créé) le dossier /front
|
|
||||||
WORKDIR /front
|
|
||||||
|
|
||||||
# Copie du projet node dans le dossier /projet
|
|
||||||
COPY --chown=node:node science-quest/ .
|
|
||||||
|
|
||||||
# Met en variable d'environnement le port 443 pour http-server
|
|
||||||
ENV PORT=443 BASE_URL=/containers/tombiard-front/
|
|
||||||
|
|
||||||
# Installe les dépendances nécéssaires
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Lance la construction du projet
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Expose le port 443
|
|
||||||
EXPOSE 443
|
|
||||||
|
|
||||||
# Lance le serveur sur le dossier dist (le projet est build dedans)
|
|
||||||
CMD ["http-server", "dist"]
|
|
Binary file not shown.
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "ScienceQuest",
|
|
||||||
"lockfileVersion": 3,
|
|
||||||
"requires": true,
|
|
||||||
"packages": {}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
|
|
||||||
node_modules
|
|
||||||
.DS_Store
|
|
||||||
dist
|
|
||||||
dist-ssr
|
|
||||||
coverage
|
|
||||||
*.local
|
|
||||||
|
|
||||||
/cypress/videos/
|
|
||||||
/cypress/screenshots/
|
|
||||||
|
|
||||||
# Editor directories and files
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/extensions.json
|
|
||||||
.idea
|
|
||||||
*.suo
|
|
||||||
*.ntvs*
|
|
||||||
*.njsproj
|
|
||||||
*.sln
|
|
||||||
*.sw?
|
|
||||||
|
|
||||||
*.tsbuildinfo
|
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"]
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
# science-quest
|
|
||||||
|
|
||||||
This template should help get you started developing with Vue 3 in Vite.
|
|
||||||
|
|
||||||
## Recommended IDE Setup
|
|
||||||
|
|
||||||
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin).
|
|
||||||
|
|
||||||
## Customize configuration
|
|
||||||
|
|
||||||
See [Vite Configuration Reference](https://vitejs.dev/config/).
|
|
||||||
|
|
||||||
## Project Setup
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Compile and Hot-Reload for Development
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Compile and Minify for Production
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run build
|
|
||||||
```
|
|
@ -1,13 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<link rel="icon" href="/favicon.ico">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Welcome to Science Quest</title>
|
|
||||||
</head>
|
|
||||||
<body data-bs-theme="light">
|
|
||||||
<div id="app"></div>
|
|
||||||
<script type="module" src="./src/main.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["./src/*"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"exclude": ["node_modules", "dist"]
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "science-quest",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "vite",
|
|
||||||
"build": "vite build --base=$BASE_URL",
|
|
||||||
"preview": "vite preview"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"bootstrap": "^5.3.3",
|
|
||||||
"sass": "^1.71.1",
|
|
||||||
"vue": "^3.4.15",
|
|
||||||
"vue-router": "^4.3.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@vitejs/plugin-vue": "^5.0.3",
|
|
||||||
"vite": "^5.0.11"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 206 KiB |
@ -1,20 +0,0 @@
|
|||||||
<script>
|
|
||||||
import Titre from './components/Titre.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
components: { Titre }
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- header -->
|
|
||||||
<Titre />
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<router-view></router-view>
|
|
||||||
</main>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,5 +0,0 @@
|
|||||||
export const NOM_APP="ScienceQuest"
|
|
||||||
|
|
||||||
export const REST_API="https://codefirst.iut.uca.fr/containers/tombiard-api/api/v1"
|
|
||||||
|
|
||||||
export const KAHOOT_NB_APRES_LA_VIRGULE_COMPTE_A_REBOURS=2
|
|
Before Width: | Height: | Size: 206 KiB |
@ -1,4 +0,0 @@
|
|||||||
#app {
|
|
||||||
margin: 0 auto;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
@ -1,54 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { Utilisateur } from "@/data/utilisateur"
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
messageErreur:""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
creerCompte(event){
|
|
||||||
if(!formajouter.checkValidity()){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const utilisateur=new Utilisateur(Object.fromEntries(new FormData(formajouter)))
|
|
||||||
utilisateur.creerCompte().then(response=>this.$router.push("/login")).catch(ex=>this.messageErreur=ex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<form id="formajouter" @submit.prevent>
|
|
||||||
<h1 class="h3 mb-3 fw-normal">S'inscrire</h1>
|
|
||||||
|
|
||||||
<div class="form-floating">
|
|
||||||
<input type="email" class="form-control" id="emailInput" name="email" required>
|
|
||||||
<label for="emailInput">Email</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-floating">
|
|
||||||
<input type="text" class="form-control" id="pseudoInput" name="pseudo" required min="6">
|
|
||||||
<label for="pseudoInput">Pseudo</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-floating">
|
|
||||||
<input type="password" class="form-control" id="motDePasseInput" name="motDePasse" required min="6">
|
|
||||||
<label for="motDePasseInput">Mot de passe</label>
|
|
||||||
</div>
|
|
||||||
<br/>
|
|
||||||
<p class="text-danger">{{ messageErreur }}</p>
|
|
||||||
<br/>
|
|
||||||
<button class="btn btn-lg btn-primary" @click="creerCompte">S'inscrire</button>
|
|
||||||
</form>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction:column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,61 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { RouterLink } from 'vue-router'
|
|
||||||
import { Utilisateur } from "@/data/utilisateur"
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
messageErreur:""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
login(){
|
|
||||||
if(!formajouter.checkValidity()){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const utilisateur=new Utilisateur(Object.fromEntries(new FormData(formajouter)))
|
|
||||||
utilisateur.connecter().then(response=>
|
|
||||||
//rediriger vers la page de son profil
|
|
||||||
this.$router.push("/profil")
|
|
||||||
).catch(ex=>this.messageErreur=ex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<form @submit.prevent id="formajouter">
|
|
||||||
<h1 class="h3 mb-3 fw-normal">Se connecter</h1>
|
|
||||||
|
|
||||||
<div class="form-floating">
|
|
||||||
<input type="email" class="form-control" id="emailInput" name="email" required>
|
|
||||||
<label for="emailInput">Email</label>
|
|
||||||
</div>
|
|
||||||
<div class="form-floating">
|
|
||||||
<input type="password" class="form-control" id="motDePasseInput" name="motDePasse" required min="6">
|
|
||||||
<label for="motDePasseInput">Mot de passe</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!--div class="checkbox mb-3">
|
|
||||||
<label>
|
|
||||||
<label for="rememberMe">Se souvenir de moi</label>
|
|
||||||
<input type="checkbox" value="1" id="rememberMe" name="rememberMe">
|
|
||||||
</label>
|
|
||||||
</div-->
|
|
||||||
<RouterLink to="/inscription">Pas de compte?</RouterLink>
|
|
||||||
<br/>
|
|
||||||
<p class="text-danger">{{ messageErreur }}</p>
|
|
||||||
<br/>
|
|
||||||
<button class="btn btn-lg btn-primary" @click="login">Se connecter</button>
|
|
||||||
</form>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction:column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,38 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { NOM_APP } from "@/assets/const";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
nomApp: NOM_APP
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "@/scss/landingPage.scss";
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="landingPage">
|
|
||||||
<div class="landingContent">
|
|
||||||
<h1>{{ nomApp }}</h1>
|
|
||||||
<p> Science Quest est un jeu réalisé par 6 étudiants en deuxième années de l'IUT Clermont Auvergne <br />
|
|
||||||
dans le cadre d'un projet tuteuré. Le but de ce jeu est de vous faire découvrir des scientifiques (principalement des femmes) <br />
|
|
||||||
et leurs découvertes à travers des énigmes et des mini-jeux. Bonne chance !
|
|
||||||
</p>
|
|
||||||
<p> Actuellement les jeux sont en cours de développement 🚧</p> <!-- TODO: Rajouter les jeux disponibles -->
|
|
||||||
<div class="routes-button">
|
|
||||||
<router-link to="/kahoot" class="btn btn-dark">Kahoot 🚧</router-link>
|
|
||||||
<router-link to="/pendu" class="btn btn-dark">Pendu 🚧</router-link>
|
|
||||||
</div>
|
|
||||||
<img src="@/temporary_ressources/img/marie-curie.png" alt="Marie Curie" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<footer>
|
|
||||||
<p>Réalisé par des étudiants de l'IUT Clermont Auvergne <br /> <!-- TODO: Mettre les noms des étudiants -->
|
|
||||||
© 2024 Science Quest
|
|
||||||
</p>
|
|
||||||
</footer>
|
|
||||||
</template>
|
|
@ -1,36 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { RouterLink } from 'vue-router'
|
|
||||||
import { Utilisateur } from "@/data/utilisateur"
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
utilisateur:null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
Utilisateur.utilisateurConnecte().then(user=>{
|
|
||||||
this.utilisateur=user
|
|
||||||
if(!this.utilisateur){
|
|
||||||
//rediriger si on n'a pas d'utilisateur connecté
|
|
||||||
//TODO : mettre noms aux routes au lieu de mettre le lien
|
|
||||||
this.$router.push("/login")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
{{ JSON.stringify(utilisateur) }}
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction:column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>{{ $route.params.id }}</div>
|
|
||||||
</template>
|
|
@ -1,102 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { NOM_APP } from "@/assets/const";
|
|
||||||
import { Utilisateur } from "@/data/utilisateur";
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
nomApp: NOM_APP,
|
|
||||||
utilisateur: {},
|
|
||||||
estConnecte: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
changerDarkMode: function () {
|
|
||||||
document.body.dataset.bsTheme != "dark" ? document.body.dataset.bsTheme = "dark" : document.body.dataset.bsTheme = "light"
|
|
||||||
},
|
|
||||||
obtenirUtilisateur(){
|
|
||||||
Utilisateur.utilisateurConnecte().then(user => {
|
|
||||||
this.estConnecte = user != null
|
|
||||||
this.utilisateur = user
|
|
||||||
})
|
|
||||||
},
|
|
||||||
seDeconnecter(){
|
|
||||||
Utilisateur.deconnecter().then(location.reload())
|
|
||||||
},
|
|
||||||
creerInvite(){
|
|
||||||
Utilisateur.utilisateurConnecteOuCreerInvite().then(user=>{location.reload()})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.obtenirUtilisateur()
|
|
||||||
//HACK : ecouter Utilisateur en boucle pour mettre a jour la barre en "temps pas trop mais suffisament reel"
|
|
||||||
window.setInterval(this.obtenirUtilisateur,5000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- logo temporaire
|
|
||||||
<img alt="Vue logo" src="@/assets/logo.png" />
|
|
||||||
-->
|
|
||||||
<nav class="navbar navbar-expand-lg bg-body-tertiary">
|
|
||||||
<div class="container-fluid">
|
|
||||||
<router-link class="navbar-brand" to="/">{{ nomApp }}</router-link>
|
|
||||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent"
|
|
||||||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
<span class="navbar-toggler-icon"></span>
|
|
||||||
</button>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
|
||||||
<!-- cote gauche -->
|
|
||||||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
|
||||||
<!--li class="nav-item">
|
|
||||||
TODO : trouver un moyen de gerer la page courante
|
|
||||||
<a class="nav-link active" aria-current="page" href="#">Accueil</a>
|
|
||||||
</li-->
|
|
||||||
<li class="nav-item">
|
|
||||||
<router-link class="nav-link" to="/">Accueil</router-link>
|
|
||||||
</li>
|
|
||||||
<!--li class="nav-item">
|
|
||||||
<router-link class="nav-link" to="/partie">Créer une partie</router-link>
|
|
||||||
</li-->
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
||||||
Jeux
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu">
|
|
||||||
<li><router-link class="dropdown-item" to="/pendu">Pendu</router-link></li>
|
|
||||||
<li><router-link class="dropdown-item" to="/kahoot">Kahoot</router-link></li>
|
|
||||||
<li>
|
|
||||||
<hr class="dropdown-divider">
|
|
||||||
</li>
|
|
||||||
<li><router-link class="dropdown-item disabled" to="/qui_est_ce">Qui-est-ce</router-link></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<!-- cote droit -->
|
|
||||||
<ul class="navbar-nav ms-auto mb-2 mb-lg-0">
|
|
||||||
<button id="boutondarkmode" class="btn" v-on:click="changerDarkMode">💡</button>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
||||||
{{ utilisateur ? utilisateur?.pseudo : "Mon compte" }}
|
|
||||||
</a>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
|
||||||
<div v-if="!estConnecte">
|
|
||||||
<li><router-link class="dropdown-item" to="/login">Se connecter</router-link></li>
|
|
||||||
<li><a @click="creerInvite">Se connecter en tant qu'invité</a></li>
|
|
||||||
</div>
|
|
||||||
<div v-if="estConnecte">
|
|
||||||
<li><router-link class="dropdown-item" to="/profil">Profil</router-link></li>
|
|
||||||
<li><hr class="dropdown-divider"></li>
|
|
||||||
<li><a @click="seDeconnecter">Se déconnecter</a></li>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped></style>
|
|
@ -1,49 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { REST_API } from '@/assets/const';
|
|
||||||
|
|
||||||
export default{
|
|
||||||
props:["champs", "endpoint"], //format : {"nomColonne":"typeChamp", ...} => {"nom":"text", "desc":"text", ...}
|
|
||||||
methods:{
|
|
||||||
envoyerDonnees: function(event){
|
|
||||||
const donnees=new FormData(formajouter)
|
|
||||||
|
|
||||||
//envoyer le form en JSON
|
|
||||||
fetch(REST_API+"/"+this.endpoint, {method:"POST", body:JSON.stringify(Object.fromEntries(donnees)), headers: {"Content-Type": "application/json"}})
|
|
||||||
//sans le JSON.stringify et Object.fromEntries ca fait une requete en Content-Disposition
|
|
||||||
},
|
|
||||||
typeDeChamp: function(champ){ //TODO mettre cette fonction dans un fichier commun
|
|
||||||
switch(typeof champ){
|
|
||||||
case 'number':
|
|
||||||
case 'bigint':
|
|
||||||
return "number"
|
|
||||||
case 'string':
|
|
||||||
return this.estUneDate(champ) ? "date" : "text"
|
|
||||||
case 'boolean':
|
|
||||||
return "checkbox"
|
|
||||||
case 'symbol':
|
|
||||||
case 'undefined':
|
|
||||||
case 'object':
|
|
||||||
case 'function':
|
|
||||||
return "hidden" //TODO : implementer le reste
|
|
||||||
//TODO faire un select au lieu d'un input si jamais on trouve un endpoint en mettant un "s" a la fin du nomColonne
|
|
||||||
}
|
|
||||||
},
|
|
||||||
estUneDate: function(date) { //TODO mettre cette fonction dans un fichier commun
|
|
||||||
return new Date(date) != "Invalid Date";
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<form id="formajouter" @submit.prevent>
|
|
||||||
<div>
|
|
||||||
<fieldset v-for="nomColonne in Object.keys(champs??{})">
|
|
||||||
<label v-show="typeDeChamp(champs[nomColonne])!='hidden'" :for="nomColonne+'_temp_add_form'">{{nomColonne}}</label>
|
|
||||||
<input class="form-control" :type="typeDeChamp(champs[nomColonne])" :id="nomColonne+'_temp_add_form'" :aria-label="nomColonne" :name="nomColonne"/>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<button v-on:click="envoyerDonnees" class="btn btn-primary">Ajouter</button>
|
|
||||||
</form>
|
|
||||||
</template>
|
|
@ -1,103 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { REST_API } from '@/assets/const';
|
|
||||||
|
|
||||||
import LigneDonnee from './ListeLigne.vue';
|
|
||||||
import Ajout from './Ajout.vue';
|
|
||||||
|
|
||||||
export default{
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
endpoint:this.$route.query.endpoint ?? "thematiques", //endpoint de l'api a recuperer
|
|
||||||
//données obtenues par l'api
|
|
||||||
donnees: [],
|
|
||||||
page:0,
|
|
||||||
REST_API:REST_API,
|
|
||||||
|
|
||||||
//HATEOAS
|
|
||||||
self:"",
|
|
||||||
first:null, // a prendre a partir de la requete
|
|
||||||
prev:null,
|
|
||||||
next:null,
|
|
||||||
last:null,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
this.rafraichirEndpoint()
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
rafraichirEndpoint(){
|
|
||||||
this.self=`${REST_API}/${this.endpoint}?page=${this.page}`
|
|
||||||
this.getDonnees(this.self)
|
|
||||||
},
|
|
||||||
getDonnees(url){
|
|
||||||
//HACK : s'assurer que les liens sont en HTTPS
|
|
||||||
url=url.replace("http://", "https://")
|
|
||||||
//enlever les anciens du tableau
|
|
||||||
this.donnees=[]
|
|
||||||
//TODO : ajouter un delai si jamais la requete est trop rapide pour VueJS
|
|
||||||
//appeler l'API
|
|
||||||
fetch(url).then(response=>{
|
|
||||||
response.json().then(json=>{
|
|
||||||
const oldLength=this.donnees.length
|
|
||||||
//prendre les donnees de la requete
|
|
||||||
this.donnees.push(...json._embedded)
|
|
||||||
|
|
||||||
//HATEOAS
|
|
||||||
this.self=json._links.self.href;
|
|
||||||
this.first=json._links.first ? json._links.first.href : null;
|
|
||||||
this.prev=json._links.prev ? json._links.prev.href : null;
|
|
||||||
this.next=json._links.next ? json._links.next.href : null;
|
|
||||||
this.last=json._links.last ? json._links.last.href : null;
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: { LigneDonnee, Ajout }
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<!-- TODO : remplacer input par select ?-->
|
|
||||||
<label for="endpointInput">Endpoint API (REST) {{ REST_API }}/</label>
|
|
||||||
<input v-model="endpoint" id="endpointInput">
|
|
||||||
<button @click="rafraichirEndpoint()">Rafraichir</button>
|
|
||||||
<table class="table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th scope="col" v-for="nomColonne in Object.keys(donnees[0]??{})">{{nomColonne}}</th>
|
|
||||||
<th scope="col">Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<LigneDonnee v-for="champ in donnees"
|
|
||||||
:champs-init="champ"
|
|
||||||
></LigneDonnee>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<button :class="{ invisible: !first }" class="btn btn-secondary" @click="this.getDonnees(this.first)">First</button>
|
|
||||||
<button :class="{ invisible: !prev }" class="btn btn-secondary" @click="this.getDonnees(this.prev)">Prev</button>
|
|
||||||
<button :class="{ invisible: !next }" class="btn btn-secondary" @click="this.getDonnees(this.next)">Next</button>
|
|
||||||
<button :class="{ invisible: !last }" class="btn btn-secondary" @click="this.getDonnees(this.last)">Last</button>
|
|
||||||
|
|
||||||
<!-- Button trigger modal -->
|
|
||||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#popupAjout">
|
|
||||||
Ajouter
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Modal -->
|
|
||||||
<div class="modal fade" id="popupAjout" tabindex="-1" aria-labelledby="popupLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h1 class="modal-title fs-5" id="popupLabel">Ajout de données</h1>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<Ajout :endpoint="endpoint" :champs="donnees[0]??{}"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</template>
|
|
@ -1,79 +0,0 @@
|
|||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: ["champsInit"],
|
|
||||||
data(){
|
|
||||||
return{
|
|
||||||
modeEdition:false, //vrai = remplacer les champs par des inputs
|
|
||||||
|
|
||||||
champs:this.champsInit
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
changerModeEdition: function(){
|
|
||||||
this.modeEdition=!this.modeEdition
|
|
||||||
},
|
|
||||||
annuler: function(){
|
|
||||||
//remettre les valeurs a 0
|
|
||||||
this.champs=this.champsInit
|
|
||||||
|
|
||||||
this.changerModeEdition()
|
|
||||||
},
|
|
||||||
sauverScientifique: function(){
|
|
||||||
//TODO : comme dans ajout
|
|
||||||
//TODO comment trouver l'endpoint depuis Liste.vue ?
|
|
||||||
//fetch("localhost/api/v1/scientifiques", {method:"PUT", body:JSON.stringify(donnees)})
|
|
||||||
console.log(this.champs)
|
|
||||||
this.changerModeEdition()
|
|
||||||
},
|
|
||||||
typeDeChamp: function(champ){
|
|
||||||
switch(typeof champ){
|
|
||||||
case 'number':
|
|
||||||
case 'bigint':
|
|
||||||
return "number"
|
|
||||||
case 'string':
|
|
||||||
return this.estUneDate(champ) ? "date" : "text"
|
|
||||||
case 'boolean':
|
|
||||||
return "checkbox"
|
|
||||||
case 'symbol':
|
|
||||||
case 'undefined':
|
|
||||||
case 'object':
|
|
||||||
case 'function':
|
|
||||||
return "hidden" //TODO : implementer le reste
|
|
||||||
}
|
|
||||||
},
|
|
||||||
estUneDate: function(date) {
|
|
||||||
return new Date(date) != "Invalid Date";
|
|
||||||
},
|
|
||||||
formatterString(champ){
|
|
||||||
//mieux formatter les dates
|
|
||||||
if(this.typeDeChamp(champ)=="date"){
|
|
||||||
return new Date(champ).toLocaleString()
|
|
||||||
}
|
|
||||||
return champ
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<tr v-if="!this.modeEdition">
|
|
||||||
<td v-for="champ in champs">
|
|
||||||
<p>{{ formatterString(champ) }}</p>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button class="btn-outline-secondary btn" v-on:click="changerModeEdition()">Modifier</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr v-if="this.modeEdition">
|
|
||||||
|
|
||||||
<!-- TODO : fix date, creer input objet (bouton qui ouvre une popup qui propose de changer les champs de l'objet)-->
|
|
||||||
<td v-for="cleChamp in Object.keys(champs)">
|
|
||||||
<input class="form-control" :type="typeDeChamp(champs[cleChamp])" v-model="champs[cleChamp]" :aria-label="cleChamp">
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-success" v-on:click="sauverScientifique()">Sauvegarder</button>
|
|
||||||
<button class="btn btn-secondary" v-on:click="annuler()">Annuler</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</template>
|
|
@ -1,3 +0,0 @@
|
|||||||
<template>
|
|
||||||
404
|
|
||||||
</template>
|
|
@ -1,84 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { RouterLink } from 'vue-router'
|
|
||||||
import { Partie } from '@/data/partie';
|
|
||||||
import { ListeJeux } from '@/data/jeu';
|
|
||||||
import { Thematiques } from '@/data/thematique';
|
|
||||||
import { Difficultes } from '@/data/difficulte';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
jeuxDispo:[],
|
|
||||||
|
|
||||||
thematiquesDispo:[],
|
|
||||||
choixThematiques:[],
|
|
||||||
|
|
||||||
difficultesDispo:[],
|
|
||||||
choixDifficulte:-1,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
login(){
|
|
||||||
const partieACreer=new Partie(Object.fromEntries(new FormData(formajouter)))
|
|
||||||
partieACreer.thematiques=this.choixThematiques
|
|
||||||
partieACreer.creerPartie().then(response=>console.log(response))
|
|
||||||
//console.log(partieACreer)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
ListeJeux.get().then(jeux=>this.jeuxDispo=Object.values(jeux))
|
|
||||||
Difficultes.getPage(0,999).then(difficultes=>{
|
|
||||||
this.difficultesDispo=difficultes._embedded
|
|
||||||
//choisir une difficulté par défaut
|
|
||||||
this.choixDifficulte=this.difficultesDispo[0].id
|
|
||||||
})
|
|
||||||
Thematiques.getPage(0,999).then(thematiques=>this.thematiquesDispo=thematiques._embedded)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<form @submit.prevent id="formajouter">
|
|
||||||
<h1 class="h3 mb-3 fw-normal">Creer une partie</h1>
|
|
||||||
|
|
||||||
<div class="form-floating">
|
|
||||||
</div>
|
|
||||||
<div class="form-floating">
|
|
||||||
<select name="idJeu">
|
|
||||||
<option v-for="jeu in jeuxDispo" :value="jeu.id" required>
|
|
||||||
{{ jeu.nom }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="checkbox mb-3">
|
|
||||||
<label for="thematiquesInput">Thématiques</label>
|
|
||||||
<br/>
|
|
||||||
<select v-model="choixThematiques" id="thematiquesInput" multiple required>
|
|
||||||
<option v-for="thematique in thematiquesDispo" :value="thematique.id">
|
|
||||||
{{ thematique.libelle }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="checkbox mb-3">
|
|
||||||
<label for="idDifficulteInput">Difficulté</label>
|
|
||||||
<br/>
|
|
||||||
<select v-model="choixDifficulte" id="idDifficulteInput" name="idDifficulte" required>
|
|
||||||
<option v-for="difficulte in difficultesDispo" :value="difficulte.id">
|
|
||||||
{{ difficulte.libelle }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-lg btn-primary" @click="login">Créer une partie</button>
|
|
||||||
</form>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
form {
|
|
||||||
display: flex;
|
|
||||||
flex-direction:column;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
</style>
|
|
@ -1,143 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { Difficultes } from '@/data/difficulte';
|
|
||||||
import KahootListeParties from './KahootListeParties.vue'
|
|
||||||
import {Partie} from "@/data/partie"
|
|
||||||
import { Thematiques } from '@/data/thematique';
|
|
||||||
import {KahootPartie} from '@/data/kahoot';
|
|
||||||
|
|
||||||
//TODO définir les méthodes -> à définir grâce à l'API
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
//creer partie
|
|
||||||
titreKahoot: "",
|
|
||||||
nbQuestions: 0,
|
|
||||||
//rejoindre partie
|
|
||||||
codeKahootARejoindre: "",
|
|
||||||
//listes parties crees ( TODO : appeler l'api pour obtenir les parties)
|
|
||||||
partiesCrees: [],
|
|
||||||
|
|
||||||
//input popup creation partie
|
|
||||||
thematiquesDispo:[],
|
|
||||||
choixThematiques:[],
|
|
||||||
|
|
||||||
difficultesDispo:[],
|
|
||||||
choixDifficulte:-1,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
this.STUB_partiesCrees().then(response=>this.partiesCrees=response)
|
|
||||||
|
|
||||||
Difficultes.getPage(0,999).then(difficultes=>{
|
|
||||||
this.difficultesDispo=difficultes._embedded
|
|
||||||
//choisir une difficulté par défaut
|
|
||||||
this.choixDifficulte=this.difficultesDispo[0].id
|
|
||||||
})
|
|
||||||
Thematiques.getPage(0,999).then(thematiques=>this.thematiquesDispo=thematiques._embedded)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
// TODO : demander a l'api de creer un kahoot (et rediriger vers la partie si possible via HATEOAS)
|
|
||||||
creerKahoot: function () {
|
|
||||||
if(!formCreerKahoot.checkValidity()){
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const partie=new KahootPartie({
|
|
||||||
"thematiques": this.choixThematiques,
|
|
||||||
"idDifficulte": this.choixDifficulte
|
|
||||||
})
|
|
||||||
partie.creerPartie().then(kahoot=>{
|
|
||||||
//fermer la popup
|
|
||||||
fermerPopup.click()
|
|
||||||
//rejoindre sa propre partie
|
|
||||||
this.codeKahootARejoindre=kahoot.codeInvitation
|
|
||||||
this.rejoindrePartie()
|
|
||||||
//afficher le bouton qui uniquement la pour le créateur de la partie
|
|
||||||
window.setTimeout(function(){boutonDemarrerKahoot.style.visibility=""}, 1000)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
// TODO : demander a l'api de rejoindre un kahoot (et rediriger vers la partie si possible via HATEOAS)
|
|
||||||
rejoindrePartie(){
|
|
||||||
this.$router.push(`/kahoot/partie/${this.codeKahootARejoindre}`)
|
|
||||||
},
|
|
||||||
async STUB_partiesCrees(){
|
|
||||||
return JSON.parse(`[
|
|
||||||
{"titreKahoot":"Titre du Kahoot", "nbQuestions":10, "createur":"Professeur X"},
|
|
||||||
{"titreKahoot":"Titre du Kahoot2", "nbQuestions":69, "createur":"Professeur Y"},
|
|
||||||
{"titreKahoot":"Titre du Kahoot3", "nbQuestions":234, "createur":"Professeur XXX"}
|
|
||||||
]
|
|
||||||
`)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: { KahootListeParties }
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "@/scss/kahoot.scss";
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="Kahoot">
|
|
||||||
<h1 style="padding-left: 0.5em;">Kahoot</h1>
|
|
||||||
<div class="Kahoot-Header">
|
|
||||||
<h2>Rejoindre un Kahoot</h2>
|
|
||||||
<button type="button" class="btn btn-light" data-bs-toggle="modal" data-bs-target="#createKahootModal">
|
|
||||||
Créer un Kahoot
|
|
||||||
</button>
|
|
||||||
<form @submit.prevent>
|
|
||||||
<label for="Kahoot-Code">Code</label>
|
|
||||||
<input class="form-control bg-light" type="text" id="Kahoot-Code" name="Kahoot-Code" v-model="codeKahootARejoindre" minlength="6" maxlength="10">
|
|
||||||
<button class="btn btn-light" v-on:click="rejoindrePartie">Rejoindre</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<div class="Kahoot-content">
|
|
||||||
<div class="Kahoot-List">
|
|
||||||
<h2> Vos Quizz</h2>
|
|
||||||
<KahootListeParties v-for="partie in partiesCrees" :titreKahoot="partie.titreKahoot" :nbQuestions="partie.nbQuestions" :createur="partie.createur"></KahootListeParties>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal fade" id="createKahootModal" tabindex="-1" role="dialog" aria-labelledby="creationKahoot" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h2 class="modal-title" id="creationKahoot">Créer un Kahoot</h2>
|
|
||||||
</div>
|
|
||||||
<form id="formCreerKahoot" @submit.prevent>
|
|
||||||
<div class="modal-body">
|
|
||||||
<!--div>
|
|
||||||
<label for="Kahoot-Create-Title">Titre</label>
|
|
||||||
<input class="form-control" type="text" id="Kahoot-Create-Title" name="Kahoot-Create-Title" v-model="titreKahoot" required minlength="2" maxlength="255">
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="Kahoot-Create-Questions">Nombre de questions</label>
|
|
||||||
<input class="form-control" type="number" id="Kahoot-Create-Questions" name="Kahoot-Create-Questions" v-model="nbQuestions" required min="1" max="99">
|
|
||||||
</div-->
|
|
||||||
<div class="checkbox mb-3">
|
|
||||||
<label for="thematiquesInput">Thématiques</label>
|
|
||||||
<br/>
|
|
||||||
<select v-model="choixThematiques" id="thematiquesInput" multiple required>
|
|
||||||
<option v-for="thematique in thematiquesDispo" :value="thematique.id">
|
|
||||||
{{ thematique.libelle }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="checkbox mb-3">
|
|
||||||
<label for="idDifficulteInput">Difficulté</label>
|
|
||||||
<br/>
|
|
||||||
<select v-model="choixDifficulte" id="idDifficulteInput" name="idDifficulte" required>
|
|
||||||
<option v-for="difficulte in difficultesDispo" :value="difficulte.id">
|
|
||||||
{{ difficulte.libelle }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button id="fermerPopup" type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button class="btn btn-primary" v-on:click="creerKahoot">Créer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
@ -1,15 +0,0 @@
|
|||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: ["titreKahoot", "nbQuestions", "createur"]
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="Kahoot-List-Item">
|
|
||||||
<h2>{{ titreKahoot }}</h2>
|
|
||||||
<p>{{ nbQuestions }}</p>
|
|
||||||
<p>{{ createur }}</p>
|
|
||||||
<button class="btn btn-dark">Jouer</button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
@ -1,198 +0,0 @@
|
|||||||
<script>
|
|
||||||
import { KAHOOT_NB_APRES_LA_VIRGULE_COMPTE_A_REBOURS} from "@/assets/const"
|
|
||||||
import { Kahoot } from "@/data/kahoot"
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
codePartie: this.$route.params.code ?? -1,
|
|
||||||
kahootAPI:null,
|
|
||||||
//unix timestamp pour indiquer la date limite pour repondre a la question, -1 indiquera la fin de la partie
|
|
||||||
tempsLimite:0,
|
|
||||||
compteARebours:0,
|
|
||||||
compteAReboursId:0, //id donné par le setInterval pour pouvoir l'arreter quand il est a 0
|
|
||||||
obtenirTimeoutId:0, //id donné par le setTimeout
|
|
||||||
|
|
||||||
//affichage dans la vue
|
|
||||||
etats:{
|
|
||||||
question:true, //afficher la question
|
|
||||||
score:false, //afficher les scores
|
|
||||||
salleAttente:false, //afficher la salle d'attente (ecran avec pseudos)
|
|
||||||
},
|
|
||||||
|
|
||||||
//variables pour l'etat question
|
|
||||||
question:{
|
|
||||||
question:"",
|
|
||||||
reponses:{},
|
|
||||||
},
|
|
||||||
//variables pour la salle d'attente
|
|
||||||
salleAttente:{
|
|
||||||
joueurs:[],
|
|
||||||
partieDemarree:false,
|
|
||||||
},
|
|
||||||
//variables pour les scores
|
|
||||||
score:{
|
|
||||||
score:0,
|
|
||||||
pointsGagne:0,
|
|
||||||
},
|
|
||||||
pointsAnimation:0,
|
|
||||||
partieTerminee:false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
this.kahootAPI=new Kahoot(this.codePartie)
|
|
||||||
this.obtenirSalleAttente()
|
|
||||||
|
|
||||||
},
|
|
||||||
unmounted(){
|
|
||||||
//arreter le jeu quand la page n'est plus affichée
|
|
||||||
window.clearTimeout(this.obtenirTimeoutId)
|
|
||||||
window.clearInterval(this.compteAReboursId)
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
//retourne la fonction appropriée
|
|
||||||
choisirLeProchainEtat(){
|
|
||||||
//si la partie n'a pas démarrée, on reste dans la salle d'attente
|
|
||||||
if(!this.salleAttente.partieDemarree){
|
|
||||||
return this.obtenirSalleAttente
|
|
||||||
}
|
|
||||||
//si on vient de faire une question, on demander les resultats
|
|
||||||
if(this.etats.question){
|
|
||||||
return this.obtenirScores
|
|
||||||
}
|
|
||||||
return this.obtenirQuestion
|
|
||||||
},
|
|
||||||
obtenirQuestion(){
|
|
||||||
this.kahootAPI.obtenirQuestion().then(response=>{
|
|
||||||
this.resetEtats() //cacher l'etat precedent
|
|
||||||
this.tempsLimite=response.tempsLimite
|
|
||||||
//afficher cet etat
|
|
||||||
this.etats.question=true
|
|
||||||
|
|
||||||
this.question=response.questionActuel
|
|
||||||
|
|
||||||
if(this.tempsLimite!=-1){
|
|
||||||
//executer la fonction en boucle jusqu'a ce que la partie se termine
|
|
||||||
this.obtenirTimeoutId=window.setTimeout(this.choisirLeProchainEtat(),(this.tempsLimite+100)-Date.now())
|
|
||||||
//demarrer le compte a rebours
|
|
||||||
this.compteAReboursId=window.setInterval(this.calculerCompteARebours,22)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
).catch(ex=>this.partieTerminee=true)
|
|
||||||
},
|
|
||||||
obtenirScores(){
|
|
||||||
this.resetEtats() //cacher l'etat precedent
|
|
||||||
this.kahootAPI.obtenirScore(this.score.score).then(response=>{
|
|
||||||
this.tempsLimite=response.tempsLimite
|
|
||||||
this.score=response
|
|
||||||
//afficher cet etat
|
|
||||||
this.etats.score=true
|
|
||||||
|
|
||||||
//reduire les points pour pouvoir l'incrementer progressivement
|
|
||||||
this.pointsAnimation=this.score.score-this.score.pointsGagne
|
|
||||||
this.animerIncrementationPoints()
|
|
||||||
|
|
||||||
if(this.tempsLimite!=-1){
|
|
||||||
//executer la fonction en boucle jusqu'a ce que la partie se termine
|
|
||||||
this.obtenirTimeoutId=window.setTimeout(this.choisirLeProchainEtat(),(this.tempsLimite+100)-Date.now())
|
|
||||||
//demarrer le compte a rebours
|
|
||||||
this.compteAReboursId=window.setInterval(this.calculerCompteARebours,22)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
|
||||||
obtenirSalleAttente(){
|
|
||||||
this.resetEtats() //cacher l'etat precedent
|
|
||||||
//afficher cet etat
|
|
||||||
this.etats.salleAttente=true
|
|
||||||
this.kahootAPI.obtenirSalleAttente().then(response=>{
|
|
||||||
this.tempsLimite=response.tempsLimite
|
|
||||||
this.salleAttente=response
|
|
||||||
|
|
||||||
this.obtenirTimeoutId=window.setTimeout(this.choisirLeProchainEtat(),(this.tempsLimite+100)-Date.now())
|
|
||||||
if(this.salleAttente.partieDemarree){
|
|
||||||
//demarrer le compte a rebours
|
|
||||||
this.compteAReboursId=window.setInterval(this.calculerCompteARebours,22)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
},
|
|
||||||
repondre(reponse){
|
|
||||||
this.kahootAPI.repondreQuestion(reponse).then()
|
|
||||||
|
|
||||||
const reponseEnvoyee=this.question.reponses.find(r=>r.id==reponse).reponse
|
|
||||||
this.question.question=`Réponse "${reponseEnvoyee}" envoyée`
|
|
||||||
this.question.reponses=[]
|
|
||||||
},
|
|
||||||
calculerCompteARebours(){
|
|
||||||
if(this.tempsLimite<Date.now()){
|
|
||||||
//si il reste plus de temps
|
|
||||||
this.compteARebours=(0).toFixed(KAHOOT_NB_APRES_LA_VIRGULE_COMPTE_A_REBOURS)
|
|
||||||
//arreter le compte a rebours
|
|
||||||
window.clearInterval(this.compteAReboursId)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
this.compteARebours=((this.tempsLimite-Date.now())/1000).toFixed(KAHOOT_NB_APRES_LA_VIRGULE_COMPTE_A_REBOURS)
|
|
||||||
},
|
|
||||||
resetEtats(){
|
|
||||||
Object.keys(this.etats).forEach(nomEtat=>this.etats[nomEtat]=0)
|
|
||||||
},
|
|
||||||
animerIncrementationPoints(){
|
|
||||||
if(this.pointsAnimation<this.score.score){
|
|
||||||
this.pointsAnimation++
|
|
||||||
//continuer jusqu'a que les points sont tous additionnés
|
|
||||||
window.setTimeout(this.animerIncrementationPoints,5)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
demarrerPartie(){
|
|
||||||
this.kahootAPI.demarrerPartie().then(boutonDemarrerKahoot.style.visibility="hidden")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.jeu{
|
|
||||||
display:flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leaderboard{
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="jeu">
|
|
||||||
<!-- Afficher le compte a rebours seulement quand la partie va demarrer, pour eviter de prendre par surprise les joueurs qui attendent dans la salle d'attente-->
|
|
||||||
<p v-if="salleAttente.partieDemarree">Temps : {{ compteARebours }}s</p>
|
|
||||||
<div v-show="etats.question">
|
|
||||||
<p>{{ question.question }}</p>
|
|
||||||
<button v-for="reponse in question.reponses" @click="repondre(reponse.id)">{{ reponse.reponse }}</button>
|
|
||||||
</div>
|
|
||||||
<div v-show="etats.score">
|
|
||||||
<h2 v-if="partieTerminee">Partie Terminée</h2>
|
|
||||||
<h2>Votre score : {{ pointsAnimation }} (+{{ score.pointsGagne }})</h2>
|
|
||||||
<ol class="leaderboard">
|
|
||||||
<li v-for="scorejoueur in score.scores">
|
|
||||||
{{ scorejoueur.joueur.pseudo }} : {{scorejoueur.score}}
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
<div v-show="etats.salleAttente">
|
|
||||||
<ul>
|
|
||||||
<h2>Code : {{ codePartie }}</h2>
|
|
||||||
<p>Invitez tout le monde !</p>
|
|
||||||
<li v-for="joueur in salleAttente.joueurs">
|
|
||||||
{{ joueur }}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<button style="visibility: hidden" id="boutonDemarrerKahoot" @click="demarrerPartie()">Démarrer la partie</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
@ -1,226 +0,0 @@
|
|||||||
<script>
|
|
||||||
import PenduDessin from './PenduDessin.vue'
|
|
||||||
import { REST_API } from "@/assets/const";
|
|
||||||
import { Scientifiques } from "@/data/scientifique"
|
|
||||||
import { Thematiques } from '@/data/thematique';
|
|
||||||
import { Difficultes } from '@/data/difficulte';
|
|
||||||
|
|
||||||
export default{
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
nbLettresADeviner: 0,
|
|
||||||
progression: "",
|
|
||||||
viesRestantes: 0, //-1 == pendu; partie terminée,
|
|
||||||
viesMaximum:10,
|
|
||||||
partieTerminee: true, //plus de lettres a deviner
|
|
||||||
premierePartie: true, //ne pas afficher "Perdu" pour ceux qui viennent de rejoindre
|
|
||||||
lettresDejaDevine: "",
|
|
||||||
|
|
||||||
afficherChoixThematiques:false,
|
|
||||||
thematiquesDispo:[],
|
|
||||||
choixThematique:-1,
|
|
||||||
|
|
||||||
afficherChoixDifficultes:false,
|
|
||||||
difficultesDispo:[],
|
|
||||||
choixDifficulte:-1,
|
|
||||||
|
|
||||||
//a recuperer a partir de l'api (prendre nom et prenom d'un scientifique nous meme)
|
|
||||||
motADeviner: "einstein",
|
|
||||||
description: "", //s'affiche en dessous du resultat a la fin
|
|
||||||
imageScientifique: "",
|
|
||||||
api_pagesMaximum: 0, //impossible de connaitre le nombre de page a l'avance
|
|
||||||
|
|
||||||
regexExceptions: [ //caracteres qu'on ne fera pas deviner au joueur
|
|
||||||
/\W/, //caracteres blanc
|
|
||||||
/[^a-z]/, //non alphabetique minuscule
|
|
||||||
],
|
|
||||||
lettresANePasFaireDevinerAuJoueur:"", //meme utilité que lettresDejaDevine mais n'est pas visible au joueur
|
|
||||||
};
|
|
||||||
},
|
|
||||||
watch:{
|
|
||||||
afficherChoixThematiques(to){
|
|
||||||
if(to && this.thematiquesDispo.length==0){
|
|
||||||
Thematiques.getPage(0,999).then(thematiques=>this.thematiquesDispo=thematiques._embedded)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
afficherChoixDifficultes(to){
|
|
||||||
if(to && this.difficultesDispo.length==0){
|
|
||||||
Difficultes.getPage(0,999).then(difficultes=>this.difficultesDispo=difficultes._embedded)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
creerPartie: function () {
|
|
||||||
this.lettresDejaDevine = "";
|
|
||||||
this.lettresANePasFaireDevinerAuJoueur="";
|
|
||||||
this.progression="";
|
|
||||||
|
|
||||||
//appeler l'API
|
|
||||||
Scientifiques.getPage(
|
|
||||||
this.intAleatoire(this.api_pagesMaximum),
|
|
||||||
0,
|
|
||||||
this.afficherChoixThematiques ? this.choixThematique : -1,
|
|
||||||
this.afficherChoixDifficultes ? this.choixDifficulte : -1
|
|
||||||
).then(json=>{
|
|
||||||
//prendre le scientifique de la requete
|
|
||||||
const arrayScientifique=json._embedded
|
|
||||||
const scientifiqueADeviner=arrayScientifique[this.intAleatoire(arrayScientifique.length)]
|
|
||||||
//prendre le mot a deviner a partir du nom du scientifique
|
|
||||||
this.motADeviner = scientifiqueADeviner.nomComplet.toLowerCase()
|
|
||||||
this.description = scientifiqueADeviner.descriptif
|
|
||||||
this.imageScientifique = scientifiqueADeviner.pathToPhoto
|
|
||||||
|
|
||||||
//mettre a jour le nombre de pages maximum de l'api scientifiques
|
|
||||||
this.api_pagesMaximum=json.page.totalPages
|
|
||||||
|
|
||||||
//verifier que le mot a deviner ne contient pas des lettres exemptées
|
|
||||||
this.motADeviner.split("").forEach(lettre=>
|
|
||||||
this.regexExceptions.forEach(regex=>regex.test(lettre) ? this.lettresANePasFaireDevinerAuJoueur+=lettre /* faire jouer la lettre a la place de l'utilisateur */ : null)
|
|
||||||
)
|
|
||||||
|
|
||||||
//rafraichir la progression pour enlever les lettres a ne pas faire deviner
|
|
||||||
this.progression = this.afficherProgression()
|
|
||||||
//compter le nombre de trous (enlever tout ce qui est pas underscore et compter)
|
|
||||||
this.nbLettresADeviner = this.progression.replace(/[^_]/g, "").length
|
|
||||||
|
|
||||||
this.viesRestantes=this.viesMaximum;
|
|
||||||
//demarrer le jeu
|
|
||||||
this.afficherLeJeu()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
afficherLeJeu(){
|
|
||||||
this.partieTerminee = false;
|
|
||||||
this.premierePartie = false;
|
|
||||||
},
|
|
||||||
deviner: function (event) {
|
|
||||||
//prendre la lettre depuis l'event
|
|
||||||
const lettreDevinee = event.data.toLowerCase();
|
|
||||||
//vider l'input
|
|
||||||
event.target.value = "";
|
|
||||||
//voir si la lettre devinée est valide
|
|
||||||
let lettreValide=true
|
|
||||||
this.regexExceptions.forEach(regex=>lettreValide ? lettreValide=!regex.test(lettreDevinee) : null)
|
|
||||||
if(!lettreValide){
|
|
||||||
//ne pas faire deviner une lettre invalide
|
|
||||||
return
|
|
||||||
}
|
|
||||||
//ajouter la lettre dans la liste des lettres devinées
|
|
||||||
if (!this.lettresDejaDevine.includes(lettreDevinee)) {
|
|
||||||
this.lettresDejaDevine += lettreDevinee;
|
|
||||||
} else {
|
|
||||||
//ne pas faire deviner une lettre qui a deja été devinée
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
//comparer la progression
|
|
||||||
const oldprogression = this.progression;
|
|
||||||
this.progression = this.afficherProgression();
|
|
||||||
|
|
||||||
if (oldprogression == this.progression) {
|
|
||||||
//si on n'a pas progressé = lettre incorrecte
|
|
||||||
this.viesRestantes--; //l'api devrait aussi retourner le nombre de vies restantes
|
|
||||||
|
|
||||||
if(this.viesRestantes<0){
|
|
||||||
this.partieTerminee = true
|
|
||||||
this.progression = this.afficherProgression();
|
|
||||||
}
|
|
||||||
} else if (!this.progression.includes("_")) {
|
|
||||||
//plus de lettres a deviner
|
|
||||||
this.partieTerminee = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
afficherProgression: function () {
|
|
||||||
if (this.viesRestantes < 0) {
|
|
||||||
return this.motADeviner; //plus de vies = fin de la partie, on retourne le mot qu'on devait trouver
|
|
||||||
}
|
|
||||||
let progression = "";
|
|
||||||
const lettresAAfficher=this.lettresDejaDevine + this.lettresANePasFaireDevinerAuJoueur;
|
|
||||||
this.motADeviner.split("").forEach(w =>lettresAAfficher.includes(w) ? progression += w : progression += "_");
|
|
||||||
return progression;
|
|
||||||
},
|
|
||||||
intAleatoire: function(nb){
|
|
||||||
return Math.floor(Math.random() * nb)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: { PenduDessin }
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<h1 style="padding-left: 0.5em;">Pendu</h1>
|
|
||||||
<div class="separateur">
|
|
||||||
<div v-if="partieTerminee" class="divjeu">
|
|
||||||
<!-- hors partie -->
|
|
||||||
<div v-if="!premierePartie">
|
|
||||||
<div v-if="viesRestantes >= 0">
|
|
||||||
Gagné!
|
|
||||||
</div>
|
|
||||||
<div v-if="viesRestantes < 0">
|
|
||||||
Perdu!
|
|
||||||
</div>
|
|
||||||
<p>Le mot était : </p>
|
|
||||||
<!-- l'api devrait retourner le mot entier quand la vie est a 0 -->
|
|
||||||
<h2 style="font-family: monospace">{{ progression }}</h2>
|
|
||||||
<p>{{ description }}</p>
|
|
||||||
<img :src="imageScientifique" :alt="'Photo de '+motADeviner">
|
|
||||||
</div>
|
|
||||||
<button class="btn btn-primary" v-on:click="creerPartie">Créer une partie</button>
|
|
||||||
<div>
|
|
||||||
<label for="afficherChoixThematiquesCheckbox">Choisir une thématique </label>
|
|
||||||
<input type="checkbox" id="afficherChoixThematiquesCheckbox" v-model="afficherChoixThematiques"/>
|
|
||||||
<br/>
|
|
||||||
<select v-if="afficherChoixThematiques" v-model="choixThematique">
|
|
||||||
<option v-for="thematique in thematiquesDispo" :value="thematique.id">
|
|
||||||
{{ thematique.libelle }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="afficherChoixDifficultesCheckbox">Choisir une difficulté </label>
|
|
||||||
<input type="checkbox" id="afficherChoixDifficultesCheckbox" v-model="afficherChoixDifficultes"/>
|
|
||||||
<br/>
|
|
||||||
<select v-if="afficherChoixDifficultes" v-model="choixDifficulte">
|
|
||||||
<option v-for="difficulte in difficultesDispo" :value="difficulte.id">
|
|
||||||
{{ difficulte.libelle }}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="!partieTerminee" class="divjeu">
|
|
||||||
<!--PenduDessin :viesRestantes="viesRestantes"></PenduDessin-->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-if="!partieTerminee" class="divjeu">
|
|
||||||
<!-- dans une partie -->
|
|
||||||
|
|
||||||
<p>Mot a deviner ({{ nbLettresADeviner }} lettres) : </p>
|
|
||||||
<h2 class="trous">{{ progression }}</h2>
|
|
||||||
<input class="form-control" type="text" minlength="1" maxlength="1" @input="deviner"
|
|
||||||
placeholder="Devinez la lettre ici">
|
|
||||||
<p>Vies restantes : {{ viesRestantes }}</p>
|
|
||||||
<label for="barreViePendu">Barre de vie</label>
|
|
||||||
<meter min="0" :max="viesMaximum" :value="viesRestantes"></meter>
|
|
||||||
<p>Lettres devinées : <span style="font-family: monospace">{{ lettresDejaDevine }}</span></p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.trous{
|
|
||||||
letter-spacing:0.5em;
|
|
||||||
font-family: monospace;
|
|
||||||
}
|
|
||||||
.divjeu {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.separateur{
|
|
||||||
display: flex;
|
|
||||||
flex:1;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
@ -1,131 +0,0 @@
|
|||||||
<script>
|
|
||||||
export default{
|
|
||||||
props:["viesRestantes"], //maximum 10, 10 par defaut
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
ordreDessin:[
|
|
||||||
this.potenceVertical,
|
|
||||||
this.potencePoutre,
|
|
||||||
this.potenceEquerre,
|
|
||||||
this.corde,
|
|
||||||
this.tete,
|
|
||||||
this.corps,
|
|
||||||
this.brasGauche,
|
|
||||||
this.brasDroit,
|
|
||||||
this.jambeDroite,
|
|
||||||
this.jambeGauche
|
|
||||||
],
|
|
||||||
viesEpuisees:0,
|
|
||||||
ctx:null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted(){
|
|
||||||
this.$refs.pendu.width=200
|
|
||||||
this.$refs.pendu.height=200
|
|
||||||
this.ctx = this.$refs.pendu.getContext("2d");
|
|
||||||
this.viesEpuisees=this.ordreDessin.length-(this.viesRestantes??this.ordreDessin.length)
|
|
||||||
},
|
|
||||||
watch:{
|
|
||||||
viesRestantes: function(newVal, oldVal){
|
|
||||||
const viesAEpuiser=this.ordreDessin.length-(newVal??this.ordreDessin.length)
|
|
||||||
this.viesEpuisees=0;
|
|
||||||
//nettoyer le canvas
|
|
||||||
this.ctx.clearRect(0, 0, this.$refs.width, this.$refs.height);
|
|
||||||
|
|
||||||
for(let i=0; i<viesAEpuiser; i++){
|
|
||||||
this.dessiner()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods:{
|
|
||||||
dessiner(){
|
|
||||||
if(this.viesEpuisees<this.ordreDessin.length){
|
|
||||||
this.ordreDessin[this.viesEpuisees]()
|
|
||||||
this.viesEpuisees++;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
potenceBas: function(){
|
|
||||||
// Tracer la potence (trait bas)
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(50, 200);
|
|
||||||
this.ctx.lineTo(150, 200);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
potenceVertical: function(){
|
|
||||||
this.potenceBas()
|
|
||||||
// Tracer la potence (trait vertical)
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(100, 200);
|
|
||||||
this.ctx.lineTo(100, 50);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
potencePoutre: function(){
|
|
||||||
// Tracer la potence (poutre)
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(100, 50);
|
|
||||||
this.ctx.lineTo(150, 50);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
potenceEquerre: function(){
|
|
||||||
// Tracer la potence (equerre)
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(100, 70);
|
|
||||||
this.ctx.lineTo(130, 50);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
corde: function(){
|
|
||||||
// Tracer la corde
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(150, 50); // Déplacer le point de départ au sommet de la potence
|
|
||||||
this.ctx.lineTo(150, 75); // Tracer une ligne verticale jusqu'à la tête du pendu
|
|
||||||
this.ctx.stroke(); // Dessiner le trait
|
|
||||||
},
|
|
||||||
tete: function(){
|
|
||||||
// Tracer la tête
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.arc(150, 87, 12, 0, Math.PI * 2);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
corps: function(){
|
|
||||||
// Tracer le corps
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(150, 100);
|
|
||||||
this.ctx.lineTo(150, 150);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
brasGauche: function(){
|
|
||||||
// Tracer le bras gauche
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(150, 110);
|
|
||||||
this.ctx.lineTo(130, 130);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
brasDroit: function(){
|
|
||||||
// Tracer le bras droit
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(150, 110);
|
|
||||||
this.ctx.lineTo(170, 130);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
jambeGauche: function(){
|
|
||||||
// Tracer la jambe gauche
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(150, 150);
|
|
||||||
this.ctx.lineTo(130, 180);
|
|
||||||
this.ctx.stroke();
|
|
||||||
},
|
|
||||||
jambeDroite: function(){
|
|
||||||
// Tracer la jambe droite
|
|
||||||
this.ctx.beginPath();
|
|
||||||
this.ctx.moveTo(150, 150);
|
|
||||||
this.ctx.lineTo(170, 180);
|
|
||||||
this.ctx.stroke();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<canvas ref="pendu"></canvas>
|
|
||||||
</template>
|
|
@ -1,22 +0,0 @@
|
|||||||
export class DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
//mettre les données du json directement dans l'objet
|
|
||||||
Object.keys(parsedJSON).forEach(dataName=>this[dataName]=parsedJSON[dataName])
|
|
||||||
//mettre les alias ici
|
|
||||||
//ex : l'API change _embedded en _objectList mais que l'ancien code utilisait _embedded
|
|
||||||
//this._objectList = this._embedded
|
|
||||||
|
|
||||||
//ne pas autoriser les messages d'erreur, on va plutot lancer une exception
|
|
||||||
if(this.error){
|
|
||||||
throw this.error + " : " + this.message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class PagedDataObject extends DataObject{
|
|
||||||
constructor(parsedJSON, dataObject){
|
|
||||||
super(parsedJSON)
|
|
||||||
//mettre objets correspondant dans la liste (ex : new Scientifique(obj) dans Scientifiques)
|
|
||||||
this._embedded=this._embedded.map(obj=>new dataObject(obj))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
import { REST_API } from "@/assets/const"
|
|
||||||
import { DataObject, PagedDataObject } from "./dataObject"
|
|
||||||
|
|
||||||
export class Difficulte extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Difficultes extends PagedDataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON, Difficulte)
|
|
||||||
}
|
|
||||||
static async getPage(pageNb=0, size=0){
|
|
||||||
let params=""
|
|
||||||
if(size>0){
|
|
||||||
params+=`&size=${size}`
|
|
||||||
}
|
|
||||||
const response = await fetch(`${REST_API}/difficultes?page=${pageNb}${params}`)
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* JSON de reference (Difficultes)
|
|
||||||
{
|
|
||||||
"_links" : {
|
|
||||||
"first" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/difficultes?page=0&size=2"
|
|
||||||
},
|
|
||||||
"self" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/difficultes?page=0&size=2"
|
|
||||||
},
|
|
||||||
"next" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/difficultes?page=1&size=2"
|
|
||||||
},
|
|
||||||
"last" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/difficultes?page=1&size=2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"page" : {
|
|
||||||
"size" : 2,
|
|
||||||
"totalElements" : 3,
|
|
||||||
"totalPages" : 2,
|
|
||||||
"number" : 0
|
|
||||||
},
|
|
||||||
"_embedded" : [ {
|
|
||||||
"id" : 1,
|
|
||||||
"libelle" : "Facile"
|
|
||||||
}, {
|
|
||||||
"id" : 2,
|
|
||||||
"libelle" : "Intermédiaire"
|
|
||||||
} ]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
import { REST_API } from "@/assets/const"
|
|
||||||
import { DataObject, PagedDataObject } from "./dataObject"
|
|
||||||
|
|
||||||
export class ListeJeux extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
}
|
|
||||||
static async get(){
|
|
||||||
const response = await fetch(`${REST_API}/jeux`)
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* JSON de reference (get ListeJeux)
|
|
||||||
[ {
|
|
||||||
"id" : 1,
|
|
||||||
"nom" : "Qui-est-ce ?",
|
|
||||||
"nbrParties" : 0,
|
|
||||||
"links" : [ {
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/jeux/1"
|
|
||||||
} ]
|
|
||||||
}, {
|
|
||||||
"id" : 2,
|
|
||||||
"nom" : "Science Quizz",
|
|
||||||
"nbrParties" : 0,
|
|
||||||
"links" : [ {
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/jeux/2"
|
|
||||||
} ]
|
|
||||||
}, {
|
|
||||||
"id" : 3,
|
|
||||||
"nom" : "Pendu",
|
|
||||||
"nbrParties" : 0,
|
|
||||||
"links" : [ {
|
|
||||||
"rel" : "self",
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/jeux/3"
|
|
||||||
} ]
|
|
||||||
} ]
|
|
||||||
*/
|
|
||||||
|
|
@ -1,132 +0,0 @@
|
|||||||
import { REST_API } from "@/assets/const"
|
|
||||||
import { DataObject, PagedDataObject } from "./dataObject"
|
|
||||||
import { Utilisateur } from "./utilisateur"
|
|
||||||
|
|
||||||
export class Kahoot{
|
|
||||||
constructor(codeInvitation){
|
|
||||||
this.codeInvitation=codeInvitation
|
|
||||||
this.rejoindrePartie().then()
|
|
||||||
}
|
|
||||||
async obtenirSalleAttente(){
|
|
||||||
const response=await fetch(`${REST_API}/partie/kahoot/${this.codeInvitation}/status`)
|
|
||||||
return new KahootSalleAttente(await response.json())
|
|
||||||
}
|
|
||||||
async obtenirQuestion(){
|
|
||||||
const response=await fetch(`${REST_API}/partie/kahoot/${this.codeInvitation}/question`)
|
|
||||||
return new KahootQuestion(await response.json())
|
|
||||||
}
|
|
||||||
async obtenirScore(ancienScore=0){
|
|
||||||
const user = await Utilisateur.utilisateurConnecteOuCreerInvite()
|
|
||||||
const response=await fetch(`${REST_API}/partie/kahoot/${this.codeInvitation}/status`)
|
|
||||||
let json=await response.json()
|
|
||||||
json.score=json.scores.find(score=>score.joueur.id==user.id).score
|
|
||||||
json.pointsGagne=json.score-ancienScore
|
|
||||||
return new KahootScore(json)
|
|
||||||
}
|
|
||||||
async repondreQuestion(id){
|
|
||||||
const user = await Utilisateur.utilisateurConnecteOuCreerInvite()
|
|
||||||
const response = await fetch(`${REST_API}/partie/kahoot/${this.codeInvitation}/reponse`,{
|
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify({"idJoueur":user.id, "idReponse":id})
|
|
||||||
})
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
async rejoindrePartie(){
|
|
||||||
const user = await Utilisateur.utilisateurConnecteOuCreerInvite()
|
|
||||||
const response = await fetch(`${REST_API}/partie/kahoot/${this.codeInvitation}`,{
|
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify({"idJoueur":user.id})
|
|
||||||
})
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
async demarrerPartie(){
|
|
||||||
const response = await fetch(`${REST_API}/partie/kahoot/${this.codeInvitation}/demarrer`,{
|
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"}
|
|
||||||
})
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* JSON de reference (salleAttente)
|
|
||||||
{
|
|
||||||
"joueurs":["Moi","Titouan"],
|
|
||||||
"partieDemarree":true,
|
|
||||||
"tempsLimite":${Date.now()+this.DEBUG_temps maintenant + 1 seconde}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
export class KahootSalleAttente extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
this.partieDemarree=this.status!="Pending"
|
|
||||||
this.joueurs=this.scores.map(score=>score.joueur.pseudo)
|
|
||||||
this.tempsLimite=Date.now()+1000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* JSON de reference (PartieDetails)
|
|
||||||
in: {"idJoueur": 0, "thematiques": [0,1,2,3], "idDifficulte": 0}
|
|
||||||
|
|
||||||
out:
|
|
||||||
{"id": 0,
|
|
||||||
"codeInvitation": 0,
|
|
||||||
"joueurs": [
|
|
||||||
{"id": 0, "pseudo": 0},
|
|
||||||
],
|
|
||||||
"thematiques": [
|
|
||||||
{"id": 0, "libelle": 0},
|
|
||||||
],
|
|
||||||
"difficulte": {"id":0, "libelle": 0}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
export class KahootPartie extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
}
|
|
||||||
async creerPartie(){
|
|
||||||
const user = await Utilisateur.utilisateurConnecteOuCreerInvite()
|
|
||||||
const response = await fetch(`${REST_API}/partie/kahoot`,{
|
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
//{"idJoueur": 0, "thematiques": [0,1,2,3], "idDifficulte": 0}
|
|
||||||
body:JSON.stringify({"idJoueur":user.id, "thematiques":this.thematiques, "idDifficulte":this.idDifficulte})
|
|
||||||
})
|
|
||||||
return new this.constructor(await response.json())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* JSON de reference (question)
|
|
||||||
{
|
|
||||||
"question":"Qui a reçu le prix Nobel de chimie en 1911, pour avoir réussi à isoler un gramme de radium ?",
|
|
||||||
"reponses":["Marie Curie","Einstein","Sophie Germain","Ada Lovelace"],
|
|
||||||
"tempsLimite":${Date.now()+this.DEBUG_temps maintenant + 10 secondes pour repondre}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
export class KahootQuestion extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
this.tempsLimite=new Date(this.tempsLimiteReponse).getTime()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* JSON de reference (score)
|
|
||||||
{
|
|
||||||
"status": "Pending|Started|Ended",
|
|
||||||
"scores": [
|
|
||||||
{"joueur": {"id": 0, "pseudo": 0},
|
|
||||||
"score": 0},
|
|
||||||
],
|
|
||||||
"pointsGagne":100,
|
|
||||||
"score":1337,
|
|
||||||
"tempsLimite":${Date.now()+this.DEBUG_temps maintenant + 10 secondes le temps de regarder les scores}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
export class KahootScore extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
this.tempsLimite=new Date(this.tempsAffichageScore).getTime()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
import { REST_API } from "@/assets/const"
|
|
||||||
import { DataObject, PagedDataObject } from "./dataObject"
|
|
||||||
|
|
||||||
export class Partie extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
}
|
|
||||||
async creerPartie(){
|
|
||||||
const response = await fetch(`${REST_API}/partie`,{
|
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify(this)
|
|
||||||
})
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
static async rejoindrePartie(codeInvitation, idJoueur){
|
|
||||||
const response = await fetch(`${REST_API}/partie/${codeInvitation}`,{
|
|
||||||
method:"PUT",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:{"idJoueur":idJoueur}
|
|
||||||
})
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* JSON de reference (creerInvite)
|
|
||||||
in : {pseudo: "...."}
|
|
||||||
out : {id: ?, pseudo: "?"}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* JSON de reference (creerPartie)
|
|
||||||
in:
|
|
||||||
{
|
|
||||||
"idJeu": 1,
|
|
||||||
"idJoueur": 1,
|
|
||||||
"thematiques": [1],
|
|
||||||
"idDifficulte": 1
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"codeInvitation": "44122",
|
|
||||||
"joueurs": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"pseudo": "moi, le meilleur joueur du monde"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"jeu": {
|
|
||||||
"id": 1,
|
|
||||||
"nom": "Qui-est-ce ?",
|
|
||||||
"nbrParties": 0
|
|
||||||
},
|
|
||||||
"thematiques": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"libelle": "Nucléaire"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"libelle": "Mathématiques"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"difficulte": {
|
|
||||||
"id": 3,
|
|
||||||
"libelle": "Difficile"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
@ -1,184 +0,0 @@
|
|||||||
import { REST_API } from "@/assets/const"
|
|
||||||
import { DataObject, PagedDataObject } from "./dataObject"
|
|
||||||
|
|
||||||
export class Scientifique extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
//exemple d'alias pour le pendu
|
|
||||||
this.nomComplet = this.nomComplet ?? this.nom + " " + this.prenom
|
|
||||||
}
|
|
||||||
static async get(id){
|
|
||||||
const response = await fetch(`${REST_API}/scientifiques/${id}`)
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Scientifiques extends PagedDataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON, Scientifique)
|
|
||||||
}
|
|
||||||
static async getPage(pageNb, size=0, thematiqueId=-1, difficulteId=-1){
|
|
||||||
let params=""
|
|
||||||
if(size>0){
|
|
||||||
params+=`&size=${size}`
|
|
||||||
}
|
|
||||||
if(thematiqueId>-1){
|
|
||||||
params+=`&thematiqueId=${thematiqueId}`
|
|
||||||
}
|
|
||||||
if(difficulteId>-1){
|
|
||||||
params+=`&difficulteId=${difficulteId}`
|
|
||||||
}
|
|
||||||
const response = await fetch(`${REST_API}/scientifiques?page=${pageNb}${params}`)
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ScientifiqueIndice extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ScientifiqueIndices extends PagedDataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON, ScientifiqueIndice)
|
|
||||||
}
|
|
||||||
static async getPage(idScientifique, size){
|
|
||||||
const response = await fetch(`${REST_API}/scientifiques/${idScientifique}/indices`)
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* JSON de reference (Scientifique)
|
|
||||||
{
|
|
||||||
"id" : 1,
|
|
||||||
"difficulte" : {
|
|
||||||
"id" : 1,
|
|
||||||
"libelle" : "Facile"
|
|
||||||
},
|
|
||||||
"thematique" : {
|
|
||||||
"id" : 1,
|
|
||||||
"libelle" : "Nucléaire"
|
|
||||||
},
|
|
||||||
"pathToPhoto" : "",
|
|
||||||
"nom" : "Marie",
|
|
||||||
"prenom" : "Curie",
|
|
||||||
"descriptif" : "desc",
|
|
||||||
"dateNaissance" : "2024-03-01T00:00:00.000+00:00",
|
|
||||||
"sexe" : "F",
|
|
||||||
"ratioTrouve" : 0.5,
|
|
||||||
"_links" : {
|
|
||||||
"indices" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques/1/indices"
|
|
||||||
},
|
|
||||||
"self" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques/1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* JSON de reference (Scientifiques / Page de scientifiques)
|
|
||||||
|
|
||||||
{
|
|
||||||
"_links" : {
|
|
||||||
"first" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques?page=0&size=2"
|
|
||||||
},
|
|
||||||
"self" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques?page=0&size=2"
|
|
||||||
},
|
|
||||||
"next" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques?page=1&size=2"
|
|
||||||
},
|
|
||||||
"last" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques?page=1&size=2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"page" : {
|
|
||||||
"size" : 2,
|
|
||||||
"totalElements" : 3,
|
|
||||||
"totalPages" : 2,
|
|
||||||
"number" : 0
|
|
||||||
},
|
|
||||||
"_embedded" : [ {
|
|
||||||
"id" : 1,
|
|
||||||
"difficulte" : {
|
|
||||||
"id" : 1,
|
|
||||||
"libelle" : "Facile"
|
|
||||||
},
|
|
||||||
"thematique" : {
|
|
||||||
"id" : 1,
|
|
||||||
"libelle" : "Nucléaire"
|
|
||||||
},
|
|
||||||
"pathToPhoto" : "",
|
|
||||||
"nom" : "Marie",
|
|
||||||
"prenom" : "Curie",
|
|
||||||
"descriptif" : "desc",
|
|
||||||
"dateNaissance" : "2024-03-01T00:00:00.000+00:00",
|
|
||||||
"sexe" : "F",
|
|
||||||
"ratioTrouve" : 0.5,
|
|
||||||
"_links" : {
|
|
||||||
"indices" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques/1/indices"
|
|
||||||
},
|
|
||||||
"self" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques/1"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"id" : 2,
|
|
||||||
"difficulte" : {
|
|
||||||
"id" : 1,
|
|
||||||
"libelle" : "Facile"
|
|
||||||
},
|
|
||||||
"thematique" : {
|
|
||||||
"id" : 2,
|
|
||||||
"libelle" : "Mathématiques"
|
|
||||||
},
|
|
||||||
"pathToPhoto" : "",
|
|
||||||
"nom" : "Albert",
|
|
||||||
"prenom" : "Einstein",
|
|
||||||
"descriptif" : "desc",
|
|
||||||
"dateNaissance" : "2024-03-01T00:00:00.000+00:00",
|
|
||||||
"sexe" : "H",
|
|
||||||
"ratioTrouve" : 0.754,
|
|
||||||
"_links" : {
|
|
||||||
"indices" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques/2/indices"
|
|
||||||
},
|
|
||||||
"self" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques/2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ]
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* JSON de reference (ScientifiqueIndices)
|
|
||||||
|
|
||||||
{
|
|
||||||
"_links" : {
|
|
||||||
"self" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/scientifiques/1/indices"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"_embedded" : [ {
|
|
||||||
"id" : 1,
|
|
||||||
"libelle" : "Indice pour aider",
|
|
||||||
"scientifique" : {
|
|
||||||
"id" : 1
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
"id" : 2,
|
|
||||||
"libelle" : "S'appelle Marie",
|
|
||||||
"scientifique" : {
|
|
||||||
"id" : 1
|
|
||||||
}
|
|
||||||
} ]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
@ -1,57 +0,0 @@
|
|||||||
import { REST_API } from "@/assets/const"
|
|
||||||
import { DataObject, PagedDataObject } from "./dataObject"
|
|
||||||
|
|
||||||
export class Thematique extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Thematiques extends PagedDataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON, Thematique)
|
|
||||||
}
|
|
||||||
static async getPage(pageNb=0, size=0){
|
|
||||||
let params=""
|
|
||||||
if(size>0){
|
|
||||||
params+=`&size=${size}`
|
|
||||||
}
|
|
||||||
const response = await fetch(`${REST_API}/thematiques?page=${pageNb}${params}`)
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* JSON de reference (Thematiques)
|
|
||||||
{
|
|
||||||
"_links" : {
|
|
||||||
"first" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/thematiques?page=0&size=2"
|
|
||||||
},
|
|
||||||
"self" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/thematiques?page=0&size=2"
|
|
||||||
},
|
|
||||||
"next" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/thematiques?page=1&size=2"
|
|
||||||
},
|
|
||||||
"last" : {
|
|
||||||
"href" : "http://sae-java.alix-jdlm.fr/api/v1/thematiques?page=2&size=2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"page" : {
|
|
||||||
"size" : 2,
|
|
||||||
"totalElements" : 6,
|
|
||||||
"totalPages" : 3,
|
|
||||||
"number" : 0
|
|
||||||
},
|
|
||||||
"_embedded" : [ {
|
|
||||||
"id" : 1,
|
|
||||||
"libelle" : "Nucléaire"
|
|
||||||
}, {
|
|
||||||
"id" : 2,
|
|
||||||
"libelle" : "Mathématiques"
|
|
||||||
} ]
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
|||||||
import { REST_API } from "@/assets/const"
|
|
||||||
import { DataObject, PagedDataObject } from "./dataObject"
|
|
||||||
|
|
||||||
export class Utilisateur extends DataObject{
|
|
||||||
constructor(parsedJSON){
|
|
||||||
super(parsedJSON)
|
|
||||||
}
|
|
||||||
static async get(id){
|
|
||||||
const response = await fetch(`${REST_API}/utilisateur/${id}`)
|
|
||||||
return new this(await response.json())
|
|
||||||
}
|
|
||||||
async creerCompte(){
|
|
||||||
const response = await fetch(`${REST_API}/utilisateur`,{
|
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify(this)
|
|
||||||
})
|
|
||||||
return new this.constructor(await response.json())
|
|
||||||
}
|
|
||||||
async creerInvite(){
|
|
||||||
const response = await fetch(`${REST_API}/invite`,{
|
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify(this)
|
|
||||||
})
|
|
||||||
const utilisateurConnecte=new this.constructor(await response.json())
|
|
||||||
localStorage.setItem("utilisateurConnecte",JSON.stringify(utilisateurConnecte))
|
|
||||||
return utilisateurConnecte;
|
|
||||||
}
|
|
||||||
async connecter(){
|
|
||||||
const response = await fetch(`${REST_API}/utilisateur/connexion`,{
|
|
||||||
method:"POST",
|
|
||||||
headers:{"Content-Type":"application/json"},
|
|
||||||
body:JSON.stringify(this)
|
|
||||||
})
|
|
||||||
const utilisateurConnecte=new this.constructor(await response.json())
|
|
||||||
localStorage.setItem("utilisateurConnecte",JSON.stringify(utilisateurConnecte))
|
|
||||||
return utilisateurConnecte;
|
|
||||||
}
|
|
||||||
static async deconnecter(){
|
|
||||||
localStorage.removeItem("utilisateurConnecte")
|
|
||||||
}
|
|
||||||
static async utilisateurConnecte(){
|
|
||||||
const utilisateur=JSON.parse(localStorage.getItem("utilisateurConnecte"))
|
|
||||||
if(utilisateur){
|
|
||||||
return new this(utilisateur)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
static async utilisateurConnecteOuCreerInvite(){
|
|
||||||
const utilisateur=JSON.parse(localStorage.getItem("utilisateurConnecte"))
|
|
||||||
if(utilisateur==null){
|
|
||||||
const invite=new this({"pseudo":"invitetest123123"+Date.now()})
|
|
||||||
return await invite.creerInvite()
|
|
||||||
}
|
|
||||||
return new this(utilisateur)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* JSON de reference pour le get, et retour des autres fonctions
|
|
||||||
{"email":"amogus@amog.us", "pseudo":"amogus", "id":"2"}
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* JSON de reference (creerCompte)
|
|
||||||
{"email":"amogus@amog.us", "pseudo":"amogus", "motDePasse":"hunter2"}
|
|
||||||
*/
|
|
||||||
/* JSON de reference (creerInvite)
|
|
||||||
{"pseudo":"amogus"}
|
|
||||||
*/
|
|
||||||
/* JSON de reference (connecter)
|
|
||||||
in : {"email":"amogus@amog.us", "motDePasse":"hunter2"}
|
|
||||||
out : {"email":"amogus@amog.us", "pseudo":"amogus", "id":"2"}
|
|
||||||
*/
|
|
@ -1,45 +0,0 @@
|
|||||||
import './assets/main.css'
|
|
||||||
|
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
|
||||||
import { createApp } from 'vue'
|
|
||||||
import App from './App.vue'
|
|
||||||
|
|
||||||
//importer bootstrap
|
|
||||||
import * as bootstrap from 'bootstrap'
|
|
||||||
import './scss/styles.scss'
|
|
||||||
|
|
||||||
//importer les components pour le routing
|
|
||||||
import PagePrincipale from "./components/PagePrincipale.vue"
|
|
||||||
import NotFound from "./components/erreurs/NotFound.vue"
|
|
||||||
import TestParametreURL from "./components/TestParametreURL.vue"
|
|
||||||
|
|
||||||
import Login from "./components/Login.vue"
|
|
||||||
import Inscription from './components/Inscription.vue'
|
|
||||||
import Profil from './components/Profil.vue'
|
|
||||||
|
|
||||||
import KahootVue from './components/jeux/kahoot/Kahoot.vue'
|
|
||||||
import KahootPartie from './components/jeux/kahoot/KahootPartie.vue'
|
|
||||||
import CreerPartie from './components/jeux/creerPartie.vue'
|
|
||||||
import Pendu from './components/jeux/pendu/Pendu.vue'
|
|
||||||
import AdminGestionDonnees from "./components/admin/gestion/Liste.vue"
|
|
||||||
|
|
||||||
const routes = [
|
|
||||||
{ path: '/', component: PagePrincipale },
|
|
||||||
{ path: '/login', component: Login },
|
|
||||||
{ path: '/inscription', component: Inscription },
|
|
||||||
{ path: '/profil', component: Profil },
|
|
||||||
{ path: '/kahoot', component: KahootVue}, //TODO: changer la route pour qu'elle soit trouvée automatiquement par le serveur (ce que demande l'utilisateur)
|
|
||||||
{ path: '/kahoot/partie/:code', component: KahootPartie},
|
|
||||||
{ path: '/partie', component: CreerPartie},
|
|
||||||
{ path: '/pendu', component: Pendu },
|
|
||||||
{ path: '/exemple/:id', component: TestParametreURL },
|
|
||||||
{ path: '/admin/gestion', component: AdminGestionDonnees },
|
|
||||||
{ path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound },
|
|
||||||
]
|
|
||||||
|
|
||||||
const router = createRouter({
|
|
||||||
history: createWebHistory(import.meta.env.BASE_URL),
|
|
||||||
routes, // short for `routes: routes`
|
|
||||||
})
|
|
||||||
|
|
||||||
createApp(App).use(router).mount('#app')
|
|
@ -1,65 +0,0 @@
|
|||||||
// kahoot styles
|
|
||||||
|
|
||||||
@import "styles.scss";
|
|
||||||
|
|
||||||
.Kahoot-Header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1em;
|
|
||||||
background-color: var(--bs-primary);
|
|
||||||
color: $light;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Kahoot-content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Kahoot-List {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Kahoot-Create {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
background-color: var(--bs-primary);
|
|
||||||
color: $light;
|
|
||||||
}
|
|
||||||
|
|
||||||
// kahoot styles
|
|
||||||
.Kahoot-content {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Kahoot-List {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.Kahoot-Create {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
padding: 1em;
|
|
||||||
|
|
||||||
label {
|
|
||||||
font-weight: bold;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.Kahoot-List-Item {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1em;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
background-color: var(--bs-secondary-bg);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 2px 4px var(--bs-border-color)
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
//template
|
|
||||||
template {
|
|
||||||
font-family: 'Roboto', sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 1.6;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
//landing page styles
|
|
||||||
.landingPage {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1em;
|
|
||||||
justify-content: space-around;
|
|
||||||
height: 100vh;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingContent {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingContent h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
animation: dropIn 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingContent p {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
animation: dropIn 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingPage img {
|
|
||||||
width: 20%;
|
|
||||||
height: auto;
|
|
||||||
animation: slideInRight 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.routes-button{
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
align-items: center;
|
|
||||||
margin-top: 2rem;
|
|
||||||
animation: dropIn 2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
//footer
|
|
||||||
footer {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: flex-start;
|
|
||||||
align-items: center;
|
|
||||||
padding: 1em;
|
|
||||||
background-color: #000;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
//keyframes
|
|
||||||
@keyframes dropIn {
|
|
||||||
0% {
|
|
||||||
transform: translateY(-100%);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateY(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slideIn {
|
|
||||||
0% {
|
|
||||||
transform: translateX(-100%);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slideInRight {
|
|
||||||
0% {
|
|
||||||
transform: translateX(100%);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Media queries for responsiveness
|
|
||||||
@media screen and (max-width: 768px) {
|
|
||||||
.landingPage {
|
|
||||||
flex-direction: row;
|
|
||||||
justify-content: start;
|
|
||||||
padding: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingContent {
|
|
||||||
margin-bottom: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingContent h1 {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingContent p {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingPage img {
|
|
||||||
width: 50%;
|
|
||||||
height: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.landingContent button {
|
|
||||||
font-size: 1rem;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
@import "bootstrap/scss/bootstrap";
|
|
Before Width: | Height: | Size: 110 KiB |
@ -1,16 +0,0 @@
|
|||||||
import { fileURLToPath, URL } from 'node:url'
|
|
||||||
|
|
||||||
import { defineConfig } from 'vite'
|
|
||||||
import vue from '@vitejs/plugin-vue'
|
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [
|
|
||||||
vue(),
|
|
||||||
],
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
Loading…
Reference in new issue