Visual for vote majoritaire

This commit is contained in:
ArenMg 2021-07-14 00:12:10 +03:00
parent 0e188df57a
commit e8fd938e1c
9 changed files with 769 additions and 87 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -19,6 +19,8 @@ const router = new VueRouter({
{path: '/sondages', component: vueLoader('views/sondages')}, {path: '/sondages', component: vueLoader('views/sondages')},
{path: '/sondage', component: vueLoader('views/sondage')}, {path: '/sondage', component: vueLoader('views/sondage')},
{path: '/votemajoritaire', component: vueLoader('views/votemajoritaire')}, {path: '/votemajoritaire', component: vueLoader('views/votemajoritaire')},
{path: '/createVoteMajoritaire', component: vueLoader('views/createVoteMajoritaire')},
{path: '/votemajoritairedetails', component: vueLoader('views/votemajoritairedetails')},
{path: '*', component: vueLoader('views/404')}, {path: '*', component: vueLoader('views/404')},
] ]
}); });

File diff suppressed because one or more lines are too long

View file

@ -54,12 +54,7 @@
</p> </p>
<button <button
class="exit-btn" class="exit-btn"
@click=" @click="() => {isNotInserted = false;}">
() => {
isNotInserted = false;
}
"
>
fermer fermer
</button> </button>
</div> </div>

View file

