├── miniprogram
├── custom-tab-bar
│ ├── index.json
│ ├── index.js
│ ├── index.wxml
│ └── index.wxss
├── box.png
├── ec-canvas
│ ├── ec-canvas.json
│ ├── ec-canvas.wxss
│ ├── ec-canvas.wxml
│ ├── wx-canvas.js
│ └── ec-canvas.js
├── icon
│ ├── check-exam.png
│ ├── check-grade.png
│ ├── check-courses.png
│ ├── check-schedule.png
│ ├── check-exam-selected.png
│ ├── check-grade-selected.png
│ ├── check-courses-selected.png
│ └── check-schedule-selected.png
├── pages
│ ├── previousScore
│ │ ├── previousScore.json
│ │ ├── previousScore.wxss
│ │ ├── previousScore.ts
│ │ └── previousScore.wxml
│ ├── CET
│ │ ├── CET.json
│ │ ├── CET.ts
│ │ ├── CET.wxss
│ │ └── CET.wxml
│ ├── exam
│ │ ├── exam.json
│ │ ├── exam.wxml
│ │ ├── exam.wxss
│ │ └── exam.ts
│ ├── index
│ │ ├── index.json
│ │ ├── index.wxss
│ │ ├── index.wxml
│ │ └── index.ts
│ ├── login
│ │ ├── login.json
│ │ ├── login.wxss
│ │ ├── login.wxml
│ │ └── login.ts
│ ├── entireClass
│ │ ├── entireClass.json
│ │ ├── entireClass.wxss
│ │ ├── entireClass.wxml
│ │ └── entireClass.ts
│ ├── scoreList
│ │ ├── scoreList.json
│ │ ├── scoreList.wxss
│ │ └── scoreList.wxml
│ ├── more
│ │ ├── more.json
│ │ ├── more.wxss
│ │ ├── more.wxml
│ │ └── more.ts
│ ├── scoreDetailPage
│ │ ├── scoreDetailPage.json
│ │ ├── scoreDetailPage.wxss
│ │ ├── scoreDetailPage.ts
│ │ └── scoreDetailPage.wxml
│ └── overAllPage
│ │ ├── overAllPage.json
│ │ ├── overAllPage.wxss
│ │ ├── overAllPage.wxml
│ │ └── overAllPage.ts
├── sitemap.json
├── theme.json
├── utils
│ ├── util.js
│ └── filter.wxs
└── app.json
├── typings
├── index.d.ts
├── declaration.d.ts
└── bjut
│ └── index.d.ts
├── .gitmodules
├── tsconfig.json
├── .gitignore
├── .idea
├── codeStyles
│ ├── codeStyleConfig.xml
│ └── Project.xml
├── misc.xml
├── .gitignore
├── vcs.xml
├── compiler.xml
├── dictionaries
│ └── ze3kr.xml
├── BjutHelper-MiniProgram.iml
├── modules.xml
└── inspectionProfiles
│ └── Project_Default.xml
├── CHANGELOG.md
├── package.json
├── project.config.json
├── README.md
└── tslint.json
/miniprogram/custom-tab-bar/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true
3 | }
--------------------------------------------------------------------------------
/miniprogram/box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/box.png
--------------------------------------------------------------------------------
/miniprogram/ec-canvas/ec-canvas.json:
--------------------------------------------------------------------------------
1 | {
2 | "component": true,
3 | "usingComponents": {}
4 | }
--------------------------------------------------------------------------------
/miniprogram/ec-canvas/ec-canvas.wxss:
--------------------------------------------------------------------------------
1 | .ec-canvas {
2 | width: 100%;
3 | height: 100%;
4 | }
5 |
--------------------------------------------------------------------------------
/typings/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
--------------------------------------------------------------------------------
/miniprogram/icon/check-exam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/icon/check-exam.png
--------------------------------------------------------------------------------
/miniprogram/icon/check-grade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/icon/check-grade.png
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "typings/wx"]
2 | path = typings/wx
3 | url = https://github.com/wechat-miniprogram/api-typings
4 |
--------------------------------------------------------------------------------
/miniprogram/icon/check-courses.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/icon/check-courses.png
--------------------------------------------------------------------------------
/miniprogram/icon/check-schedule.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/icon/check-schedule.png
--------------------------------------------------------------------------------
/miniprogram/pages/previousScore/previousScore.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "navigationBarTitleText": "各学期成绩"
4 | }
--------------------------------------------------------------------------------
/miniprogram/ec-canvas/ec-canvas.wxml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/miniprogram/icon/check-exam-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/icon/check-exam-selected.png
--------------------------------------------------------------------------------
/miniprogram/icon/check-grade-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/icon/check-grade-selected.png
--------------------------------------------------------------------------------
/miniprogram/pages/CET/CET.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "navigationBarTitleText": "四六级成绩",
4 | "enablePullDownRefresh": true
5 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es5",
4 | "lib": [
5 | "es2015",
6 | "dom"
7 | ]
8 | }
9 | }
--------------------------------------------------------------------------------
/miniprogram/icon/check-courses-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/icon/check-courses-selected.png
--------------------------------------------------------------------------------
/miniprogram/icon/check-schedule-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WildHelper/MiniProgram/HEAD/miniprogram/icon/check-schedule-selected.png
--------------------------------------------------------------------------------
/miniprogram/pages/exam/exam.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "navigationBarTitleText": "考试时间",
4 | "enablePullDownRefresh": true
5 | }
--------------------------------------------------------------------------------
/miniprogram/pages/index/index.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {},
3 | "navigationBarTitleText": "课表 - 野生助手",
4 | "enablePullDownRefresh": true
5 | }
--------------------------------------------------------------------------------
/typings/declaration.d.ts:
--------------------------------------------------------------------------------
1 | declare function requirePlugin(pluginName: string): any;
2 | declare function require(pluginName: string): any;
3 | type TODO = any;
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | /miniprogram/miniprogram_npm
4 | /miniprogram/pages/*/*.js
5 | /miniprogram/app.js
6 | /miniprogram/ec-canvas/echarts.js
7 | package-lock.json
8 |
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "mp-loading": "/miniprogram_npm/weui-miniprogram/loading/loading"
4 | },
5 | "navigationBarTitleText": "野生助手"
6 | }
--------------------------------------------------------------------------------
/.idea/codeStyles/codeStyleConfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Datasource local storage ignored files
5 | /dataSources/
6 | /dataSources.local.xml
7 | # Editor-based HTTP Client requests
8 | /httpRequests/
9 |
--------------------------------------------------------------------------------
/miniprogram/pages/entireClass/entireClass.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "mp-msg": "/miniprogram_npm/weui-miniprogram/msg/msg"
4 | },
5 | "navigationBarTitleText": "选课指导",
6 | "enablePullDownRefresh": true
7 | }
--------------------------------------------------------------------------------
/miniprogram/pages/scoreList/scoreList.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "mp-halfScreenDialog": "/miniprogram_npm/weui-miniprogram/half-screen-dialog/half-screen-dialog"
4 | },
5 | "navigationBarTitleText": "成绩详情 - 野生助手",
6 | "enablePullDownRefresh": true
7 | }
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/miniprogram/pages/more/more.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "mp-actionSheet": "/miniprogram_npm/weui-miniprogram/actionsheet/actionsheet",
4 | "mp-msg": "/miniprogram_npm/weui-miniprogram/msg/msg"
5 | },
6 | "navigationBarTitleText": "关于"
7 | }
8 |
--------------------------------------------------------------------------------
/miniprogram/pages/scoreDetailPage/scoreDetailPage.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "ec-canvas": "../../ec-canvas/ec-canvas",
4 | "mp-halfScreenDialog": "/miniprogram_npm/weui-miniprogram/half-screen-dialog/half-screen-dialog"
5 | },
6 | "navigationBarTitleText": "课程详情"
7 | }
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/miniprogram/sitemap.json:
--------------------------------------------------------------------------------
1 | {
2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
3 | "rules": [{
4 | "action": "allow",
5 | "page": "pages/login/login"
6 | }, {
7 | "action": "disallow",
8 | "page": "*"
9 | }]
10 | }
--------------------------------------------------------------------------------
/miniprogram/pages/overAllPage/overAllPage.json:
--------------------------------------------------------------------------------
1 | {
2 | "usingComponents": {
3 | "mp-msg": "/miniprogram_npm/weui-miniprogram/msg/msg",
4 | "mp-loading": "/miniprogram_npm/weui-miniprogram/loading/loading"
5 | },
6 | "navigationBarTitleText": "野生助手",
7 | "enablePullDownRefresh": true
8 | }
--------------------------------------------------------------------------------
/.idea/dictionaries/ze3kr.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | affero
5 | bjut
6 | echarts
7 | pako
8 | weixin
9 | weui
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/BjutHelper-MiniProgram.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/miniprogram/theme.json:
--------------------------------------------------------------------------------
1 | {
2 | "light": {
3 | "navBgColor": "#FFF",
4 | "navTxtStyle": "black",
5 | "bgColor": "#e5e9eb",
6 | "bgTxtStyle": "dark"
7 | },
8 | "dark": {
9 | "navBgColor": "#121212",
10 | "navTxtStyle": "white",
11 | "bgColor": "#000",
12 | "bgTxtStyle": "light"
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 小程序版本更新日志
2 |
3 | ## v4.2.9
4 |
5 | + 第一个开源版本,改进了广告加载,上线了 Banner Ad,重写了部分重复逻辑
6 |
7 | ## v4.2.10
8 |
9 | + `A` 数据预拉取支持数据加密和数据压缩
10 | + `M` 修复了几个数据预拉取的 Bug
11 |
12 | ## v4.2.11
13 |
14 | + `A` 出分提醒消息跳转,支持高亮显示教师
15 | + `F` 修复单页模式白屏
16 | + `F` 修复预拉取在页面加载完成前拉取到数据则不会使用预拉取数据的问题
17 | + `F` 修复无法重置订阅的问题
18 | + `F` 修复成绩页无法二次分享的问题
19 | + `F` 修复无法清除预拉取数据的问题
20 |
--------------------------------------------------------------------------------
/miniprogram/custom-tab-bar/index.js:
--------------------------------------------------------------------------------
1 | Component({
2 | data: {
3 | selected: 0,
4 | color: "#595959",
5 | selectedColor: "#0197c2",
6 | list: wx.$initTab(undefined)
7 | },
8 | methods: {
9 | switchTab(e) {
10 | const data = e.currentTarget.dataset
11 | const url = data.path
12 | console.log(data, this)
13 | wx.$initTab(this);
14 | wx.switchTab({url})
15 | },
16 | attached() {
17 | },
18 | }
19 | })
--------------------------------------------------------------------------------
/miniprogram/custom-tab-bar/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{item.text}}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/miniprogram/utils/util.js:
--------------------------------------------------------------------------------
1 | const formatTime = date => {
2 | const year = date.getFullYear()
3 | const month = date.getMonth() + 1
4 | const day = date.getDate()
5 | const hour = date.getHours()
6 | const minute = date.getMinutes()
7 | const second = date.getSeconds()
8 |
9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
10 | }
11 |
12 | const formatNumber = n => {
13 | n = n.toString()
14 | return n[1] ? n : '0' + n
15 | }
16 |
17 | module.exports = {
18 | formatTime: formatTime
19 | }
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "wild-helper-mini-program",
3 | "version": "1.0.0",
4 | "description": "野生助手小程序",
5 | "main": "app.js",
6 | "dependencies": {
7 | "pako": "^1.0.11",
8 | "crypto-js": "^4.0.0",
9 | "weui-miniprogram": "^1.0.4"
10 | },
11 | "devDependencies": {
12 | "tslint": "^6.1.2",
13 | "typescript": "^3.9.5"
14 | },
15 | "scripts": {
16 | "test": "echo \"Error: no test specified\" && exit 1"
17 | },
18 | "repository": {
19 | "type": "git",
20 | "url": "git+https://github.com/WildHelper/MiniProgram.git"
21 | },
22 | "author": "",
23 | "license": "ISC",
24 | "bugs": {
25 | "url": "https://github.com/WildHelper/MiniProgram/issues"
26 | },
27 | "homepage": "https://github.com/WildHelper/MiniProgram#readme"
28 | }
29 |
--------------------------------------------------------------------------------
/.idea/codeStyles/Project.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.wxss:
--------------------------------------------------------------------------------
1 | /*!
2 | * WeUI v2.3.0 (https://github.com/weui/weui-wxss)
3 | * Copyright 2020 Tencent, Inc.
4 | * Licensed under the MIT license
5 | */
6 |
7 | .page{
8 | height:100%
9 | }
10 |
11 | .weui-label{
12 | width: 2.1em
13 | }
14 |
15 | .imgArea {
16 | height: 90px;
17 | }
18 |
19 | .img {
20 | height: 75px;
21 | width: 75px;
22 | margin: auto;
23 | }
24 |
25 | .weui-form__control-area {
26 | margin-top: 50rpx;
27 | margin-bottom: 30rpx;
28 | margin-left: 50rpx;
29 | margin-right: 50rpx;
30 | overflow: hidden;
31 | border-radius: 20rpx;
32 | box-shadow: 0rpx 0rpx 15rpx #CCC;
33 | }
34 |
35 | .weui-cell__bd {
36 | padding: 0 16px;
37 | }
38 |
39 | .weui-cells__title {
40 | padding: 0 32px;
41 | }
42 |
43 | .weui-cell:before {
44 | left: 32px;
45 | right: 32px;
46 | }
47 |
48 | .weui-cell_select .weui-cell__bd:after {
49 | right: 32px;
50 | }
51 |
52 | .weui-cells {
53 | margin-top: 0;
54 | background-color: #FFF;
55 | }
56 |
--------------------------------------------------------------------------------
/miniprogram/pages/exam/exam.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 暂无考试信息
5 |
6 | {{item}}
7 |
8 |
9 |
10 |
11 |
12 | {{item.courseName}}
13 | 已结束
14 |
15 |
16 |
17 | 考试日期:{{item.time}}
18 | 考试地点:{{item.room}}
19 | 考场校区:{{item.campus}}
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/miniprogram/custom-tab-bar/index.wxss:
--------------------------------------------------------------------------------
1 | .tab-bar {
2 | position: fixed;
3 | bottom: 0;
4 | left: 0;
5 | right: 0;
6 | height: 55px;
7 | background: white;
8 | display: flex;
9 | padding-bottom: env(safe-area-inset-bottom);
10 | z-index: 100;
11 | }
12 |
13 | @media (prefers-color-scheme: dark) {
14 | .tab-bar {
15 | background: #121212;
16 | }
17 | .tab-bar-item-selected-false {
18 | -webkit-filter: invert(100%);
19 | filter: invert(100%);
20 | }
21 | }
22 |
23 | .tab-bar-border {
24 | background-color: rgba(0, 0, 0, 0.33);
25 | position: absolute;
26 | left: 0;
27 | top: 0;
28 | width: 100%;
29 | height: 1px;
30 | transform: scaleY(0.5);
31 | }
32 |
33 | .tab-bar-item {
34 | flex: 1;
35 | text-align: center;
36 | display: flex;
37 | justify-content: center;
38 | align-items: center;
39 | flex-direction: column;
40 | }
41 |
42 | .tab-bar-item image {
43 | width: 20px;
44 | height: 20px;
45 | margin: 8px 0 5px;
46 | }
47 |
48 | .tab-bar-item[data-path="/pages/exam/exam"] image {
49 | width: 19px;
50 | height: 19px;
51 | padding-top: 1px;
52 | }
53 |
54 | .tab-bar-item[data-path="/pages/entireClass/entireClass"] image {
55 | width: 21px;
56 | height: 21px;
57 | margin-top: 7px;
58 | }
59 |
60 | .tab-bar-item {
61 | font-size: 10px;
62 | }
63 |
--------------------------------------------------------------------------------
/miniprogram/pages/more/more.wxss:
--------------------------------------------------------------------------------
1 | .previousAndCETScore {
2 | margin: 30rpx 40rpx!important;
3 | padding: 30rpx 30rpx;
4 | border-radius: 20rpx;
5 | box-shadow: 0rpx 0rpx 15rpx #CCC;
6 | font-size: 40rpx;
7 | font-weight:bold;
8 | display: flex;
9 | background-color: #FFF;
10 | width: initial!important;
11 | text-align: left!important;
12 | }
13 |
14 | .title {
15 | flex: 9;
16 | }
17 |
18 | .message {
19 | margin: 30rpx 40rpx;
20 | color: #888888;
21 | font-size: 25rpx;
22 | }
23 |
24 | .message icon, .message text {
25 | margin-top: auto;
26 | margin-bottom: auto;
27 | }
28 |
29 | .h1 {
30 | font-size: 49rpx;
31 | }
32 |
33 | .h2 {
34 | font-size: 45rpx;
35 | }
36 |
37 | .h3 {
38 | font-size: 41rpx;
39 | }
40 |
41 | .h4 {
42 | font-size: 37rpx;
43 | }
44 |
45 | .h5 {
46 | font-size: 33rpx;
47 | }
48 |
49 | .h6 {
50 | font-size: 29rpx;
51 | }
52 |
53 | .list {
54 | margin: 0 40rpx 0 80rpx;
55 | list-style-type: disc;
56 | display: list-item;
57 | }
58 |
59 | .numbered-list {
60 | margin: 0 40rpx 0 80rpx;
61 | list-style-type: decimal;
62 | display: list-item;
63 | }
64 |
65 | .weui-msg__icon-area {
66 | margin-bottom: 16px!important;
67 | }
68 | .weui-msg__text-area {
69 | margin-bottom: 0!important;
70 | }
71 | .weui-msg__tips-area, .weui-msg__extra-area {
72 | display: none!important;
73 | }
74 |
--------------------------------------------------------------------------------
/miniprogram/pages/exam/exam.wxss:
--------------------------------------------------------------------------------
1 | .info {
2 | color: #888888;
3 | text-align: center;
4 | margin: 30rpx 40rpx;
5 | background-color: #FFF;
6 | border-radius: 20rpx;
7 | box-shadow: 0rpx 0rpx 15rpx #CCC;
8 | }
9 |
10 | .classes {
11 | margin: 30rpx 40rpx;
12 | background-color: #FFF;
13 | border-radius: 20rpx;
14 | box-shadow: 0rpx 0rpx 15rpx #CCC;
15 | }
16 | .classes .line1{
17 | display: flex;
18 | margin-bottom: 30rpx;
19 | }
20 | .classes .line1 .name{
21 | font-size: 35rpx;
22 | display: inline-block;
23 | white-space: nowrap;
24 | overflow: hidden;
25 | text-overflow: ellipsis;
26 | width: 60vw;
27 | }
28 | .classes .line1 .isOver{
29 | margin-top: auto;
30 | font-size: 25rpx;
31 | color: red;
32 | }
33 | .classes .line2{
34 | display: flex;
35 | flex-direction: column;
36 | margin-bottom: 20rpx;
37 | }
38 | .classes .line2 .item {
39 | flex: 1;
40 | color: #888888;
41 | }
42 | view.page {
43 | padding-bottom: 80px;
44 | }
45 |
46 | @supports (padding-bottom: calc(55px + 50rpx)) {
47 | view.page {
48 | padding-bottom: calc(55px + 50rpx);
49 | }
50 | }
51 |
52 | @supports (padding-bottom: calc(55px + 50rpx + env(safe-area-inset-bottom))) {
53 | view.page {
54 | padding-bottom: calc(55px + 50rpx + env(safe-area-inset-bottom));
55 | }
56 | }
57 |
58 | .message {
59 | margin: 30rpx 40rpx;
60 | color: #888888;
61 | font-size: 25rpx;
62 | text-align: center;
63 | }
64 |
--------------------------------------------------------------------------------
/miniprogram/pages/previousScore/previousScore.wxss:
--------------------------------------------------------------------------------
1 | .line{
2 | width: 100%; /* 分隔线的长度 */
3 | margin: auto;
4 | height: 1px; /* 分隔线粗细 */
5 | text-align: center;
6 | font-size: 24rpx;
7 | color: #aaa;
8 | background: #ccc;
9 | margin-top: 30rpx;
10 | margin-bottom: 5rpx;
11 | flex: 1;
12 | }
13 | .arrow{
14 | width: 10px;
15 | height: 10px;
16 | border-top: 2px solid #999;
17 | border-right: 2px solid #999;
18 |
19 | right: 20rpx;
20 | transform: rotate(45deg);
21 | margin-top:20rpx;
22 | }
23 | .title {
24 | flex: 9;
25 | }
26 |
27 |
28 | .totalScore {
29 | margin: 30rpx 40rpx;
30 | padding: 10rpx 30rpx 20rpx 30rpx;
31 | border-radius: 20rpx;
32 | box-shadow: 0rpx 0rpx 15rpx #CCC;
33 | background-color: #FFF;
34 | }
35 | .totalScore .line1 {
36 | font-size: 40rpx;
37 | font-weight:bold;
38 | margin: 10rpx 0;
39 | display: flex;
40 | }
41 | .totalScore .line2 {
42 | margin-bottom: 30rpx;
43 | }
44 | .totalScore .line3 {
45 | display: flex;
46 | }
47 | .totalScore .line3 .item {
48 | flex: 1;
49 | margin-right: 20rpx;
50 | border-right: 1rpx solid rgba(204, 204, 204, 0.4);
51 | }
52 | .totalScore .line3 .item_1 {
53 | flex: 1;
54 | margin-right: 20rpx;
55 | }
56 | .totalScore .line3 .title {
57 | font-size: 25rpx;
58 | color: #999999;
59 | }
60 | .totalScore .line3 .value {
61 | font-size: 50rpx;
62 | }
63 | .totalScore .time {
64 | font-size: 25rpx;
65 | text-align: right;
66 | color: #c4c4c4;
67 | }
--------------------------------------------------------------------------------
/project.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "description": "项目配置文件",
3 | "packOptions": {
4 | "ignore": []
5 | },
6 | "setting": {
7 | "urlCheck": false,
8 | "es6": true,
9 | "enhance": true,
10 | "postcss": true,
11 | "preloadBackgroundData": true,
12 | "minified": true,
13 | "newFeature": true,
14 | "coverView": true,
15 | "nodeModules": true,
16 | "autoAudits": false,
17 | "showShadowRootInWxmlPanel": true,
18 | "scopeDataCheck": false,
19 | "uglifyFileName": true,
20 | "checkInvalidKey": true,
21 | "checkSiteMap": true,
22 | "uploadWithSourceMap": true,
23 | "compileHotReLoad": false,
24 | "babelSetting": {
25 | "ignore": [],
26 | "disablePlugins": [],
27 | "outputPath": ""
28 | },
29 | "bundle": true,
30 | "useIsolateContext": true,
31 | "useCompilerModule": true,
32 | "userConfirmedUseCompilerModuleSwitch": true,
33 | "packNpmManually": true,
34 | "packNpmRelationList": [
35 | {
36 | "packageJsonPath": "./package.json",
37 | "miniprogramNpmDistDir": "./miniprogram"
38 | }
39 | ]
40 | },
41 | "compileType": "miniprogram",
42 | "libVersion": "2.12.0",
43 | "appid": "wx07fc056677624f68",
44 | "projectname": "%E5%B7%A5%E5%A4%A7%E5%8A%A9%E6%89%8B",
45 | "debugOptions": {
46 | "hidedInDevtools": []
47 | },
48 | "isGameTourist": false,
49 | "simulatorType": "wechat",
50 | "simulatorPluginLibVersion": {},
51 | "miniprogramRoot": "miniprogram/",
52 | "condition": {
53 | "search": {
54 | "current": -1,
55 | "list": []
56 | },
57 | "conversation": {
58 | "current": -1,
59 | "list": []
60 | },
61 | "game": {
62 | "currentL": -1,
63 | "list": []
64 | },
65 | "miniprogram": {
66 | "current": -1,
67 | "list": []
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/miniprogram/pages/CET/CET.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | Page({
4 | data: {
5 | exams: [],
6 | time: null,
7 | timestamp: null,
8 | },
9 |
10 | onLoad: function() {
11 | wx.showToast({
12 | title: '加载中',
13 | icon: 'loading',
14 | duration: 6000,
15 | })
16 | wx.$request({
17 | path: 'scores/cet',
18 | actions: true,
19 | methods: 'GET',
20 | type: 'cets',
21 | success: (result: ICets, messages) => {
22 | const exams = []
23 | for (const i in result.results) {
24 | const exam = result.results[i]
25 | let PorF = '未通过'
26 | if (parseFloat(exam.total) >= 425) {
27 | PorF = '已通过'
28 | }
29 | const date = exam.year + ' 第' + exam.term + '学期'
30 | const e = {
31 | name: exam.name,
32 | PorF: PorF,
33 | date: date,
34 | total: exam.total,
35 | listening: exam.listening,
36 | reading: exam.reading,
37 | comprehensive: exam.comprehensive,
38 | }
39 | exams.push(e)
40 | }
41 | this.setData({
42 | exams: exams,
43 | messages: messages,
44 | time: wx.$formatDate(result.time),
45 | timestamp: result.time,
46 | })
47 | wx.showToast({
48 | title: '加载成功',
49 | icon: 'success',
50 | duration: 500,
51 | })
52 | },
53 | failed: () => {
54 | wx.navigateBack()
55 | },
56 | })
57 | },
58 |
59 | onShow: function() {
60 | this.setData({time: wx.$formatDate(this.data.timestamp)})
61 | },
62 |
63 | onPullDownRefresh: function() {
64 | wx.stopPullDownRefresh()
65 | this.onLoad()
66 | },
67 | })
68 |
69 | export {}
70 |
--------------------------------------------------------------------------------
/miniprogram/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "pages":[
3 | "pages/login/login",
4 | "pages/entireClass/entireClass",
5 | "pages/exam/exam",
6 | "pages/scoreDetailPage/scoreDetailPage",
7 | "pages/overAllPage/overAllPage",
8 | "pages/previousScore/previousScore",
9 | "pages/scoreList/scoreList",
10 | "pages/index/index",
11 | "pages/CET/CET",
12 | "pages/more/more"
13 | ],
14 | "window":{
15 | "backgroundTextStyle":"light",
16 | "navigationBarBackgroundColor": "@navBgColor",
17 | "navigationBarTitleText": "野生助手",
18 | "navigationBarTextStyle":"@navTxtStyle",
19 | "backgroundColor": "@bgColor",
20 | "backgroundTextStyle": "@bgTxtStyle"
21 | },
22 | "tabBar": {
23 | "custom": true,
24 | "color": "#0197c2",
25 | "selectedColor": "#0197c2",
26 | "borderStyle": "black" ,
27 | "list": [{
28 | "iconPath":"icon/check-grade.png",
29 | "selectedIconPath":"icon/check-grade-selected.png",
30 | "pagePath": "pages/overAllPage/overAllPage",
31 | "text": "成绩"
32 | }, {
33 | "iconPath":"icon/check-schedule.png",
34 | "selectedIconPath":"icon/check-schedule-selected.png",
35 | "pagePath": "pages/index/index",
36 | "text": "课表"
37 | }, {
38 | "iconPath":"icon/check-exam.png",
39 | "selectedIconPath":"icon/check-exam-selected.png",
40 | "pagePath": "pages/exam/exam",
41 | "text": "考试时间"
42 | }, {
43 | "iconPath":"icon/check-courses.png",
44 | "selectedIconPath":"icon/check-courses-selected.png",
45 | "pagePath": "pages/entireClass/entireClass",
46 | "text": "选课指导"
47 | }
48 | ]
49 | },
50 | "style": "v2",
51 | "sitemapLocation": "sitemap.json",
52 | "cloud": true,
53 | "darkmode": true,
54 | "themeLocation": "theme.json"
55 | }
56 |
--------------------------------------------------------------------------------
/miniprogram/pages/CET/CET.wxss:
--------------------------------------------------------------------------------
1 | .totalScore {
2 | margin: 30rpx 40rpx;
3 | padding: 10rpx 30rpx 20rpx 30rpx;
4 | border-radius: 20rpx;
5 | box-shadow: 0rpx 0rpx 15rpx #CCC;
6 | background-color: #FFF;
7 | }
8 | .totalScore .line1 {
9 | font-size: 40rpx;
10 | font-weight:bold;
11 | margin: 10rpx 0;
12 | display: flex;
13 | }
14 | .totalScore .line3 .subTitle{
15 | margin-right: 20rpx;
16 | padding: 15rpx;
17 | font-size: 20rpx;
18 | border-radius: 25px;
19 | background-color: rgba(204, 204, 204, 0.2);
20 | }
21 | .totalScore .line3 {
22 | margin-bottom: 30rpx;
23 | }
24 | .totalScore .line1 .time {
25 | color: #888888;
26 | font-size: 30rpx;
27 | font-weight: 200;
28 | margin-left: auto;
29 | margin-top: auto;
30 | }
31 |
32 | .totalScore .update-time {
33 | font-size: 25rpx;
34 | text-align: right;
35 | color: var(--weui-FG-2);
36 | }
37 |
38 | .totalScore .line2 {
39 | display: flex;
40 | }
41 | .totalScore .line2 .item {
42 | flex: 1;
43 | margin-right: 20rpx;
44 | border-right: 1rpx solid rgba(204, 204, 204, 0.4);
45 | }
46 | .totalScore .line2 .item_1 {
47 | flex: 1;
48 | margin-right: 20rpx;
49 | }
50 | .totalScore .line2 .item_2 {
51 | margin-left: auto;
52 | margin-right: auto;
53 | }
54 | .totalScore .line2 .title {
55 | font-size: 25rpx;
56 | color: #999999;
57 | }
58 | .totalScore .line2 .value {
59 | font-size: 50rpx;
60 | }
61 |
62 | .totalScore .line3 {
63 | font-size: 25rpx;
64 | }
65 | .totalScore .line4 {
66 | display: flex;
67 | margin-bottom: 10rpx;
68 | }
69 | .totalScore .line4 .item {
70 | flex: 1;
71 | margin-right: 20rpx;
72 | border-right: 1px solid #EFEFEF ;
73 | }
74 | .totalScore .line4 .item_1 {
75 | flex: 1;
76 | margin-right: 20rpx;
77 | }
78 | .totalScore .line4 .value {
79 | font-size: 50rpx;
80 | }
81 | .message {
82 | margin: 30rpx 40rpx;
83 | color: #888888;
84 | font-size: 25rpx;
85 | text-align: center;
86 | }
87 |
--------------------------------------------------------------------------------
/miniprogram/pages/previousScore/previousScore.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | const app: IMyApp = getApp()
4 |
5 | Page({
6 | data: {
7 | term: [],
8 | time: null,
9 | unread: false,
10 | share_score: false,
11 | },
12 |
13 | onLoad: function() {
14 | if (
15 | typeof app.globalData.scoreData === 'undefined' || !app.globalData.scoreData ||
16 | !wx.$validateType(app.globalData.scoreData.result, 'term')
17 | ) {
18 | wx.reLaunch({
19 | url: '/pages/login/login',
20 | })
21 | return
22 | }
23 |
24 | const t = []
25 | this.setData({time: wx.$formatDate(app.globalData.scoreData.result.time)})
26 | for (const year in app.globalData.scoreData.result.terms) {
27 | for (const term in app.globalData.scoreData.result.terms[year]) {
28 | // 计算通过率与总学分
29 | const courses = app.globalData.scoreData.result.terms[year][term]
30 | const {unreadCount, ungraded, unsubscribed} = wx.$forCourses(courses.courses, app.globalData.unread)
31 | const {credits, passCredits, gradedCredits} = wx.$forCourses(courses.courses, app.globalData.unread, false, false)
32 |
33 |
34 | const passRate = passCredits / gradedCredits * 100
35 |
36 | t.push({
37 | name: year + ' 第 ' + term + ' 学期',
38 | detail: {
39 | gpa: app.globalData.scoreData.result.terms[year][term].average_GPA_term,
40 | score: app.globalData.scoreData.result.terms[year][term].average_score_term,
41 | count: app.globalData.scoreData.result.terms[year][term].term_lesson_count,
42 | passRate,
43 | passCredits,
44 | totalCredit: credits,
45 | },
46 | unread: unreadCount,
47 | ungraded,
48 | unsubscribed,
49 | year,
50 | term,
51 | })
52 | }
53 | }
54 | this.setData({
55 | term: t,
56 | unread: this.data.unread,
57 | share_score: app.globalData.scoreData.result.share_score,
58 | first_semester: app.globalData.scoreData.result.first_semester,
59 | })
60 | },
61 |
62 | onShow: function() {
63 | this.onLoad()
64 | },
65 |
66 | bindtapHandeler: function(e) {
67 | const {year, term} = e.currentTarget.dataset
68 | wx.navigateTo({
69 | url: '/pages/scoreList/scoreList?year=' + year + '&term=' + term,
70 | })
71 | },
72 | })
73 |
74 | export {}
75 |
--------------------------------------------------------------------------------
/miniprogram/pages/CET/CET.wxml:
--------------------------------------------------------------------------------
1 |
2 | {{item}}
3 |
4 |
5 |
6 | 大学英语四级 大学英语六级 {{item.name}}
7 |
8 |
9 |
10 | {{item.date}}
11 | {{item.PorF}}
12 |
13 |
14 |
15 |
16 |
17 |
18 | 总分
19 |
20 | {{item.total}}
21 |
22 |
23 |
24 |
25 | 听力
26 |
27 |
28 | {{item.listening}}
29 | —
30 |
31 |
32 |
33 |
34 | 阅读
35 |
36 | {{item.reading}}
37 | —
38 |
39 |
40 |
41 |
42 | 写作
43 |
44 | {{item.comprehensive}}
45 | —
46 |
47 |
48 |
49 | 更新时间:{{time}}
50 |
51 |
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | {{message}}
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/miniprogram/pages/previousScore/previousScore.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | {{filter.startYear(item.year, item.term, first_semester)}}
9 |
10 |
11 |
12 |
13 | 通过率:{{filter.toFix(item.detail.passRate, 0)}}%
14 | 学分:{{item.detail.passCredits}}/{{item.detail.totalCredit}}
15 |
16 |
17 |
18 |
19 |
20 |
21 | GPA
22 |
23 | {{filter.toFix(item.detail.gpa, 2)}}
24 | —
25 |
26 |
27 |
28 |
29 | 加权平均分
30 |
31 | {{filter.toFix(item.detail.score, 2)}}
32 | —
33 |
34 |
35 |
36 |
37 | 已出课程数
38 |
39 | {{item.detail.count}}/{{item.detail.count+item.ungraded}}
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 野生助手前端 - 小程序版
2 |
3 | 本程序在 [GNU Affero GPL v3.0](LICENSE) 下开源。若修改本程序并在网络上提供服务,必须使用相同协议公开修改后的完整源代码。
4 |
5 | Copyright (C) WildHelper
6 |
7 | [版本更新日志](CHANGELOG.md)
8 |
9 | 
10 |
11 | ## 安装
12 |
13 | 开发时使用了 TypeScript,需要将其将其编译成 JavaScript 才可使用
14 |
15 | 先运行 `npm install`;然后进入微信开发者工具,选择 `工具 - 构建 npm`
16 |
17 | 下载 `echart.js` 到 `./miniprogram/ec-canvas` 目录中
18 |
19 | 该项目有意将 `.idea` 提交。使用 WebStorm/PhpStorm 编辑文件时会原地将 TypeScript 文件编译为 JavaScript。
20 |
21 | ## 配置
22 |
23 | 修改 `./miniprogram/app.ts` 中 `App()` 函数的 `globalData.url_api` 和 `globalData.url_logo` 以自定义 API 地址和首页图标。
24 |
25 | ## 截图
26 |
27 |
28 |
29 | ## 核心技术
30 |
31 | + 通用 RESTful API
32 | + **爬虫**与学校官方对接实现数据**实时自动获取**
33 | + 第四版开始支持**校友认证**,学校网关账户绑定微信OpenID实现认证,毕业后可使用免密OpenID授权,100%保证用户真实,比学信网更简单易用
34 | + 使用了**端到端加密 (AES-256-GCM)**,中间人(包括微信)不可拿到任何用户数据;非选课周用户只能看到自己选择的课程;服务器**永不存储用户密码**;**撤销授权机制**,不想用了可以彻底删除所有用户数据,保证用户安全
35 | + DDOS防火墙、异地多活、WAF防火墙限频、等等……
36 |
37 | ## 开软软件使用
38 |
39 | ### GNU Affero GPL v3.0
40 |
41 | + [WildHelper/MiniProgram](https://github.com/WildHelper/MiniProgram)
42 |
43 | ### MIT License
44 |
45 | + [leoleoasd/zf_spider](https://github.com/leoleoasd/zf_spider)
46 | + [slimphp/Slim](https://github.com/slimphp/Slim)
47 | + [slimphp/Slim-Psr7](https://github.com/slimphp/Slim-Psr7)
48 | + [Tencent/weui](https://github.com/Tencent/weui)
49 | + [brix/crypto-js](https://github.com/brix/crypto-js)
50 | + [nodeca/pako](https://github.com/nodeca/pako)
51 |
52 | ### Apache License v2.0
53 |
54 | + [apache/incubator-echarts](https://github.com/apache/incubator-echarts)
55 |
56 | ### BSD 3-Clause License
57 |
58 | + [ecomfe/echarts-for-weixin](https://github.com/ecomfe/echarts-for-weixin)
59 |
--------------------------------------------------------------------------------
/miniprogram/ec-canvas/wx-canvas.js:
--------------------------------------------------------------------------------
1 | export default class WxCanvas {
2 | constructor(ctx, canvasId, isNew, canvasNode) {
3 | this.ctx = ctx;
4 | this.canvasId = canvasId;
5 | this.chart = null;
6 | this.isNew = isNew
7 | if (isNew) {
8 | this.canvasNode = canvasNode;
9 | }
10 | else {
11 | this._initStyle(ctx);
12 | }
13 |
14 | // this._initCanvas(zrender, ctx);
15 |
16 | this._initEvent();
17 | }
18 |
19 | getContext(contextType) {
20 | if (contextType === '2d') {
21 | return this.ctx;
22 | }
23 | }
24 |
25 | // canvasToTempFilePath(opt) {
26 | // if (!opt.canvasId) {
27 | // opt.canvasId = this.canvasId;
28 | // }
29 | // return wx.canvasToTempFilePath(opt, this);
30 | // }
31 |
32 | setChart(chart) {
33 | this.chart = chart;
34 | }
35 |
36 | attachEvent() {
37 | // noop
38 | }
39 |
40 | detachEvent() {
41 | // noop
42 | }
43 |
44 | _initCanvas(zrender, ctx) {
45 | zrender.util.getContext = function () {
46 | return ctx;
47 | };
48 |
49 | zrender.util.$override('measureText', function (text, font) {
50 | ctx.font = font || '12px sans-serif';
51 | return ctx.measureText(text);
52 | });
53 | }
54 |
55 | _initStyle(ctx) {
56 | var styles = ['fillStyle', 'strokeStyle', 'globalAlpha',
57 | 'textAlign', 'textBaseAlign', 'shadow', 'lineWidth',
58 | 'lineCap', 'lineJoin', 'lineDash', 'miterLimit', 'fontSize'];
59 |
60 | styles.forEach(style => {
61 | Object.defineProperty(ctx, style, {
62 | set: value => {
63 | if (style !== 'fillStyle' && style !== 'strokeStyle'
64 | || value !== 'none' && value !== null
65 | ) {
66 | ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
67 | }
68 | }
69 | });
70 | });
71 |
72 | ctx.createRadialGradient = () => {
73 | return ctx.createCircularGradient(arguments);
74 | };
75 | }
76 |
77 | _initEvent() {
78 | this.event = {};
79 | const eventNames = [{
80 | wxName: 'touchStart',
81 | ecName: 'mousedown'
82 | }, {
83 | wxName: 'touchMove',
84 | ecName: 'mousemove'
85 | }, {
86 | wxName: 'touchEnd',
87 | ecName: 'mouseup'
88 | }, {
89 | wxName: 'touchEnd',
90 | ecName: 'click'
91 | }];
92 |
93 | eventNames.forEach(name => {
94 | this.event[name.wxName] = e => {
95 | const touch = e.touches[0];
96 | this.chart.getZr().handler.dispatch(name.ecName, {
97 | zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
98 | zrY: name.wxName === 'tap' ? touch.clientY : touch.y
99 | });
100 | };
101 | });
102 | }
103 |
104 | set width(w) {
105 | if (this.canvasNode) this.canvasNode.width = w
106 | }
107 | set height(h) {
108 | if (this.canvasNode) this.canvasNode.height = h
109 | }
110 |
111 | get width() {
112 | if (this.canvasNode)
113 | return this.canvasNode.width
114 | return 0
115 | }
116 | get height() {
117 | if (this.canvasNode)
118 | return this.canvasNode.height
119 | return 0
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/miniprogram/pages/entireClass/entireClass.wxss:
--------------------------------------------------------------------------------
1 | .search{
2 | margin: 30rpx 40rpx;
3 | padding: 20rpx;
4 | border-radius: 20rpx;
5 | box-shadow: 0rpx 0rpx 15rpx #CCC;
6 | background-color: #FFF;
7 | display: flex;
8 | }
9 | .search .input {
10 | flex: 7;
11 | margin: auto 0;
12 | }
13 | .search .searchConfirm {
14 | flex: 1;
15 | margin-left: 20rpx;
16 | }
17 |
18 | .sort {
19 | margin: 0 40rpx;
20 | display: flex;
21 | font-size: 25rpx;
22 | }
23 | .sort view {
24 | color: #5e5e5e;
25 | }
26 | .sort .item {
27 | text-align: center;
28 | margin: 0 30rpx;
29 | }
30 |
31 | .classes {
32 | margin: 30rpx 40rpx;
33 | background-color: #FFF;
34 | border-radius: 20rpx;
35 | box-shadow: 0rpx 0rpx 15rpx #CCC;
36 | overflow: hidden;
37 | }
38 | .classes .line1{
39 | display: flex;
40 | }
41 | .classes .line1 .name{
42 | font-size: 30rpx;
43 | display: inline-block;
44 | white-space: nowrap;
45 | overflow: hidden;
46 | text-overflow: ellipsis;
47 | width: calc(100vw - 330rpx);
48 | }
49 | .classes .line1 .sampleSize{
50 | margin-top: auto;
51 | margin-bottom: auto;
52 | font-size: 20rpx;
53 | }
54 | .classes .line2{
55 | display: flex;
56 | margin-bottom: 10rpx;
57 | }
58 | .classes .line2 .item {
59 | color: #888888;
60 | }
61 | .classes .line3{
62 | display: flex;
63 | font-size: 20rpx;
64 | color: #888888;
65 | }
66 | .classes .line4 .content {
67 | flex: 1
68 | }
69 | .classes .line4 {
70 | color: #888888;
71 | display: flex;
72 | font-size: 20rpx;
73 | }
74 | .weui-msg__icon-area {
75 | margin-bottom: 16px!important;
76 | }
77 | .weui-msg__text-area {
78 | margin-bottom: 0!important;
79 | }
80 | .weui-msg__opr-area, .weui-msg__tips-area, .weui-msg__extra-area {
81 | display: none!important;
82 | }
83 | .count, .message {
84 | margin: 30rpx 40rpx;
85 | color: #888888;
86 | font-size: 25rpx;
87 | text-align: center;
88 | }
89 |
90 | .paging {
91 | margin: 0 40rpx;
92 | display: flex;
93 | }
94 | .paging .up{
95 | flex: 2;
96 | margin: 20rpx 20rpx;
97 | font-size: 25rpx;
98 | }
99 | .paging .select{
100 | flex:4;
101 | margin: 20rpx;
102 | font-size: 25rpx;
103 | padding: 8px 12px;
104 | }
105 | .paging .select view{
106 | text-overflow: ellipsis;
107 | width: 100%;
108 | display: inline-block;
109 | white-space: nowrap;
110 | overflow: hidden;
111 | }
112 | .paging .down{
113 | flex:2;
114 | margin: 20rpx 20rpx;
115 | font-size: 25rpx;
116 | }
117 | .weui-select {
118 | background-color: #5e5e5e;
119 | width: 100%;
120 | /* font-size: inherit; */
121 | height: 0;
122 | line-height: 0;
123 | position: relative;
124 | z-index: 300;
125 | /* padding-left: 0; */
126 | color: var(--weui-FG-0);
127 | }
128 | .arrow {
129 | position: absolute;
130 | right: 30rpx;
131 | top: 16rpx;
132 | }
133 | view.page {
134 | padding-bottom: 80px;
135 | }
136 |
137 | @supports (padding-bottom: calc(55px + 50rpx)) {
138 | view.page {
139 | padding-bottom: calc(55px + 50rpx);
140 | }
141 | }
142 |
143 | @supports (padding-bottom: calc(55px + 50rpx + env(safe-area-inset-bottom))) {
144 | view.page {
145 | padding-bottom: calc(55px + 50rpx + env(safe-area-inset-bottom));
146 | }
147 | }
148 | .weui-cell {
149 | padding: 24rpx 30rpx;
150 | }
151 |
--------------------------------------------------------------------------------
/miniprogram/pages/exam/exam.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | const app: IMyApp = getApp()
4 |
5 | Page({
6 | data: {
7 | examList: [],
8 | isNull: null,
9 | isOver: [],
10 | messages: [],
11 | },
12 | time: 0,
13 |
14 | onLoad: function() {
15 | const exam: IExams = wx.getStorageSync('exam2')
16 | if (exam && wx.$validateType(exam, 'exams')) {
17 | this.time = exam.updated_time
18 | this.setData({
19 | examList: exam.list,
20 | isNull: false,
21 | })
22 | this.parseTime()
23 | }
24 | if (this.time + 21600 < +new Date() / 1000) {
25 | this.fetch()
26 | }
27 | },
28 |
29 | fetch: function() {
30 | this.time = +new Date() / 1000
31 | wx.showToast({
32 | title: '更新考试时间中',
33 | icon: 'loading',
34 | duration: 6000,
35 | })
36 | wx.$request({
37 | path: 'courses/exams',
38 | actions: true,
39 | methods: 'GET',
40 | type: 'exams',
41 | success: (result: IExams, messages) => {
42 | this.setData({messages: messages})
43 | const isNull = false
44 | if (result.list.length === 0) {
45 | if (this.data.isNull === null) {
46 | this.setData({
47 | examList: [],
48 | isNull: true,
49 | })
50 | }
51 | wx.showToast({
52 | title: '考试为空',
53 | icon: 'none',
54 | duration: 500,
55 | })
56 | } else {
57 | wx.setStorageSync('exam2', result)
58 | this.setData({
59 | examList: result.list,
60 | isNull: isNull,
61 | })
62 | this.parseTime()
63 | wx.showToast({
64 | title: '更新成功',
65 | icon: 'success',
66 | duration: 500,
67 | })
68 | }
69 | },
70 | complete: () => {
71 | wx.stopPullDownRefresh()
72 | },
73 | })
74 | },
75 |
76 | parseTime: function() {
77 | // TODO: undefined is not an object (evaluating 's.split("年")[1].split')
78 | // const isOver = []
79 | // for (const i in this.data.examList) {
80 | // let examEndTime = this.data.examList[i].time
81 | // if (typeof this.data.examList[i].time.split === 'function') {
82 | // examEndTime = examEndTime.split('年')[0] + '-' + examEndTime.split('年')[1].split('月')[0] + '-' + examEndTime.split('月')[1].split('日')[0] + ' ' + examEndTime.split('-')[1].split(')')[0]
83 | // }
84 | // const date = new Date()
85 | // const curTime = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes()
86 | // if (examEndTime > curTime) {
87 | // isOver.push(true)
88 | // } else {
89 | // isOver.push(false)
90 | // }
91 | // }
92 | //
93 | // this.setData({isOver: isOver})
94 | },
95 |
96 | onShow: function() {
97 | if (typeof this.getTabBar === 'function' && this.getTabBar()) {
98 | wx.$initTab(this.getTabBar())
99 | this.getTabBar().setData({
100 | selected: app.globalData.exam_tab,
101 | })
102 | }
103 | },
104 |
105 | onPullDownRefresh: function() {
106 | if (this.time + 60 > +new Date() / 1000) {
107 | wx.stopPullDownRefresh()
108 | wx.showToast({
109 | title: '手速太快了,等一会儿再刷新试试吧',
110 | icon: 'none',
111 | duration: 3000,
112 | })
113 | return
114 | }
115 | this.fetch()
116 | },
117 | })
118 |
119 | export {}
120 |
--------------------------------------------------------------------------------
/miniprogram/pages/scoreList/scoreList.wxss:
--------------------------------------------------------------------------------
1 | .line{
2 | width: 100%; /* 分隔线的长度 */
3 | margin: auto;
4 | height: 1px; /* 分隔线粗细 */
5 | text-align: center;
6 | font-size: 24rpx;
7 | color: #aaa;
8 | background: #ccc;
9 | margin-top: 30rpx;
10 | margin-bottom: 5rpx;
11 | flex: 1;
12 | }
13 | .arrow{
14 | width: 10px;
15 | height: 10px;
16 | border-top: 2px solid #999;
17 | border-right: 2px solid #999;
18 |
19 | right: 20rpx;
20 | transform: rotate(45deg);
21 | margin-top:20rpx;
22 | }
23 | .title {
24 | flex: 9;
25 | }
26 |
27 | .search{
28 | margin: 30rpx 40rpx;
29 | padding: 20rpx;
30 | border-radius: 20rpx;
31 | box-shadow: 0rpx 0rpx 15rpx #CCC;
32 | background-color: #FFF;
33 | display: flex;
34 | }
35 | .search .input {
36 | flex: 7;
37 | margin: auto 0;
38 | }
39 | .search .searchConfirm {
40 | flex: 1;
41 | margin-left: 20rpx;
42 | }
43 |
44 | .title {
45 | display: flex;
46 | }
47 | .sort {
48 | font-size: 25rpx;
49 | }
50 |
51 | .totalScore {
52 | overflow: hidden;
53 | margin: 30rpx 40rpx;
54 | padding-bottom: 10rpx;
55 | border-radius: 20rpx;
56 | box-shadow: 0rpx 0rpx 15rpx #CCC;
57 | background-color: #FFF;
58 | }
59 |
60 | .totalScore .line1 {
61 | font-size: 40rpx;
62 | padding: 30rpx 30rpx 10rpx 30rpx;
63 | background-color: #0197C2;
64 | color: #FFF;
65 | display: flex;
66 | }
67 | .totalScore .line2 {
68 | margin-bottom: 30rpx;
69 | }
70 | .totalScore .line3 {
71 | display: flex;
72 | }
73 | .totalScore .line3 .item {
74 | flex: 1;
75 | margin-right: 20rpx;
76 | border-right: 1rpx solid rgba(204, 204, 204, 0.4);
77 | }
78 | .totalScore .line3 .item_1 {
79 | flex: 1;
80 | margin-right: 20rpx;
81 | }
82 | .totalScore .line3 .title {
83 | font-size: 25rpx;
84 | color: #999999;
85 | }
86 | .totalScore .line3 .value {
87 | font-size: 50rpx;
88 | }
89 | .totalScore .time {
90 | font-size: 25rpx;
91 | text-align: right;
92 | color: var(--weui-FG-2);
93 | flex: 1;
94 | }
95 |
96 | .search{
97 | margin: 30rpx 40rpx;
98 | padding: 20rpx;
99 | border-radius: 20rpx;
100 | box-shadow: 0rpx 0rpx 15rpx #CCC;
101 | background-color: #FFF;
102 | }
103 |
104 | .sortDisplay {
105 | display: flex;
106 | margin: 30rpx 40rpx;
107 | }
108 | .sortDisplay view {
109 | color: #5e5e5e;
110 | }
111 | .typeSet {
112 | margin: 30rpx 40rpx;
113 | }
114 | .typeSet .title {
115 | font-size: 25rpx;
116 | color: #B2B2B2;
117 | }
118 | .scores {
119 | box-shadow: 0rpx 0rpx 15rpx #CCC;
120 | background-color: #FFF;
121 | padding: 0 30rpx;
122 | margin-top: 5rpx;
123 | border-radius: 10rpx;
124 | }
125 |
126 | .weui-cell {
127 | padding: 18rpx 0;
128 | position: relative;
129 | display: -webkit-box;
130 | display: -webkit-flex;
131 | display: flex;
132 | align-items: center;
133 | }
134 | .weui-cell:before {
135 | content: " ";
136 | position: absolute;
137 | left: 0;
138 | top: 0;
139 | right: 0;
140 | height: 1px;
141 | border-top: 1px solid var(--weui-FG-3);
142 | color: var(--weui-FG-3);
143 | transform-origin: 0 0;
144 | transform: scaleY(.5);
145 | z-index: 2;
146 | }
147 | .course-title {
148 | font-size: 90%;
149 | display: block;
150 | overflow: hidden;
151 | text-overflow: ellipsis;
152 | white-space: nowrap;
153 | width: calc(100vw - 360rpx);
154 | }
155 | .course-desc {
156 | font-size: 60%;
157 | display: block;
158 | color: #999999;
159 | }
160 | @media (prefers-color-scheme: dark) {
161 | .totalScore .line1 {
162 | background-color: #143F54 !important;
163 | }
164 | }
165 | .message {
166 | margin: 30rpx 40rpx;
167 | color: #888888;
168 | font-size: 25rpx;
169 | text-align: center;
170 | }
171 |
--------------------------------------------------------------------------------
/miniprogram/pages/index/index.wxss:
--------------------------------------------------------------------------------
1 | /**index.wxss**/
2 | .container {
3 | height: 100%;
4 | display: flex;
5 | flex-direction: column;
6 | align-items: center;
7 | justify-content: space-between;
8 | padding: 0 0;
9 | box-sizing: border-box;
10 |
11 | }
12 | .page page {
13 | background-color: #FFF;
14 | }
15 | .date {
16 | background-color: var(--weui-BG-0);
17 | display: flex;
18 | color: #4c4c4c;
19 | }
20 | .date .dateItem {
21 | font-size: 30rpx;
22 | flex: 1;
23 | text-align: center;
24 | padding: 0 5rpx;
25 | box-sizing: border-box;
26 | border: 5rpx solid var(--weui-BG-0);
27 | }
28 | .date .s {
29 | flex: 1;
30 | background-color: #888;
31 | font-size: 20rpx;
32 | text-align: center;
33 | padding-top: 10rpx;
34 | color: #fff;
35 | }
36 |
37 | .classCol {
38 | background-color: #FFF;
39 | }
40 |
41 | .time {
42 | display: flex;
43 | }
44 | .classItem1,.classItem2,.classItem3,.classItem4,.classItem5,.classItem6,.classItem7 {
45 | flex: 1;
46 | height: 250rpx;
47 | font-size: 25rpx;
48 | border: 5rpx solid #FFF;
49 | box-sizing: border-box;
50 | border-radius: 15rpx;
51 | padding: 0 5rpx;
52 | color: #4c4c4c;
53 | overflow: hidden;
54 | }
55 | .opacity-true {
56 | opacity: 0.2;
57 | }
58 | .classItem0 {
59 | flex: 1;
60 | height: 250rpx;
61 | text-align: center;
62 | color: #4c4c4c;
63 | }
64 | .classItem0 .content {
65 | display: block;
66 | font-size: 30rpx;
67 | margin-top: 60rpx;
68 | }
69 | view.page {
70 | padding-bottom: 55px;
71 | }
72 | view.page.is-single-true {
73 | padding-bottom: 30rpx;
74 | }
75 |
76 | @supports (padding-bottom: calc(55px + env(safe-area-inset-bottom))) {
77 | view.page {
78 | padding-bottom: calc(55px + env(safe-area-inset-bottom));
79 | }
80 | }
81 |
82 | @media (prefers-color-scheme: dark) {
83 | .page page {
84 | background-color: #000;
85 | }
86 | .date {
87 | color: #b3b3b3;
88 | }
89 | .date .dateItem {
90 | border: 5rpx solid var(--weui-BG-0);
91 | }
92 | .date .s {
93 | color: #000;
94 | }
95 | view {
96 | color: #FFF;
97 | }
98 | .classCol {
99 | background-color: #000;
100 | }
101 | .classItem1,.classItem2,.classItem3,.classItem4,.classItem5,.classItem6,.classItem7 {
102 | border: 5rpx solid #000;
103 | color: #b3b3b3;
104 | }
105 | .opacity-true {
106 | opacity: 0.2;
107 | }
108 | .classItem0 {
109 | flex: 1;
110 | height: 250rpx;
111 | text-align: center;
112 | color: #b3b3b3;
113 | }
114 | }
115 | .message {
116 | margin: 30rpx 40rpx;
117 | color: #888888;
118 | font-size: 25rpx;
119 | text-align: center;
120 | }
121 | .weui-cell {
122 | padding: 18rpx 0;
123 | position: relative;
124 | display: -webkit-box;
125 | display: -webkit-flex;
126 | display: flex;
127 | align-items: center;
128 | }
129 | .weui-cell:before {
130 | content: " ";
131 | position: absolute;
132 | left: 0;
133 | top: 0;
134 | right: 0;
135 | height: 1px;
136 | border-top: 1px solid var(--weui-FG-3);
137 | color: var(--weui-FG-3);
138 | transform-origin: 0 0;
139 | transform: scaleY(.5);
140 | z-index: 2;
141 | }
142 | .typeSet {
143 | margin: 30rpx 40rpx;
144 | }
145 | .typeSet .title {
146 | font-size: 25rpx;
147 | color: #B2B2B2;
148 | }
149 | .scores {
150 | box-shadow: 0rpx 0rpx 15rpx #CCC;
151 | background-color: #FFF;
152 | padding: 0 30rpx;
153 | margin-top: 5rpx;
154 | border-radius: 10rpx;
155 | }
156 | .course-title {
157 | font-size: 90%;
158 | display: block;
159 | overflow: hidden;
160 | text-overflow: ellipsis;
161 | white-space: nowrap;
162 | width: calc(100vw - 360rpx);
163 | }
164 | .course-desc {
165 | font-size: 60%;
166 | display: block;
167 | color: #999999;
168 | }
169 |
--------------------------------------------------------------------------------
/miniprogram/pages/index/index.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{comment}}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 周一
15 | 周二
16 | 周三
17 | 周四
18 | 周五
19 | 周六
20 | 周日
21 |
22 |
23 |
24 |
25 |
26 |
27 | 上午\n
28 | 下午\n
29 | 晚上\n
30 | {{item.text}}
31 | {{item}}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | {{message}}
40 |
41 |
42 |
43 | 无上课时间课程
44 |
45 |
46 | {{item.name}}{{item.credit}} | {{item.type}} | {{item.instructor}}
47 | {{item.hours}}
48 |
49 |
50 |
51 |
52 | {{message}}
53 |
54 |
59 | 点击右上角 … 进行分享后好友可看到您当前学期课表
60 | {{item}}
61 |
62 |
--------------------------------------------------------------------------------
/miniprogram/pages/overAllPage/overAllPage.wxss:
--------------------------------------------------------------------------------
1 | .line{
2 | width: 100%; /* 分隔线的长度 */
3 | margin: auto;
4 | height: 1px; /* 分隔线粗细 */
5 | text-align: center;
6 | font-size: 24rpx;
7 | color: #aaa;
8 | background: #ccc;
9 | margin-top: 30rpx;
10 | margin-bottom: 5rpx;
11 | flex: 1;
12 | }
13 |
14 | .title {
15 | flex: 9;
16 | }
17 |
18 | .view-box-btn-hover{
19 | background-color: #4D4D4D;
20 | }
21 |
22 | .card {
23 | background-color: #0197C2;
24 | }
25 | .card view {
26 | color: #FFF;
27 | }
28 | .page .userInfo {
29 | padding: 40rpx 60rpx;
30 | }
31 | .card2 {
32 | position: relative;
33 | height: 60vw;
34 | top: -35vw;
35 | width: 140vw;
36 | background-color: #0197C2;
37 | -moz-border-radius: 100vw / 60vw;
38 | -webkit-border-radius: 100vw / 60vw;
39 | border-radius: 100vw / 60vw;
40 | z-index: -1;
41 | left: -20vw;
42 | }
43 | .page .userInfo .nameAndPic {
44 | display: flex;
45 | }
46 | .page .userInfo .nameAndPic .name {
47 | flex:2;
48 | white-space: nowrap;
49 | overflow: hidden;
50 | text-overflow: ellipsis;
51 | }
52 | .page .userInfo .nameAndPic .name .welcome {
53 | font-size: 24rpx;
54 | display: block;
55 | }
56 | .page .userInfo .nameAndPic .name .userName {
57 | font-size: 50rpx;
58 | font-weight:bold;
59 | display: inline-block;
60 | }
61 | .page .userInfo .nameAndPic .name .expression {
62 | margin-top: 20rpx;
63 | font-size: 26rpx;
64 | display: inline-block;
65 | }
66 | .page .userInfo .nameAndPic .pic {
67 | height: 120rpx;
68 | width: 120rpx;
69 | border-radius: 60rpx;
70 | overflow: hidden;
71 | }
72 |
73 | .page .userInfo .detailInfo .line1 {
74 | display: flex;
75 | }
76 | .page .userInfo .detailInfo .line2 {
77 | display: flex;
78 | }
79 | .page .userInfo .detailInfo .infoLeft{
80 | font-size: 24rpx;
81 | flex: 1;
82 | }
83 | .page .userInfo .detailInfo .infoRight{
84 | font-size: 24rpx;
85 | flex: 1;
86 | }
87 |
88 |
89 |
90 | .totalScore {
91 | margin: 30rpx 40rpx;
92 | padding: 10rpx 30rpx 20rpx 30rpx;
93 | border-radius: 20rpx;
94 | box-shadow: 0rpx 0rpx 15rpx #CCC;
95 | background-color: #FFF;
96 | }
97 | .totalScore .line1 {
98 | font-size: 40rpx;
99 | font-weight:bold;
100 | margin: 10rpx 0;
101 | display: flex;
102 | }
103 | .totalScore .line2 {
104 | margin-bottom: 30rpx;
105 | }
106 | .totalScore .line3 {
107 | display: flex;
108 | }
109 | .totalScore .line3 .item {
110 | flex: 1;
111 | margin-right: 20rpx;
112 | border-right: 1rpx solid rgba(204, 204, 204, 0.4);
113 | }
114 | .totalScore .line3 .item_1 {
115 | flex: 1;
116 | margin-right: 20rpx;
117 | }
118 | .totalScore .line3 .title {
119 | font-size: 25rpx;
120 | color: #999999;
121 | }
122 | .totalScore .line3 .value {
123 | font-size: 50rpx;
124 | }
125 | .totalScore .time {
126 | font-size: 25rpx;
127 | text-align: right;
128 | color: var(--weui-FG-2);
129 | }
130 |
131 | .previousAndCETScore {
132 | margin: 30rpx 40rpx;
133 | padding: 30rpx 30rpx;
134 | padding-bottom: 30rpx;
135 | border-radius: 20rpx;
136 | box-shadow: 0rpx 0rpx 15rpx #CCC;
137 | font-size: 40rpx;
138 | font-weight:bold;
139 | display: flex;
140 | background-color: #FFF;
141 | }
142 |
143 | .message {
144 | margin: 30rpx 40rpx;
145 | color: #888888;
146 | font-size: 25rpx;
147 | text-align: center;
148 | }
149 |
150 | view.page {
151 | padding-bottom: 80px;
152 | }
153 | view.page.is-single-true {
154 | padding-bottom: 30rpx;
155 | }
156 |
157 | @supports (padding-bottom: calc(55px + 50rpx)) {
158 | view.page {
159 | padding-bottom: calc(55px + 50rpx);
160 | }
161 | }
162 |
163 | @supports (padding-bottom: calc(55px + 50rpx + env(safe-area-inset-bottom))) {
164 | view.page {
165 | padding-bottom: calc(55px + 50rpx + env(safe-area-inset-bottom));
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/miniprogram/pages/scoreDetailPage/scoreDetailPage.wxss:
--------------------------------------------------------------------------------
1 | .head {
2 | margin: 30rpx 40rpx;
3 | font-size: 25rpx;
4 | color: #888888;
5 | }
6 | .totalScore {
7 | margin: 0 40rpx 30rpx 40rpx;
8 | padding-bottom: 10rpx;
9 | border-radius: 20rpx;
10 | box-shadow: 0rpx 0rpx 15rpx #CCC;
11 | background-color: #FFF;
12 | overflow: hidden;
13 | }
14 | .totalScore .line1 {
15 | font-size: 40rpx;
16 | padding: 30rpx 30rpx 10rpx 30rpx;
17 | background-color: #0197C2;
18 | color: #FFF;
19 | display: block;
20 | overflow: hidden;
21 | text-overflow: ellipsis;
22 | white-space: nowrap;
23 | }
24 | .totalScore .line2 {
25 | display: flex;
26 | }
27 | .totalScore .line2 .item {
28 | flex: 1;
29 | margin-right: 20rpx;
30 | border-right: 1rpx solid rgba(204, 204, 204, 0.4);
31 | }
32 | .totalScore .line2 .item_1 {
33 | flex: 1;
34 | margin-right: 20rpx;
35 | }
36 | .totalScore .line2 .title {
37 | font-size: 25rpx;
38 | color: #999999;
39 | }
40 | .totalScore .line2 .value {
41 | font-size: 50rpx;
42 | }
43 | .totalScore .time {
44 | font-size: 25rpx;
45 | text-align: right;
46 | color: var(--weui-FG-2);
47 | }
48 |
49 |
50 | .distribution {
51 | margin: 0rpx 40rpx 30rpx;
52 | padding: 40rpx 30rpx 30rpx;
53 | border-radius: 20rpx;
54 | box-shadow: 0rpx 0rpx 15rpx #CCC;
55 | background-color: #FFF;
56 | }
57 | .distribution .line1 {
58 | display: flex;
59 | margin: 20rpx 0;
60 | }
61 | .distribution .line1 .item {
62 | flex: 1;
63 | margin-right: 20rpx;
64 | border-right: 1rpx solid rgba(204, 204, 204, 0.4);
65 | }
66 | .distribution .line1 .item_1 {
67 | flex: 1;
68 | margin-right: 20rpx;
69 | }
70 | .distribution .line1 .title {
71 | font-size: 25rpx;
72 | color: #999999;
73 | }
74 | .distribution .line1 .value {
75 | font-size: 50rpx;
76 | }
77 | .distribution .course-type {
78 | font-size: 20rpx;
79 | text-align: left;
80 | color: #999999;
81 | display: flex;
82 | }
83 | .distribution .course-type .course-type-flex {
84 | flex: 1;
85 | }
86 | .distribution .time {
87 | font-size: 25rpx;
88 | text-align: right;
89 | color: #999999;
90 | }
91 | .distribution .line2 {
92 | font-size: 40rpx;
93 | font-weight:bold;
94 | margin-top: 30rpx;
95 | display: flex;
96 | flex-direction: column;
97 | }
98 | .message {
99 | margin: 30rpx 40rpx;
100 | color: #888888;
101 | font-size: 25rpx;
102 | text-align: center;
103 | }
104 | .distribution .line2 .statement {
105 | color: red;
106 | font-size: 25rpx;
107 | }
108 | .distributionChart {
109 | width: 100%;
110 | height: 1000rpx;
111 | margin: auto;
112 | flex-direction: column;
113 | }
114 | .distribution .line3 {
115 | display: flex;
116 | margin-bottom: 10rpx;
117 | }
118 | .distribution .line3 .item {
119 | flex: 1;
120 | margin-right: 20rpx;
121 | border-right: 1rpx solid rgba(204, 204, 204, 0.4);
122 | }
123 |
124 | .distribution .line3 .item_1 {
125 | flex: 1;
126 | margin-right: 20rpx;
127 | }
128 |
129 | .distribution .line3 .title {
130 | font-size: 25rpx;
131 | color: #999999;
132 | margin-bottom: 10rpx;
133 | }
134 | .distribution .line3 .value {
135 | font-size: 40rpx;
136 | }
137 | .distributionChart_notSshow {
138 | margin-top: 0rpx;
139 | padding-bottom: 30rpx;
140 | color: #FF0000;
141 | font-weight: 200;
142 | }
143 |
144 | .teacher {
145 | margin: 0rpx 40rpx 30rpx;
146 | padding: 0;
147 | border-radius: 20rpx;
148 | box-shadow: 0rpx 0rpx 15rpx #CCC;
149 | background-color: #FFF;
150 | overflow: hidden;
151 | }
152 | .diff-green {
153 | color: #09BB07;
154 | }
155 | .diff-red {
156 | color: #E64340;
157 | }
158 | .highlight-true {
159 | background-color: #576B95;
160 | }
161 | .highlight-true .weui-cell__bd {
162 | color: #fff;
163 | }
164 | .highlight-true .weui-cell__ft {
165 | color: #cecece;
166 | }
167 | .weui-cell {
168 | padding: 20rpx 30rpx
169 | }
170 | @media (prefers-color-scheme: dark) {
171 | .totalScore .line1 {
172 | background-color: #143F54 !important;
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/miniprogram/utils/filter.wxs:
--------------------------------------------------------------------------------
1 | var filter = {
2 | toFix: function (value, n) {
3 | if(value == null) {
4 | return '';
5 | } else if ( isNaN(value) ) {
6 | return value;
7 | } else if (typeof value === "string") {
8 | return parseInt(value, 10).toFixed(n)
9 | } else {
10 | return value.toFixed(n)
11 | }
12 | },
13 | toStr: function (value) {
14 | return value.toString()
15 | },
16 | toNum: function (value) {
17 | return value.toNumber()
18 | },
19 | isNum: function (value) {
20 | return !isNaN(value);
21 | },
22 | join: function (value, separator) {
23 | if(typeof value.join === "function") {
24 | return value.join(separator);
25 | }
26 | return value;
27 | },
28 | diff: function (value) {
29 | if(typeof value !== "number") {
30 | return value;
31 | }
32 | var prefix = '';
33 | var number = value.toFixed(2);
34 | if (value === 0 || number === '0.00' || number === '-0.00'){
35 | return '-'
36 | }
37 | if (value > 0) {
38 | prefix = '+';
39 | if (number.substring(0, 2) === '0.') {
40 | number = number.substring(1);
41 | }
42 | } else if (number.substring(0, 3) === '-0.') {
43 | prefix = '-';
44 | number = number.substring(2);
45 | }
46 | return prefix + number;
47 | },
48 | diffClass: function (value, cmp) {
49 | if (value > cmp) {
50 | return 'green';
51 | } else if (value < -cmp) {
52 | return 'red';
53 | }
54 | return 'default';
55 | },
56 | addHeading: function (value, choice) {
57 | var ret = {className: '', text: value}
58 | if (typeof value === 'string') {
59 | if (value.substring(0, 7) === '###### ') {
60 | ret = {className: 'h6', text: value.substring(7)};
61 | }
62 | if (value.substring(0, 6) === '##### ') {
63 | ret = {className: 'h5', text: value.substring(6)};
64 | }
65 | if (value.substring(0, 5) === '#### ') {
66 | ret = {className: 'h4', text: value.substring(5)};
67 | }
68 | if (value.substring(0, 4) === '### ') {
69 | ret = {className: 'h3', text: value.substring(4)};
70 | }
71 | if (value.substring(0, 3) === '## ') {
72 | ret = {className: 'h2', text: value.substring(3)};
73 | }
74 | if (value.substring(0, 2) === '# ') {
75 | ret = {className: 'h1', text: value.substring(2)};
76 | }
77 | if (value.substring(0, 2) === '+ ' || value.substring(0, 2) === '- ') {
78 | ret = {className: 'list', text: value.substring(2)};
79 | }
80 | if (value.substring(0, 3) === '1. ') {
81 | ret = {className: 'numbered-list', text: value.substring(3)};
82 | }
83 | }
84 | switch (choice) {
85 | case 'class':
86 | return ret.className;
87 | case 'text':
88 | return ret.text;
89 | default:
90 | return value;
91 | }
92 | },
93 | shortYear: function (year) {
94 | if (typeof year !== 'string') {
95 | return year
96 | }
97 | return year.substring(2, 4) + '-' + year.substring(7, 9)
98 | },
99 | startYear: function (year, semester, first) {
100 | var append = ' 第 ' + semester + ' 学期'
101 | if (typeof year !== 'string' || typeof first !== 'string') {
102 | return year + append
103 | }
104 | var firstYear = parseInt(first.substring(0, 4), 10)
105 | var currentYear = parseInt(year.substring(0, 4), 10)
106 | switch (semester) {
107 | case 1:
108 | case '1':
109 | append = '上'
110 | break;
111 | case 2:
112 | case '2':
113 | append = '下'
114 | break;
115 | case 3:
116 | case '3':
117 | append = '小学期'
118 | break;
119 | }
120 | switch (currentYear - firstYear) {
121 | case 0:
122 | return '大一' + append
123 | case 1:
124 | return '大二' + append
125 | case 2:
126 | return '大三' + append
127 | case 3:
128 | return '大四' + append
129 | case 4:
130 | return '大五' + append
131 | case 5:
132 | return '大六' + append
133 | default:
134 | return year + append
135 | }
136 | }
137 | }
138 |
139 | module.exports = {
140 | toFix: filter.toFix,
141 | toStr: filter.toStr,
142 | toNum: filter.toNum,
143 | isNum: filter.isNum,
144 | join: filter.join,
145 | diff: filter.diff,
146 | diffClass: filter.diffClass,
147 | addHeading: filter.addHeading,
148 | shortYear: filter.shortYear,
149 | startYear: filter.startYear
150 | }
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [],
4 | "rules": {
5 | "adjacent-overload-signatures": true,
6 | "align": {
7 | "options": [
8 | "parameters",
9 | "statements"
10 | ]
11 | },
12 | "arrow-return-shorthand": true,
13 | "ban-types": {
14 | "options": [
15 | ["Object", "Avoid using the `Object` type. Did you mean `object`?"],
16 | ["Function", "Avoid using the `Function` type. Prefer a specific function type, like `() => void`."],
17 | ["Boolean", "Avoid using the `Boolean` type. Did you mean `boolean`?"],
18 | ["Number", "Avoid using the `Number` type. Did you mean `number`?"],
19 | ["String", "Avoid using the `String` type. Did you mean `string`?"],
20 | ["Symbol", "Avoid using the `Symbol` type. Did you mean `symbol`?"]
21 | ]
22 | },
23 | "comment-format": {
24 | "options": ["check-space"]
25 | },
26 | "curly": {
27 | "options": ["ignore-same-line"]
28 | },
29 | "cyclomatic-complexity": false,
30 | "import-spacing": true,
31 | "indent": {
32 | "options": ["spaces"]
33 | },
34 | "interface-name": true,
35 | "interface-over-type-literal": true,
36 | "no-angle-bracket-type-assertion": true,
37 | "no-arg": true,
38 | "no-conditional-assignment": true,
39 | "no-debugger": true,
40 | "no-duplicate-super": true,
41 | "no-eval": true,
42 | "no-internal-module": true,
43 | "no-misused-new": true,
44 | "no-reference-import": true,
45 | "no-string-literal": true,
46 | "no-string-throw": true,
47 | "no-unnecessary-initializer": true,
48 | "no-unsafe-finally": true,
49 | "no-unused-expression": true,
50 | "no-use-before-declare": false,
51 | "no-var-keyword": true,
52 | "no-var-requires": true,
53 | "one-line": {
54 | "options": [
55 | "check-catch",
56 | "check-else",
57 | "check-finally",
58 | "check-open-brace",
59 | "check-whitespace"
60 | ]
61 | },
62 | "one-variable-per-declaration": {
63 | "options": ["ignore-for-loop"]
64 | },
65 | "prefer-const": true,
66 | "prefer-for-of": true,
67 | "quotemark": {
68 | "options": [
69 | "single",
70 | "avoid-escape",
71 | "jsx-double"
72 | ]
73 | },
74 | "radix": true,
75 | "semicolon": {
76 | "options": ["never"]
77 | },
78 | "space-before-function-paren": {
79 | "options": {
80 | "anonymous": "never",
81 | "asyncArrow": "always",
82 | "constructor": "never",
83 | "method": "never",
84 | "named": "never"
85 | }
86 | },
87 | "trailing-comma": {
88 | "options": {
89 | "esSpecCompliant": true,
90 | "multiline": "always",
91 | "singleline": "never"
92 | }
93 | },
94 | "triple-equals": {
95 | "options": ["allow-null-check"]
96 | },
97 | "typedef": false,
98 | "typedef-whitespace": {
99 | "options": [{
100 | "call-signature": "nospace",
101 | "index-signature": "nospace",
102 | "parameter": "nospace",
103 | "property-declaration": "nospace",
104 | "variable-declaration": "nospace"
105 | },
106 | {
107 | "call-signature": "onespace",
108 | "index-signature": "onespace",
109 | "parameter": "onespace",
110 | "property-declaration": "onespace",
111 | "variable-declaration": "onespace"
112 | }
113 | ]
114 | },
115 | "typeof-compare": false,
116 | "unified-signatures": true,
117 | "use-isnan": true,
118 | "whitespace": {
119 | "options": [
120 | "check-branch",
121 | "check-decl",
122 | "check-operator",
123 | "check-separator",
124 | "check-type",
125 | "check-typecast"
126 | ]
127 | }
128 | },
129 | "jsRules": {},
130 | "rulesDirectory": [],
131 | "compilerOptions": {
132 | "lib": [ "es2015" ]
133 | }
134 | }
--------------------------------------------------------------------------------
/miniprogram/pages/login/login.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | const app: IMyApp = getApp()
4 |
5 | Page({
6 | data: {
7 | count: '',
8 | password: '',
9 | showClearBtn: false,
10 | isWaring: false,
11 | isLoggedIn: true,
12 | url_logo: app.globalData.url_logo,
13 | message: '',
14 | },
15 |
16 | // 登陆表单数据处理-用户名输入框变更
17 | onInputCount(evt) {
18 | const count = evt.detail.value
19 | this.data.count = count
20 | this.setData({
21 | showClearBtnCount: !!count.length,
22 | isWaring: false,
23 | })
24 |
25 | },
26 | // 登陆表单数据处理-密码输入框变更
27 | onInputPassword(evt) {
28 | const password = evt.detail.value
29 | this.data.password = password
30 | this.setData({
31 | showClearBtnPassword: !!password.length,
32 | isWaring: false,
33 | })
34 |
35 | },
36 | // 登陆表单数据处理-用户名输入框清空
37 | onClearCount() {
38 | this.setData({
39 | count: '',
40 | showClearBtnCount: false,
41 | isWaring: false,
42 | })
43 | },
44 | // 登陆表单数据处理-密码输入框清空
45 | onClearPassword() {
46 | this.setData({
47 | password: '',
48 | showClearBtnPassword: false,
49 | isWaring: false,
50 | })
51 | },
52 |
53 | // 确定按钮处理
54 | onConfirm() {
55 | // 用户名格式不正确时,warning效果的判定
56 | if (this.data.count.length !== 8) {
57 | this.setData({
58 | isWaring: true,
59 | })
60 | }
61 |
62 | wx.showLoading({
63 | title: '登录中',
64 | })
65 | wx.login({
66 | success: (res) => {
67 | wx.$request({
68 | actions: false,
69 | methods: 'POST',
70 | data: {
71 | 'no': this.data.count,
72 | 'pass': this.data.password,
73 | 'code': res.code,
74 | },
75 | path: 'login',
76 | success: wx.$loginSuccess,
77 | type: 'any',
78 | })
79 | },
80 | })
81 | },
82 |
83 | onLoad: function(options) {
84 | if (typeof options !== 'undefined' && options.year && options.term && options.courseId) {
85 | app.globalData.redirect = {
86 | year: options.year,
87 | term: options.term,
88 | courseId: options.courseId,
89 | }
90 | }
91 |
92 | if (!app.globalData.authorization || !app.globalData.open || !app.globalData.student_id) {
93 | app.globalData.authorization = ''
94 | app.globalData.open = ''
95 | app.globalData.student_id = ''
96 | }
97 |
98 | let version = '-1'
99 | if (options.version) {
100 | version = options.version
101 | wx.setStorageSync('version', version)
102 | } else {
103 | const getVersion = wx.getStorageSync('version')
104 | if (getVersion) {
105 | version = getVersion
106 | }
107 | }
108 |
109 | wx.$request({
110 | actions: false,
111 | methods: 'GET',
112 | path: 'endpoint/' + version,
113 | type: 'any',
114 | success: (resp) => {
115 | app.globalData.url_api = resp.default.url
116 | const complete = () => {
117 | this.setData({message: resp.default.message})
118 | if (app.globalData.student_id && app.globalData.authorization && app.globalData.open) {
119 | wx.getBackgroundFetchToken({
120 | complete: (res: any) => {
121 | if (res.errMsg !== 'getBackgroundFetchToken:ok' || res.token !== app.globalData.authorization) {
122 | wx.setBackgroundFetchToken({
123 | token: app.globalData.authorization,
124 | complete: () => {
125 | wx.switchTab({
126 | url: '/pages/overAllPage/overAllPage',
127 | })
128 | },
129 | })
130 | } else {
131 | wx.switchTab({
132 | url: '/pages/overAllPage/overAllPage',
133 | })
134 | }
135 | },
136 | })
137 | } else {
138 | app.globalData.authorization = ''
139 | app.globalData.open = ''
140 | app.globalData.student_id = ''
141 | this.setData( { isLoggedIn: false } )
142 | }
143 | }
144 | if (resp.default.trusted) {
145 | wx.setEnableDebug({
146 | enableDebug: false,
147 | complete,
148 | })
149 | } else {
150 | wx.setEnableDebug({
151 | enableDebug: true,
152 | complete,
153 | })
154 | }
155 | },
156 | })
157 | },
158 |
159 | onShareAppMessage: function() {
160 | return {
161 | title: '快来查分啦',
162 | path: '/pages/login/login',
163 | }
164 | },
165 |
166 | morePage: function() {
167 | wx.navigateTo({
168 | url: '/pages/more/more',
169 | })
170 | },
171 | })
172 |
173 | export {}
174 |
--------------------------------------------------------------------------------
/miniprogram/pages/more/more.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{status_messages['is_no_password']['desc']}}
7 |
8 |
9 |
10 | {{status_messages['share']['desc']}}
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | {{status_messages['1']['desc']}}
19 |
20 |
21 |
22 |
23 | {{status_messages['2']['desc']}}
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | {{status_messages['0']['desc']}}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | {{status_messages['default']['desc']}}
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | 四六级成绩
50 |
51 |
52 |
53 |
54 |
55 | 选课指导
56 |
57 |
58 |
59 |
60 | 考试时间
61 |
62 |
63 |
64 |
65 |
66 |
67 | {{adMessage}}
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | {{filter.addHeading(item, 'text')}}
81 |
82 |
86 |
87 |
91 |
92 | {{filter.addHeading(item, 'text')}}
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
--------------------------------------------------------------------------------
/miniprogram/pages/entireClass/entireClass.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
35 |
38 |
39 |
40 |
41 |
46 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | 样本量
58 |
59 |
60 |
61 | 成绩
62 |
63 |
64 |
65 | 绩点
66 |
67 |
68 |
69 | 优秀率
70 |
71 |
72 |
73 | 及格率
74 |
75 |
76 |
77 |
78 | {{item}}
79 |
80 |
81 |
82 |
83 |
84 |
85 | {{item.name}}
86 | 样本量:{{item.count}}
87 |
88 |
89 |
90 |
91 | {{filter.toFix((item.A*4+item.B*3+item.C*2)/(item.count), 2)}} | {{filter.toFix(item.avg, 2)}}
92 | {{item.A}} | {{filter.toFix(item.avg, 2)}}
93 |
94 |
95 | 优 {{filter.toFix(item.A/(item.count)*100, 1)}}%
96 | 优 {{item.A}}
97 |
98 |
99 | 过 {{filter.toFix((item.A+item.B+item.C)/(item.count)*100, 1)}}%
100 | 过 {{item.F}}
101 |
102 |
103 |
104 |
105 |
106 | 课程性质:{{filter.join(item.type_full, ', ')}}
107 |
108 |
109 |
110 | 开设学院:{{filter.join(item.academy_full, '\n ')}}
111 | 课程代码:{{filter.join(item.id_full, ', ')}}
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | 请尝试其他匹配条件
127 |
128 |
129 |
130 |
131 | 显示第{{startIndex}}至{{endIndex}}项结果 共{{count}}项
132 |
133 |
134 |
135 |
136 |
137 |
142 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/miniprogram/pages/scoreList/scoreList.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{comment}}
5 |
6 |
7 |
8 | {{filter.startYear(year, term, first_semester)}}
9 | {{title}}
10 |
11 |
12 |
13 |
14 | 通过率:{{filter.toFix(passRate, 0)}}%
15 | 学分:{{passCredit}}/{{totalCredit}}
16 |
17 |
18 |
19 |
20 |
21 |
22 | GPA
23 |
24 | {{filter.toFix(termGPA, 2)}}
25 | —
26 |
27 |
28 |
29 |
30 | 加权平均分
31 |
32 | {{filter.toFix(termScore, 2)}}
33 | —
34 |
35 |
36 |
37 |
38 | 已出课程数
39 |
40 | {{termNums}}/{{termNums + ungraded}}
41 |
42 |
43 |
44 | 选课更新时间:{{course_time}}
45 | 分数更新时间:{{time}}
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 | 成绩排序
76 |
77 |
78 |
79 |
80 |
81 | {{value.type}} (共 {{value.credits}} 学分)
82 |
83 |
84 |
87 | {{item.name}}{{item.credit}} | {{item.id}} | {{item.instructor}} | {{item.comment}}
88 | 点击查看
89 | {{filter.toFix(item.gpa, 2)}} | {{item.score}}
90 | 失效需授权
91 | 授权后订阅
92 | 已订阅
93 | {{item.comment}}
94 | 无分数
95 | 点击订阅
96 | 无法订阅
97 |
98 |
99 |
100 |
101 |
102 | 点击右上角 … 进行分享后好友可看到您当前页成绩
103 |
115 |
--------------------------------------------------------------------------------
/miniprogram/pages/more/more.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | const app: IMyApp = getApp()
4 |
5 | Page({
6 | data: {
7 | logged_in: false,
8 | share_score: true,
9 | show_exam: true,
10 | show_courses: true,
11 | switches: {},
12 | messages: undefined,
13 | open_status: undefined,
14 | status_messages: undefined,
15 | adMessage: undefined,
16 | showAd: false,
17 |
18 | showActionsheet: false,
19 | groups: [],
20 | actionSheetTitle: undefined,
21 | is_no_password: false,
22 | finished: false,
23 | },
24 |
25 | onLoad: function(options) {
26 | wx.showToast({
27 | title: '加载中',
28 | icon: 'loading',
29 | duration: 6000,
30 | })
31 | wx.$request({
32 | path: 'more',
33 | actions: false,
34 | methods: 'GET',
35 | type: 'any',
36 | success: (result: any) => {
37 | this.setData({
38 | messages: result.more_messages,
39 | footer: result.footer_messages,
40 | open_status: result.open_status,
41 | status_messages: result.status_messages,
42 | finished: true,
43 | })
44 | wx.hideToast()
45 | },
46 | failed: () => {
47 | wx.navigateBack()
48 | },
49 | })
50 | if (options.logged_in) {
51 | this.setData({logged_in: true})
52 | } else {
53 | this.setData({logged_in: false})
54 | }
55 | },
56 |
57 | onShow: function() {
58 | if (
59 | app.globalData.scoreData && typeof app.globalData.scoreData.result !== 'undefined' && wx.$validateType(app.globalData.scoreData.result, 'term')
60 | ) {
61 | this.setData({
62 | share_score: app.globalData.scoreData.result.share_score,
63 | switches: app.globalData.scoreData.result.switches,
64 | is_no_password: app.globalData.scoreData.result.is_no_password,
65 | })
66 | wx.$createVideoAd(this)
67 | }
68 | this.setData({
69 | show_exam: app.globalData.show_exam,
70 | show_courses: app.globalData.show_courses,
71 | })
72 | },
73 |
74 | bindtapHandeler: function(e) {
75 | switch (e.currentTarget.dataset.from) {
76 | case 'CET':
77 | wx.navigateTo({
78 | url: '/pages/CET/CET',
79 | })
80 | break
81 |
82 | case 'exam':
83 | wx.switchTab({
84 | url: '/pages/exam/exam',
85 | })
86 | break
87 |
88 | case 'entireClass':
89 | wx.switchTab({
90 | url: '/pages/entireClass/entireClass',
91 | })
92 | break
93 |
94 | default:
95 | break
96 | }
97 | },
98 |
99 | cancel: function() {
100 | this.setData({
101 | showActionsheet: true,
102 | actionSheetTitle: '此操作会删除本地所有数据,但不会撤销授权。你将需要重新登录',
103 | groups: [
104 | { text: '确认退出登录', type: 'warn', value: 1 },
105 | ],
106 | })
107 | },
108 |
109 | demo: function() {
110 | wx.showLoading({
111 | title: '登录中',
112 | })
113 | wx.login({
114 | success: (res) => {
115 | wx.$request({
116 | actions: false,
117 | methods: 'POST',
118 | data: {
119 | 'no': this.data.status_messages.demo.id,
120 | 'pass': '',
121 | 'code': res.code,
122 | },
123 | path: 'login',
124 | success: wx.$loginSuccess,
125 | type: 'any',
126 | })
127 | },
128 | })
129 | },
130 |
131 | close: function() {
132 | this.setData({
133 | showActionsheet: false,
134 | })
135 | },
136 |
137 | btnClick: function(e) {
138 | switch (e.detail.value) {
139 | case 1:
140 | wx.$logout()
141 | break
142 | case 2:
143 | wx.showToast({
144 | title: '取消中',
145 | icon: 'loading',
146 | duration: 6000,
147 | })
148 | wx.$request({
149 | path: 'share_score',
150 | actions: false,
151 | methods: 'DELETE',
152 | type: 'any',
153 | success: (resp: null, messages) => {
154 | this.onLoad()
155 | let title = '已经取消共享'
156 | let content = '你的分数已经被删除,分数订阅已经取消'
157 | if (messages.length > 0) {
158 | title = messages[0]
159 | }
160 | if (messages.length > 1) {
161 | content = messages[1]
162 | }
163 | wx.showModal({
164 | title: title,
165 | content: content,
166 | showCancel: false,
167 | success: () => {
168 | if (
169 | typeof app.globalData.scoreData !== 'undefined' && typeof app.globalData.scoreData.result !== 'undefined' &&
170 | typeof app.globalData.scoreData.result.share_score !== 'undefined'
171 | ) {
172 | app.globalData.scoreData.result.share_score = false
173 | }
174 | wx.setStorageSync('share_score', false)
175 | this.setData({share_score: false})
176 | app.globalData.refreshCourses = true
177 | wx.pageScrollTo({
178 | scrollTop: 0,
179 | duration: 0,
180 | })
181 | wx.hideToast()
182 | },
183 | })
184 | },
185 | })
186 | break
187 | case 3:
188 | wx.showToast({
189 | title: '重置中',
190 | icon: 'loading',
191 | duration: 6000,
192 | })
193 | const success = () => {
194 | wx.showToast({
195 | title: '重置成功',
196 | icon: 'success',
197 | duration: 500,
198 | })
199 | }
200 | wx.$request({
201 | actions: false,
202 | path: 'subscribe/RESET',
203 | success,
204 | noneData: success,
205 | type: 'any',
206 | methods: 'POST',
207 | })
208 | break
209 | default:
210 | }
211 | this.close()
212 | },
213 |
214 | optIn: function() {
215 | wx.navigateTo({
216 | url: '/pages/scoreDetailPage/scoreDetailPage?id=0007929',
217 | })
218 | },
219 |
220 | optOut: function() {
221 | this.setData({
222 | showActionsheet: true,
223 | actionSheetTitle: '此操作会删除你的分数和微信绑定。毕业后教务账号会被学校回收,撤销将导致毕业后再也无法使用此程序',
224 | groups: [
225 | { text: '确认撤销授权', type: 'warn', value: 2 },
226 | ],
227 | })
228 | },
229 |
230 | resetSubscribe: function() {
231 | this.setData({
232 | showActionsheet: true,
233 | actionSheetTitle: '此操作会重置所有订阅并重新绑定微信号',
234 | groups: [
235 | { text: '确认重置订阅', type: 'warn', value: 3 },
236 | ],
237 | })
238 | },
239 | connectAccount: function() {
240 | this.btnClick({
241 | detail: {
242 | value: 3,
243 | },
244 | })
245 | },
246 | cancelNoWarning: function() {
247 | this.btnClick({
248 | detail: {
249 | value: 1,
250 | },
251 | })
252 | },
253 | ad: function() {
254 | wx.showToast({
255 | title: '加载广告中',
256 | icon: 'loading',
257 | duration: 3000,
258 | })
259 | wx.$loadVideoAd()
260 | },
261 | })
262 |
263 | export {}
264 |
--------------------------------------------------------------------------------
/typings/bjut/index.d.ts:
--------------------------------------------------------------------------------
1 | import GeneralCallbackResult = WechatMiniprogram.GeneralCallbackResult
2 | type ApiMethods = 'GET'|'POST'|'DELETE'
3 | type ApiRespTypes = 'term'|'schedule'|'exams'|'overview'|'detail'|'cets'|'any'
4 |
5 | interface IExtendedWx extends WechatMiniprogram.Wx {
6 | $formatDate(arg0: any),
7 | $base64(arg0: any),
8 | $initTab(arg0: any),
9 | $waterMark(arg0: any),
10 | $forCourses(c: ICourse[], unread: { [courseId: string]: ICourse }, minor?: boolean, all?: boolean): {unreadCount, credits, pass, ungraded, unsubscribed, passCredits, gradedCredits, nums},
11 | $request(options: {
12 | success: (resp: T, messages: string[], errors?: IApiError[]) => void,
13 | noneData?: () => void,
14 | failed?: (res?) => void,
15 | complete?: (res?) => void,
16 | actions: boolean,
17 | path: string,
18 | methods: ApiMethods,
19 | type: ApiRespTypes,
20 | data?: object,
21 | }),
22 | $validateType(arg: any, type: ApiRespTypes): boolean,
23 | $getTypeOrder(arg: string): number,
24 | $validateTypeResp(arg: IApi, type: ApiRespTypes, callbacks?: {noneData?: () => void, failed?: (res?) => void, success: (resp: T, messages: string[]) => void}): boolean,
25 | $loginSuccess(resp: any): void,
26 | $createVideoAd(arg: any): void,
27 | $loadVideoAd(): void,
28 | $logout(): void,
29 | }
30 |
31 | // tslint:disable-next-line:interface-name
32 | interface Wx extends WechatMiniprogram.Wx {
33 | [functionName: string]: any
34 | }
35 |
36 | // @ts-ignore
37 | declare const wx: IExtendedWx
38 |
39 | interface IMyApp {
40 | // @ts-ignore
41 | getCurrentPage(): wx.Page,
42 | globalData: IGlobalData
43 | }
44 |
45 | interface IGlobalData {
46 | unread?: {
47 | [courseId: string]: ICourse,
48 | },
49 | scoreData?: IApi,
50 | student_id?: string,
51 | authorization?: string,
52 | show_exam?: boolean,
53 | show_courses?: boolean,
54 | refreshCourses?: boolean,
55 | map?: {
56 | [courseId: string]: boolean,
57 | },
58 | exam_tab?: number,
59 | courses_tab?: number,
60 | background?: string,
61 | schedule: ISchedule,
62 | backgroundFetchTimestamp: number,
63 | redirect?: {
64 | year?: string,
65 | term?: string,
66 | courseId?: string,
67 | },
68 | open?: string,
69 | videoAd?: WechatMiniprogram.RewardedVideoAd,
70 | sceneId: number,
71 | url_api: string,
72 | url_logo: string,
73 | }
74 |
75 | interface IResp {
76 | /** 回调函数返回的内容 */
77 | data: T,
78 | /** 开发者服务器返回的 HTTP 状态码 */
79 | statusCode: number,
80 | /** 开发者服务器返回的 HTTP Response Header */
81 | header: object,
82 | }
83 |
84 | interface IApi {
85 | errors: IApiError[],
86 | messages: string[],
87 | result: T,
88 | success: boolean,
89 | result_info?: {
90 | count: number,
91 | page: number,
92 | per_page: number,
93 | total_count: number,
94 | },
95 | encrypted?: {
96 | iv: string,
97 | data: string,
98 | }
99 | }
100 |
101 | interface IApiError {
102 | code: number,
103 | message: string,
104 | }
105 |
106 | interface IRespWithTime {
107 | time: number,
108 | updated_time?: number
109 | }
110 |
111 | interface IRespWithList {
112 | list: T[]
113 | }
114 |
115 | interface ITerms extends IRespWithTime {
116 | ad_messages: string[], // TODO: 解释每个string的含义
117 | ad_times: number,
118 | current_year_term: string,
119 | exam_week: {
120 | [current_year_term: string]: [number, number], // [0] 为开始周,[1] 为结束周,[1] 可能大于 [0]
121 | },
122 | registration_week: {
123 | [current_year_term: string]: [number, number],
124 | },
125 | share_message: {
126 | imageUrl: string,
127 | imageUrlId: string,
128 | title: string,
129 | },
130 | switches: {
131 | cet: boolean,
132 | },
133 | share_score: boolean,
134 | has_open: boolean,
135 | is_no_password: boolean,
136 | course_time: number, // 课表更新时间
137 | subscribe_ids: string[], // 订阅成绩的模版 id 列表,至少一个
138 | first_semester?: string, // 入学时间
139 | average_GPA_minor?: number, // 辅修 GPA
140 | average_GPA_term?: number, // 在校期间总 GPA
141 | average_score_minor?: number, // 辅修加权
142 | average_score_term?: number, // 总加权
143 | term_lesson_count?: number, // 已出分的课程数
144 | term_lesson_minor?: number, // 辅修课程数
145 | sid?: string, // 学号
146 | class?: string, // 班级号
147 | institute?: string, // 学院
148 | major?: string,
149 | name?: string,
150 | terms?: {
151 | [year: string]: {
152 | [term: string]: ITerm,
153 | },
154 | },
155 | shared?: string,
156 | ad_id?: string,
157 | ad_id_banner?: string,
158 | }
159 |
160 | interface ITerm {
161 | course_time?: number,
162 | average_GPA_minor: number,
163 | average_GPA_term: number,
164 | average_score_minor: number,
165 | average_score_term: number,
166 | term_lesson_count: number,
167 | courses: (IGradedCourse|IUngradedCourse)[]
168 | }
169 |
170 | interface ICourse {
171 | academy: string,
172 | belong: string,
173 | comment: string,
174 | credit: string,
175 | gpa: string|number,
176 | id: string,
177 | makeup_score: string,
178 | minor_maker: string,
179 | name: string,
180 | retake_maker: string,
181 | retake_score: string,
182 | score: string|number,
183 | type: string,
184 | unread?: boolean,
185 | term: string,
186 | year: string,
187 | }
188 |
189 | interface IGradedCourse extends ICourse {
190 | gpa: string,
191 | score: string,
192 | }
193 |
194 | interface IUngradedCourse extends ICourse {
195 | courseSelectId: string,
196 | gpa: number,
197 | score: number,
198 | hours: string,
199 | instructor: string,
200 | room: string,
201 | selected: boolean, // 选修课
202 | textbook: boolean, // 需要教材
203 | time: string, // 上课时间
204 | }
205 |
206 | interface IFetchCallback extends GeneralCallbackResult {
207 | fetchedData: string,
208 | timeStamp: number,
209 | }
210 |
211 | interface IOverview {
212 | A: number,
213 | B: number,
214 | C: number,
215 | F: number,
216 | academy: string,
217 | academy_full: string[],
218 | avg: number,
219 | belong: string,
220 | count: number,
221 | credit: string,
222 | id: string,
223 | id_full: string[],
224 | max: number,
225 | name: string,
226 | std: number,
227 | type: string,
228 | type_full: string[],
229 | majors?: string[],
230 | is_elective?: boolean
231 | }
232 |
233 | interface IDetail extends IOverview, IRespWithTime {
234 | year_term?: {
235 | [name: string]: {
236 | score: number,
237 | gpa: number,
238 | count: number,
239 | },
240 | },
241 | instructors?: {
242 | [name: string]: {
243 | score: number,
244 | gpa: number,
245 | count: number,
246 | },
247 | },
248 | scores?: {
249 | [score: string]: number,
250 | },
251 | }
252 |
253 | interface ISchedule extends IRespWithTime, IRespWithList {
254 | term: string,
255 | week: {
256 | [year: string]: {
257 | 1: number,
258 | 2: number,
259 | },
260 | },
261 | year: string,
262 | shared?: string,
263 | major?: string,
264 | name?: string,
265 | id?: string,
266 | semesters?: string[],
267 | }
268 |
269 | interface IExam {
270 | campus: string,
271 | courseName: string,
272 | id: string,
273 | name: string,
274 | room: string,
275 | seat: string,
276 | time: string,
277 | type: string,
278 | }
279 |
280 | interface IExams extends IRespWithTime, IRespWithList {}
281 |
282 | interface ICet {
283 | comprehensive: string,
284 | date: string,
285 | id: string,
286 | listening: string,
287 | name: string,
288 | reading: string,
289 | term: string,
290 | total: string,
291 | year: string,
292 | }
293 |
294 | interface ICets extends IRespWithTime {
295 | results: ICet[],
296 | }
297 |
--------------------------------------------------------------------------------
/miniprogram/ec-canvas/ec-canvas.js:
--------------------------------------------------------------------------------
1 | import WxCanvas from './wx-canvas';
2 | import * as echarts from './echarts';
3 |
4 | let ctx;
5 |
6 | function compareVersion(v1, v2) {
7 | v1 = v1.split('.')
8 | v2 = v2.split('.')
9 | const len = Math.max(v1.length, v2.length)
10 |
11 | while (v1.length < len) {
12 | v1.push('0')
13 | }
14 | while (v2.length < len) {
15 | v2.push('0')
16 | }
17 |
18 | for (let i = 0; i < len; i++) {
19 | const num1 = parseInt(v1[i])
20 | const num2 = parseInt(v2[i])
21 |
22 | if (num1 > num2) {
23 | return 1
24 | } else if (num1 < num2) {
25 | return -1
26 | }
27 | }
28 | return 0
29 | }
30 |
31 | Component({
32 | properties: {
33 | canvasId: {
34 | type: String,
35 | value: 'ec-canvas'
36 | },
37 |
38 | ec: {
39 | type: Object
40 | },
41 |
42 | forceUseOldCanvas: {
43 | type: Boolean,
44 | value: false
45 | }
46 | },
47 |
48 | data: {
49 | isUseNewCanvas: false
50 | },
51 |
52 | ready: function () {
53 | // Disable prograssive because drawImage doesn't support DOM as parameter
54 | // See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
55 | echarts.registerPreprocessor(option => {
56 | if (option && option.series) {
57 | if (option.series.length > 0) {
58 | option.series.forEach(series => {
59 | series.progressive = 0;
60 | });
61 | }
62 | else if (typeof option.series === 'object') {
63 | option.series.progressive = 0;
64 | }
65 | }
66 | });
67 |
68 | if (!this.data.ec) {
69 | console.warn('组件需绑定 ec 变量,例:');
71 | return;
72 | }
73 |
74 | if (!this.data.ec.lazyLoad) {
75 | this.init();
76 | }
77 | },
78 |
79 | methods: {
80 | init: function (callback) {
81 | const version = wx.getSystemInfoSync().SDKVersion
82 |
83 | const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0;
84 | const forceUseOldCanvas = this.data.forceUseOldCanvas;
85 | const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
86 | this.setData({ isUseNewCanvas });
87 |
88 | if (forceUseOldCanvas && canUseNewCanvas) {
89 | console.warn('开发者强制使用旧canvas,建议关闭');
90 | }
91 |
92 | if (isUseNewCanvas) {
93 | // console.log('微信基础库版本大于2.9.0,开始使用');
94 | // 2.9.0 可以使用
95 | this.initByNewWay(callback);
96 | } else {
97 | const isValid = compareVersion(version, '1.9.91') >= 0
98 | if (!isValid) {
99 | console.error('微信基础库版本过低,需大于等于 1.9.91。'
100 | + '参见:https://github.com/ecomfe/echarts-for-weixin'
101 | + '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');
102 | return;
103 | } else {
104 | console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能');
105 | this.initByOldWay(callback);
106 | }
107 | }
108 | },
109 |
110 | initByOldWay(callback) {
111 | // 1.9.91 <= version < 2.9.0:原来的方式初始化
112 | ctx = wx.createCanvasContext(this.data.canvasId, this);
113 | const canvas = new WxCanvas(ctx, this.data.canvasId, false);
114 |
115 | echarts.setCanvasCreator(() => {
116 | return canvas;
117 | });
118 | // const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
119 | const canvasDpr = 1
120 | var query = wx.createSelectorQuery().in(this);
121 | query.select('.ec-canvas').boundingClientRect(res => {
122 | if (typeof callback === 'function') {
123 | this.chart = callback(canvas, res.width, res.height, canvasDpr);
124 | }
125 | else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
126 | this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr);
127 | }
128 | else {
129 | this.triggerEvent('init', {
130 | canvas: canvas,
131 | width: res.width,
132 | height: res.height,
133 | canvasDpr: canvasDpr // 增加了dpr,可方便外面echarts.init
134 | });
135 | }
136 | }).exec();
137 | },
138 |
139 | initByNewWay(callback) {
140 | // version >= 2.9.0:使用新的方式初始化
141 | const query = wx.createSelectorQuery().in(this)
142 | query
143 | .select('.ec-canvas')
144 | .fields({ node: true, size: true })
145 | .exec(res => {
146 | try {
147 | const canvasNode = res[0].node
148 | this.canvasNode = canvasNode
149 |
150 | const canvasDpr = wx.getSystemInfoSync().pixelRatio
151 | const canvasWidth = res[0].width
152 | const canvasHeight = res[0].height
153 |
154 | const ctx = canvasNode.getContext('2d')
155 |
156 | const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
157 | echarts.setCanvasCreator(() => {
158 | return canvas
159 | })
160 |
161 | if (typeof callback === 'function') {
162 | this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)
163 | } else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
164 | this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr)
165 | } else {
166 | this.triggerEvent('init', {
167 | canvas: canvas,
168 | width: canvasWidth,
169 | height: canvasHeight,
170 | dpr: canvasDpr
171 | })
172 | }
173 | } catch (e) {
174 | console.log(e)
175 | }
176 | })
177 | },
178 | canvasToTempFilePath(opt) {
179 | if (this.data.isUseNewCanvas) {
180 | // 新版
181 | const query = wx.createSelectorQuery().in(this)
182 | query
183 | .select('.ec-canvas')
184 | .fields({ node: true, size: true })
185 | .exec(res => {
186 | const canvasNode = res[0].node
187 | opt.canvas = canvasNode
188 | wx.canvasToTempFilePath(opt)
189 | })
190 | } else {
191 | // 旧的
192 | if (!opt.canvasId) {
193 | opt.canvasId = this.data.canvasId;
194 | }
195 | ctx.draw(true, () => {
196 | wx.canvasToTempFilePath(opt, this);
197 | });
198 | }
199 | },
200 |
201 | touchStart(e) {
202 | if (this.chart && e.touches.length > 0) {
203 | var touch = e.touches[0];
204 | var handler = this.chart.getZr().handler;
205 | handler.dispatch('mousedown', {
206 | zrX: touch.x,
207 | zrY: touch.y
208 | });
209 | handler.dispatch('mousemove', {
210 | zrX: touch.x,
211 | zrY: touch.y
212 | });
213 | handler.processGesture(wrapTouch(e), 'start');
214 | }
215 | },
216 |
217 | touchMove(e) {
218 | if (this.chart && e.touches.length > 0) {
219 | var touch = e.touches[0];
220 | var handler = this.chart.getZr().handler;
221 | handler.dispatch('mousemove', {
222 | zrX: touch.x,
223 | zrY: touch.y
224 | });
225 | handler.processGesture(wrapTouch(e), 'change');
226 | }
227 | },
228 |
229 | touchEnd(e) {
230 | if (this.chart) {
231 | const touch = e.changedTouches ? e.changedTouches[0] : {};
232 | var handler = this.chart.getZr().handler;
233 | handler.dispatch('mouseup', {
234 | zrX: touch.x,
235 | zrY: touch.y
236 | });
237 | handler.dispatch('click', {
238 | zrX: touch.x,
239 | zrY: touch.y
240 | });
241 | handler.processGesture(wrapTouch(e), 'end');
242 | }
243 | }
244 | }
245 | });
246 |
247 | function wrapTouch(event) {
248 | for (let i = 0; i < event.touches.length; ++i) {
249 | const touch = event.touches[i];
250 | touch.offsetX = touch.x;
251 | touch.offsetY = touch.y;
252 | }
253 | return event;
254 | }
255 |
--------------------------------------------------------------------------------
/miniprogram/pages/scoreDetailPage/scoreDetailPage.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | // 获取应用实例
4 | // @ts-ignore
5 | import * as echarts from '../../ec-canvas/echarts'
6 |
7 | const app: IMyApp = getApp()
8 | let chart = null
9 |
10 | // 全校成绩分布
11 | const scoreDistribute = [0, 0, 0, 0, 0, 0, 0, 0, 0,
12 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
13 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
14 |
15 | let chartNext = function() {}
16 | let init = false
17 |
18 | // 分布图初始化(先不画出来)
19 | function initChart(canvas, width, height, dpr) {
20 | try {
21 | chart = echarts.init(canvas, null, {
22 | width: width,
23 | height: height,
24 | devicePixelRatio: dpr, // new
25 | })
26 | canvas.setChart(chart)
27 | chart.setOption({})
28 | init = true
29 | chartNext()
30 | return chart
31 | } catch (e) {
32 | console.log(e)
33 | }
34 | }
35 |
36 | Page({
37 |
38 | data: {
39 | option: {},
40 |
41 | // 服务器返回信息
42 | class: null,
43 |
44 | // 课程基本信息
45 | className: '',
46 | classID: undefined,
47 | credit: undefined,
48 | classType: undefined,
49 | academy: undefined,
50 |
51 | // 你的成绩
52 | yourScore: undefined,
53 | yourGPA: undefined,
54 | predict: undefined,
55 |
56 | // 全校平均成绩
57 | averScore: null,
58 | averGPA: null,
59 | stdDev: null,
60 | GPAdistribution_ABC_Rate: null,
61 | GPAdistribution_A_Rate: null,
62 | higestScoree: null,
63 | GPAdistribution_A: null,
64 | GPAdistribution_B: null,
65 | GPAdistribution_C: null,
66 | GPAdistribution_D: null,
67 |
68 | // 更新时间与样本量
69 | count: 0,
70 |
71 | // 是否显示成绩分布直方图
72 | ifDistribution: true,
73 |
74 | ec: {
75 | onInit: initChart,
76 | },
77 | halfScreen: {
78 | show: false,
79 | title: '加载中',
80 | subtitle: undefined,
81 | desc: '',
82 | tips: '',
83 | },
84 | buttons: [{
85 | type: 'primary',
86 | text: '接受',
87 | }, {
88 | type: 'default',
89 | text: '拒绝',
90 | }],
91 | demo: false,
92 | hidePersonal: false,
93 | share_score: false,
94 | messages: [],
95 | my_time: null,
96 | time: null,
97 | timestamp: 0,
98 |
99 | ad: undefined,
100 | },
101 |
102 | redirected: false,
103 |
104 | onLoad: function(option) {
105 | if (
106 | typeof app.globalData.scoreData === 'undefined' || !app.globalData.scoreData ||
107 | !wx.$validateType(app.globalData.scoreData.result, 'term') ||
108 | !app.globalData.authorization || !app.globalData.student_id
109 | ) {
110 | wx.reLaunch({
111 | url: '/pages/login/login',
112 | })
113 | return
114 | }
115 | wx.showToast({
116 | title: '加载中',
117 | icon: 'loading',
118 | duration: 6000,
119 | })
120 | const classID = option.id
121 | if (
122 | typeof option.year !== 'undefined' && typeof option.term !== 'undefined' &&
123 | typeof app.globalData.unread[option.year + '-' + option.term + '-' + classID] !== 'undefined'
124 | ) {
125 | const classDetail = app.globalData.unread[option.year + '-' + option.term + '-' + classID]
126 | option.score = String(classDetail.score)
127 | option.gpa = String(classDetail.gpa)
128 | option.name = classDetail.name
129 | }
130 | this.setData({
131 | yourScore: option.score,
132 | yourGPA: option.gpa,
133 | classID: classID,
134 | share_score: app.globalData.scoreData.result.share_score,
135 | ad: app.globalData.scoreData.result.ad_id_banner,
136 | my_time: wx.$formatDate(app.globalData.scoreData.result.time),
137 | option,
138 | })
139 | if (typeof option.name !== 'undefined' && option.name) {
140 | this.setData({ className: option.name })
141 | }
142 | if (option.score === 'NotAScore' || option.gpa === 'NotAScore') {
143 | // 此时为全校成绩页导航至此,不显示个人成绩卡片
144 | this.setData({ hidePersonal: true })
145 | }
146 |
147 | // 通过api获取课程详情成绩信息
148 | wx.$request({
149 | path: 'overview/scores/' + classID,
150 | actions: false,
151 | methods: 'GET',
152 | type: 'detail',
153 | failed: () => {
154 | wx.navigateBack()
155 | },
156 | success: (result: IDetail, messages) => {
157 | this.setData({messages: [], time: wx.$formatDate(result.time), timestamp: result.time})
158 | if (messages.length > 2) {
159 | const data: any = {
160 | show: true,
161 | title: messages[0],
162 | desc: messages[1],
163 | tips: messages[2],
164 | }
165 | if (messages.length > 3) {
166 | data.subtitle = messages[3]
167 | } else {
168 | data.subtitle = undefined
169 | }
170 | this.initDate(result, option.score)
171 | wx.hideToast()
172 | this.setData ({
173 | halfScreen: data,
174 | demo: true,
175 | })
176 | } else {
177 | this.setData({messages: messages})
178 | this.initDate(result, option.score)
179 | wx.hideToast()
180 | }
181 | wx.$waterMark(this)
182 | },
183 | })
184 | },
185 |
186 | onShow: function() {
187 | this.setData({timestamp: this.data.timestamp, time: wx.$formatDate(this.data.timestamp), my_time: wx.$formatDate(app.globalData.scoreData.result.time)})
188 | },
189 |
190 | shareScore: function() {
191 | wx.showToast({
192 | title: '授权中',
193 | icon: 'loading',
194 | duration: 6000,
195 | })
196 | wx.$request({
197 | path: 'share_score',
198 | actions: true,
199 | methods: 'POST',
200 | type: 'any',
201 | success: () => {
202 | app.globalData.scoreData.result.share_score = true
203 | this.setData({share_score: true, halfScreen: {show: false}})
204 | wx.setStorageSync('share_score', true)
205 | wx.showModal({
206 | title: '共享分数成功',
207 | content: '请重新进入该课程详情页面',
208 | showCancel: false,
209 | success() {
210 | app.globalData.refreshCourses = true
211 | wx.navigateBack({delta: 1})
212 | },
213 | })
214 | },
215 | failed: () => {
216 | wx.navigateBack()
217 | },
218 | })
219 | },
220 |
221 | bindHalf: function(e) {
222 | switch (e.detail.index) {
223 | case 0:
224 | this.shareScore()
225 | break
226 | case 1:
227 | this.setData ({
228 | halfScreen: {show: false},
229 | })
230 | break
231 | }
232 | },
233 |
234 |
235 | initDate: function(data: IDetail, yourScore) {
236 | let predict = null
237 | if (data.scores !== null) {
238 | predict = data.count
239 | for (let i = 100; i > yourScore; i--) {
240 | predict -= data.scores[i]
241 | }
242 | predict = (predict / data.count * 100).toFixed(0) + '%'
243 | }
244 | if (this.data.className) {
245 | data.name = this.data.className
246 | }
247 | this.setData({
248 | className: data.name,
249 | credit: data.credit,
250 | classType: data.type,
251 | academy: data.academy,
252 | type_full: data.type_full,
253 | academy_full: data.academy_full,
254 | majors: data.majors,
255 | id_full: data.id_full,
256 | // 全校平均成绩
257 | averScore: data.avg,
258 | averGPA: (4.0 * data.A + 3.0 * data.B + 2.0 * data.C) / (data.A + data.B + data.C + data.F),
259 | stdDev: data.std,
260 | higestScoree: data.max,
261 | GPAdistribution_A: data.A,
262 | GPAdistribution_B: data.B,
263 | GPAdistribution_C: data.C,
264 | GPAdistribution_D: data.F,
265 | GPAdistribution_A_Rate: data.A / data.count * 100,
266 | GPAdistribution_ABC_Rate: (data.A + data.B + data.C) / data.count * 100,
267 | // 时间与样本量
268 | count: data.count,
269 | predict: predict,
270 | instructors: data.instructors,
271 | year_term: data.year_term,
272 | })
273 |
274 | if (data.scores === null) {
275 | this.setData({ifDistribution: false})
276 | return
277 | }
278 |
279 | for (let i = 60; i <= 100; i++) {
280 | scoreDistribute[i - 60] = data.scores[i]
281 | }
282 |
283 | chartNext = function() {
284 | // 画出分布图
285 | chart.setOption({
286 | color: ['#5e5e5e'],
287 |
288 | grid: {
289 | left: 10,
290 | right: 40,
291 | bottom: 20,
292 | top: 40,
293 | containLabel: true,
294 | },
295 | xAxis: [
296 | {
297 | type: 'value',
298 | name: '人数',
299 | axisLine: {
300 | lineStyle: {
301 | color: '#999',
302 | },
303 | },
304 | axisLabel: {
305 | color: '#666',
306 | },
307 |
308 | },
309 | ],
310 | yAxis: [
311 | {
312 | type: 'category',
313 | name: '成绩/分',
314 | axisTick: { show: false },
315 | data: [60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
316 | 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100],
317 | axisLine: {
318 | lineStyle: {
319 | color: '#999',
320 | },
321 | },
322 | axisLabel: {
323 | color: '#666',
324 | },
325 | },
326 | ],
327 | series: [
328 | {
329 | name: '人数',
330 | type: 'bar',
331 | label: {
332 | normal: {
333 | show: true,
334 | position: 'right',
335 | },
336 | },
337 | data: scoreDistribute,
338 | itemStyle: {
339 | // emphasis: {
340 | // color: '#37a2da'
341 | // }
342 | },
343 | },
344 | ],
345 | })
346 | }
347 |
348 | if (init) {
349 | chartNext()
350 | }
351 | },
352 | })
353 |
354 | export {}
355 |
--------------------------------------------------------------------------------
/miniprogram/pages/overAllPage/overAllPage.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 欢迎回来!
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 学号:{{sid}}
23 | 学院:{{institute}}
24 |
25 |
26 | 姓名:{{name}}
27 | 专业:{{major}}
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | {{filter.startYear(item.year, item.term, first_semester)}}
43 |
44 |
45 |
46 |
47 | 通过率:{{filter.toFix(item.detail.passRate, 0)}}%
48 | 学分:{{item.detail.passCredits}}/{{item.detail.totalCredit}}
49 |
50 |
51 |
52 |
53 |
54 |
55 | GPA
56 |
57 | {{filter.toFix(item.detail.gpa, 2)}}
58 | —
59 |
60 |
61 |
62 |
63 | 加权平均分
64 |
65 | {{filter.toFix(item.detail.score, 2)}}
66 | —
67 |
68 |
69 |
70 |
71 | 已出课程数
72 |
73 | {{item.detail.count}}/{{item.detail.count+item.ungraded}}
74 |
75 |
76 |
77 |
78 |
79 | 分数更新时间:{{time}}
80 | 选课更新时间:{{item.course_time}}
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 | 第一学位成绩
89 | 总成绩
90 |
91 |
92 |
93 |
94 | 通过率:{{filter.toFix(passRate_total, 0)}}%
95 | 学分:{{passCredit_total}}/{{totalCredit_total}}
96 |
97 |
98 |
99 |
100 |
101 |
102 | GPA
103 |
104 | {{filter.toFix(totalGPA, 2)}}
105 | —
106 |
107 |
108 |
109 |
110 | 加权平均分
111 |
112 | {{filter.toFix(totalScore, 2)}}
113 | —
114 |
115 |
116 |
117 |
118 | 已出课程数
119 |
120 | {{totalNums}}/{{totalUngraded+totalNums}}
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | 辅修/双学位成绩
129 |
130 |
131 |
132 |
133 | 通过率:{{filter.toFix(passRate_minor, 0)}}%
134 | 学分:{{passCredit_minor}}/{{totalCredit_minor}}
135 |
136 |
137 |
138 |
139 |
140 |
141 | GPA
142 |
143 | {{filter.toFix(minorGPA, 2)}}
144 | —
145 |
146 |
147 |
148 |
149 | 加权平均分
150 |
151 | {{filter.toFix(minorScore, 2)}}
152 | —
153 |
154 |
155 |
156 |
157 | 已出课程数
158 |
159 | {{minorNums}}/{{minorNums+minorUngraded}}
160 |
161 |
162 |
163 |
164 |
165 |
166 | 各学期成绩
167 |
168 |
169 |
170 |
171 |
172 | 设置/关于
173 |
174 |
175 |
176 | {{item}}
177 |
178 | 点击右上角 … 进行分享,分享此页不会分享分数
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 | 可能是教务分数接口目前不可用,请稍后再试
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 | 本小程序支持查分、查课表、查考试、出分提醒,专供北工大在校生和已毕业校友使用,点击页面底部 “前往小程序” 登录
202 |
203 |
204 |
205 |
206 |
207 |
--------------------------------------------------------------------------------
/miniprogram/pages/scoreDetailPage/scoreDetailPage.wxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 你的成绩
11 |
12 |
13 | {{yourName}}的
14 | {{className}}
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 绩点
23 |
24 | {{filter.toFix(yourGPA, 1)}}
25 |
26 |
27 |
28 |
29 | 得分
30 |
31 | {{yourScore}}
32 |
33 |
34 |
35 |
36 | 超越
37 |
38 | {{predict}}
39 |
40 |
41 |
42 |
43 |
44 |
45 | 绩点
46 |
47 | —
48 |
49 |
50 |
51 |
52 | 得分
53 |
54 | —
55 |
56 |
57 |
58 |
59 | 超越
60 |
61 | —
62 |
63 |
64 |
65 | 分数更新时间:{{my_time}}
66 | 统计更新时间:{{time}}
67 |
68 |
69 |
70 |
71 | {{item}}
72 |
73 |
74 | 年级分数情况
75 |
76 |
77 | 演示 - {{className}}
78 |
79 |
80 | 课程性质:{{filter.join(type_full, ', ')}}
81 |
82 | 开设学院:{{filter.join(academy_full, '\n ')}}
83 | 课程代码:{{filter.join(id_full, ', ')}}
84 |
85 | 开设专业:{{filter.join(majors, ', ')}}
86 |
87 |
88 |
89 |
90 |
91 | 平均绩点
92 |
93 | {{filter.toFix(averGPA, 2)}}
94 |
95 |
96 |
97 |
98 | 平均分
99 |
100 | {{filter.toFix(averScore, 2)}}
101 |
102 |
103 |
104 |
105 | 标准差
106 |
107 | {{filter.toFix(stdDev, 2)}}
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | 优秀率
116 |
117 | {{filter.toFix(GPAdistribution_A_Rate, 1)}}%
118 |
119 |
120 |
121 |
122 | 及格率
123 |
124 | {{filter.toFix(GPAdistribution_ABC_Rate, 1)}}%
125 |
126 |
127 |
128 |
129 | 最高分
130 |
131 | {{higestScoree}}
132 |
133 |
134 |
135 |
136 | 成绩分布直方图
137 |
138 |
139 |
140 |
141 |
142 |
143 | 该课程样本量太少,不予显示分布直方图
144 |
145 |
146 |
147 |
148 |
149 | A (4.0)
150 |
151 |
152 | {{GPAdistribution_A}}
153 |
154 |
155 |
156 | B (3.0)
157 |
158 |
159 | {{GPAdistribution_B}}
160 |
161 |
162 |
163 | C (2.0)
164 |
165 |
166 | {{GPAdistribution_C}}
167 |
168 |
169 |
170 | F (0.0)
171 |
172 |
173 | {{GPAdistribution_D}}
174 |
175 |
176 |
177 | 更新时间:{{time}}
178 | 样本量:{{count}}
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | 学期平均成绩
187 |
188 |
189 | {{index}} ({{item.count}})
190 | {{filter.toFix(item.gpa/item.count, 2)}} ({{filter.diff(item.gpa/item.count - averGPA)}}) | {{filter.toFix(item.score/item.count, 2)}} ({{filter.diff(item.score/item.count - averScore)}})
191 |
192 |
193 |
194 |
195 |
196 | 教师平均成绩
197 |
198 |
199 | {{index}} ({{item.count}})
200 | {{filter.toFix(item.gpa/item.count, 2)}} ({{filter.diff(item.gpa/item.count - averGPA)}}) | {{filter.toFix(item.score/item.count, 2)}} ({{filter.diff(item.score/item.count - averScore)}})
201 |
202 |
203 |
204 |
216 |
--------------------------------------------------------------------------------
/miniprogram/pages/entireClass/entireClass.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | const app: IMyApp = getApp()
4 |
5 | Page({
6 | defaultData: {
7 | // 全部课程数
8 | count: undefined,
9 | // 当前页显示的课程
10 | classes_show: [],
11 | // 当前显示页
12 | curPage: 0,
13 | // 显示起始项与显示终止项序号
14 | startIndex: undefined,
15 | endIndex: undefined,
16 | // 页面号
17 | pages: [],
18 | // 每页显示内容
19 | perpage: 10,
20 | // 课程种类
21 | types: [],
22 | curType: '全部课程类型',
23 | academys: [],
24 | major: undefined,
25 | curAcademy: '全部学院',
26 | // 搜索框输入内容
27 | searchKey: '',
28 | showClearBtn: false,
29 | messages: [],
30 | checked: false,
31 | checkedElective: false,
32 | // 当前排序方式 true为降序
33 | sortD: {
34 | 'avg': true,
35 | 'count': true,
36 | 'excellentRate': true,
37 | 'passRate': true,
38 | 'gpa': true,
39 | },
40 | ad: undefined,
41 | },
42 | data: {},
43 | // 全部课程
44 | resDate: [],
45 | classes: [],
46 | classesRaw: [],
47 | classesNew: [],
48 | searchKey: '',
49 | time: 0,
50 | onInput(evt) {
51 | this.searchKey = evt.detail.value
52 | this.setData({
53 | showClearBtn: !!this.searchKey.length,
54 | })
55 | this.search(this.searchKey)
56 | },
57 | onClearCount() {
58 | this.search('')
59 | },
60 | search: function(searchKey) {
61 | if (searchKey === '') {
62 | this.setData({
63 | searchKey: '',
64 | showClearBtn: false,
65 | })
66 | }
67 | const classes: IOverview[] = this.classesRaw
68 | // 筛选全部课程列表 更新总页数 总课程数
69 | const classesNew = []
70 | for (const i in classes) {
71 | // tslint:disable-next-line:triple-equals
72 | if ((classes[i].name.toLowerCase() + ' / ' + classes[i].id_full.join(' / ')).indexOf(searchKey.toLowerCase()) != -1) {
73 | classesNew.push(classes[i])
74 | }
75 | }
76 | const totalPageNumber = parseInt(String((classesNew.length - 1) / this.data.perpage + 1), 10)
77 | const pages = []
78 | for (let i = 1; i <= totalPageNumber; i += 1) { pages.push(i) }
79 | this.classesNew = classesNew
80 | this.setData({
81 | count: classesNew.length,
82 | pages: pages,
83 | })
84 | // 重置各数据
85 | this.changeShow(0)
86 | },
87 |
88 | // 根据页数,更改显示内容、显示起始项、显示终止项序号
89 | changeShow: function(curPage) {
90 | if (typeof this.classesNew === 'undefined' || !this.classesNew || typeof this.classesNew.slice !== 'function') {
91 | return
92 | }
93 | const classes_show: IOverview[] = this.classesNew.slice(curPage * this.data.perpage, curPage * this.data.perpage + this.data.perpage)
94 | let endIndex: number
95 | if ((curPage + 1) * this.data.perpage < this.data.count) { endIndex = (curPage + 1) * this.data.perpage } else { endIndex = this.data.count}
96 | this.setData({
97 | curPage: curPage,
98 | classes_show: classes_show,
99 | startIndex: curPage * this.data.perpage + 1,
100 | endIndex: endIndex,
101 | })
102 | wx.pageScrollTo({
103 | scrollTop: 0,
104 | duration: 0,
105 | })
106 | },
107 |
108 | bindPageChange: function(e) {
109 | const curPage = parseInt(e.detail.value, 10)
110 | this.changeShow(curPage)
111 | },
112 |
113 | bindTypeChange: function(e) {
114 | const curType = this.data.types[parseInt(e.detail.value, 10)]
115 | this.setData({curType: curType, classes_show: []}, () => {
116 | this.filter()
117 | })
118 | },
119 |
120 | bindAcademyChange: function(e) {
121 | const curAcademy = this.data.academys[parseInt(e.detail.value, 10)]
122 | this.setData({curAcademy: curAcademy, classes_show: []}, () => {
123 | this.filter()
124 | })
125 | },
126 |
127 | filter: function() {
128 | const classesNew: IOverview[] = []
129 | const {curType, curAcademy} = this.data
130 | // 筛选type与academy
131 | for (const i in this.resDate) {
132 | const curClass: IOverview = this.resDate[i]
133 | if ((curType === '全部课程类型' || curClass.type_full.indexOf(this.data.curType) !== -1) && (curAcademy === '全部学院' || curClass.academy_full.indexOf(this.data.curAcademy) !== -1)) {
134 | if (typeof this.data.major === 'undefined') {
135 | classesNew.push(curClass)
136 | } else if (this.data.major === '仅公选课' && curClass.is_elective) {
137 | classesNew.push(curClass)
138 | } else if (curClass.majors.indexOf(this.data.major) !== -1) {
139 | classesNew.push(curClass)
140 | }
141 | }
142 | }
143 |
144 | this.classesRaw = classesNew
145 | this.classes = classesNew
146 | this.setData({
147 | count: classesNew.length,
148 | })
149 | this.search('')
150 | this.changeShow(0)
151 | },
152 |
153 | setTypesAndAcademies: function(classesRaw: IOverview[]) {
154 | const typeSet: any = {}
155 | const academySet: any = {}
156 | for (const i of classesRaw) {
157 | for (const j of i.type_full) {
158 | if (typeof typeSet[j] === 'undefined') {
159 | typeSet[j] = 1
160 | } else {
161 | ++typeSet[j]
162 | }
163 | }
164 | for (const j of i.academy_full) {
165 | if (typeof academySet[j] === 'undefined') {
166 | academySet[j] = 1
167 | } else {
168 | ++academySet[j]
169 | }
170 | }
171 | }
172 |
173 | if (typeof academySet.体育教学部 !== 'undefined') {
174 | academySet.体育教学部 = Number.MAX_SAFE_INTEGER - 100
175 | }
176 |
177 | const types = []
178 | for (const i in typeSet) {
179 | if (typeSet[i] >= 10 || wx.$getTypeOrder(i) <= 100) {
180 | types.push(i)
181 | }
182 | }
183 | const academy = []
184 | for (const i in academySet) {
185 | academy.push(i)
186 | }
187 | if (!types || typeof types.sort !== 'function') {
188 | return
189 | }
190 | types.sort((a: string, b: string) => {
191 | let l = wx.$getTypeOrder(a)
192 | let r = wx.$getTypeOrder(b)
193 | if (l >= Number.MAX_SAFE_INTEGER - 100) {
194 | l -= typeSet[a]
195 | }
196 | if (r === Number.MAX_SAFE_INTEGER - 100) {
197 | r -= typeSet[b]
198 | }
199 | return l - r
200 | })
201 | if (!academy || typeof academy.sort !== 'function') {
202 | return
203 | }
204 | academy.sort((a: string, b: string) => {
205 | return academySet[b] - academySet[a]
206 | })
207 | types.unshift('全部课程类型')
208 | academy.unshift('全部学院')
209 | this.setData({types: types, academys: academy})
210 | },
211 |
212 | resp: undefined,
213 | onLoad: function() {
214 | if (
215 | typeof app.globalData.scoreData === 'undefined' || !app.globalData.scoreData ||
216 | !wx.$validateType(app.globalData.scoreData.result, 'term')
217 | ) {
218 | wx.reLaunch({
219 | url: '/pages/login/login',
220 | })
221 | return
222 | }
223 | this.defaultData.ad = app.globalData.scoreData.result.ad_id_banner
224 | this.setData(JSON.parse(JSON.stringify(this.defaultData)), () => {
225 | const success = (result: IOverview[], messages) => {
226 | this.resDate = result
227 | this.classes = result
228 | this.classesRaw = result
229 | this.classesNew = result
230 | this.setData({
231 | count: result.length,
232 | messages: messages,
233 | })
234 | if (typeof this.classes === 'undefined' || !this.classes || typeof this.classes.slice !== 'function') {
235 | return
236 | }
237 | // 默认显示第一页
238 | const classes_show: IOverview[] = this.classes.slice(this.data.curPage, this.data.curPage + this.data.perpage)
239 | let endIndex
240 | if (this.data.perpage < this.classes.length) { endIndex = this.data.perpage } else { endIndex = this.classes.length}
241 | this.setData({
242 | classes_show: classes_show,
243 | startIndex: 1,
244 | endIndex: endIndex,
245 | })
246 |
247 | // 遍历所有课程 总结课程种类信息
248 | this.setTypesAndAcademies(this.classesRaw)
249 |
250 | // 计算总页数
251 | const totalPageNumber = parseInt(String((this.classes.length - 1) / this.data.perpage + 1), 10)
252 | const pages = []
253 | for (let i = 1; i <= totalPageNumber; i += 1) { pages.push(i) }
254 | this.setData({pages: pages})
255 | wx.showToast({
256 | title: '加载成功',
257 | icon: 'success',
258 | duration: 500,
259 | })
260 | wx.$waterMark(this)
261 | }
262 | if (this.resp) {
263 | success(this.resp.resp, this.resp.messages)
264 | wx.stopPullDownRefresh()
265 | return
266 | }
267 | this.time = +new Date() / 1000
268 | // 获取全部成绩列表
269 | wx.showLoading({
270 | title: '加载中',
271 | })
272 | wx.$request({
273 | path: 'overview/scores',
274 | actions: false,
275 | methods: 'GET',
276 | type: 'overview',
277 | success: (resp, messages) => {
278 | this.resp = {
279 | resp,
280 | messages,
281 | }
282 | success(resp, messages)
283 | },
284 | failed: () => {
285 | wx.hideLoading()
286 | },
287 | complete: () => {
288 | wx.stopPullDownRefresh()
289 | },
290 | })
291 | })
292 | },
293 |
294 | pagingHandeler: function(e) {
295 | this.setData({classes_show: []}, () => {
296 | let curPage = this.data.curPage
297 | if (e.currentTarget.dataset.d === 'up') {
298 | // 上翻页
299 | if (curPage > 0) {
300 | curPage -= 1
301 | } else {
302 | // 弹窗 已到首页
303 | wx.showToast({
304 | title: '已到首页',
305 | icon: 'none',
306 | duration: 1500,
307 | })
308 | }
309 | } else {
310 | // 下翻页
311 | if (curPage < this.data.pages.length - 1) {
312 | curPage += 1
313 | } else {
314 | // 弹窗 已到末页
315 | wx.showToast({
316 | title: '已到末页',
317 | icon: 'none',
318 | duration: 1500,
319 | })
320 | }
321 | }
322 |
323 | this.changeShow(curPage)
324 |
325 | })
326 | },
327 |
328 | JumpHandeler: function(e) {
329 | const id = e.currentTarget.dataset.id
330 | wx.navigateTo({
331 | url: '../scoreDetailPage/scoreDetailPage?id=' + id + '&gpa=' + 'NotAScore' + '&score=' + 'NotAScore',
332 | })
333 | },
334 |
335 | sort: function(event) {
336 | this.setData({
337 | classes_show: [],
338 | }, () => {
339 | const classesNew: IOverview[] = this.classesNew
340 | const poperty = event.currentTarget.dataset.poperty
341 | const sortD = this.data.sortD
342 | const d = true
343 | this.setData({
344 | sortD: sortD,
345 | })
346 | if (!classesNew || typeof classesNew.sort !== 'function') {
347 | return
348 | }
349 | classesNew.sort(function(a, b) {
350 | let score0
351 | let score1
352 | switch (poperty) {
353 | case 'avg':
354 | score0 = a.avg
355 | score1 = b.avg
356 | break
357 | case 'count':
358 | score0 = a.count
359 | score1 = b.count
360 | break
361 | case 'excellentRate':
362 | score0 = a.A / a.count
363 | score1 = b.A / b.count
364 | break
365 | case 'passRate':
366 | score0 = (a.A + a.B + a.C) / a.count
367 | score1 = (b.A + b.B + b.C) / b.count
368 | break
369 | case 'gpa':
370 | score0 = (a.A * 4 + a.B * 3 + a.C * 2) / a.count
371 | score1 = (b.A * 4 + b.B * 3 + b.C * 2) / b.count
372 | break
373 | default:
374 | return 0
375 | }
376 | if (typeof score0 !== 'number' || isNaN(score0)) {
377 | score0 = -1
378 | }
379 | if (typeof score1 !== 'number' || isNaN(score1)) {
380 | score1 = -1
381 | }
382 | // 默认降序,再次点击后升序
383 | if (d) {
384 | return score1 - score0
385 | } else {
386 | return score0 - score1
387 | }
388 | })
389 | this.classes = classesNew
390 | this.changeShow(0)
391 | })
392 | },
393 |
394 | onShow: function() {
395 | if (typeof this.getTabBar === 'function' && this.getTabBar()) {
396 | wx.$initTab(this.getTabBar())
397 | this.getTabBar().setData({
398 | selected: app.globalData.courses_tab,
399 | })
400 | }
401 | if (app.globalData.refreshCourses) {
402 | this.onLoad()
403 | app.globalData.refreshCourses = false
404 | }
405 | },
406 |
407 | onPullDownRefresh: function() {
408 | if (this.time + 6 > +new Date() / 1000) {
409 | wx.stopPullDownRefresh()
410 | wx.showToast({
411 | title: '手速太快了,等一会儿再刷新试试吧',
412 | icon: 'none',
413 | duration: 3000,
414 | })
415 | return
416 | }
417 | this.onLoad()
418 | },
419 |
420 | bindMajor: function(e) {
421 | this.setData({classes_show: []}, () => {
422 | if (e.detail.value.length === 2) {
423 | if (this.data.major === '仅公选课') {
424 | e.detail.value = ['majorOnly']
425 | } else {
426 | e.detail.value = ['elective']
427 | }
428 | }
429 | if (e.detail.value[0] === 'majorOnly') {
430 | this.data.major = app.globalData.scoreData.result.major
431 | this.setData({checkedElective: false})
432 | } else if (e.detail.value[0] === 'elective') {
433 | this.data.major = '仅公选课'
434 | this.setData({checked: false})
435 | } else {
436 | this.data.major = undefined
437 | this.setData({checked: false, checkedElective: false})
438 | }
439 | this.setData({curAcademy: '全部学院', curType: '全部课程类型'})
440 | this.filter()
441 | this.setTypesAndAcademies(this.classesNew)
442 | if (this.data.major === '仅公选课') {
443 | this.setData({types: ['全部课程类型', '体育课', '通识教育选修课', '外语选修课', '通识教育任意选修', '经济管理选修课',
444 | '数学与自然科学选修课', '校选修课', '经管文法艺术类选修课', '工程自然类选修课']})
445 | }
446 | })
447 | },
448 | })
449 |
450 | export {}
451 |
--------------------------------------------------------------------------------
/miniprogram/pages/overAllPage/overAllPage.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | const app: IMyApp = getApp()
4 |
5 | Page({
6 | data: {
7 | name: null, // 姓名
8 | institute: null, // 学院
9 | sid: null, // 学号
10 | major: null, // 专业
11 | first_semester: '9999-9999-9',
12 |
13 | totalGPA: null, // 总成绩-GPA
14 | totalScore: null, // 总成绩-加权平均分
15 | totalNums: null, // 总成绩-已出课程数
16 | passRate_total: null, // 总成绩-通过率
17 | totalCredit_total: null, // 总成绩-总学分
18 | passCredit_total: null, // 总成绩-通过学分
19 | totalUnread: 0, // 总成绩-未读
20 | totalUngraded: 0, // 总成绩-未出分
21 |
22 | minorGPA: null,
23 | minorScore: null,
24 | minorNums: null,
25 | minorUngraded: null,
26 | passRate_minor: null,
27 | totalCredit_minor: null,
28 | passCredit_minor: null,
29 |
30 | term: [],
31 | termNums: 0,
32 |
33 | success: 0,
34 | fail: false,
35 | messages: [],
36 | time: null,
37 | share_score: false,
38 | has_open: false,
39 | is_no_password: false,
40 | sceneId: app.globalData.sceneId,
41 | },
42 | time: 0,
43 | request: undefined,
44 | timeoutId: undefined,
45 |
46 | onLoad: function() {
47 | if (app.globalData.sceneId === 1154) {
48 | this.setData( { success: 3 } )
49 | return
50 | } else {
51 | wx.setNavigationBarTitle({
52 | title: '成绩总览',
53 | })
54 | }
55 | if (app.globalData.sceneId === 1155) {
56 | const authorization = wx.getStorageSync('authorization3')
57 | const student_id = wx.getStorageSync('student_id')
58 | const open = wx.getStorageSync('open')
59 | if (authorization && student_id && open) {
60 | app.globalData.authorization = authorization
61 | app.globalData.student_id = student_id
62 | app.globalData.open = open
63 | } else {
64 | wx.reLaunch({
65 | url: '/pages/login/login',
66 | })
67 | return
68 | }
69 | }
70 |
71 | // 通过api获取分数信息
72 | this.setData( { success: 0 } )
73 |
74 | wx.showToast({
75 | title: '更新成绩中',
76 | icon: 'loading',
77 | duration: 6000,
78 | })
79 | if (typeof app.globalData.redirect !== 'undefined' && typeof app.globalData.redirect.term !== 'undefined' && typeof app.globalData.redirect.year !== 'undefined') {
80 | this.fetchData()
81 | } else {
82 | const score: IApi = wx.getStorageSync('score')
83 | if (score && wx.$validateType(score.result, 'term') && !score.result.is_no_password) {
84 | this.time = score.result.updated_time
85 | app.globalData.scoreData = score
86 | this.setData({messages: score.messages, time: wx.$formatDate(score.result.time), course_time: wx.$formatDate(app.globalData.scoreData.result.course_time)})
87 | this.scoreSparser(score.result)
88 | // 不是基础库 2.12.0,直接再发一次请求
89 | if (!wx.canIUse('updateWeChatApp')) {
90 | this.fetchData()
91 | } else {
92 | wx.showToast({
93 | title: '等待预拉取中',
94 | icon: 'loading',
95 | duration: 3000,
96 | })
97 | this.timeoutId = setTimeout(() => {
98 | if (typeof this.request === 'undefined') {
99 | wx.showToast({
100 | title: '重试中',
101 | icon: 'loading',
102 | duration: 6000,
103 | })
104 | this.fetchData()
105 | }
106 | }, 3000)
107 | }
108 | this.setBackgroundFetch()
109 | } else {
110 | this.fetchData()
111 | }
112 | }
113 |
114 | // @ts-ignore
115 | // TODO: Typings 错误
116 | wx.onBackgroundFetchData((res) => {
117 | console.log('onBackgroundFetchData接收到数据')
118 | this.parseFetchData(res)
119 | })
120 | },
121 |
122 | setBackgroundFetch: function() {
123 | wx.getBackgroundFetchData({
124 | fetchType: 'pre',
125 | success: this.parseFetchData,
126 | fail: () => {
127 | this.fetchData()
128 | },
129 | })
130 | },
131 |
132 | parseFetchData: function(res: IFetchCallback) {
133 | if (res && (res.errMsg === 'getBackgroundFetchData:ok' || res.errMsg === 'onBackgroundFetchData:ok')) {
134 | const {fetchedData} = res
135 | let parsedData: IApi<{score: ITerms}>
136 | if (fetchedData) {
137 | parsedData = JSON.parse(fetchedData)
138 | }
139 | if (
140 | wx.$validateTypeResp(parsedData, 'any') && typeof parsedData.result.score !== 'undefined'
141 | && parsedData.result.score && wx.$validateType(parsedData.result.score, 'term')
142 | ) {
143 | app.globalData.scoreData = {
144 | success: parsedData.success,
145 | result: parsedData.result.score,
146 | messages: parsedData.messages,
147 | errors: parsedData.errors,
148 | }
149 | this.setData({messages: parsedData.messages, time: wx.$formatDate(parsedData.result.score.time), course_time: wx.$formatDate(app.globalData.scoreData.result.course_time)})
150 | this.scoreSparser(parsedData.result.score)
151 | if (this.time < parsedData.result.score.updated_time) {
152 | // 预拉取到的是新数据
153 | this.time = parsedData.result.score.updated_time
154 | wx.setStorageSync('score', app.globalData.scoreData)
155 | wx.showToast({
156 | title: '预拉取成功',
157 | icon: 'success',
158 | duration: 500,
159 | })
160 | console.log('预拉取成功', parsedData.result.score.updated_time)
161 | if (typeof this.request !== 'undefined' && typeof this.request.abort === 'function') {
162 | this.request.abort()
163 | }
164 | this.request = {}
165 | if (typeof this.timeoutId !== 'undefined') {
166 | clearTimeout(this.timeoutId)
167 | this.timeoutId = undefined
168 | }
169 | }
170 | } else if (typeof this.request === 'undefined') {
171 | wx.showToast({
172 | title: '重试中',
173 | icon: 'loading',
174 | duration: 6000,
175 | })
176 | this.fetchData()
177 | }
178 | }
179 | },
180 |
181 | fetchData: function() {
182 | if (typeof this.request !== 'undefined') {
183 | return
184 | }
185 | this.time = +new Date() / 1000 - 5
186 | this.request = wx.$request({
187 | path: 'scores/term',
188 | actions: true,
189 | methods: 'GET',
190 | type: 'term',
191 | success: (result, messages, errors) => {
192 | if (errors && errors.length > 0) {
193 | wx.hideToast()
194 | wx.showModal({
195 | content: errors.map((elem) => {
196 | return elem.message
197 | }).join(' '),
198 | showCancel: false,
199 | })
200 | } else {
201 | wx.showToast({
202 | title: '更新成功',
203 | icon: 'success',
204 | duration: 500,
205 | })
206 | }
207 | app.globalData.scoreData = {
208 | result,
209 | messages,
210 | success: true,
211 | errors: [],
212 | }
213 | if (result.term_lesson_count > 0) {
214 | wx.setStorageSync('score', app.globalData.scoreData)
215 | this.setData({messages, time: wx.$formatDate(result.time), course_time: wx.$formatDate(app.globalData.scoreData.result.course_time)})
216 | } else {
217 | this.setData( { success: 2 } )
218 | }
219 | this.scoreSparser(result)
220 |
221 | if (typeof app.globalData.redirect !== 'undefined') {
222 | const {year, term, courseId} = app.globalData.redirect
223 | app.globalData.redirect = undefined
224 | if (typeof year !== 'undefined' && typeof term !== 'undefined' && typeof courseId !== 'undefined') {
225 | const unreadKey = year + '-' + term + '-' + courseId
226 | if (typeof app.globalData.unread[unreadKey] !== 'undefined') {
227 | app.globalData.unread[unreadKey].unread = false
228 | wx.navigateTo({
229 | url: '/pages/scoreDetailPage/scoreDetailPage?year=' + year + '&term=' + term + '&id=' + courseId +
230 | '&instructor=' + encodeURIComponent((app.globalData.unread[unreadKey] as IUngradedCourse).instructor),
231 | })
232 | }
233 | }
234 | }
235 | },
236 | noneData: () => {
237 | this.setData({success: 2})
238 | },
239 | complete: () => {
240 | if (typeof this.timeoutId !== 'undefined') {
241 | clearTimeout(this.timeoutId)
242 | this.timeoutId = undefined
243 | }
244 | wx.stopPullDownRefresh()
245 | },
246 | })
247 | },
248 |
249 | scoreSparser: function(result: ITerms) {
250 | if (typeof this.getTabBar === 'function') {
251 | wx.$initTab(this.getTabBar())
252 | }
253 | const unread: {
254 | [courseId: string]: ICourse,
255 | } = {}
256 | if (result == null) {
257 | this.setData({success: 2})
258 | return
259 | }
260 | if (typeof result.terms === 'undefined' || !result.terms) {
261 | this.setData({success: 2})
262 | return
263 | }
264 | this.setData({success: 1})
265 | // 解析得到最新学期的成绩 总成绩 通过率与总学分
266 | let lastYear = Object.keys(result.terms)[Object.keys(result.terms).length - 1]
267 | let lastTerm = Object.keys(result.terms[lastYear])[Object.keys(result.terms[lastYear]).length - 1]
268 | for (const year in result.terms) {
269 | for (const term in result.terms[year]) {
270 | if (result.terms[year][term].term_lesson_count > 0) {
271 | lastYear = year
272 | lastTerm = term
273 | }
274 | }
275 | }
276 | const t = []
277 | this.setData({
278 | name: result.name,
279 | institute: result.institute,
280 | sid: result.sid,
281 | major: result.major,
282 |
283 | totalGPA: result.average_GPA_term,
284 | totalScore: result.average_score_term,
285 | totalNums: result.term_lesson_count,
286 | share_score: result.share_score,
287 | has_open: result.has_open,
288 | is_no_password: result.is_no_password,
289 | minorGPA: result.average_GPA_minor,
290 | minorScore: result.average_score_minor,
291 | minorNums: result.term_lesson_minor,
292 | first_semester: result.first_semester,
293 | })
294 |
295 | let passCredit_total = 0
296 | let passGraded_total = 0
297 | let totalCredit_total = 0
298 | let totalUnread = 0
299 | let totalUngraded = 0
300 | let termNums = 0
301 | let minorUngraded = 0
302 | let passCredit_minor = 0
303 | let totalCredit_minor = 0
304 |
305 | for (const year in result.terms) {
306 | for (const term in result.terms[year]) {
307 | if (result.terms[year][term].term_lesson_count > 0) {
308 | ++termNums
309 | }
310 | const {unreadCount, ungraded, unsubscribed} = wx.$forCourses(result.terms[year][term].courses, unread)
311 | const {credits, passCredits, gradedCredits, ungraded: ungradedTotal} = wx.$forCourses(result.terms[year][term].courses, unread, false, false)
312 |
313 | if (
314 | year + '-' + term >= app.globalData.scoreData.result.current_year_term ||
315 | (year === lastYear && term === lastTerm) ||
316 | unreadCount > 0 || ungraded > 0
317 | ) {
318 | t.push({
319 | year,
320 | term,
321 | detail: {
322 | gpa: result.terms[year][term].average_GPA_term,
323 | score: result.terms[year][term].average_score_term,
324 | count: result.terms[year][term].term_lesson_count,
325 | passRate: passCredits / gradedCredits * 100,
326 | totalCredit: credits,
327 | passCredits,
328 | },
329 | unread: unreadCount,
330 | ungraded,
331 | unsubscribed,
332 | course_time: wx.$formatDate(result.terms[year][term].course_time),
333 | })
334 | }
335 | passCredit_total += passCredits
336 | passGraded_total += gradedCredits
337 | totalCredit_total += credits
338 | totalUnread += unreadCount
339 | totalUngraded += ungradedTotal
340 | const minor = wx.$forCourses(result.terms[year][term].courses, {}, true)
341 | passCredit_minor += minor.passCredits
342 | totalCredit_minor += minor.credits
343 | minorUngraded += minor.ungraded
344 | }
345 | }
346 | let passRate_total = 0
347 | if (result.term_lesson_count > 0) {
348 | passRate_total = passCredit_total / passGraded_total * 100
349 | }
350 |
351 | this.setData({
352 | passRate_total,
353 | totalCredit_total,
354 | passCredit_total,
355 | termNums,
356 | totalUnread,
357 | totalUngraded,
358 | term: t,
359 | passRate_minor: passCredit_minor / totalCredit_minor * 100,
360 | totalCredit_minor,
361 | passCredit_minor,
362 | minorUngraded,
363 | })
364 | app.globalData.unread = unread
365 | },
366 |
367 | bindtapHandeler: function(e) {
368 | switch (e.currentTarget.dataset.from) {
369 | case 'total':
370 | wx.navigateTo({
371 | url: '/pages/scoreList/scoreList?id=total',
372 | })
373 | break
374 | case 'minor':
375 | wx.navigateTo({
376 | url: '/pages/scoreList/scoreList?id=minor',
377 | })
378 | break
379 | case 'term':
380 | const {year, term} = e.currentTarget.dataset
381 | wx.navigateTo({
382 | url: '/pages/scoreList/scoreList?year=' + year + '&term=' + term,
383 | })
384 | break
385 | case 'history':
386 | wx.navigateTo({
387 | url: '/pages/previousScore/previousScore',
388 | })
389 | break
390 | case 'more':
391 | wx.navigateTo({
392 | url: '/pages/more/more?logged_in=1',
393 | })
394 | break
395 | case 'reload':
396 | wx.showToast({
397 | title: '刷新中',
398 | icon: 'loading',
399 | duration: 6000,
400 | })
401 | this.request = undefined
402 | this.fetchData()
403 | break
404 |
405 | default:
406 | break
407 | }
408 | },
409 |
410 | onShareAppMessage: function() {
411 | if (typeof app.globalData.scoreData !== 'undefined' && wx.$validateType(app.globalData.scoreData.result, 'term')) {
412 | return {
413 | title: app.globalData.scoreData.result.share_message.title,
414 | imageUrlId: app.globalData.scoreData.result.share_message.imageUrlId,
415 | imageUrl: app.globalData.scoreData.result.share_message.imageUrl,
416 | path: '/pages/login/login',
417 | }
418 | }
419 | return {
420 | title: '快来查分啦',
421 | path: '/pages/login/login',
422 | }
423 | },
424 |
425 | onShareTimeline: function() {
426 | if (typeof app.globalData.scoreData !== 'undefined' && wx.$validateType(app.globalData.scoreData.result, 'term')) {
427 | return {
428 | title: app.globalData.scoreData.result.share_message.title,
429 | query: '',
430 | }
431 | }
432 | return {
433 | title: '快来查分啦',
434 | query: '',
435 | }
436 | },
437 |
438 | onPullDownRefresh: function() {
439 | if (app.globalData.sceneId === 1154) {
440 | wx.showToast({title: '请点击页面底部的 “前往小程序” 登录', icon: 'none', duration: 3000})
441 | wx.stopPullDownRefresh()
442 | return
443 | }
444 | if (this.time + 10 > +new Date() / 1000) {
445 | wx.stopPullDownRefresh()
446 | wx.showToast({
447 | title: '手速太快了,等一会儿再刷新试试吧',
448 | icon: 'none',
449 | duration: 3000,
450 | })
451 | return
452 | }
453 | wx.showToast({
454 | title: '更新成绩中',
455 | icon: 'loading',
456 | duration: 6000,
457 | })
458 | this.request = undefined
459 | this.fetchData()
460 | },
461 |
462 | onShow: function() {
463 | if (typeof this.getTabBar === 'function' && this.getTabBar()) {
464 | wx.$initTab(this.getTabBar())
465 | this.getTabBar().setData({
466 | selected: 0,
467 | })
468 | }
469 |
470 | if (typeof app.globalData.scoreData !== 'undefined' && app.globalData.scoreData &&
471 | typeof app.globalData.scoreData.result !== 'undefined'
472 | && wx.$validateType(app.globalData.scoreData.result, 'term')) {
473 | this.setData({
474 | time: wx.$formatDate(app.globalData.scoreData.result.time),
475 | course_time: wx.$formatDate(app.globalData.scoreData.result.course_time),
476 | })
477 | this.scoreSparser(app.globalData.scoreData.result)
478 | }
479 |
480 | if (this.data.fail) {
481 | this.setData({success: 2})
482 | wx.showModal({
483 | title: '无法连接到服务器,请检查网络',
484 | showCancel: false,
485 | })
486 | }
487 |
488 | this.setData({fail: false})
489 | },
490 | })
491 |
492 | export {}
493 |
--------------------------------------------------------------------------------
/miniprogram/pages/index/index.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | // index.js
4 | // 获取应用实例
5 | const app: IMyApp = getApp()
6 |
7 | Page({
8 | time: 0,
9 | share_title: '快查查北工大最新的课表',
10 | theme: 'light',
11 | originalData: {
12 | // curWeek: 15,
13 | finished: true,
14 |
15 | classes: {
16 | '1,2节': ['1 2节', '', '', '', '', '', '', ''],
17 | '3,4节': ['3 4节', '', '', '', '', '', '', ''],
18 | '5,6节': ['5 6节', '', '', '', '', '', '', ''],
19 | '7,8节': ['7 8节', '', '', '', '', '', '', ''],
20 | '9,10节': ['9 10节', '', '', '', '', '', '', ''],
21 | '11,12节': ['11 12节', '', '', '', '', '', '', ''],
22 | },
23 |
24 | backgroundColor: 'transparent',
25 | optionalColorList: ['#fbcd9e', '#e4b0f5', '#9ef2e0', '#fb93ab', '#b1b1dc', '#b4cfc2', '#ead3c7', '#ffba71', '#ffccff', '#a1afc9', '#a4e2c6', '#eedeb0', '#96ce54', '#c2ccd0' ],
26 |
27 | color: {
28 | '1,2节': ['var(--weui-BG-0);', '', '', '', '', '', '', ''],
29 | '3,4节': ['var(--weui-BG-0);', '', '', '', '', '', '', ''],
30 | '5,6节': ['var(--weui-BG-0);', '', '', '', '', '', '', ''],
31 | '7,8节': ['var(--weui-BG-0);', '', '', '', '', '', '', ''],
32 | '9,10节': ['var(--weui-BG-0);', '', '', '', '', '', '', ''],
33 | '11,12节': ['var(--weui-BG-0);', '', '', '', '', '', '', ''],
34 | },
35 |
36 | marker: {
37 | '1,2节': [0, 0, 0, 0, 0, 0, 0, 0],
38 | '3,4节': [0, 0, 0, 0, 0, 0, 0, 0],
39 | '5,6节': [0, 0, 0, 0, 0, 0, 0, 0],
40 | '7,8节': [0, 0, 0, 0, 0, 0, 0, 0],
41 | '9,10节': [0, 0, 0, 0, 0, 0, 0, 0],
42 | '11,12节': [0, 0, 0, 0, 0, 0, 0, 0],
43 | },
44 |
45 | comment: '',
46 | message: '',
47 | messages: [],
48 | semester: '最新学期',
49 | semesters: ['最新学期'],
50 | sceneId: app.globalData.sceneId,
51 | },
52 |
53 | data: {
54 | noTime: [],
55 | allClasses: 0,
56 | },
57 | shared: {
58 | title: '分享错误,请重试',
59 | },
60 | isShared: false,
61 | semester: '0/0',
62 | semesters: ['最新学期'],
63 |
64 | onLoad: function(options) {
65 | if (app.globalData.sceneId !== 1154) {
66 | wx.setNavigationBarTitle({
67 | title: '我的课表',
68 | })
69 | }
70 | this.theme = wx.getSystemInfoSync().theme
71 | if ( typeof wx.onThemeChange === 'function') {
72 | wx.onThemeChange(() => {
73 | this.onShow()
74 | })
75 | }
76 | this.setData({finished: false})
77 | const score: IApi = wx.getStorageSync('score')
78 | if (score && wx.$validateType(score.result, 'term') && !score.result.is_no_password) {
79 | app.globalData.scoreData = score
80 | }
81 |
82 | if (app.globalData.sceneId === 1155) {
83 | options = {}
84 | }
85 |
86 | if (options && options.shared && options.id && options.semester) {
87 | app.globalData.authorization = options.shared
88 | app.globalData.student_id = options.id
89 | app.globalData.open = ''
90 | this.semester = options.semester
91 | if (app.globalData.sceneId === 1154) {
92 | this.originalData.comment = '点击 “前往小程序” 查看自己的课表'
93 | } else {
94 | this.originalData.comment = '下拉刷新以查看自己的课表'
95 | }
96 | this.fetch(false, true)
97 | const authorization = wx.getStorageSync('authorization3')
98 | const student_id = wx.getStorageSync('student_id')
99 | const open = wx.getStorageSync('open')
100 | if (authorization && student_id && open) {
101 | app.globalData.authorization = authorization
102 | app.globalData.student_id = student_id
103 | app.globalData.open = open
104 | } else {
105 | app.globalData.authorization = ''
106 | app.globalData.student_id = ''
107 | app.globalData.open = ''
108 | }
109 | this.semester = '0/0'
110 | } else {
111 | this.originalData.comment = ''
112 | const schedule: ISchedule = wx.getStorageSync('schedule')
113 | if (schedule && wx.$validateType(schedule, 'schedule')) {
114 | app.globalData.schedule = schedule
115 | this.time = schedule.updated_time
116 | this.initSchedule(schedule)
117 | }
118 | if (this.time + 21600 < +new Date() / 1000) {
119 | this.fetch()
120 | } else if (app.globalData.scoreData && app.globalData.scoreData.result && app.globalData.scoreData.result.share_score === true) {
121 | this.fetch(false, false)
122 | }
123 | }
124 | },
125 |
126 | fetch: function(actions: boolean = true, shared: boolean = false) {
127 | this.time = +new Date() / 1000
128 | wx.showToast({
129 | title: '更新课表中',
130 | icon: 'loading',
131 | duration: 6000,
132 | })
133 | wx.$request({
134 | path: 'courses/term/' + this.semester,
135 | actions,
136 | methods: 'GET',
137 | type: 'schedule',
138 | success: (result, messages, errors) => {
139 | this.originalData.messages = messages
140 | app.globalData.schedule = result
141 | if (result.list.length > 0) {
142 | if (actions) {
143 | wx.setStorageSync('schedule', result)
144 | }
145 | this.initSchedule(result)
146 | }
147 | if (!errors || errors.length === 0) {
148 | if (actions) {
149 | wx.showToast({
150 | title: '更新成功',
151 | icon: 'success',
152 | duration: 500,
153 | })
154 | } else {
155 | wx.hideToast()
156 | }
157 | } else {
158 | wx.showToast({
159 | title: errors.map((elem) => {
160 | return elem.message
161 | }).join(' '),
162 | icon: 'none',
163 | duration: 3000,
164 | })
165 | }
166 | },
167 | complete: () => {
168 | wx.stopPullDownRefresh()
169 | this.isShared = shared
170 | },
171 | })
172 | },
173 |
174 | initSchedule: function(res: ISchedule) {
175 | this.originalData.semester = res.year + '/' + res.term
176 |
177 | if (res.semesters) {
178 | this.semesters = res.semesters
179 | if (this.originalData.semester > res.semesters[res.semesters.length - 1]) {
180 | this.originalData.semester = '最新学期'
181 | }
182 | this.originalData.semesters = JSON.parse(JSON.stringify(res.semesters))
183 | this.originalData.semesters.unshift('最新学期')
184 | }
185 |
186 | this.setData(JSON.parse(JSON.stringify(this.originalData)))
187 | const classList = res.list
188 | const week = res.week
189 | const term = res.term
190 | const year = res.year
191 | // 初始化color列表背景颜色
192 | const color = this.data.color
193 | for (const key in color) {
194 | for (const index in color[key]) {
195 | // @ts-ignore
196 | // tslint:disable-next-line:triple-equals
197 | if (index != 0) {
198 | color[key][index] = this.data.backgroundColor
199 | }
200 | }
201 | }
202 | this.setData({color: color})
203 |
204 | const classes = this.data.classes
205 | const marker = this.data.marker
206 | const dateTable = {'周一': 1, '周二': 2, '周三': 3, '周四': 4, '周五': 5, '周六': 6, '周日': 7}
207 | // 课程解析并填入
208 | this.data.noTime = []
209 | let credits = 0
210 | for (const i in classList) {
211 | if (classList[i].type !== '第二课堂' && classList[i].belong !== '第二课堂') {
212 | credits += parseFloat(classList[i].credit)
213 | }
214 | if (classList[i].time === '') {
215 | this.data.noTime.push(classList[i])
216 | continue
217 | }
218 |
219 | const timeList = classList[i].time.split(';')
220 |
221 | // 解决‘9,10,11,12节‘这种情况
222 | // 只能解决四节连续的问题,‘7,8,9,10,11,12节‘不支持
223 | for (const j in timeList) {
224 | const time = timeList[j].slice(3).split('节')[0].split(',')
225 | if (time.length > 2) {
226 | const time0 = time.slice(0, 2)
227 | const time1 = time.slice(2)
228 | timeList[j] = timeList[j].slice(0, 3) + time0 + '节' + timeList[j].split('节')[1]
229 | timeList.push(timeList[j].slice(0, 3) + time1 + '节' + timeList[j].split('节')[1])
230 | if (classList[i].room && classList[i].room !== ' ') {
231 | classList[i].room = classList[i].room + ';' + classList[i].room
232 | }
233 | }
234 | }
235 | // console.log(timeList);
236 |
237 | for (const j in timeList) {
238 | const date = dateTable[timeList[j].slice(0, 2)]
239 | let time = timeList[j].slice(3).split('{')[0]
240 | let appendDate = ''
241 |
242 | switch (time.split(',').length) {
243 | case 1:
244 | const timeNum = parseInt(time.split('节')[0], 10)
245 | appendDate = '(仅第' + timeNum + '节)'
246 | let set
247 | if (timeNum % 2 === 1) {
248 | time = timeNum + ',' + (timeNum + 1) + '节'
249 | set = 1
250 | } else {
251 | time = timeNum - 1 + ',' + timeNum + '节'
252 | set = 2
253 | }
254 | if (typeof marker[time] !== 'undefined' && typeof marker[time][date] !== 'undefined') {
255 | marker[time][date] = set
256 | } else {
257 | continue
258 | }
259 | break
260 | case 2:
261 | break
262 | default:
263 | continue
264 | }
265 |
266 | if (typeof color === 'undefined' || typeof color[time] === 'undefined' || typeof color[time][date] === 'undefined') {
267 | console.log({color, time, date})
268 | continue
269 | }
270 | // @ts-ignore
271 | let newColor = this.data.optionalColorList[Math.abs(classList[i].instructor.hashCode()) % this.data.optionalColorList.length]
272 | if (this.theme === 'dark') {
273 | newColor = '#' + newColor.substring(1) + '80'
274 | }
275 | if (color[time][date] === 'transparent') {
276 | color[time][date] = newColor
277 | }
278 | // console.log(classList[i].name+" "+this.data.optionalColorList[i]+" "+i)
279 | const weekRange = timeList[j].split('{')[1].split('}')[0]
280 | let prev = ''
281 | if (typeof classes[time][date].text !== 'undefined') {
282 | prev = classes[time][date].text + '\n\n'
283 | } else {
284 | classes[time][date] = {}
285 | }
286 | if (classList[i].room && classList[i].room !== ' ' && classList[i].room.split(';')[j]) {
287 | classes[time][date].text = prev + classList[i].room.split(';')[j] + '\n' + classList[i].name + '-' + classList[i].instructor + '\n' + weekRange + appendDate
288 | } else {
289 | classes[time][date].text = prev + classList[i].name + '-' + classList[i].instructor + '\n' + weekRange + appendDate
290 | }
291 | const weekNoStart = weekRange.indexOf('第')
292 | const weekNoEnd = weekRange.indexOf('周')
293 | if (weekNoStart !== -1 && weekNoEnd !== -1) {
294 | const weekNo = weekRange.substr(weekNoStart + 1, weekNoStart + weekNoEnd - 1).split('-')
295 | if (weekNo.length === 2) {
296 | // @ts-ignore
297 | let currentWeek = new Date().getWeek()
298 | if (typeof week[year] !== 'undefined' && typeof week[year][term] === 'number') {
299 | currentWeek += 1 - week[year][term]
300 | if (currentWeek <= 0 || currentWeek > 24) {
301 | currentWeek = 1
302 | }
303 | const test = (currentWeek > weekNo[1] || currentWeek < weekNo[0])
304 | if (typeof classes[time][date].opacity === 'undefined' && test) {
305 | classes[time][date].opacity = 'true'
306 | } else {
307 | if (classes[time][date].opacity === 'true') { // 新 append 到最后额课程是目前在上的课程
308 | classes[time][date].text = classes[time][date].text.split('\n\n').reverse().join('\n\n')
309 | color[time][date] = newColor
310 | }
311 | if (test) {
312 | continue
313 | }
314 | if (classes[time][date].opacity !== 'false') {
315 | if (weekRange.indexOf('单周') !== -1) {
316 | if (currentWeek % 2 !== 1) {
317 | classes[time][date].opacity = 'true'
318 | } else {
319 | classes[time][date].opacity = 'false'
320 | }
321 | } else if (weekRange.indexOf('双周') !== -1) {
322 | if (currentWeek % 2 !== 0) {
323 | classes[time][date].opacity = 'true'
324 | } else {
325 | classes[time][date].opacity = 'false'
326 | }
327 | } else {
328 | classes[time][date].opacity = 'false'
329 | }
330 | }
331 | }
332 | }
333 | }
334 | }
335 | }
336 | }
337 |
338 | if (
339 | typeof res.major === 'string' && res.major && res.name && res.shared && res.id
340 | ) {
341 | this.share_title = res.name + '的' +
342 | res.year.substring(2, 4) + '-' + res.year.substring(7, 9) + '第' + res.term + '学期有' +
343 | res.list.length + '门课, 共' + credits + '学分, 快来围观'
344 | if (res.shared) {
345 | this.shared = {
346 | title: this.share_title,
347 | query: 'shared=' + res.shared + '&semester=' + res.year + '/' + res.term + '&id=' + res.id,
348 | }
349 | }
350 | if (this.data.comment) {
351 | this.data.comment = '这是' + res.major + ' – ' + res.name + '的课表\n' + this.data.comment
352 | if (app.globalData.sceneId !== 1154) {
353 | wx.setNavigationBarTitle({
354 | title: res.name + '的课表',
355 | })
356 | }
357 | } else {
358 | if (app.globalData.sceneId !== 1154) {
359 | wx.setNavigationBarTitle({
360 | title: '我的课表',
361 | })
362 | }
363 | }
364 | } else {
365 | this.share_title = '快查查' + res.year.substring(2, 4) + '-' + res.year.substring(7, 9) + '第' + res.term + '学期的课表!'
366 | }
367 |
368 | let title
369 | if (res.list.length > 0) {
370 | const {week, year, term} = res
371 | // @ts-ignore
372 | let currentWeek = new Date().getWeek()
373 | if (typeof week[year] !== 'undefined' && typeof week[year][term] === 'number') {
374 | currentWeek += 1 - week[year][term]
375 | if (this.data.noTime.length >= classList.length) {
376 | title = '您的' + res.year.substring(2, 4) + '-' + res.year.substring(7, 9) + '第' + res.term + '学期没有其他课程'
377 | } else {
378 | title = '正在显示' + res.year.substring(2, 4) + '-' + res.year.substring(7, 9) + '第' + res.term + '学期第' + (currentWeek > 0 ? currentWeek : 1) + '周课程'
379 | }
380 | if (currentWeek < 0) {
381 | title += ';距离开学还有' + (1 - currentWeek) + '周'
382 | } else if (currentWeek === 0) {
383 | title += ';下周就开学了,做好准备吧!'
384 | } else if (currentWeek > 24) {
385 | title = '正在显示' + res.year.substring(2, 4) + '-' + res.year.substring(7, 9) + '第' + res.term + '学期第1周课程'
386 | }
387 | } else {
388 | title = '正在显示' + res.year.substring(2, 4) + '-' + res.year.substring(7, 9) + '第' + res.term + '学期课程'
389 | }
390 | } else {
391 | title = res.year + '学年第' + res.term + '学期的课表为空'
392 | }
393 | this.setData({classes, color, height: marker, noTime: this.data.noTime, allClasses: classList.length, message: title, comment: this.data.comment})
394 | },
395 |
396 | onShow: function() {
397 | if (typeof this.getTabBar === 'function' && this.getTabBar()) {
398 | wx.$initTab(this.getTabBar())
399 | this.getTabBar().setData({
400 | selected: 1,
401 | })
402 | }
403 | // @ts-ignore
404 | const theme = wx.getSystemInfoSync().theme
405 | if (typeof theme === 'string' && theme !== this.theme) {
406 | this.theme = theme
407 | this.initSchedule(app.globalData.schedule)
408 | } else if (typeof app.globalData.schedule !== 'undefined') {
409 | this.initSchedule(app.globalData.schedule)
410 | }
411 | },
412 |
413 | onPullDownRefresh: function() {
414 | if (app.globalData.sceneId === 1154) {
415 | wx.showToast({title: '请点击页面底部的 “前往小程序” 查看自己的课表', icon: 'none', duration: 3000})
416 | wx.stopPullDownRefresh()
417 | return
418 | }
419 | if (!app.globalData.authorization || !app.globalData.student_id || !app.globalData.open) {
420 | wx.stopPullDownRefresh()
421 | }
422 | if (this.isShared) {
423 | this.originalData.comment = ''
424 | this.isShared = false
425 | if (app.globalData.scoreData && app.globalData.scoreData.result && typeof app.globalData.scoreData.result.share_score === 'boolean') {
426 | this.fetch(!app.globalData.scoreData.result.share_score, false)
427 | } else {
428 | this.fetch()
429 | }
430 | return
431 | } else if (this.time + 10 > +new Date() / 1000) {
432 | wx.stopPullDownRefresh()
433 | wx.showToast({
434 | title: '手速太快了,等一会儿再刷新试试吧',
435 | icon: 'none',
436 | duration: 3000,
437 | })
438 | return
439 | }
440 | this.fetch()
441 | },
442 |
443 | onShareAppMessage: function() {
444 | if (this.shared.query) {
445 | return {
446 | title: this.share_title,
447 | path: '/pages/index/index?' + this.shared.query,
448 | }
449 | } else {
450 | return {
451 | title: this.share_title,
452 | path: '/pages/login/login',
453 | }
454 | }
455 | },
456 |
457 | onShareTimeline: function() {
458 | return this.shared
459 | },
460 |
461 | bindSemesterChange: function(e) {
462 | console.log(e)
463 | const value = parseInt(e.detail.value, 10) - 1
464 | if (value < 0) {
465 | this.semester = '0/0'
466 | this.setData({semester: '最新学期'})
467 | this.fetch()
468 | } else if (this.semesters[value]) {
469 | this.semester = this.semesters[value]
470 | this.setData({semester: this.semester})
471 | if (app.globalData.scoreData && app.globalData.scoreData.result && app.globalData.scoreData.result.share_score === true) {
472 | this.fetch(false, false)
473 | } else {
474 | this.fetch()
475 | }
476 | }
477 | },
478 | })
479 |
480 | export {}
481 |
--------------------------------------------------------------------------------