Fixed stats graph being filled below line. Added page to show after successful observation submission.

This commit is contained in:
neviyn 2018-10-08 14:10:19 +01:00
parent ed3b748469
commit 02ed4b8b08
7 changed files with 238 additions and 205 deletions

View File

@ -53,7 +53,8 @@ data class ChartDataset(
val label: String,
val backgroundColor: String,
val borderColor: String,
val data: List<Double>
val data: List<Double>,
val fill: Boolean = false
){
constructor(label: String, color: String, data: List<Double>): this(label, color, color, data)
}

View File

@ -10,9 +10,9 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.core.AuthenticationException
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint
import org.springframework.stereotype.Component
import java.io.IOException
import javax.servlet.ServletException

View File

@ -6,6 +6,8 @@
<b-collapse is-nav id="nav_collapse">
<b-navbar-nav>
<b-nav-item to="/">New Observation</b-nav-item>
<b-nav-item to="/observations">View Observations</b-nav-item>
<b-nav-item to="/stats">Graphs</b-nav-item>
</b-navbar-nav>
<!-- Right aligned nav items -->
<b-navbar-nav class="ml-auto">
@ -31,12 +33,4 @@
text-align: center;
color: #2c3e50;
}
#nav {
padding: 10px;
}
#nav a.router-link-exact-active {
color: #42b983;
}
</style>

View File

@ -6,40 +6,46 @@ import Stats from "./views/Stats.vue";
import NewSite from "./views/NewSite.vue";
import NewTutor from "./views/NewTutor.vue";
import ViewObservations from "./views/ViewObservations.vue";
import ObservationComplete from "./views/ObservationComplete.vue";
Vue.use(Router);
export default new Router({
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/observation",
name: "observation",
component: Observation
},
{
path: "/stats",
name: "stats",
component: Stats
},
{
path: "/newsite",
name: "newSite",
component: NewSite
},
{
path: "/newtutor",
name: "newTutor",
component: NewTutor
},
{
path: "/observations",
name: "observations",
component: ViewObservations
}
]
routes: [
{
path: "/",
name: "home",
component: Home
},
{
path: "/observation",
name: "observation",
component: Observation
},
{
path: "/stats",
name: "stats",
component: Stats
},
{
path: "/newsite",
name: "newSite",
component: NewSite
},
{
path: "/newtutor",
name: "newTutor",
component: NewTutor
},
{
path: "/observations",
name: "observations",
component: ViewObservations
},
{
path: "/complete",
name: "complete",
component: ObservationComplete
}
]
});

View File