@ -0,0 +1,291 @@
<template>
<div class="box-container">
<base-layout id="majoritaire">
<p></p>
<template v-slot:title>
<h1>Création vote majoritaire</h1>
<div class="space-top">
<span>Selectionnez un groupe</span>
<select class="browser-default" v-model="themeInfo.team">
<option v-for="team in teams" :key="team.id" :value="team">
{{ team.name }}
</option>
</select>
<label>
<span>Titre</span>
<input type="text" v-model="themeInfo.title" />
</label>
<label>
<span>Description</span>
</label>
<div class="choice-container">
<tooltiped tag="div" v-bind:value="editionMode">
<wysiwyg-editor
v-model="themeInfo.description"
v-bind:enabled="editionMode"
>
</wysiwyg-editor>
</tooltiped>
</div>
<label class="block space-top">
<span class="block">Date de fin de vote</span>
<v-date-picker
v-model="themeInfo.expiracyDate"
mode="dateTime"
:timezone="timezone"
:min-date="new Date()"
color="red"
/>
</label>
</div>
<div class="space-top">
<div v-for="(choice, k) in choices" :key="k" class="sous-theme-block">
<label>
<span>{{ choice.choice_title_label }}</span>
<div class="choice-container">
<input
class="choice-text"
type="text"
v-model="choice.choice_title"
/>
</div>
</label>
<label>
<span>Description</span>
</label>
<div class="choice-container">
<tooltiped tag="div" v-bind:value="editionMode">
<wysiwyg-editor
v-model="choice.choice_description"
v-bind:enabled="editionMode"
>
</wysiwyg-editor>
</tooltiped>
</div>
<label>
<span>Image</span>
<div class="choice-container">
<input
class="choice-text"
type="text"
v-model="choice.choice_image"
/>
</div>
</label>
<label>
<span>URL</span>
<div class="choice-container">
<input
class="choice-text"
type="text"
v-model="choice.choice_url"
/>
</div>
</label>
</div>
<div class="box-footer">
<button
@click="addMoreChoice()"
class="add-choice-btn"
title="Ajouter un nouveau choix"
>
<img
height="50"
width="50"
alt="ajouter"
src="assets/img/add.png"
/>
</button>
<button
v-if="choices.length > 2"
@click="removeChoice()"
class="rem-choice-btn"
title="Supprimer le dernier choix"
>
<img
height="40"
width="40"
alt="supprimer"
src="assets/img/delete.png"
/>
</button>
<button @click="saveVoteMajoritaire()" class="create-vote-btn">
<span>Créer la vote majoritaire</span>
</button>
</div>
</div>
</template>
</base-layout>
</div>
</template>
<style scoped>
.block {
display: block;
}
.space-top {
margin-top: 4em;
}
.box-container {
border: 1px solid #a1a3a1;
border-radius: 10px;
padding-top: 2em;
width: 50%;
margin: 2em auto;
}
.box-footer {
display: flex;
flex-direction: row;
}
.choice-container {
display: flex;
flex-direction: column;
}
.choice-text {
flex: 1;
margin-right: 1rem !important;
}
.sous-theme-block {
border: 1px solid;
padding: 1.5em;
margin: 1em 0;
}
.add-choice-btn {
background-color: #3d82bb;
padding: 0.3rem;
border-radius: 0.5rem;
color: white;
border-color: transparent;
box-shadow: 0.1rem 0.1rem 1rem #3d82bb;
margin: 2rem 1rem;
cursor: pointer;
}
.rem-choice-btn {
background-color: #e06d6d;
padding: 0.6rem;
border-radius: 0.5rem;
color: white;
border-color: transparent;
box-shadow: 0.1rem 0.1rem 1rem #e06d6d;
margin: 2rem 1rem;
cursor: pointer;
}
.create-vote-btn {
background-color: #6de09d;
padding: 0.3rem;
border-radius: 0.5rem;
color: white;
border-color: transparent;
box-shadow: 0.1rem 0.1rem 1rem #6de09d;
margin: 2rem 1rem;
cursor: pointer;
}
</style>
<script>
module.exports = {
data() {
return {
timezone: "",
themeInfo: {
author: false,
team: false,
title: "",
description: "",
expiracyDate: new Date(),
},
document: { content: "" },
teams: false,
editionMode: true,
choices: [
{
choice_title_label: "Choix numéro 1",
choice_title: "",
choice_description: "",
choice_image: "",
choice_url: "",
},
{
choice_title_label: "Choix numéro 2",
choice_title: "",
choice_description: "",
choice_image: "",
choice_url: "",
},
],
};
},
created() {
if (!this.$root.user.is("MODO")) {
this.$router.push("/404");
}
this.fetchData();
},
methods: {
async fetchData() {
try {
let user = await axios.get(`${ApiBaseUri}/users/me`);
this.themeInfo.author = user.data;
let allteams = await axios.get(`${ApiBaseUri}/teams`);
this.teams = allteams.data;
} catch (error) {
alert(
"ERREUR INTERNE\n\nToutes nos excuses, une erreur s'est produite sur nos serveurs.\nVeuillez réessayer ou contacter un administrateur si l'erreur persiste."
);
console.error(error);
}
},
addMoreChoice() {
this.choices.push({
choice_title_label: `Choix numéro ${this.choices.length + 1}`,
choice_title: "",
choice_description: "",
choice_image: "",
choice_url: "",
});
},
removeChoice() {
this.choices.pop();
},
async saveVoteMajoritaire() {
let data = { ...this.themeInfo };
try {
let newVoteMajoritaire = await axios({
method: "POST",
url: `${ApiBaseUri}/vm/themes`,
data,
});
for (const choice of this.choices) {
const choice_data = {
themeId: newVoteMajoritaire.data,
title: choice.choice_title,
description: choice.choice_description,
img: choice.choice_image,
url: choice.choice_url,
};
const newChoice = await axios({
method: "POST",
url: `${ApiBaseUri}/vm/choices`,
data: choice_data,
});
}
swal("Succès!", "L a été créé", "success").then((value) => {
this.$router.push("/");
});
} catch (error) {
swal("Erreur!", `Erreur, Veuillez réésayer plus tard`, "error");
console.error(error);
}
},
},
components: {
"wysiwyg-editor": vueLoader("components/widgets/wysiwygEditor"),
},
};
</script>

View file

