Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b41296507 |
-21
@@ -1,21 +0,0 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
/dist
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.*.local
|
||||
|
||||
# Log files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>404: Redirecting...</title>
|
||||
<meta http-equiv = "refresh" content = "0; url = https://vera.hydev.org/" />
|
||||
</head>
|
||||
<body>
|
||||
404 Not Found! Redirecting to (<a href="https://vera.hydev.org">https://vera.hydev.org</a>)...
|
||||
<script>
|
||||
window.location.href = 'https://vera.hydev.org';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,29 +0,0 @@
|
||||
# veracross-analyzer
|
||||
|
||||
## Project setup
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Compiles and hot-reloads for development
|
||||
```
|
||||
npm run serve
|
||||
```
|
||||
|
||||
### Compiles and minifies for production
|
||||
```
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Run your tests
|
||||
```
|
||||
npm run test
|
||||
```
|
||||
|
||||
### Lints and fixes files
|
||||
```
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Customize configuration
|
||||
See [Configuration Reference](https://cli.vuejs.org/config/).
|
||||
@@ -1,5 +0,0 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
'@vue/app'
|
||||
]
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"success":true,"data":{"assignments":[{"score_id":5593330,"id":322150,"assignment_id":322150,"assignment_type_id":3,"assignment_type":"Quiz","assignment_type_sort_key":3,"assignment_description":"2.3 Open Notes","grading_period":"Quarter 1","assignment_date_long":"Wed, Sep 11","due_date_long":"Wed, Sep 11","due_date":"Sep 11","due_day":"Wed","_date":"09/11/2019","include_in_calculated_grade":1,"num_attachments":0,"num_criteria":0,"num_feedback":0,"maximum_score":16,"points_possible":16,"raw_score":"14","percent_grade":"8750%","completion_status_id":3,"completion_status":"Complete","is_unread":1.0,"is_notification":0,"is_problem":0,"display_grade":1,"display_score":1,"display_maximum_score":1,"display_percent_grade":1,"display_points_possible":1,"allow_student_feedback":0},{"score_id":5584935,"id":321649,"assignment_id":321649,"assignment_type_id":3,"assignment_type":"Quiz","assignment_type_sort_key":3,"assignment_description":"2.2 Open Notes","grading_period":"Quarter 1","assignment_date_long":"Mon, Sep 09","due_date_long":"Mon, Sep 09","due_date":"Sep 09","due_day":"Mon","_date":"09/09/2019","include_in_calculated_grade":1,"num_attachments":0,"num_criteria":0,"num_feedback":0,"maximum_score":10,"points_possible":10,"raw_score":"6","percent_grade":"6000%","completion_status_id":3,"completion_status":"Complete","is_notification":0,"is_problem":0,"display_grade":1,"display_score":1,"display_maximum_score":1,"display_percent_grade":1,"display_points_possible":1,"allow_student_feedback":0},{"score_id":5602940,"id":322723,"assignment_id":322723,"assignment_type_id":2,"assignment_type":"Homework","assignment_type_sort_key":2,"assignment_description":"Autobiography","grading_period":"Quarter 1","assignment_date_long":"Wed, Sep 04","due_date_long":"Thu, Sep 05","due_date":"Sep 05","due_day":"Thu","_date":"09/05/2019","include_in_calculated_grade":1,"num_attachments":0,"num_criteria":0,"num_feedback":0,"maximum_score":10,"points_possible":10,"raw_score":"","percent_grade":"0%","completion_status_id":0,"completion_status":"Pending","is_notification":0,"is_problem":0,"display_grade":1,"display_score":1,"display_maximum_score":1,"display_percent_grade":1,"display_points_possible":1,"allow_student_feedback":0}],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
|
||||
@@ -0,0 +1 @@
|
||||
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
|
||||
@@ -0,0 +1 @@
|
||||
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
|
||||
@@ -0,0 +1 @@
|
||||
{"success":true,"data":{"assignments":[],"attachments":[],"criteria":[],"criteria_grade_scale_levels":[]}}
|
||||
@@ -0,0 +1,250 @@
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"user": {
|
||||
"id": 1,
|
||||
"schoolPersonPk": 109467,
|
||||
"username": "ygui21",
|
||||
"lastLogin": "Jun 5, 2020 1:28:51 PM",
|
||||
"firstLogin": "Dec 2, 2019 7:31:15 PM",
|
||||
"firstName": "Yijie",
|
||||
"lastName": "Gui",
|
||||
"graduationYear": 2021,
|
||||
"emails": "ygui21@stjohnsprep.org",
|
||||
"classes": "32451|32453|32458|32856|32872|32874|32878|32880|32882|32890|33070|33093|33121|33173|33337|33464|34174|34197|34199|34209"
|
||||
},
|
||||
"token": "Removed",
|
||||
"courses": [
|
||||
{
|
||||
"level": "H",
|
||||
"id_ci": 196,
|
||||
"rating": {
|
||||
"id_ci": 196,
|
||||
"id_user": 1,
|
||||
"userFullName": "Yijie]\u003d[Gui",
|
||||
"ratings": [
|
||||
5,
|
||||
5,
|
||||
3,
|
||||
5,
|
||||
4
|
||||
],
|
||||
"comment": "Mr. Crowell\u0027s selected books for this course are very interesting, and the essay topics are generally unique too, allowing us to express our creativity. His lectures are also very in-depth, strengthening our understanding of the ideas that the authors wanted to express. However, the style of the classroom might be boring for some people. For grading fairness, I think it is very fair, but his standards are a little bit too high because achieving a perfect score for an essay is very much impossible."
|
||||
},
|
||||
"name": "English 3 H",
|
||||
"teacherName": "Mr. Crowell",
|
||||
"id": 33337,
|
||||
"assignmentsId": 10934147,
|
||||
"letterGrade": "A+",
|
||||
"numericGrade": 97.14,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "AP",
|
||||
"id_ci": 19,
|
||||
"rating": {
|
||||
"id_ci": 19,
|
||||
"id_user": -1,
|
||||
"userFullName": "Anonymous]\u003d[Student",
|
||||
"ratings": [
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
5
|
||||
],
|
||||
"comment": "Calculus made so much easier"
|
||||
},
|
||||
"name": "AP Calculus AB (Juniors)",
|
||||
"teacherName": "Ms. Dobrowolski",
|
||||
"id": 32453,
|
||||
"assignmentsId": 10934142,
|
||||
"letterGrade": "A+",
|
||||
"numericGrade": 100.0,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "AP",
|
||||
"id_ci": 251,
|
||||
"rating": {
|
||||
"id_ci": 251,
|
||||
"id_user": 1,
|
||||
"userFullName": "Yijie]\u003d[Gui",
|
||||
"ratings": [
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
5
|
||||
],
|
||||
"comment": "Cations go meow"
|
||||
},
|
||||
"name": "AP Chemistry",
|
||||
"teacherName": "Ms. Stone",
|
||||
"id": 33464,
|
||||
"assignmentsId": 10934148,
|
||||
"letterGrade": "A+",
|
||||
"numericGrade": 100.0,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "AP",
|
||||
"id_ci": 22,
|
||||
"rating": {
|
||||
"id_ci": 22,
|
||||
"id_user": 1,
|
||||
"userFullName": "Yijie]\u003d[Gui",
|
||||
"ratings": [
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
3,
|
||||
4
|
||||
],
|
||||
"comment": "Mr. Dankert can\u0027t really systematically teach, often he forgets to tell us something very important and then forgets that he forgot. The labs explained a lot of them very well."
|
||||
},
|
||||
"name": "AP Physics 1",
|
||||
"teacherName": "Mr. Dankert",
|
||||
"id": 32458,
|
||||
"assignmentsId": 10934143,
|
||||
"letterGrade": "A",
|
||||
"numericGrade": 95.67,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "AP",
|
||||
"id_ci": 18,
|
||||
"rating": {
|
||||
"id_ci": 18,
|
||||
"id_user": 1,
|
||||
"userFullName": "Yijie]\u003d[Gui",
|
||||
"ratings": [
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
5
|
||||
],
|
||||
"comment": "Psychology is the best, and most valuable class I\u0027ve ever taken! Everything is just so relatable to my life!"
|
||||
},
|
||||
"name": "AP Psychology",
|
||||
"teacherName": "Mr. Emerson",
|
||||
"id": 32451,
|
||||
"assignmentsId": 10934141,
|
||||
"letterGrade": "A+",
|
||||
"numericGrade": 100.0,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "A",
|
||||
"id_ci": 98,
|
||||
"rating": {
|
||||
"id_ci": 98,
|
||||
"id_user": 1,
|
||||
"userFullName": "Yijie]\u003d[Gui",
|
||||
"ratings": [
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
5,
|
||||
5
|
||||
],
|
||||
"comment": "Mr. Pynchon is very nice and encouraging."
|
||||
},
|
||||
"name": "US History A",
|
||||
"teacherName": "Mr. Pynchon",
|
||||
"id": 33093,
|
||||
"assignmentsId": 10941280,
|
||||
"letterGrade": "A+",
|
||||
"numericGrade": 99.39,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "H",
|
||||
"id_ci": 100,
|
||||
"name": "US History H",
|
||||
"teacherName": "Ms. Heath",
|
||||
"id": 33096,
|
||||
"assignmentsId": 10934144,
|
||||
"status": "past"
|
||||
},
|
||||
{
|
||||
"level": "A",
|
||||
"id_ci": 134,
|
||||
"name": "Relational Dynamics A",
|
||||
"teacherName": "Mr. Reinbold",
|
||||
"id": 33173,
|
||||
"assignmentsId": 10934146,
|
||||
"status": "past"
|
||||
},
|
||||
{
|
||||
"level": "A",
|
||||
"id_ci": 77,
|
||||
"rating": {
|
||||
"id_ci": 77,
|
||||
"id_user": -1,
|
||||
"userFullName": "Anonymous]\u003d[Student",
|
||||
"ratings": [
|
||||
5,
|
||||
4,
|
||||
5,
|
||||
5,
|
||||
3
|
||||
],
|
||||
"comment": "Honestly, everything is great except that the grading is way too harsh for an Accelerated course."
|
||||
},
|
||||
"name": "Social Justice A",
|
||||
"teacherName": "Mr. Reinbold",
|
||||
"id": 33121,
|
||||
"assignmentsId": 10934145,
|
||||
"letterGrade": "A+",
|
||||
"numericGrade": 97.0,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "Sport",
|
||||
"name": "Yoga AS",
|
||||
"teacherName": "Ms. Fanikos",
|
||||
"id": 33070,
|
||||
"assignmentsId": 10935189,
|
||||
"status": "past"
|
||||
},
|
||||
{
|
||||
"level": "Club",
|
||||
"id_ci": 316,
|
||||
"name": "HS Magic Trick Club 2019",
|
||||
"teacherName": "Mr. Reinbold",
|
||||
"id": 34174,
|
||||
"assignmentsId": 10949139,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "Club",
|
||||
"id_ci": 331,
|
||||
"name": "HS Science \u0026amp; Technology 2019",
|
||||
"teacherName": "Ms. Erwin",
|
||||
"id": 34197,
|
||||
"assignmentsId": 10952100,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "Club",
|
||||
"id_ci": 333,
|
||||
"name": "HS Computer Club 2019",
|
||||
"teacherName": "Mr. Gilmore",
|
||||
"id": 34199,
|
||||
"assignmentsId": 10951448,
|
||||
"status": "active"
|
||||
},
|
||||
{
|
||||
"level": "Club",
|
||||
"id_ci": 336,
|
||||
"name": "HS Chinese Ambassadors Club 2019",
|
||||
"teacherName": "Mrs. Mills",
|
||||
"id": 34209,
|
||||
"assignmentsId": 10953979,
|
||||
"status": "active"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1,5 @@
|
||||
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=1024"><link rel=icon href=/logo@32px.png><title>Veracross Analyzer</title><link href=/css/app.72ceade9.css rel=preload as=style><link href=/js/app.c7702e9a.js rel=preload as=script><link href=/js/chunk-vendors.4383782d.js rel=preload as=script><link href=/css/app.72ceade9.css rel=stylesheet></head><body style="margin: 0"><noscript><strong>We're sorry but veracross-analyzer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js></script><script src=https://cdn.jsdelivr.net/npm/v-charts/lib/index.min.js></script><link rel=stylesheet href=https://cdn.jsdelivr.net/npm/v-charts/lib/style.min.css><link rel=stylesheet href=https://unpkg.com/element-ui/lib/theme-chalk/index.css><link href="https://fonts.googleapis.com/css?family=Nunito+Sans&display=swap" rel=stylesheet><script src=/js/chunk-vendors.4383782d.js></script><script src=/js/app.c7702e9a.js></script></body><script async src="https://www.googletagmanager.com/gtag/js?id=G-Q615K1KFLC"></script><script>window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-Q615K1KFLC');</script></html>
|
||||
@@ -0,0 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Redirecting...</title>
|
||||
<meta http-equiv = "refresh" content = "0; url = https://vera.hydev.org/#info" />
|
||||
</head>
|
||||
<body>
|
||||
Redirecting to (<a href="https://vera.hydev.org/#info">https://vera.hydev.org/#info</a>)...
|
||||
<script>
|
||||
window.location.href = 'https://vera.hydev.org/#info';
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
|
After Width: | Height: | Size: 5.2 KiB |
Generated
-11595
File diff suppressed because it is too large
Load Diff
@@ -1,38 +0,0 @@
|
||||
{
|
||||
"name": "veracross-analyzer",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"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",
|
||||
"vue-property-decorator": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "^3.10.0",
|
||||
"@vue/cli-plugin-typescript": "^3.10.0",
|
||||
"@vue/cli-service": "^3.10.0",
|
||||
"node-sass": "^4.9.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
"typescript": "^3.4.3",
|
||||
"vue-template-compiler": "^2.6.10"
|
||||
},
|
||||
"postcss": {
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions"
|
||||
]
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
|
||||
<title>Veracross Analyzer</title>
|
||||
</head>
|
||||
|
||||
<body style="margin: 0">
|
||||
<noscript>
|
||||
<strong>We're sorry but veracross-analyzer doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
|
||||
<div id="app"></div>
|
||||
|
||||
<!-- V-Charts -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/v-charts/lib/index.min.js"></script>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/v-charts/lib/style.min.css">
|
||||
|
||||
<!-- ElementUI -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
|
||||
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,2 +0,0 @@
|
||||
cd ../
|
||||
npm run serve
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 6.7 KiB |
@@ -1,8 +0,0 @@
|
||||
#app
|
||||
{
|
||||
font-family: 'Avenir', Helvetica, Arial, sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
text-align: center;
|
||||
color: #2c3e50;
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
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;
|
||||
|
||||
// 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: Course[])
|
||||
{
|
||||
// Hide login bar
|
||||
this.showLogin = false;
|
||||
|
||||
// Assign courses
|
||||
this.courses = courses;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when a navigation tab is clicked
|
||||
*
|
||||
* @param tab Tab name
|
||||
*/
|
||||
public onNavigate(tab: string)
|
||||
{
|
||||
// Debug output TODO: Remove this
|
||||
console.log(tab);
|
||||
|
||||
// Update selected tab
|
||||
this.selectedTab = tab;
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<login v-if="showLogin" v-on:login:courses="onLogin"></login>
|
||||
<navigation :courses="courses" v-on:navigation:select="onNavigate"></navigation>
|
||||
|
||||
<div id="app-content">
|
||||
<overall :courses="courses" v-if="selectedTab === 'overall' && assignmentsReady"></overall>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./app.ts" lang="ts"></script>
|
||||
<style src="./app.scss" lang="scss"></style>
|
||||
@@ -1,74 +0,0 @@
|
||||
|
||||
// Parent div for login
|
||||
#login
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Parent overlay
|
||||
.login-overlay
|
||||
{
|
||||
// Credit to w3schools.com:
|
||||
// https://www.w3schools.com/howto/howto_js_fullscreen_overlay.asp
|
||||
|
||||
// Fill entire screen
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
|
||||
// Stay in place
|
||||
position: fixed;
|
||||
|
||||
// Sit on top layer
|
||||
z-index: 1;
|
||||
|
||||
// Overlay color
|
||||
background-color: rgba(0,0,0, 0.65);
|
||||
|
||||
// Disable horizontal scroll
|
||||
overflow-x: hidden;
|
||||
|
||||
// Make it a table for vertical centering
|
||||
display: table;
|
||||
}
|
||||
|
||||
.login-vertical-center
|
||||
{
|
||||
// Vertically center
|
||||
display: table-cell;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
// The user interacting panel
|
||||
.login-panel
|
||||
{
|
||||
// Make it smaller
|
||||
width: 256px;
|
||||
|
||||
// Center
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
|
||||
// Borders
|
||||
padding: 15px;
|
||||
border-radius: 10px;
|
||||
// box-shadow: 0 0 20px 0 white;
|
||||
border: 1px solid #DCDFE6;
|
||||
|
||||
// Make it white
|
||||
background-color: white;
|
||||
|
||||
// Input bars
|
||||
.el-input
|
||||
{
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
// Button
|
||||
.el-button
|
||||
{
|
||||
margin: 5px 0;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import {Component, Vue} from 'vue-property-decorator';
|
||||
import Constants from '@/constants';
|
||||
|
||||
/**
|
||||
* This component handles user login, and obtains data from the server.
|
||||
*/
|
||||
@Component({
|
||||
components: {},
|
||||
})
|
||||
export default class Login extends Vue
|
||||
{
|
||||
public username: any = '';
|
||||
public password: any = '';
|
||||
|
||||
public loading: boolean = false;
|
||||
|
||||
/**
|
||||
* On click, sends username and password to the server.
|
||||
*/
|
||||
public onLoginClick()
|
||||
{
|
||||
// Make login button loading
|
||||
this.loading = true;
|
||||
|
||||
// Fetch request TODO: Add username and password when the https server is ready.
|
||||
fetch(`${Constants.API_URL}/veracross/courses`).then(res =>
|
||||
{
|
||||
// Get response body text
|
||||
res.text().then(text =>
|
||||
{
|
||||
// Call custom event with courses info
|
||||
this.$emit('login:courses', JSON.parse(text));
|
||||
})
|
||||
})
|
||||
.catch(err =>
|
||||
{
|
||||
alert(err);
|
||||
|
||||
// Allow the user to retry
|
||||
this.loading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<template>
|
||||
<div id="login" class="login-overlay">
|
||||
<div class="login-vertical-center">
|
||||
<div class="login-panel">
|
||||
<img alt="Vue logo" src="../../assets/logo.png">
|
||||
<h1>Veracross Analyzer</h1>
|
||||
<el-input v-model="username" placeholder="School Username"></el-input>
|
||||
<el-input v-model="password" placeholder="Veracross Password" show-password=""></el-input>
|
||||
<el-button plain type="primary" @click="onLoginClick" :loading="loading">Login</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./login.ts" lang="ts"></script>
|
||||
<style src="./login.scss" lang="scss"></style>
|
||||
@@ -1,5 +0,0 @@
|
||||
.el-menu.centered li
|
||||
{
|
||||
display: inline-block !important;
|
||||
float: none !important;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
import {Component, Prop, Vue} from 'vue-property-decorator';
|
||||
import Constants from '@/constants';
|
||||
|
||||
/**
|
||||
* This component is the top navigation bar
|
||||
*/
|
||||
@Component({
|
||||
components: {},
|
||||
})
|
||||
export default class Navigation extends Vue
|
||||
{
|
||||
public activeIndex: string = 'overall';
|
||||
|
||||
@Prop() courses: any;
|
||||
|
||||
/**
|
||||
* This function is called when the selection changes.
|
||||
*
|
||||
* @param index The index selected
|
||||
* @param indexPath The path of the index
|
||||
*/
|
||||
public onSelect(index: string, indexPath: string)
|
||||
{
|
||||
// Update active index
|
||||
this.activeIndex = index;
|
||||
|
||||
// Call custom event
|
||||
this.$emit('navigation:select', this.activeIndex);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<template>
|
||||
<div id="navigation">
|
||||
<el-menu class="centered" :default-active="activeIndex" mode="horizontal" @select="onSelect">
|
||||
|
||||
<el-menu-item index="overall">Overall</el-menu-item>
|
||||
|
||||
<el-submenu index="courses">
|
||||
<template slot="title">Courses</template>
|
||||
<el-menu-item v-for="course in courses"
|
||||
:index="`course-${course.name}`"
|
||||
:key="course.name">{{course.name}}</el-menu-item>
|
||||
</el-submenu>
|
||||
|
||||
</el-menu>
|
||||
<div class="line"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./navigation.ts" lang="ts"></script>
|
||||
<style src="./navigation.scss" lang="scss"></style>
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* This class stores the static constants.
|
||||
*/
|
||||
export default class Constants
|
||||
{
|
||||
/**
|
||||
* Base url for api access
|
||||
* TODO: Use https for actual usage
|
||||
*/
|
||||
public static API_URL: string = 'http://cn2.hydev.org:24021/api';
|
||||
}
|
||||
-18
@@ -1,18 +0,0 @@
|
||||
import Vue from 'vue';
|
||||
import ElementUI from 'element-ui';
|
||||
const VCharts = require('v-charts');
|
||||
|
||||
import App from './components/app/app.vue';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
// Use Element UI
|
||||
Vue.use(ElementUI, {locale: 'en-us'});
|
||||
|
||||
// Use VCharts
|
||||
Vue.use(VCharts);
|
||||
|
||||
// Init app
|
||||
new Vue({
|
||||
render: (h) => h(App),
|
||||
}).$mount('#app');
|
||||
@@ -1,22 +0,0 @@
|
||||
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: ['日期', '访问用户', '下单用户', '下单率'],
|
||||
rows: [
|
||||
{ '日期': '1/1', '访问用户': 1393, '下单用户': 1093, '下单率': 0.32 },
|
||||
{ '日期': '1/2', '访问用户': 3530, '下单用户': 3230, '下单率': 0.26 },
|
||||
{ '日期': '1/3', '访问用户': 2923, '下单用户': 2623, '下单率': 0.76 },
|
||||
{ '日期': '1/4', '访问用户': 1723, '下单用户': 1423, '下单率': 0.49 },
|
||||
{ '日期': '1/5', '访问用户': 3792, '下单用户': 3492, '下单率': 0.323 },
|
||||
{ '日期': '1/6', '访问用户': 4593, '下单用户': 4293, '下单率': 0.78 }
|
||||
]
|
||||
};
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<template>
|
||||
<div id="graph-overall">
|
||||
<ve-line :data="chart" :extend="{series: {smooth: false}}"></ve-line>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./graph-overall.ts" lang="ts"></script>
|
||||
<style src="./graph-overall.scss" lang="scss"></style>
|
||||
@@ -1,98 +0,0 @@
|
||||
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,9 +0,0 @@
|
||||
<template>
|
||||
<div id="overall">
|
||||
<p>这是 Overall</p>
|
||||
<graph-overall :chart="convertCharts"></graph-overall>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./overall.ts" lang="ts"></script>
|
||||
<style src="./overall.scss" lang="scss"></style>
|
||||
Vendored
-13
@@ -1,13 +0,0 @@
|
||||
import Vue, { VNode } from 'vue';
|
||||
|
||||
declare global {
|
||||
namespace JSX {
|
||||
// tslint:disable no-empty-interface
|
||||
interface Element extends VNode {}
|
||||
// tslint:disable no-empty-interface
|
||||
interface ElementClass extends Vue {}
|
||||
interface IntrinsicElements {
|
||||
[elem: string]: any;
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
-4
@@ -1,4 +0,0 @@
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue';
|
||||
export default Vue;
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"strict": true,
|
||||
"jsx": "preserve",
|
||||
"importHelpers": true,
|
||||
"moduleResolution": "node",
|
||||
"experimentalDecorators": true,
|
||||
"esModuleInterop": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"types": [
|
||||
"webpack-env"
|
||||
],
|
||||
"paths": {
|
||||
"@/*": [
|
||||
"src/*"
|
||||
]
|
||||
},
|
||||
"lib": [
|
||||
"esnext",
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"scripthost"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx",
|
||||
"src/**/*.vue",
|
||||
"tests/**/*.ts",
|
||||
"tests/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"defaultSeverity": "warning",
|
||||
"linterOptions": {
|
||||
"exclude": [
|
||||
"node_modules/**"
|
||||
]
|
||||
},
|
||||
"rules": {
|
||||
"indent": [true, "spaces", 4],
|
||||
"curly": false,
|
||||
"interface-name": false,
|
||||
"no-consecutive-blank-lines": false,
|
||||
"object-literal-sort-keys": false,
|
||||
"ordered-imports": false,
|
||||
"quotemark": [true, "single"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user