@ -91,14 +91,14 @@
</b-row>
</b-form>
<b-modal id="submissionModal"
ref="modal"
ref="submissionModal"
title="Enter password to confirm submission"
@ok="handleOk"
@shown="clearPassword">
<form @submit.stop.prevent="handleSubmit">
<b-form-input type="password"
placeholder="Enter password"
v-model="name"></b-form-input>
v-model="submitPassword"></b-form-input>
</form>
</b-modal>
</b-container>
@ -209,23 +209,26 @@
showModal() {
this.$refs.submissionModal.show();
},
hideModal() {
this.$refs.submissionModal.hide();
this.submitPassword = null;
},
clearPassword() {
this.submitPassword = null
},
handleOk(evt) {
// Prevent modal from closing
evt.preventDefault();
if (this.password) {
if (this.submitPassword !== null) {
this.handleSubmit()
}
},
handleSubmit() {
var form = document.getElementById("submission-form");
if (form.checkValidity()) {
let axiosConfig = {
auth: {
username: "admin",
password: this.submitPassword
}
};
var self = this;
Vue.axios
.post("/observation", {
site: this.site,
@ -234,9 +237,9 @@
whom: this.whom,
type: this.type,
entries: JSON.parse(JSON.stringify(this.observations))
})
}, axiosConfig)
.then(function (response) {
this.hideModal();
self.$router.push("/complete");
console.log(response);
})
.catch(function (error) {

View File

@ -0,0 +1,23 @@
<template>
<b-container>
<h2>Submission Complete</h2>
<p>{{ type }}/{{ description }} has been submitted successfully.</p>
<b-button size="lg" variant="primary" to="/">
Start New Observation
</b-button>
</b-container>
</template>
<script>
import {mapState} from "vuex";
export default {
name: "ObservationComplete",
computed: {
...mapState(["description", "type", "whom", "site", "tutors"])
}
}
</script>
<style scoped>
</style>

View File

@ -1,164 +1,170 @@
<template>
<b-container>
<b-modal ref="errorModal" class="text-center" centered hide-header hide-footer>
<div class="modal-header">
<h3 class="modal-title w-100">{{ errorStatus }}</h3>
</div>
<div class="d-block">
<br />
<span style="font-size:20px;" v-html="errorMessage" />
<button class="btn btn-warning" @click="$refs.errorModal.hide()">
<v-icon name="exclamation-circle" /> Dismiss</button>
</div>
</b-modal>
<b-row>
<b-col>
<b-form-group label="Site">
<b-form-select class="text-center" v-model="siteSelection" :options="siteOptions" />
</b-form-group>
</b-col>
<b-col>
<b-form-group label="Tutor">
<b-form-select class="text-center" v-model="tutorSelection" :options="tutorOptions" />
</b-form-group>
</b-col>
<b-col>
<b-form-group label="Who">
<b-form-input class="text-center" v-model="whom" type="text"></b-form-input>
</b-form-group>
</b-col>
<b-col>
<b-form-group label="From">
<date-picker v-model="startDate" @dp-change="changeStartDate" value="startDate" :config="dateOptions" />
</b-form-group>
</b-col>
<b-col>
<b-form-group label="To">
<date-picker v-model="endDate" @dp-change="changeEndDate" value="endDate" :config="dateOptions" />
</b-form-group>
</b-col>
<b-col>
<b-button v-on:click="getFilteredAverage()">Refresh</b-button>
</b-col>
</b-row>
<b-row>
<b-col>
<stats-view v-if="chartData != null && chartData != {}" v-bind:chartData="chartData" :options="options" />
</b-col>
</b-row>
</b-container>
<b-container>
<b-modal ref="errorModal" class="text-center" centered hide-header hide-footer>
<div class="modal-header">
<h3 class="modal-title w-100">{{ errorStatus }}</h3>
</div>
<div class="d-block">
<br/>
<span style="font-size:20px;" v-html="errorMessage"/>
<button class="btn btn-warning" @click="$refs.errorModal.hide()">
<v-icon name="exclamation-circle"/>
Dismiss
</button>
</div>
</b-modal>
<b-row>
<b-col>
<b-form-group label="Site">
<b-form-select class="text-center" v-model="siteSelection" :options="siteOptions"/>
</b-form-group>
</b-col>
<b-col>
<b-form-group label="Tutor">
<b-form-select class="text-center" v-model="tutorSelection" :options="tutorOptions"/>
</b-form-group>
</b-col>
<b-col>
<b-form-group label="Who">
<b-form-input class="text-center" v-model="whom" type="text"></b-form-input>
</b-form-group>
</b-col>
<b-col>
<b-form-group label="From">
<date-picker v-model="startDate" @dp-change="changeStartDate" value="startDate"
:config="dateOptions"/>
</b-form-group>
</b-col>
<b-col>
<b-form-group label="To">
<date-picker v-model="endDate" @dp-change="changeEndDate" value="endDate" :config="dateOptions"/>
</b-form-group>
</b-col>
<b-col>
<b-button v-on:click="getFilteredAverage()">Refresh</b-button>
</b-col>
</b-row>
<b-row>
<b-col>
<stats-view v-if="chartData != null && chartData !== {}" v-bind:chartData="chartData"
style="position: relative; height:80vh" :options="options"/>
</b-col>
</b-row>
</b-container>
</template>
<script>
import Vue from "vue";
import StatsView from "../components/StatsView";
var moment = require("moment");
export default {
name: "stats",
components: { StatsView },
data: function() {
return {
chartData: null,
options: {
responsive: true,
tooltips: {
mode: "index",
intersect: false
import Vue from "vue";
import StatsView from "../components/StatsView";
var moment = require("moment");
export default {
name: "stats",
components: {StatsView},
data: function () {
return {
chartData: null,
options: {
responsive: true,
maintainAspectRatio: false,
tooltips: {
mode: "index",
intersect: false
},
hover: {
mode: "nearest",
intersect: true
},
scales: {
xAxes: [
{
display: true,
scaleLabel: {
display: true,
labelString: "Date"
}
}
],
yAxes: [
{
display: true,
scaleLabel: {
display: true,
labelString: "Average Score"
}
}
]
}
},
errorStatus: null,
errorMessage: null,
startDate: moment().subtract(7, "days"),
endDate: moment(),
dateOptions: {
format: "DD/MM/YYYY",
useCurrent: false
},
siteSelection: null,
siteOptions: [],
tutorSelection: null,
tutorOptions: [],
whom: null
};
},
hover: {
mode: "nearest",
intersect: true
methods: {
getFilteredAverage: function () {
Vue.axios
.post("/observations/chartdata", {
'site': this.siteSelection,
'tutor': this.tutorSelection,
'startDate': moment(this.startDate).format("YYYY-MM-DD"),
'endDate': moment(this.endDate).format("YYYY-MM-DD"),
'whom': this.whom
})
.then(response => {
this.chartData = response.data;
})
.catch(error => {
this.errorStatus = error.response.status;
this.errorMessage = error.response.data;
this.$refs.errorModal.show();
});
},
getTutors: function () {
if (this.siteSelection != null) {
Vue.axios
.get("/site/" + this.siteSelection + "/tutors")
.then(response => {
this.tutorOptions = response.data;
});
}
},
changeStartDate: function (e) {
this.startDate = e.date;
},
changeEndDate: function (e) {
this.endDate = e.date;
}
},
scales: {
xAxes: [
{
display: true,
scaleLabel: {
display: true,
labelString: "Date"
}
watch: {
siteSelection: function () {
this.tutorOptions = [];
this.tutorSelection = null;
this.getTutors();
}
],
yAxes: [
{
display: true,
scaleLabel: {
display: true,
labelString: "Average Score"
}
}
]
},
mounted() {
this.getFilteredAverage();
Vue.axios
.get("/site")
.then(response => {
this.siteOptions = response.data;
})
.catch(error => {
this.errorStatus = error.response.status;
this.errorMessage = error.response.data;
this.$refs.errorModal.show();
});
}
},
errorStatus: null,
errorMessage: null,
startDate: moment().subtract(7, "days"),
endDate: moment(),
dateOptions: {
format: "DD/MM/YYYY",
useCurrent: false
},
siteSelection: null,
siteOptions: [],
tutorSelection: null,
tutorOptions: null,
whom: null
};
},
methods: {
getFilteredAverage: function() {
Vue.axios
.post("/observations/chartdata", {
'site': this.siteSelection,
'tutor': this.tutorSelection,
'startDate': moment(this.startDate).format("YYYY-MM-DD"),
'endDate': moment(this.endDate).format("YYYY-MM-DD"),
'whom': this.whom
})
.then(response => {
this.chartData = response.data;
})
.catch(error => {
this.errorStatus = error.response.status;
this.errorMessage = error.response.data;
this.$refs.errorModal.show();
});
},
getTutors: function() {
if (this.siteSelection != null) {
Vue.axios
.get("/site/" + this.siteSelection + "/tutors")
.then(response => {
this.tutorOptions = response.data;
});
}
},
changeStartDate: function(e) {
this.startDate = e.date;
},
changeEndDate: function(e) {
this.endDate = e.date;
}
},
watch: {
siteSelection: function() {
this.tutorOptions = [];
this.tutorSelection = null;
this.getTutors();
}
},
mounted() {
this.getFilteredAverage();
Vue.axios
.get("/site")
.then(response => {
this.siteOptions = response.data;
})
.catch(error => {
this.errorStatus = error.response.status;
this.errorMessage = error.response.data;
this.$refs.errorModal.show();
});
}
};
</script>