@ -2,16 +2,54 @@
<div class="box-container"> <div class="box-container">
<base-layout id="votelayout"> <base-layout id="votelayout">
<template v-slot:title> <template v-slot:title>
<h1>Vote majoritaire</h1> <div class="vm-header">
<h1 class="vm-header-title">Vote majoritaire</h1>
<router-link
v-if="$root.user.is('MODO')"
to="/createVoteMajoritaire"
class="waves-effect waves-light btn"
>
Créer vote majoritaires
</router-link>
</div>
</template> </template>
<div class="space-top"> <div class="space-top">
<div id="chart"> <div
<apexchart class="empty-container"
type="bar" v-if="!voteMajoritaireList || !voteMajoritaireList.length"
height="350" >
:options="chartOptions" <span>Aucun</span>
:series="series" </div>
></apexchart> <div class="vm-container">
<div class="row center-align" id="vmList">
<div
v-for="program in voteMajoritaireList"
v-bind:key="program.id"
class="col"
>
<router-link
v-bind:to="'/votemajoritairedetails?id=' + program.id"
class="card hoverable center-align"
>
<div class="card-image light-color valign-wrapper">
<img
alt="image"
class="category-picture"
src="assets/img/vmajoritaire.png"
/>
</div>
<div>
<h2 v-bind:title="program.title">{{ program.title }}</h2>
</div>
<div class="card-footer light-color">
<span
>Fin de vote le
{{ new Date(program.expiracyDate).toLocaleString() }}</span
>
</div>
</router-link>
</div>
</div>
</div> </div>
</div> </div>
</base-layout> </base-layout>
@ -26,6 +64,16 @@
width: 50%; width: 50%;
margin: 2em auto; margin: 2em auto;
} }
.vm-header {
display: flex;
flex-direction: row;
align-items: center;
}
.vm-header-title {
flex: 1;
}
.vm-container {
}
.space-top { .space-top {
margin-top: 4em; margin-top: 4em;
} }
@ -38,77 +86,30 @@
module.exports = { module.exports = {
data() { data() {
return { return {
series: [ voteMajoritaireList: false,
{
name: "Marine Sprite",
data: [44, 55, 41, 37, 22, 43, 21],
},
{
name: "Striking Calf",
data: [53, 32, 33, 52, 13, 43, 32],
},
{
name: "Tank Picture",
data: [12, 17, 11, 9, 15, 11, 20],
},
{
name: "Bucket Slope",
data: [9, 7, 5, 8, 6, 9, 4],
},
{
name: "Reborn Kid",
data: [25, 12, 19, 32, 25, 24, 10],
},
],
chartOptions: {
chart: {
type: "bar",
height: 350,
stacked: true,
},
plotOptions: {
bar: {
horizontal: true,
},
},
stroke: {
width: 1,
colors: ["#fff"],
},
title: {
text: "Fiction Books Sales",
},
xaxis: {
categories: [2008, 2009, 2010, 2011, 2012, 2013, 2014],
labels: {
formatter: function (val) {
return val + "K";
},
},
},
yaxis: {
title: {
text: undefined,
},
},
tooltip: {
y: {
formatter: function (val) {
return val + "K";
},
},
},
fill: {
opacity: 1,
},
legend: {
position: "top",
horizontalAlign: "left",
offsetX: 40,
},
},
}; };
}, },
methods: {}, created() {
if (!this.$root.user.is("USER")) {
this.$router.push("/404");
}
this.fetchData();
},
methods: {
async fetchData() {
try {
const vms = await axios({
method: "GET",
url: `${ApiBaseUri}/vm/themes`,
});
this.voteMajoritaireList = vms.data;
} catch (error) {
alert(
"ERREUR INTERNE\n\nToutes nos excuses, une erreur s'est produite sur nos serveurs.\nVeuillez réessayer ou contacter un administrateur si l'erreur persiste."
);
console.log(error);
}
},
},
}; };
</script> </script>

View file

