Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 86ed26afeb | |||
| 35c4147cc1 | |||
| 711e69ddfb | |||
| 90d9cac19a | |||
| 61593d7d23 | |||
| 7c41e7adcc | |||
| 0215be8681 | |||
| 1139384ab3 | |||
| 45174422e9 | |||
| 2077d784fd | |||
| fa341101a8 | |||
| 1959ac589d | |||
| 5744493ac3 | |||
| 64eb4530af | |||
| d38fdfaced | |||
| f76484f824 | |||
| ef6adb0a27 | |||
| ca80df9541 | |||
| 828907120b | |||
| 460074b18a | |||
| 104bd4498e | |||
| 97082b1e55 | |||
| c9561fba71 | |||
| 8aa913fe09 | |||
| a598521491 | |||
| 6461456c16 | |||
| b4f697bdea | |||
| 721295b9d1 | |||
| 70c6e74623 | |||
| 1348ca27ab | |||
| 116592e436 | |||
| 19284a4ddf | |||
| 35e603b850 | |||
| 882c7bb35e | |||
| 9c8ce3a7f2 | |||
| 8a6af65786 | |||
| 4633bd902c | |||
| 10fcb8a2f6 | |||
| 3ad47eddfd | |||
| 636f1474bd | |||
| ebc9fac4dc | |||
| a0e5db6ed9 | |||
| f8acd8e222 | |||
| 7b21f82024 | |||
| 240cd7ce69 | |||
| 8a4f9c6f79 | |||
| 16f5865c4c | |||
| 25c3d8e6c1 | |||
| e1584c80a5 | |||
| 89dc493edf | |||
| aa59075939 | |||
| c55beaf30d | |||
| 67f1343744 | |||
| 6b0e0fc8e8 | |||
| af41ad5f53 | |||
| 622cd524e5 | |||
| 7266cf0d80 | |||
| 47fc11ed96 | |||
| fd927991c7 | |||
| 4b5e6d9856 | |||
| 3aa5ef9c95 | |||
| ded76b774c | |||
| 1bcf2f7410 | |||
| d8cce9ae11 | |||
| b4f29559cf | |||
| a7ea833860 | |||
| 9c54033343 | |||
| 7b9dab9d78 | |||
| 7f094cbafb | |||
| c4b8542b5b |
Generated
+5
@@ -6935,6 +6935,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.24.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
|
||||
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npm.taobao.org/move-concurrently/download/move-concurrently-1.0.1.tgz",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"core-js": "^2.6.5",
|
||||
"echarts": "^4.2.1",
|
||||
"element-ui": "^2.11.1",
|
||||
"moment": "^2.24.0",
|
||||
"p-wait-for": "^3.1.0",
|
||||
"v-charts": "^1.19.0",
|
||||
"vue": "^2.6.10",
|
||||
|
||||
@@ -11,4 +11,8 @@
|
||||
{
|
||||
--unread: #ff6c00;
|
||||
--main: #0c6dad;
|
||||
|
||||
--assignment-type-2: #3f991e;
|
||||
--assignment-type-3: #ff9900;
|
||||
--assignment-type-4: #b02b02;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ export interface Assignment
|
||||
{
|
||||
id: number,
|
||||
type: string,
|
||||
typeId: number,
|
||||
description: string,
|
||||
date: string,
|
||||
complete: string,
|
||||
@@ -188,7 +189,7 @@ export default class App extends Vue
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the courses' grading algorithms. (Total-average or percent-type)
|
||||
* Check the courses' grading algorithms. (Total-mean or percent-type)
|
||||
*/
|
||||
private checkGradingAlgorithms()
|
||||
{
|
||||
@@ -196,9 +197,9 @@ export default class App extends Vue
|
||||
for (const course of this.filteredCourses)
|
||||
{
|
||||
// Check if total-average grade is the same with percent-type grade
|
||||
if (course.numericGrade == GPAUtils.getTotalMeanAverage(course))
|
||||
if (course.numericGrade == +GPAUtils.getTotalMeanAverage(course).toFixed(2))
|
||||
{
|
||||
course.grading = {method: 'TOTAL_AVERAGE', weightingMap: {}};
|
||||
course.grading = {method: 'TOTAL_MEAN', weightingMap: {}};
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ export default class Constants
|
||||
*/
|
||||
public static API_URL: string = 'https://va.hydev.org/api';
|
||||
|
||||
public static VERSION: string = '0.3.1.382';
|
||||
public static VERSION: string = '0.3.2.452';
|
||||
|
||||
public static GITHUB: string = 'https://github.com/HyDevelop/VeracrossAnalyzer.Client';
|
||||
|
||||
|
||||
@@ -6,10 +6,36 @@
|
||||
margin-left: 20px;
|
||||
|
||||
// Height limit
|
||||
max-height: 90px;
|
||||
max-height: 250px;
|
||||
|
||||
// Limit name length
|
||||
white-space: nowrap;
|
||||
|
||||
// Expansion color
|
||||
background: #f9f9f9;
|
||||
|
||||
// Main card content
|
||||
.course-card-content.main
|
||||
{
|
||||
padding: 0 20px 0 20px;
|
||||
height: 90px;
|
||||
|
||||
// Main color
|
||||
background: white;
|
||||
}
|
||||
|
||||
// Expansion content
|
||||
.course-card-content.expand.notification
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Remove card padding for styling issues
|
||||
div.el-card.course-card > div.el-card__body
|
||||
{
|
||||
padding-right: 0 !important;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
|
||||
.course-col-name
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import {Component, Prop, Vue} from 'vue-property-decorator';
|
||||
import {Course} from '@/components/app/app';
|
||||
import {Assignment, Course} from '@/components/app/app';
|
||||
import {GPAUtils} from '@/utils/gpa-utils';
|
||||
import Constants from '@/constants';
|
||||
import UnreadEntry from '@/pages/overall/overall-course/unread-entry/unread-entry';
|
||||
|
||||
@Component({
|
||||
components: {UnreadEntry}
|
||||
})
|
||||
export default class OverallCourse extends Vue
|
||||
{
|
||||
@@ -11,6 +13,7 @@ export default class OverallCourse extends Vue
|
||||
@Prop({required: true}) course: Course;
|
||||
|
||||
private unread: number = -1;
|
||||
private unreadAssignments: Assignment[] = [];
|
||||
|
||||
/**
|
||||
* Count the number of unread assignments with cache
|
||||
@@ -19,8 +22,14 @@ export default class OverallCourse extends Vue
|
||||
{
|
||||
if (this.unread == -1)
|
||||
{
|
||||
return this.unread = this.course.assignments.filter(a => a.unread).length;
|
||||
this.unreadAssignments = this.course.assignments.filter(a => a.unread);
|
||||
return this.unread = this.unreadAssignments.length;
|
||||
}
|
||||
else return this.unread;
|
||||
}
|
||||
|
||||
unreadTable()
|
||||
{
|
||||
return [{date: '2019-10-04', name: 'Letter from a Penn Farmer Discussion Forum', grade: '14|14'}];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +1,43 @@
|
||||
<template>
|
||||
<div id="overall-course">
|
||||
<el-card class="course-card">
|
||||
<el-row>
|
||||
<el-col :span="6" class="course-col-name">
|
||||
<div class="course-name">
|
||||
{{course.name}}
|
||||
</div>
|
||||
<div class="course-teacher">
|
||||
{{course.teacherName}}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
|
||||
</el-col>
|
||||
<el-col :span="6" class="course-col-grade">
|
||||
<div class="course-grade">
|
||||
<span class="letter">{{course.letterGrade}} </span>
|
||||
<span class="numeric">{{course.numericGrade.toFixed(2)}}</span>
|
||||
<span class="percent">%</span>
|
||||
</div>
|
||||
<div class="course-updates" :class="countUnread() === 0 ? 'none' : 'unread'">
|
||||
<span class="unread-number">
|
||||
{{countUnread()}}
|
||||
</span>
|
||||
<span class="unread-text">
|
||||
new update{{countUnread() >= 2 ? 's' : ''}}
|
||||
</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<div class="course-card-content main vertical-center">
|
||||
<el-row>
|
||||
<el-col :span="6" class="course-col-name">
|
||||
<div class="course-name">
|
||||
{{course.name}}
|
||||
</div>
|
||||
<div class="course-teacher">
|
||||
{{course.teacherName}}
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
|
||||
</el-col>
|
||||
<el-col :span="6" class="course-col-grade">
|
||||
<div class="course-grade">
|
||||
<span class="letter">{{course.letterGrade}} </span>
|
||||
<span class="numeric">{{course.numericGrade.toFixed(2)}}</span>
|
||||
<span class="percent">%</span>
|
||||
</div>
|
||||
<div class="course-updates" :class="countUnread() === 0 ? 'none' : 'unread'">
|
||||
<span class="unread-number">
|
||||
{{countUnread()}}
|
||||
</span>
|
||||
<span class="unread-text">
|
||||
new update{{countUnread() >= 2 ? 's' : ''}}
|
||||
</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="course-card-content expand notification"
|
||||
v-if="countUnread() !== 0">
|
||||
<unread-entry v-for="assignment in unreadAssignments"
|
||||
:assignment="assignment"
|
||||
:key="assignment.id">
|
||||
</unread-entry>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
|
||||
// Row
|
||||
.unread-entry
|
||||
{
|
||||
height: 40px;
|
||||
padding: 0 20px 0 20px;
|
||||
background: #f5f7fa;
|
||||
|
||||
text-align: left;
|
||||
|
||||
// Date
|
||||
.el-col.date
|
||||
{
|
||||
span.month
|
||||
{
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
span.now
|
||||
{
|
||||
font-size: 11px;
|
||||
color: #888;
|
||||
}
|
||||
}
|
||||
|
||||
.el-col.description
|
||||
{
|
||||
span.type
|
||||
{
|
||||
display: inline-block;
|
||||
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
|
||||
background: #eee;
|
||||
border-left: 2px solid #000;
|
||||
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
// Grade
|
||||
.el-col.grade
|
||||
{
|
||||
text-align: right;
|
||||
|
||||
span.percent
|
||||
{
|
||||
font-style: italic;
|
||||
background: #ffc;
|
||||
color: #555;
|
||||
|
||||
margin-right: 8px;
|
||||
|
||||
.symbol
|
||||
{
|
||||
padding: 0 1px;
|
||||
}
|
||||
}
|
||||
|
||||
// Score you got
|
||||
span.score
|
||||
{
|
||||
background: #f2f2f2;
|
||||
color: #555;
|
||||
}
|
||||
|
||||
// Max score
|
||||
span.max
|
||||
{
|
||||
background: #ddd;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.entry-box
|
||||
{
|
||||
height: 22px;
|
||||
padding: 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.unread-entry:first-child
|
||||
{
|
||||
padding-top: 3px;
|
||||
|
||||
// Top shadow
|
||||
// https://stackoverflow.com/questions/17572619/inset-box-shadow-only-on-one-side
|
||||
box-shadow: inset 0 7px 9px -7px rgba(0,0,0,0.1);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import {Component, Prop, Vue} from 'vue-property-decorator';
|
||||
import {Assignment, Course} from '@/components/app/app';
|
||||
import moment from 'moment';
|
||||
|
||||
@Component({
|
||||
})
|
||||
export default class UnreadEntry extends Vue
|
||||
{
|
||||
// @ts-ignore
|
||||
@Prop({required: true}) assignment: Assignment;
|
||||
|
||||
/**
|
||||
* Format a date to the displayed format
|
||||
*
|
||||
* @param date Date
|
||||
*/
|
||||
private getMoment(date: string)
|
||||
{
|
||||
return moment(new Date(date));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<div class="unread-entry vertical-center">
|
||||
<el-row class="unread-row">
|
||||
<el-col :span="3" class="date">
|
||||
<span class="month">{{getMoment(assignment.date).format("MMM Do")}}</span>
|
||||
<span class="now">({{getMoment(assignment.date).fromNow()}})</span>
|
||||
</el-col>
|
||||
<el-col :span="15" class="description">
|
||||
<span class="type entry-box"
|
||||
:style="`border-color: var(--assignment-type-${assignment.typeId})`">
|
||||
{{assignment.type}}
|
||||
</span>
|
||||
<span class="text">{{assignment.description}}</span>
|
||||
</el-col>
|
||||
<el-col :span="6" class="grade">
|
||||
<span class="percent entry-box">
|
||||
{{(assignment.score / assignment.scoreMax * 100).toFixed(1)}}
|
||||
<span class="symbol">%</span>
|
||||
</span>
|
||||
<span class="score entry-box">{{assignment.score}}</span>
|
||||
<span class="max entry-box">{{assignment.scoreMax}}</span>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./unread-entry.ts" lang="ts"></script>
|
||||
<style src="./unread-entry.scss" lang="scss"></style>
|
||||
@@ -3,13 +3,12 @@
|
||||
.el-card
|
||||
{
|
||||
margin: 10px;
|
||||
height: 494px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
// Vertical center
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
.el-card.large
|
||||
{
|
||||
height: 494px;
|
||||
}
|
||||
|
||||
.gpa-card
|
||||
@@ -60,3 +59,12 @@
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
// Vertical centering
|
||||
.vertical-center
|
||||
{
|
||||
// Vertical center
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div id="overall">
|
||||
<el-row>
|
||||
<el-col :span="4">
|
||||
<el-card class="gpa-card">
|
||||
<el-card class="large gpa-card vertical-center">
|
||||
<div style="padding: 14px;">
|
||||
<span class="gpa header">GPA:</span>
|
||||
<span class="gpa text">{{getGPA().gpa}}</span>
|
||||
@@ -14,18 +14,21 @@
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="14">
|
||||
<el-card class="overall-line-card">
|
||||
<el-card class="large overall-line-card vertical-center">
|
||||
<overall-line :courses="courses"></overall-line>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-card class="overall-bar-card">
|
||||
<el-card class="large overall-bar-card vertical-center">
|
||||
<overall-bar :courses="courses"></overall-bar>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<overall-course v-for="course in courses" :course="course"></overall-course>
|
||||
<overall-course v-for="course in courses"
|
||||
:course="course"
|
||||
:key="course.id">
|
||||
</overall-course>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -22,8 +22,8 @@ export class CourseUtils
|
||||
// Skip courses without levels
|
||||
if (course.level == 'None') return;
|
||||
|
||||
// Skip courses without assignments
|
||||
if (course.assignments.length == 0) return;
|
||||
// Skip courses without graded assignments
|
||||
if (course.assignments.filter(a => a.complete == 'Complete').length == 0) return;
|
||||
|
||||
// Skip if there are no grading scale
|
||||
// if (course.grading.method == 'NOT_GRADED') return;
|
||||
|
||||
@@ -18,6 +18,7 @@ export default class JsonUtils
|
||||
{
|
||||
id: assignment.assignment_id,
|
||||
type: assignment.assignment_type,
|
||||
typeId: assignment.assignment_type_id,
|
||||
description: assignment.assignment_description,
|
||||
date: assignment._date,
|
||||
complete: assignment.completion_status,
|
||||
|
||||
Reference in New Issue
Block a user