Compare commits

...

21 Commits

Author SHA1 Message Date
Hykilpikonna 0025ec9213 [O] Optimize graph creation 2019-09-06 19:43:36 -04:00
Hykilpikonna 489328c624 [+] Use the chart data to show chart 2019-08-27 20:55:33 +08:00
Hykilpikonna 36a211e186 [+] Create method to convert chart data 2019-08-27 20:55:06 +08:00
Hykilpikonna d7c4c87959 [+] Create courses prop. and pass it from overall.vue 2019-08-25 01:57:11 +08:00
Hykilpikonna 3cd9db65ec [+] Create courses prop. and pass it from app.vue 2019-08-25 01:56:52 +08:00
Hykilpikonna e03798af13 Merge branch 'optimization' into feature 2019-08-24 21:21:38 +08:00
Hykilpikonna 1fd4e89f84 [+] Add proper documentation to the fields 2019-08-24 21:21:04 +08:00
Hykilpikonna c05b799334 [O] Show overall only when assignments are ready. 2019-08-24 21:18:51 +08:00
Hykilpikonna b9f0316f76 [+] Wait for isAssignmentReady() 2019-08-24 21:16:42 +08:00
Hykilpikonna 2b3cbb4061 [+] Create method to check if the courses are ready 2019-08-24 21:16:13 +08:00
Hykilpikonna 0653deba64 [+] Import pWaitFor dependency 2019-08-24 21:08:06 +08:00
Hykilpikonna 67a9417f2b [+] Create assignmentsReady field 2019-08-24 21:05:41 +08:00
Hykilpikonna ca49223432 [+] Get assignments for all the courses 2019-08-24 21:05:23 +08:00
Hykilpikonna 6d0d23d0dd [O] Specify type for the onLogin method 2019-08-24 20:39:43 +08:00
Hykilpikonna 6c9061d4d9 [O] Specify type for the courses field 2019-08-24 20:39:29 +08:00
Hykilpikonna 56b9be01ba [+] Create course interface 2019-08-24 20:39:14 +08:00
Hykilpikonna c8935c41cb [M] Move Grade interface to App.ts 2019-08-24 20:39:00 +08:00
Hykilpikonna 1d96dcc0a8 [+] Create method to filter assignments 2019-08-22 21:58:16 +08:00
Hykilpikonna 811de8f5e2 [+] Create a grade interfacce 2019-08-22 21:58:01 +08:00
Hykilpikonna ec4196088a [+] Create json utils class 2019-08-22 21:57:48 +08:00
Hykilpikonna 863fdcb50e Merge branch 'bug-fixes' into feature 2019-08-22 21:05:51 +08:00
9 changed files with 228 additions and 9 deletions
+17 -2
View File
@@ -7546,8 +7546,7 @@
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/p-finally/download/p-finally-1.0.0.tgz",
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
"dev": true
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-is-promise": {
"version": "2.1.0",
@@ -7588,12 +7587,28 @@
"retry": "^0.12.0"
}
},
"p-timeout": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.1.0.tgz",
"integrity": "sha512-C27DYI+tCroT8J8cTEyySGydl2B7FlxrGNF5/wmMbl1V+jeehUCzEE/BVgzRebdm2K3ZitKOKx8YbdFumDyYmw==",
"requires": {
"p-finally": "^1.0.0"
}
},
"p-try": {
"version": "1.0.0",
"resolved": "https://registry.npm.taobao.org/p-try/download/p-try-1.0.0.tgz",
"integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=",
"dev": true
},
"p-wait-for": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-3.1.0.tgz",
"integrity": "sha512-0Uy19uhxbssHelu9ynDMcON6BmMk6pH8551CvxROhiz3Vx+yC4RqxjyIDk2V4ll0g9177RKT++PK4zcV58uJ7A==",
"requires": {
"p-timeout": "^3.0.0"
}
},
"pako": {
"version": "1.0.10",
"resolved": "https://registry.npm.taobao.org/pako/download/pako-1.0.10.tgz",
+1
View File
@@ -11,6 +11,7 @@
"core-js": "^2.6.5",
"echarts": "^4.2.1",
"element-ui": "^2.11.1",
"p-wait-for": "^3.1.0",
"v-charts": "^1.19.0",
"vue": "^2.6.10",
"vue-class-component": "^7.0.2",
+81 -2
View File
@@ -2,24 +2,62 @@ import {Component, Vue} from 'vue-property-decorator';
import Login from '@/components/login/login';
import Navigation from '@/components/navigation/navigation';
import Overall from '@/pages/overall/overall';
import Constants from '@/constants';
import JsonUtils from '@/utils/json-utils';
import pWaitFor from 'p-wait-for';
/**
* Objects of this interface represent assignment grades.
*/
export interface Grade
{
type: string,
description: string,
date: string,
complete: string,
include: boolean,
display: boolean,
scoreMax: number,
score: number
}
/**
* A course
*/
export interface Course
{
assignmentsId: number,
id: number,
name: string,
teacherName: string,
assignments: Grade[]
}
@Component({
components: {Login, Navigation, Overall},
})
export default class App extends Vue
{
// Is the login panel shown
public showLogin: boolean = true;
public courses = null;
// List of course that the student takes
public courses: Course[] = [];
// Currently selected tab
public selectedTab: string = "overall";
// Are the course assignments loaded from the server.
public assignmentsReady: boolean = false;
/**
* This is called when the user logs in.
*
* @param courses Courses Json
*/
public onLogin(courses: any)
public onLogin(courses: Course[])
{
// Hide login bar
this.showLogin = false;
@@ -29,6 +67,47 @@ export default class App extends Vue
// Debug output TODO: Remove this
console.log(courses);
// Get assignments for all the courses
this.courses.forEach(course =>
{
// Send request to get assignments
fetch(`${Constants.API_URL}/veracross/assignments?id=${course.assignmentsId}`).then(res =>
{
// Get response body text
res.text().then(text =>
{
// Parse json and filter it
course.assignments = JsonUtils.filterAssignments(JSON.parse(text));
})
})
.catch(err =>
{
alert(err);
});
});
// Wait for assignments to be ready.
pWaitFor(() => this.isAssignmentsReady()).then(() =>
{
// When the assignments are ready
this.assignmentsReady = true;
});
}
/**
* Are assignments ready or not
*
* @returns boolean Ready or not
*/
private isAssignmentsReady(): boolean
{
for (const course of this.courses)
{
if (course.assignments == null) return false;
}
return true;
}
/**
+1 -1
View File
@@ -4,7 +4,7 @@
<navigation :courses="courses" v-on:navigation:select="onNavigate"></navigation>
<div id="app-content">
<overall v-if="selectedTab === 'overall'"></overall>
<overall :courses="courses" v-if="selectedTab === 'overall' && assignmentsReady"></overall>
</div>
</div>
</template>
@@ -1,9 +1,12 @@
import {Component, Vue} from 'vue-property-decorator';
import {Component, Prop, Vue} from 'vue-property-decorator';
import {Course} from '@/components/app/app';
@Component({
})
export default class GraphOverall extends Vue
{
@Prop({required: true}) chart: any;
public chartData =
{
columns: ['日期', '访问用户', '下单用户', '下单率'],
@@ -1,6 +1,6 @@
<template>
<div id="graph-overall">
<ve-line :data="chartData" :extend="{series: {smooth: false}}"></ve-line>
<ve-line :data="chart" :extend="{series: {smooth: false}}"></ve-line>
</div>
</template>
+89 -1
View File
@@ -1,10 +1,98 @@
import {Component, Vue} from 'vue-property-decorator';
import {Component, Prop, Vue} from 'vue-property-decorator';
import GraphOverall from '@/pages/overall/graph-overall/graph-overall';
import {Course} from '@/components/app/app';
@Component({
components: {GraphOverall}
})
export default class Overall extends Vue
{
@Prop({required: true}) courses: any;
get convertCharts()
{
// Null case
if (this.courses == null) return [];
// Compute the column names
let columns = ['date'];
this.courses.forEach((course: Course) =>
{
columns.push(course.name);
});
// Find the min date
let minDate: Date = new Date();
this.courses.forEach((course: Course) =>
{
let date = new Date(course.assignments[course.assignments.length - 1].date);
if (date < minDate) minDate = date;
});
// Find the dates in between
let now = new Date();
let dates = [];
for (let date = minDate; date <= now; date.setDate(date.getDate() + 1))
{
dates.push(new Date(date));
}
// Initialize course specific variables
let courseScores: {[index: string]: any} = {};
let courseMaxScores: {[index: string]: any} = {};
let courseIndexes: {[index: string]: any} = {};
this.courses.forEach((course: Course) =>
{
courseScores[course.name] = 0;
courseMaxScores[course.name] = 0;
courseIndexes[course.name] = course.assignments.length - 1;
});
// Compute the rows data
let rows: {[index: string]: any}[] = [];
dates.forEach(date =>
{
// Define row object
let row: {[index: string]:any} = {'date': date.toLocaleDateString('en-US')};
// Loop through courses
this.courses.forEach((course: Course) =>
{
// Reversed loop through the assignments
for (let r = courseIndexes[course.name]; r >= 0; r--)
{
let assignment = course.assignments[r];
let assignmentDate = new Date(assignment.date);
// Date is being looked at
if (assignmentDate.getTime() == date.getTime())
{
// Record scores
courseScores[course.name] += assignment.score;
courseMaxScores[course.name] += assignment.scoreMax;
}
// Not now
else if (assignmentDate > date)
{
courseIndexes[course.name] = r;
break;
}
}
// Add average to the row
row[course.name] = courseScores[course.name] / courseMaxScores[course.name] * 100;
});
// Add it to the array
rows.push(row);
});
console.log(rows);
return {
columns: columns,
rows: rows
}
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
<template>
<div id="overall">
<p>这是 Overall</p>
<graph-overall></graph-overall>
<graph-overall :chart="convertCharts"></graph-overall>
</div>
</template>
+33
View File
@@ -0,0 +1,33 @@
import {Grade} from '@/components/app/app';
export default class JsonUtils
{
/**
* This method filters the information provided in an assignments json.
*
* @param assignments Assignments object
* @returns Grade[] Filtered assignment grade object list
*/
public static filterAssignments(assignments: any): Grade[]
{
let result: Grade[] = [];
assignments.assignments.forEach((assignment: any) =>
{
result.push(
{
type: assignment.assignment_type,
description: assignment.assignment_description,
date: assignment._date,
complete: assignment.complete_status,
include: assignment.include_in_calculated_grade == 1,
display: assignment.display_grade == 1,
scoreMax: assignment.maximum_score,
score: +assignment.raw_score
});
});
return result;
}
}