@ -0,0 +1,375 @@
<template>
<div class="box-container">
<base-layout id="votelayout">
<template v-slot:title>
<div class="vm-header">
<h1 class="vm-header-title">{{ currentTheme.title }}</h1>
<router-link
v-if="$root.user.is('MODO')"
to="/createVoteMajoritaire"
class="waves-effect waves-light btn"
>
Créer vote majoritaires
</router-link>
</div>
<span class="creaeted-at">
Créé le {{ new Date(currentTheme.createdAt).toLocaleString() }}
</span>
<div v-html="currentTheme.description"></div>
</template>
<div v-if="showVote" class="space-top tableau-vote">
<h1 class="vm-header-title">Vote</h1>
<table id="vote-majoritaire-table">
<thead>
<tr>
<th class="tab-head-cell" id="vm-vote-header">Vote</th>
<th class="tab-head-cell" id="vm-vote-reject">A rejeter</th>
<th class="tab-head-cell" id="vm-vote-insuff">Insuffisant</th>
<th class="tab-head-cell" id="vm-vote-passable">Passable</th>
<th class="tab-head-cell" id="vm-vote-gooden">Assez-bien</th>
<th class="tab-head-cell" id="vm-vote-good">Bien</th>
<th class="tab-head-cell" id="vm-vote-vergood">Très-bien</th>
</tr>
</thead>
<tbody>
<tr v-for="(choice, k) in currentTheme.choices" :key="k">
<td>{{ choice.title }}</td>
<td class="chek-cell-container">
<input
type="checkbox"
v-model="choicesValue[k].opinion"
true-value="REJECTED"
false-value="REJECTED"
class="vote-check"
disabled
/>
</td>
<td class="chek-cell-container">
<input
type="checkbox"
v-model="choicesValue[k].opinion"
true-value="INSUFFICIENT"
false-value="REJECTED"
class="vote-check"
/>
</td>
<td class="chek-cell-container">
<input
type="checkbox"
v-model="choicesValue[k].opinion"
true-value="PASS"
false-value="REJECTED"
class="vote-check"
/>
</td>
<td class="chek-cell-container">
<input
type="checkbox"
v-model="choicesValue[k].opinion"
true-value="ACCEPTABLE"
false-value="REJECTED"
class="vote-check"
/>
</td>
<td class="chek-cell-container">
<input
type="checkbox"
v-model="choicesValue[k].opinion"
true-value="GOOD"
false-value="REJECTED"
class="vote-check"
/>
</td>
<td class="chek-cell-container">
<input
type="checkbox"
v-model="choicesValue[k].opinion"
true-value="VERY_GOOD"
false-value="REJECTED"
class="vote-check"
/>
</td>
</tr>
</tbody>
</table>
<button @click="saveVoteMajoritaire()" class="create-vote-btn">
<span>Valider mon choix</span>
</button>
</div>
<div class="space-top">
<h1 class="vm-header-title">Résultat</h1>
<div v-if="typeof currentTheme === `object`" id="chart">
<apexchart
type="bar"
height="350"
:options="chartOptions"
:series="series"
></apexchart>
</div>
</div>
</base-layout>
</div>
</template>
<style lang="css" scoped>
.box-container {
border: 1px solid #a1a3a1;
border-radius: 10px;
padding-top: 2em;
width: 50%;
margin: 2em auto;
}
.vm-header {
display: flex;
flex-direction: row;
align-items: center;
}
.vm-header-title {
flex: 1;
}
.space-top {
margin-top: 4em;
}
.block {
display: block;
}
.creaeted-at {
color: gray;
font-size: 10px;
opacity: 0.7;
}
.vote-check {
opacity: 1;
pointer-events: auto;
position: unset;
}
#vote-majoritaire-table {
table-layout: fixed;
}
#vm-vote-reject {
background-color: #e3493c;
}
#vm-vote-insuff {
background-color: #f07c0a;
}
#vm-vote-passable {
background-color: #fff209;
}
#vm-vote-gooden {
background-color: #c9e537;
}
#vm-vote-good {
background-color: #92d050;
}
#vm-vote-vergood {
background-color: #00b050;
}
.chek-cell-container {
text-align: center;
}
.tab-head-cell {
text-align: center;
}
.create-vote-btn {
background-color: #6de09d;
padding: 1.3rem;
border-radius: 0.5rem;
color: white;
border-color: transparent;
box-shadow: 0.1rem 0.1rem 1rem #6de09d;
margin: 2rem 1rem;
cursor: pointer;
}
</style>
<script>
module.exports = {
data() {
return {
currentTheme: false,
choicesValue: false,
showVote: true, //Change this when check alredy make vote is avalaible in ws
series: [],
chartOptions: {
colors: [
"#E3493C",
"#F07C0A",
"#FFF209",
"#C9E537",
"#92D050",
"#00B050",
],
chart: {
type: "bar",
height: 200,
stacked: true,
},
plotOptions: {
bar: {
horizontal: true,
},
},
stroke: {
width: 1,
colors: ["#fff"],
},
title: {
text: `Résultat du vote : ${this.currentTheme.title ?? ""} `,
},
xaxis: {
categories: false,
labels: {
show: false,
},
lines: {
show: false,
},
axisBorder: {
show: false,
},
axisTicks: {
show: false,
},
},
yaxis: {
title: {
text: undefined,
},
lines: {
show: false,
},
},
fill: {
opacity: 1,
},
legend: {
position: "top",
horizontalAlign: "left",
offsetX: 40,
},
},
};
},
created() {
if (!this.$root.user.is("USER")) {
this.$router.push("/404");
}
this.fetchData();
},
methods: {
async fetchData() {
this.series = [];
try {
const user = await axios.get(`${ApiBaseUri}/users/me`);
const theme = await axios({
method: "GET",
url: `${ApiBaseUri}/vm/themes/${this.$route.query.id}`,
});
this.currentTheme = theme.data;
this.choicesValue = theme.data.choices.map((e) => ({
subThemeId: e,
authorId: user.data,
opinion: "REJECTED",
}));
this.series.push(
{
name: "A rejeter",
data: this.currentTheme.choices.map((e) => e.rejected),
},
{
name: "Insuffisant",
data: this.currentTheme.choices.map((e) => e.insufficient),
},
{
name: "Passable",
data: this.currentTheme.choices.map((e) => e.pass),
},
{
name: "Assez-bien",
data: this.currentTheme.choices.map((e) => e.acceptable),
},
{
name: "Bien",
data: this.currentTheme.choices.map((e) => e.good),
},
{
name: "Très-bien",
data: this.currentTheme.choices.map((e) => e.veryGood),
}
);
this.chartOptions.xaxis.categories = this.currentTheme.choices.map(
(e) => e.title
);
/**
* Uncomment this when check alredy make vote is avalaible in ws
*
for (const choice of theme.data.choices) {
for (const vote of choice.votes) {
const authId = vote.authorId;
if (typeof authId === "number") {
if (authId === user.data.id) {
this.showVote = false;
return;
}
}
if (typeof authId === "object") {
if (authId.id === user.data.id) {
this.showVote = false;
return;
}
}
}
this.showVote = true;
}
*/
} catch (error) {
alert(
"ERREUR INTERNE\n\nToutes nos excuses, une erreur s'est produite sur nos serveurs.\nVeuillez réessayer ou contacter un administrateur si l'erreur persiste."
);
console.log(error);
}
},
async saveVoteMajoritaire() {
try {
for (const choice of this.choicesValue) {
const newChoice = await axios({
method: "POST",
url: `${ApiBaseUri}/vm/votes`,
data: choice,
});
console.log(choice);
}
swal("Succès!", "Vote enregistré", "success").then((value) => {
this.fetchData();
});
} catch (error) {
swal("Erreur!", `Erreur, Veuillez réésayer plus tard`, "error");
console.error(error);
}
},
},
components: {
apexchart: VueApexCharts,
},
};
</script>

