Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0025ec9213 | |||
| 489328c624 | |||
| 36a211e186 | |||
| d7c4c87959 | |||
| 3cd9db65ec | |||
| e03798af13 | |||
| 1fd4e89f84 | |||
| c05b799334 | |||
| b9f0316f76 | |||
| 2b3cbb4061 | |||
| 0653deba64 | |||
| 67a9417f2b | |||
| ca49223432 | |||
| 6d0d23d0dd | |||
| 6c9061d4d9 | |||
| 56b9be01ba | |||
| c8935c41cb | |||
| 1d96dcc0a8 | |||
| 811de8f5e2 | |||
| ec4196088a | |||
| 863fdcb50e |
Generated
+17
-2
@@ -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",
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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,7 +1,7 @@
|
||||
<template>
|
||||
<div id="overall">
|
||||
<p>这是 Overall</p>
|
||||
<graph-overall></graph-overall>
|
||||
<graph-overall :chart="convertCharts"></graph-overall>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user