View file

@ -47,6 +47,8 @@
<script src="assets/js/vendors/v-calendar.umd.js"></script> <script src="assets/js/vendors/v-calendar.umd.js"></script>
<script src="assets/js/vendors/axios.js"></script> <script src="assets/js/vendors/axios.js"></script>
<script src="assets/js/vendors/sweetalert.min.js"></script> <script src="assets/js/vendors/sweetalert.min.js"></script>
<script src="assets/js/vendors/apexcharts.js"></script>
<script src="assets/js/vendors/vue-apexcharts.js"></script> <script src="assets/js/vendors/vue-apexcharts.js"></script>
<% } else { %> <% } else { %>
@ -68,7 +70,8 @@
<script src="assets/js/vendors/v-calendar.umd.js"></script> <script src="assets/js/vendors/v-calendar.umd.js"></script>
<script src="assets/js/vendors/axios.js"></script> <script src="assets/js/vendors/axios.js"></script>
<script src="assets/js/vendors/sweetalert.min.js"></script> <script src="assets/js/vendors/sweetalert.min.js"></script>
<script src="assets/js/vendors/apexcharts.js"></script>
<script src="assets/js/vendors/vue-apexcharts.js"></script> <script src="assets/js/vendors/vue-apexcharts.js"></script>
<% }%> <% }%>
</head> </head>
@ -105,8 +108,8 @@
<li v-if="user.is('ADMIN')"> <li v-if="user.is('ADMIN')">
<router-link to="/sondages" v-bind:class="{ active: $route.path === '/sondages' || $route.path === '/sondage' }">Sondages</router-link> <router-link to="/sondages" v-bind:class="{ active: $route.path === '/sondages' || $route.path === '/sondage' }">Sondages</router-link>
</li> </li>
<li> <li v-if="user.is('USER')">
<router-link to="/votemajoritaire" v-bind:class="{ active: $route.path === '/votemajoritaire' }">Votes majoritaires</router-link> <router-link to="/votemajoritaire" v-bind:class="{ active: $route.path === '/votemajoritaire' || $route.path === '/createVoteMajoritaire' || $route.path === '/votemajoritairedetails'}">Votes majoritaires</router-link>
</li> </li>
</ul> </ul>
@ -235,6 +238,7 @@
const blueColor = styles.getPropertyValue('--blue-color'); const blueColor = styles.getPropertyValue('--blue-color');
const greenColor = styles.getPropertyValue('--green-color'); const greenColor = styles.getPropertyValue('--green-color');
const greyColor = styles.getPropertyValue('--grey-color'); const greyColor = styles.getPropertyValue('--grey-color');
const ApiBaseUri = `${document.baseURI}ws`;
new Vue({ new Vue({
el: "#app", el: "#app",