Compare commits
No commits in common. "master" and "route" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
15
README.md
15
README.md
@ -1,9 +1,7 @@
|
|||||||
# 暨大排課表
|
# 暨大排課表
|
||||||
只是一個Vue練習題目,[DEMO](https://snsd0805.com/NCNU_Course/),建議用電腦開
|
只是一個Vue練習題目,[DEMO](https://snsd0805.com/NCNU_Course/),建議用電腦開
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
# 題目
|
# 題目
|
||||||
暨大生在學期前在苦惱選課的時候都會使用 @x3388638 學長開發的 [自己的課表自己排 2.0](https://github.com/x3388638/KeBiau)
|
暨大生在學期前在苦惱選課的時候都會使用 @x3388638 學長開發的 [自己的課表自己排 2.0](https://github.com/x3388638/KeBiau)
|
||||||
@ -28,22 +26,15 @@
|
|||||||
- 可選擇科系、**可篩選通識領域**
|
- 可選擇科系、**可篩選通識領域**
|
||||||
- 選課預覽
|
- 選課預覽
|
||||||
- 可安排假日課程
|
- 可安排假日課程
|
||||||
- 分享
|
|
||||||
- 產生專屬連結跟同學分享自己的課表
|
|
||||||
- 匯出jpg
|
|
||||||
- 產生課表.jpg,放成桌布、印出來,永遠不會忘記去上課
|
|
||||||
|
|
||||||
# 可能會新增的功能(非常可能不會)
|
# 可能會新增的功能(非常可能不會)
|
||||||
- [x] 儲存
|
- [x] 儲存
|
||||||
- [x] 匯出
|
- [ ] 匯出
|
||||||
- [x] 分享
|
- [ ] 分享
|
||||||
- [ ] 時間為「另訂」,額外處理
|
- [ ] 時間為「另訂」,額外處理
|
||||||
- [x] 把版排好(選課框框改成可下拉(才可以同時看到課表))
|
- [x] 把版排好(選課框框改成可下拉(才可以同時看到課表))
|
||||||
|
|
||||||
# 課程爬蟲使用說明
|
# 課程爬蟲使用說明
|
||||||
> 因為學校教務系統更新通識分類的部份很慢,因此目前的程式碼已經修改成無法對應「通識課程分類」的版本,
|
|
||||||
> 實際上線的 data 是依靠「工人智慧」,
|
|
||||||
> 如果有需要爬取資料,建議使用較舊版本的 python code
|
|
||||||
|
|
||||||
安裝所需套件
|
安裝所需套件
|
||||||
```
|
```
|
||||||
|
|||||||
8
api.py
8
api.py
@ -5,16 +5,12 @@ import sqlite3
|
|||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
CORS(app, resources={r"/.*": {"origins": ["https://course.snsd0805.com"]}})
|
CORS(app, resources={r"/.*": {"origins": ["https://snsd0805.com"]}})
|
||||||
|
|
||||||
def facebookAuth(token):
|
def facebookAuth(token):
|
||||||
url = "https://graph.facebook.com/v9.0/me?access_token={}"
|
url = "https://graph.facebook.com/v9.0/me?access_token={}"
|
||||||
|
|
||||||
try:
|
response = requests.get(url.format(token))
|
||||||
response = requests.get(url.format(token), timeout=5)
|
|
||||||
except:
|
|
||||||
return False, None, None
|
|
||||||
else:
|
|
||||||
data = json.loads(response.text)
|
data = json.loads(response.text)
|
||||||
|
|
||||||
# 若 access code 通過 facebook 驗證
|
# 若 access code 通過 facebook 驗證
|
||||||
|
|||||||
137
generalCourse.in
137
generalCourse.in
@ -1,137 +0,0 @@
|
|||||||
department 特色通識—在地實踐
|
|
||||||
994017
|
|
||||||
994057
|
|
||||||
994065
|
|
||||||
994068
|
|
||||||
994071
|
|
||||||
994075
|
|
||||||
994076
|
|
||||||
994077
|
|
||||||
994078
|
|
||||||
994080
|
|
||||||
994086
|
|
||||||
994089
|
|
||||||
994112
|
|
||||||
994113
|
|
||||||
994114
|
|
||||||
department 特色通識—綠概念
|
|
||||||
993062
|
|
||||||
994001
|
|
||||||
994012
|
|
||||||
994020
|
|
||||||
994024
|
|
||||||
994074
|
|
||||||
994027
|
|
||||||
department 特色通識—東南亞
|
|
||||||
992106
|
|
||||||
994030
|
|
||||||
994096
|
|
||||||
994098
|
|
||||||
994099
|
|
||||||
994102
|
|
||||||
994103
|
|
||||||
994105
|
|
||||||
994108
|
|
||||||
994109
|
|
||||||
994110
|
|
||||||
994111
|
|
||||||
994010
|
|
||||||
department 自然—生命與科學
|
|
||||||
993001
|
|
||||||
993002
|
|
||||||
993022
|
|
||||||
993054
|
|
||||||
993086
|
|
||||||
993093
|
|
||||||
993106
|
|
||||||
993126
|
|
||||||
993131
|
|
||||||
993132
|
|
||||||
993133
|
|
||||||
993137
|
|
||||||
993145
|
|
||||||
993008
|
|
||||||
department 自然—工程與科技
|
|
||||||
993023
|
|
||||||
993052
|
|
||||||
993055
|
|
||||||
993060
|
|
||||||
993064
|
|
||||||
993075
|
|
||||||
993116
|
|
||||||
993156
|
|
||||||
993157
|
|
||||||
993013
|
|
||||||
993066
|
|
||||||
993111
|
|
||||||
993120
|
|
||||||
993143
|
|
||||||
department 社會—社經與管理
|
|
||||||
991094
|
|
||||||
992033
|
|
||||||
992035
|
|
||||||
992110
|
|
||||||
992120
|
|
||||||
992129
|
|
||||||
992141
|
|
||||||
992143
|
|
||||||
992177
|
|
||||||
992191
|
|
||||||
992193
|
|
||||||
992203
|
|
||||||
992205
|
|
||||||
992213
|
|
||||||
992214
|
|
||||||
992216
|
|
||||||
992217
|
|
||||||
992223
|
|
||||||
992062
|
|
||||||
992211
|
|
||||||
992232
|
|
||||||
department 社會—法政與教育
|
|
||||||
984003
|
|
||||||
992076
|
|
||||||
992108
|
|
||||||
992112
|
|
||||||
992178
|
|
||||||
992179
|
|
||||||
992180
|
|
||||||
992188
|
|
||||||
992206
|
|
||||||
992234
|
|
||||||
992185
|
|
||||||
department 人文—歷史哲學與文化
|
|
||||||
991068
|
|
||||||
991075
|
|
||||||
991087
|
|
||||||
991140
|
|
||||||
991144
|
|
||||||
991154
|
|
||||||
991163
|
|
||||||
991192
|
|
||||||
991199
|
|
||||||
991212
|
|
||||||
992073
|
|
||||||
992087
|
|
||||||
992171
|
|
||||||
994044
|
|
||||||
department 人文—文學與藝術
|
|
||||||
460135
|
|
||||||
991040
|
|
||||||
991062
|
|
||||||
991065
|
|
||||||
991069
|
|
||||||
991167
|
|
||||||
991170
|
|
||||||
991183
|
|
||||||
991190
|
|
||||||
991193
|
|
||||||
991201
|
|
||||||
991203
|
|
||||||
991207
|
|
||||||
991209
|
|
||||||
991210
|
|
||||||
991211
|
|
||||||
992176
|
|
||||||
991032
|
|
||||||
991071
|
|
||||||
170
getData.py
170
getData.py
@ -4,39 +4,33 @@ import os
|
|||||||
import csv
|
import csv
|
||||||
from bs4 import BeautifulSoup as bs
|
from bs4 import BeautifulSoup as bs
|
||||||
|
|
||||||
USERNAME = ""
|
|
||||||
PASSWORD = ""
|
|
||||||
YEAR = 1111
|
|
||||||
|
|
||||||
session = requests.Session()
|
header = {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:79.0) Gecko/20100101 Firefox/79.0',
|
||||||
|
'Cookie': '輸入登入暨大教務系統後所得到的cookie'
|
||||||
|
}
|
||||||
|
|
||||||
mainURL = "https://ccweb.ncnu.edu.tw/student/"
|
mainURL = "https://ccweb.ncnu.edu.tw/student/"
|
||||||
courses = []
|
courses = []
|
||||||
generalCourse = []
|
generalCourse = []
|
||||||
|
|
||||||
def login(username, password):
|
def getGeneralCourseData(year):
|
||||||
global session
|
'''
|
||||||
response = session.get('https://ccweb.ncnu.edu.tw/student/login.php')
|
透過年份取得 通識課程分類的csv檔
|
||||||
root = bs(response.text, 'html.parser')
|
供後續課程對應。
|
||||||
loginToken = root.find('input', {'name': 'token'}).get('value')
|
|
||||||
|
|
||||||
# request login page
|
先儲存到 generalCourse list,後續再用 courseID 對應通識分類
|
||||||
response = session.post(
|
'''
|
||||||
"https://ccweb.ncnu.edu.tw/student/login.php",
|
|
||||||
data={
|
|
||||||
'token': loginToken,
|
|
||||||
'modal': '0',
|
|
||||||
'username': username,
|
|
||||||
'password': password,
|
|
||||||
'type': 'a'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
# 成功的話 return http 302, redirect
|
# 教務系統有開放 年度的query
|
||||||
if len(response.history)!=0:
|
# 但實際操作後似乎僅開放當前學年度
|
||||||
return True
|
response = requests.get(mainURL+"aspmaker_student_common_rank_courses_viewlist.php?x_studentid=0&z_studentid=LIKE&x_year={}&z_year=%3D&cmd=search&export=csv".format(year), headers=header)
|
||||||
else:
|
data = response.text
|
||||||
return False
|
|
||||||
|
courses = data.split('\r\n')[1:-1]
|
||||||
|
for course in courses:
|
||||||
|
course = course.split(',')
|
||||||
|
generalCourse.append(course)
|
||||||
|
|
||||||
def curlDepartmentCourseTable(year):
|
def curlDepartmentCourseTable(year):
|
||||||
'''
|
'''
|
||||||
@ -45,94 +39,74 @@ def curlDepartmentCourseTable(year):
|
|||||||
'''
|
'''
|
||||||
print("取得所有課程資料:")
|
print("取得所有課程資料:")
|
||||||
|
|
||||||
# 切換年度,應該是用 cookie 儲存當前閱覽的年份
|
response = requests.get(mainURL+"aspmaker_course_opened_semester_stat_viewlist.php?x_year={}&recperpage=ALL".format(year), headers=header)
|
||||||
url = 'https://ccweb6.ncnu.edu.tw/student/aspmaker_course_opened_detail_viewlist.php?cmd=search&t=aspmaker_course_opened_detail_view&z_year=%3D&x_year={}&z_courseid=%3D&x_courseid=&z_cname=LIKE&x_cname=&z_deptid=%3D&x_deptid=&z_division=LIKE&x_division=&z_grade=%3D&x_grade=&z_teachers=LIKE&x_teachers=&z_not_accessible=LIKE&x_not_accessible='
|
data = response.text
|
||||||
response = session.get(url.format(year))
|
root = bs(data, "html.parser")
|
||||||
|
|
||||||
# 取得 所有課程的 csv
|
count = 1
|
||||||
response = session.get('https://ccweb6.ncnu.edu.tw/student/aspmaker_course_opened_detail_viewlist.php?export=csv')
|
departmentsTR = root.findAll('tr')[1:] # 清除 thead
|
||||||
with open("allCourses.csv", "wb") as fp:
|
for tr in departmentsTR:
|
||||||
fp.write(response.content)
|
name = tr.findAll('td')[4].find('span').find('span').string # 取得 科系名稱
|
||||||
|
link = mainURL + tr.find('a').get('data-url').replace('amp;', '') # 清除不必要符號, 取得 連結
|
||||||
|
print("擷取{}課程... ({}/{})...".format(name, count, len(departmentsTR)))
|
||||||
|
count += 1
|
||||||
|
extractDepartmentCourseTable(name, link) # 透過連結 開始擷取 各科系課程
|
||||||
|
|
||||||
def extractDepartmentCourseTable(year):
|
def extractDepartmentCourseTable(departmentName, link):
|
||||||
'''
|
'''
|
||||||
透過各科系連結取得課程資訊
|
透過各科系連結取得課程資訊
|
||||||
若為通識類別還要跟csv檔資料做對應,取得正確通識類別
|
若為通識類別還要跟csv檔資料做對應,取得正確通識類別
|
||||||
|
|
||||||
對應後存取到 output.json
|
對應後存取到 output.json
|
||||||
'''
|
'''
|
||||||
with open("allCourses.csv") as fp:
|
response = requests.get(link, headers=header)
|
||||||
csvData = fp.read()
|
data = response.text
|
||||||
|
root = bs(data, "html.parser")
|
||||||
ans = []
|
|
||||||
courses = csvData.split('"\n')[1:-1]
|
|
||||||
for course in courses:
|
|
||||||
course = course.replace('\n', '.')
|
|
||||||
# print(course)
|
|
||||||
data = course[1:].split('","')
|
|
||||||
|
|
||||||
|
courseTR = root.findAll('tr')[1:] # 清除 thead
|
||||||
|
for tr in courseTR:
|
||||||
courseObj = {}
|
courseObj = {}
|
||||||
|
tds = tr.find_all('td')
|
||||||
|
|
||||||
baseLink = "https://ccweb6.ncnu.edu.tw/student/aspmaker_course_opened_detail_viewlist.php?cmd=search&t=aspmaker_course_opened_detail_view&z_year=%3D&x_year={}&x_courseid={}"
|
courseObj['link'] = mainURL + tds[0].find('a').get('href')
|
||||||
courseObj['link'] = baseLink.format(year, data[1].zfill(6))
|
courseObj['year'] = tds[1].find('span').string
|
||||||
courseObj['year'] = data[0]
|
courseObj['number'] = tds[2].find('span').string
|
||||||
courseObj['number'] = data[1]
|
courseObj['class'] = tds[3].find('span').string
|
||||||
courseObj['class'] = data[2]
|
courseObj['name'] = tds[4].find('span').string
|
||||||
courseObj['name'] = data[3]
|
courseObj['department'] = tds[5].find('span').string
|
||||||
courseObj['department'] = data[4]
|
courseObj['graduated'] = tds[6].find('span').string
|
||||||
courseObj['graduated'] = data[6]
|
courseObj['grade'] = tds[7].find('span').string
|
||||||
courseObj['grade'] = data[7]
|
courseObj['teacher'] = tds[8].find('span').string
|
||||||
courseObj['teacher'] = data[8]
|
courseObj['place'] = tds[9].find('span').string
|
||||||
courseObj['place'] = data[9]
|
courseObj['time'] = tds[11].find('span').string
|
||||||
courseObj['time'] = data[13].replace(' ', '')
|
|
||||||
courseObj['credit'] = data[14]
|
|
||||||
|
|
||||||
ans.append(courseObj)
|
if courseObj['department']=="99, 通識" :
|
||||||
|
flag = False
|
||||||
|
for row in generalCourse:
|
||||||
|
if row[2] == '"{}"'.format(courseObj['number']):
|
||||||
|
courseObj['department'] = row[0].replace('"', '')
|
||||||
|
generalCourse.remove(row)
|
||||||
|
flag = True
|
||||||
|
break
|
||||||
|
if not flag:
|
||||||
|
print(" - 找不到對應的通識類別: {} ( {} )".format(courseObj['name'], courseObj['number']))
|
||||||
|
|
||||||
with open("歷年課程資料/{}_output.json".format(year), 'w') as fp:
|
courses.append(courseObj)
|
||||||
json.dump(ans, fp, ensure_ascii=False)
|
|
||||||
|
|
||||||
def updateGeneralCourse():
|
|
||||||
with open("歷年課程資料/{}_output.json".format(YEAR)) as fp:
|
|
||||||
courses = json.load(fp)
|
|
||||||
|
|
||||||
with open("generalCourse.in") as fp:
|
|
||||||
line = fp.readline()
|
|
||||||
while line:
|
|
||||||
count = 0
|
|
||||||
line = line.split()
|
|
||||||
if len(line) == 2:
|
|
||||||
department = line[1]
|
|
||||||
else:
|
|
||||||
for course in courses:
|
|
||||||
if course['number'] == line[0]:
|
|
||||||
course['department'] = department
|
|
||||||
count += 1
|
|
||||||
if count == 0 and len(line) != 2:
|
|
||||||
print("{} 可能輸入錯誤 - {}".format(line[0], department))
|
|
||||||
line = fp.readline()
|
|
||||||
|
|
||||||
print("還沒有對應到的課程:")
|
|
||||||
for course in courses:
|
|
||||||
if course['department'] == "99, 通識":
|
|
||||||
course['department'] = "99, 通識(未分類)"
|
|
||||||
print("{} {}".format(course['number'], course['name']))
|
|
||||||
|
|
||||||
with open("歷年課程資料/{}_output.json".format(YEAR), "w") as fp:
|
|
||||||
json.dump(courses, fp, ensure_ascii=False)
|
|
||||||
|
|
||||||
|
with open('output.json', 'w') as fp:
|
||||||
|
json.dump(courses, fp)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
while True:
|
year = input("年份: ")
|
||||||
username = USERNAME
|
|
||||||
password = PASSWORD
|
|
||||||
if login(username, password):
|
|
||||||
print("登入成功!")
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
print("登入失敗!")
|
|
||||||
|
|
||||||
curlDepartmentCourseTable(YEAR)
|
getGeneralCourseData(year)
|
||||||
extractDepartmentCourseTable(YEAR)
|
curlDepartmentCourseTable(year)
|
||||||
updateGeneralCourse()
|
|
||||||
|
print("\n\n=====================")
|
||||||
|
print("未列入追蹤的通識課程")
|
||||||
|
print("=====================\n")
|
||||||
|
|
||||||
|
for notIn in generalCourse:
|
||||||
|
if "體育:" not in notIn[5]:
|
||||||
|
print(" - 未列入追蹤的新通識課程: {}".format(notIn))
|
||||||
@ -3,8 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
|
||||||
<meta name="description" content="你還在用紙筆或Excel在安排下學期的課表嗎?「暨大排課表」幫你篩選衝堂、科系分類、通識課程分類,讓你輕鬆排課表!" />
|
<meta name="description" content="" />
|
||||||
<meta name="author" content="snsd0805" />
|
<meta name="author" content="" />
|
||||||
<title>暨大排課表</title>
|
<title>暨大排課表</title>
|
||||||
<!-- Favicon-->
|
<!-- Favicon-->
|
||||||
<link rel="icon" type="image/x-icon" href="assets/img/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="assets/img/favicon.ico" />
|
||||||
@ -28,8 +28,6 @@
|
|||||||
<div class="container"><small>Copyright © 暨大排課表 2020</small></div>
|
<div class="container"><small>Copyright © 暨大排課表 2020</small></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- html2canvas -->
|
|
||||||
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
|
|
||||||
<!-- Bootstrap core JS-->
|
<!-- Bootstrap core JS-->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
|
||||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js"></script>
|
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|||||||
@ -19,15 +19,10 @@ var chooseDepartment = {
|
|||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
|
|
||||||
<div class="mx-auto">
|
|
||||||
<div>
|
<div>
|
||||||
<h5>1. 「課程名稱」直接搜尋</h5>
|
<h5>1. 「課程名稱」直接搜尋</h5>
|
||||||
<input class="form-control" type='text' v-model='initFounded'>
|
<input class="form-control" type='text' v-model='initFounded'>
|
||||||
</div>
|
<br>或<br><br>
|
||||||
<div class="text-center my-2">
|
|
||||||
<h5>或</h5>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h5>1. 選擇類別</h5>
|
<h5>1. 選擇類別</h5>
|
||||||
<select class="custom-select mr-sm-2" v-model="initSelect">
|
<select class="custom-select mr-sm-2" v-model="initSelect">
|
||||||
<option v-for="(item, index) in departments" :key="index"
|
<option v-for="(item, index) in departments" :key="index"
|
||||||
@ -36,7 +31,7 @@ var chooseDepartment = {
|
|||||||
{{ item }}
|
{{ item }}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`,
|
`,
|
||||||
}
|
}
|
||||||
@ -8,25 +8,35 @@ var coursesList = {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
'getTime': function(timeString){
|
'getTime': function(timeString){
|
||||||
let num;
|
if(timeString==null){
|
||||||
const timeRegex = new RegExp(/^\d[\da-z]*[a-z]$/);
|
return ""
|
||||||
return timeRegex.test(timeString)
|
|
||||||
? [...timeString].reduce((res, c) => {
|
|
||||||
if (Number.isInteger(+c)) {
|
|
||||||
num = c;
|
|
||||||
return res;
|
|
||||||
} else {
|
|
||||||
return [...res, num + c];
|
|
||||||
}
|
}
|
||||||
}, [])
|
|
||||||
: [];
|
ans = []
|
||||||
|
number = ""
|
||||||
|
for(var i of timeString){
|
||||||
|
if(i>="0" && i<="9"){
|
||||||
|
number = i
|
||||||
|
}else if(i>="a" && i<="z"){
|
||||||
|
ans.push(number+i)
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ans.push(timeString)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans
|
||||||
},
|
},
|
||||||
'isOK': function(course){
|
'isOK': function(course){
|
||||||
var time = this.getTime(course.time)
|
var time = this.getTime(course.time)
|
||||||
// console.log(course.name, " ", time)
|
// console.log(course.name, " ", time)
|
||||||
const isConflict = time.some((t) => this.selectedTime.includes(t))
|
for(t of time){
|
||||||
|
for(st of this.selectedTime){
|
||||||
return time.length && !isConflict
|
if(t==st)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
},
|
},
|
||||||
'log': function(name, data){
|
'log': function(name, data){
|
||||||
console.log(name, data)
|
console.log(name, data)
|
||||||
@ -43,12 +53,17 @@ var coursesList = {
|
|||||||
this.selectedTime = temp
|
this.selectedTime = temp
|
||||||
},
|
},
|
||||||
'find_name': function(){
|
'find_name': function(){
|
||||||
const target = this.find_name.toLowerCase();
|
var temp = []
|
||||||
this.foundedCourses = this.courses.filter((c) => c.name.toLowerCase().includes(target));
|
for(var c of this.courses){
|
||||||
|
if(c.name.indexOf(this.find_name) != -1){
|
||||||
|
temp.push(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.foundedCourses = temp
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div class="mx-auto mb-4">
|
<div>
|
||||||
<h5>2. 安排課程</h5>
|
<h5>2. 安排課程</h5>
|
||||||
<p style="color: orange" v-if="find_name"> ※ 已套用「名稱」搜尋: <br>{{find_name}}</p>
|
<p style="color: orange" v-if="find_name"> ※ 已套用「名稱」搜尋: <br>{{find_name}}</p>
|
||||||
<div style="width:275px;height:500px;overflow:auto">
|
<div style="width:275px;height:500px;overflow:auto">
|
||||||
@ -57,20 +72,22 @@ var coursesList = {
|
|||||||
<tr v-for="(course, index) in foundedCourses" :key="index"
|
<tr v-for="(course, index) in foundedCourses" :key="index"
|
||||||
v-on:mouseenter="$emit('show-temp', course)" v-on:mouseleave="$emit('delete-temp', course)">
|
v-on:mouseenter="$emit('show-temp', course)" v-on:mouseleave="$emit('delete-temp', course)">
|
||||||
<td>
|
<td>
|
||||||
<div class="container row py-2 px-0">
|
<div class="container">
|
||||||
<div class="col-12 pr-1">
|
<div class="row">
|
||||||
<b>{{ course.name }} (<a v-bind:href="course.link" target="_blank">詳</a>)</b>
|
<b>{{ course.name }} (<a v-bind:href="course.link">詳</a>)</b>
|
||||||
—— {{ (course.department.indexOf(', ')!=-1) ?(course.department.split(', ')[1]) :(course.department) }}
|
—— {{ (course.department.indexOf(', ')!=-1) ?(course.department.split(', ')[1]) :(course.department) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-8 pr-1">
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
{{ course.teacher }} ‧ {{ course.time }}
|
{{ course.teacher }} ‧ {{ course.time }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 pr-1">
|
<div class="col-sm-4">
|
||||||
<button v-if="isOK(course)" type="button" v-on:click="$emit('add-course', course)" class="btn btn-primary">
|
<button v-if="isOK(course)" type="button" v-on:click="$emit('add-course', course)" class="btn btn-primary">
|
||||||
<span>+</span>
|
<span>+</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
@ -79,19 +96,21 @@ var coursesList = {
|
|||||||
v-if="course.department == selected_d"
|
v-if="course.department == selected_d"
|
||||||
v-on:mouseenter="$emit('show-temp', course)" v-on:mouseleave="$emit('delete-temp', course)">
|
v-on:mouseenter="$emit('show-temp', course)" v-on:mouseleave="$emit('delete-temp', course)">
|
||||||
<td>
|
<td>
|
||||||
<div class="container row py-2 px-0">
|
<div class="container">
|
||||||
<div class="col-12 pr-1">
|
<div class="row">
|
||||||
<b>{{ course.name }} (<a v-bind:href="course.link" target="_blank">詳</a>)</b>
|
<b>{{ course.name }} (<a v-bind:href="course.link">詳</a>)</b>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-8 pr-1">
|
<div class="row">
|
||||||
|
<div class="col-sm-8">
|
||||||
{{ course.teacher }} ‧ {{ course.time }}
|
{{ course.teacher }} ‧ {{ course.time }}
|
||||||
</div>
|
</div>
|
||||||
<div class="col-sm-4 pr-1">
|
<div class="col-sm-4">
|
||||||
<button v-if="isOK(course)" type="button" v-on:click="$emit('add-course', course)" class="btn btn-primary">
|
<button v-if="isOK(course)" type="button" v-on:click="$emit('add-course', course)" class="btn btn-primary">
|
||||||
<span>+</span>
|
<span>+</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -7,9 +7,7 @@ var mainWindow = {
|
|||||||
'selectDepartment': '',
|
'selectDepartment': '',
|
||||||
'foundName': "",
|
'foundName': "",
|
||||||
"user": "",
|
"user": "",
|
||||||
'token': "",
|
'token': ""
|
||||||
'is_print': false,
|
|
||||||
'creditNum': 0,
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
@ -51,18 +49,6 @@ var mainWindow = {
|
|||||||
main.departments.sort()
|
main.departments.sort()
|
||||||
main.selectDepartment = main.departments[15]
|
main.selectDepartment = main.departments[15]
|
||||||
})
|
})
|
||||||
// Collapse Navbar
|
|
||||||
var navbarCollapse = function () {
|
|
||||||
if ($("#mainNav").offset().top > 100) {
|
|
||||||
$("#mainNav").addClass("navbar-shrink");
|
|
||||||
} else {
|
|
||||||
$("#mainNav").removeClass("navbar-shrink");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Collapse now if page is not at top
|
|
||||||
navbarCollapse();
|
|
||||||
// Collapse the navbar when page is scrolled
|
|
||||||
$(window).scroll(navbarCollapse);
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
'login': function(){
|
'login': function(){
|
||||||
@ -89,7 +75,7 @@ var mainWindow = {
|
|||||||
this.token = response.authResponse.accessToken
|
this.token = response.authResponse.accessToken
|
||||||
|
|
||||||
var main = this
|
var main = this
|
||||||
FB.api('/me', function (response) { main.user = response })
|
FB.api('/me', function(response){main.user = response.name})
|
||||||
|
|
||||||
fetch('https://api.snsd0805.com/courseTable?token='+this.token)
|
fetch('https://api.snsd0805.com/courseTable?token='+this.token)
|
||||||
.then(function(response){
|
.then(function(response){
|
||||||
@ -97,14 +83,6 @@ var mainWindow = {
|
|||||||
}).then(function(jsonData){
|
}).then(function(jsonData){
|
||||||
console.log(jsonData)
|
console.log(jsonData)
|
||||||
main.selectCourses = JSON.parse(jsonData['data'])
|
main.selectCourses = JSON.parse(jsonData['data'])
|
||||||
|
|
||||||
var courseSet = new Set()
|
|
||||||
for (var course of main.selectCourses) {
|
|
||||||
if (!courseSet.has(course.number+course.class)) { // 用 courseID + 班別 判斷是否重複
|
|
||||||
main.creditNum += parseFloat(course.credit)
|
|
||||||
courseSet.add(course)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.catch(function(err){
|
.catch(function(err){
|
||||||
alert("錯誤: "+err)
|
alert("錯誤: "+err)
|
||||||
@ -114,12 +92,6 @@ var mainWindow = {
|
|||||||
'saveCourseTable': function(){
|
'saveCourseTable': function(){
|
||||||
var main = this
|
var main = this
|
||||||
if(this.token!=""){
|
if(this.token!=""){
|
||||||
filteredCourses = []
|
|
||||||
for(var tempCourse of main.selectCourses){
|
|
||||||
if(tempCourse.temp == false){
|
|
||||||
filteredCourses.push(tempCourse);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fetch('https://api.snsd0805.com/courseTable',{
|
fetch('https://api.snsd0805.com/courseTable',{
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
@ -127,7 +99,7 @@ var mainWindow = {
|
|||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
'token': main.token,
|
'token': main.token,
|
||||||
'data': filteredCourses
|
'data': main.selectCourses
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.then(function(response){
|
.then(function(response){
|
||||||
@ -149,18 +121,20 @@ var mainWindow = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
'getTime': function(timeString){
|
'getTime': function(timeString){
|
||||||
let num;
|
ans = []
|
||||||
const timeRegex = new RegExp(/^\d[\da-z]*[a-z]$/);
|
number = ""
|
||||||
return timeRegex.test(timeString)
|
for(var i of timeString){
|
||||||
? [...timeString].reduce((res, c) => {
|
if(i>="0" && i<="9"){
|
||||||
if (Number.isInteger(+c)) {
|
number = i
|
||||||
num = c;
|
}else if(i>="a" && i<="z"){
|
||||||
return res;
|
ans.push(number+i)
|
||||||
} else {
|
|
||||||
return [...res, num + c];
|
|
||||||
}
|
}
|
||||||
}, [])
|
else{
|
||||||
: [];
|
ans.push(timeString)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ans
|
||||||
},
|
},
|
||||||
'select': function(department){
|
'select': function(department){
|
||||||
this.selectDepartment = department
|
this.selectDepartment = department
|
||||||
@ -174,23 +148,17 @@ var mainWindow = {
|
|||||||
this.selectCourses.push({
|
this.selectCourses.push({
|
||||||
'time': t,
|
'time': t,
|
||||||
'name': course.name,
|
'name': course.name,
|
||||||
'temp': false,
|
'temp': false
|
||||||
'number': course.number,
|
|
||||||
'class': course.class,
|
|
||||||
'credit': course.credit,
|
|
||||||
'link': course.link
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.creditNum += parseFloat(course.credit)
|
|
||||||
},
|
},
|
||||||
'removeCourse': function(course){
|
'removeCourse': function(course){
|
||||||
console.log("remove " + course.name)
|
console.log("remove "+course)
|
||||||
for(var i=this.selectCourses.length-1;i>=0;i--){
|
for(var i=this.selectCourses.length-1;i>=0;i--){
|
||||||
if (this.selectCourses[i].number === course.number && this.selectCourses[i].class === course.class) {
|
if(this.selectCourses[i].name == course){
|
||||||
this.selectCourses.splice(i, 1)
|
this.selectCourses.splice(i, 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.creditNum -= parseFloat(course.credit)
|
|
||||||
},
|
},
|
||||||
'saveTemp': function(course){
|
'saveTemp': function(course){
|
||||||
if(course==null){
|
if(course==null){
|
||||||
@ -213,31 +181,6 @@ var mainWindow = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'generatePic': function () {
|
|
||||||
var main = this
|
|
||||||
const doPrint = new Promise((resolve, reject) => {
|
|
||||||
main.is_print = true;
|
|
||||||
resolve();
|
|
||||||
});
|
|
||||||
doPrint
|
|
||||||
.then(() =>{
|
|
||||||
html2canvas(document.getElementById('course-table-div')).then(function (canvas) {
|
|
||||||
var a = document.createElement('a');
|
|
||||||
a.href = canvas.toDataURL("image/jpeg").replace("image/jpeg", "image/octet-stream");
|
|
||||||
a.download = '課表.jpg';
|
|
||||||
a.click();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
main.is_print = false;
|
|
||||||
})
|
|
||||||
},
|
|
||||||
'share': function () {
|
|
||||||
if (this.user != "")
|
|
||||||
$('#share').modal('show');
|
|
||||||
else
|
|
||||||
this.login()
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'course-table': courseTable,
|
'course-table': courseTable,
|
||||||
@ -259,7 +202,7 @@ var mainWindow = {
|
|||||||
<li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" href="https://github.com/snsd0805/NCNU_Course">Github</a></li>
|
<li class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" href="https://github.com/snsd0805/NCNU_Course">Github</a></li>
|
||||||
|
|
||||||
<li v-if="token==''" class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" href='#' v-on:click="login()">Facebook登入</a></li>
|
<li v-if="token==''" class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" href='#' v-on:click="login()">Facebook登入</a></li>
|
||||||
<li v-if="token!=''" class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" href="#" v-on:click="logout()">登出Facebook—{{user.name}}</a></li>
|
<li v-if="token!=''" class="nav-item mx-0 mx-lg-1"><a class="nav-link py-3 px-0 px-lg-3 rounded js-scroll-trigger" href="#" v-on:click="logout()">登出Facebook—{{user}}</a></li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -279,33 +222,21 @@ var mainWindow = {
|
|||||||
<div class="divider-custom-line"></div>
|
<div class="divider-custom-line"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="divider-custom">
|
<div class="divider-custom">
|
||||||
<div class="row">
|
<div v-if="token!=''"><button class="btn btn-info" @click="saveCourseTable()">儲存</button></div>
|
||||||
<div class="col-4">
|
<div v-if="token==''"><button class="btn btn-info" @click="saveCourseTable()">儲存(必須登入Facebook帳號)</button></div>
|
||||||
<div v-if="token!=''"><button class="btn btn-danger" @click="saveCourseTable()">儲存</button></div>
|
|
||||||
<div v-if="token==''"><button class="btn btn-danger" @click="saveCourseTable()">儲存(登入FB)</button></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-4">
|
|
||||||
<div><button class="btn btn-success" @click="generatePic()">下載圖檔</button></div>
|
|
||||||
</div>
|
|
||||||
<div class="col-4">
|
|
||||||
<div><button class="btn btn-primary" @click="share()">分享課表</button></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<br>
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-lg-3">
|
<div class="col-lg-3">
|
||||||
<div class="row mx-auto mb-2">
|
<div class="row">
|
||||||
<choose-department
|
<choose-department
|
||||||
v-bind:departments="departments"
|
v-bind:departments="departments"
|
||||||
v-bind:selected="selectDepartment"
|
v-bind:selected="selectDepartment"
|
||||||
v-on:selectok="select"
|
v-on:selectok="select"
|
||||||
v-on:foundedok="founded"
|
v-on:foundedok="founded"
|
||||||
>
|
>
|
||||||
</choose-department>
|
</choose-department><br>
|
||||||
</div>
|
</div><br><br>
|
||||||
<br>
|
<div class="row">
|
||||||
<div class="row mx-auto mb-2">
|
|
||||||
<course-anslist
|
<course-anslist
|
||||||
v-bind:courses="courses"
|
v-bind:courses="courses"
|
||||||
v-bind:selected_d="selectDepartment"
|
v-bind:selected_d="selectDepartment"
|
||||||
@ -316,26 +247,13 @@ var mainWindow = {
|
|||||||
v-on:delete-temp="deleteTemp"
|
v-on:delete-temp="deleteTemp"
|
||||||
>
|
>
|
||||||
</course-anslist>
|
</course-anslist>
|
||||||
|
</div><br><br>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
|
||||||
<div class="col">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
已經選了 {{ creditNum }} 學分
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<div class="col-lg-9 table-responsive " >
|
<div class="col-lg-9 table-responsive " >
|
||||||
<course-table
|
<course-table
|
||||||
id="course-table-div"
|
|
||||||
v-bind:selectCourses="selectCourses"
|
v-bind:selectCourses="selectCourses"
|
||||||
v-bind:select_c="selectCourses"
|
v-bind:select_c="selectCourses"
|
||||||
v-bind:is_print="is_print"
|
|
||||||
v-bind:is_shared="false"
|
v-bind:is_shared="false"
|
||||||
v-on:remove-course="removeCourse"
|
v-on:remove-course="removeCourse"
|
||||||
></course-table>
|
></course-table>
|
||||||
@ -356,32 +274,9 @@ var mainWindow = {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<ul>
|
已經更新為 1092 新課表<br>
|
||||||
<li>已經更新為 1101 新學期課表(包含通識課分類)</li>
|
但因學校未更新通識課資料,因此還沒有「通識課程分類」<br><br>
|
||||||
<li>有發現 Bug 可以到 <a href='https://github.com/snsd0805/NCNU_Course/issues'>GitHub</a> 發 issue 或 <a href='mailto: levi900227@gmail.com'>mail</a></li>
|
2021 01/14 更新
|
||||||
<li>請善用「連接 Facebook」功能來儲存課表!</li>
|
|
||||||
</ul>
|
|
||||||
2021 07/16 更新
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">我知道了</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal fade" id="share" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="exampleModalLabel">分享課表</h5>
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
請複製以下網址給你的朋友,跟他分享你的課表<br><br>
|
|
||||||
https://course.snsd0805.com/#/share/{{user.id}}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">我知道了</button>
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">我知道了</button>
|
||||||
|
|||||||
@ -1,14 +1,12 @@
|
|||||||
var courseDiv = {
|
var courseDiv = {
|
||||||
props: ['course', 'is_shared', 'is_print'],
|
props: ['course', 'is_shared'],
|
||||||
template: `
|
template: `
|
||||||
<div style='border: 5px #1abc9c solid; text-align: center;'>
|
<div style='border: 5px #1abc9c solid; text-align: center;'>
|
||||||
{{ course.name }}
|
{{ course.name }}
|
||||||
<a v-bind:href="course.link" target="_blank"><i class="fas fa-info-circle"></i></a>
|
|
||||||
<button type="button"
|
<button type="button"
|
||||||
v-if="!is_shared"
|
v-if="!is_shared"
|
||||||
v-on:click="$emit('remove-course', course)"
|
v-on:click="$emit('remove-course', course.name)"
|
||||||
class="btn btn-danger btn-sm"
|
class="btn btn-danger btn-sm"
|
||||||
:style="{'display': is_print ? 'none' : 'inline-block'}"
|
|
||||||
>
|
>
|
||||||
刪
|
刪
|
||||||
</button>
|
</button>
|
||||||
@ -24,7 +22,7 @@ var tempDiv = {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
var courseTable = {
|
var courseTable = {
|
||||||
props: ['select_c', 'is_shared', 'is_print'],
|
props: ['select_c', 'is_shared'],
|
||||||
data: function(){
|
data: function(){
|
||||||
return {
|
return {
|
||||||
'courses': {},
|
'courses': {},
|
||||||
@ -53,11 +51,7 @@ var courseTable = {
|
|||||||
for(var c of this.select_c){
|
for(var c of this.select_c){
|
||||||
this.courses[c.time] = {
|
this.courses[c.time] = {
|
||||||
'name': c.name,
|
'name': c.name,
|
||||||
'number': c.number,
|
'temp': c.temp
|
||||||
'class': c.class,
|
|
||||||
'temp': c.temp,
|
|
||||||
'credit': c.credit,
|
|
||||||
'link': c.link
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(c.time[0]==6 || c.time[0]==7){
|
if(c.time[0]==6 || c.time[0]==7){
|
||||||
@ -118,7 +112,6 @@ var courseTable = {
|
|||||||
v-if="exist(week+String.fromCharCode(97+((hour<5)?(hour-1):(hour-2)))) && !courses[week+String.fromCharCode(97+((hour<5)?(hour-1):(hour-2)))].temp"
|
v-if="exist(week+String.fromCharCode(97+((hour<5)?(hour-1):(hour-2)))) && !courses[week+String.fromCharCode(97+((hour<5)?(hour-1):(hour-2)))].temp"
|
||||||
v-bind:course="courses[week+String.fromCharCode(97+((hour<5)?(hour-1):(hour-2)))]"
|
v-bind:course="courses[week+String.fromCharCode(97+((hour<5)?(hour-1):(hour-2)))]"
|
||||||
v-bind:is_shared="is_shared"
|
v-bind:is_shared="is_shared"
|
||||||
v-bind:is_print="is_print"
|
|
||||||
v-on:remove-course="removeCourseHandler"
|
v-on:remove-course="removeCourseHandler"
|
||||||
></course-div>
|
></course-div>
|
||||||
<temp-div
|
<temp-div
|
||||||
|
|||||||
@ -41,7 +41,18 @@
|
|||||||
offset: 80
|
offset: 80
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Collapse Navbar
|
||||||
|
var navbarCollapse = function() {
|
||||||
|
if ($("#mainNav").offset().top > 100) {
|
||||||
|
$("#mainNav").addClass("navbar-shrink");
|
||||||
|
} else {
|
||||||
|
$("#mainNav").removeClass("navbar-shrink");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Collapse now if page is not at top
|
||||||
|
navbarCollapse();
|
||||||
|
// Collapse the navbar when page is scrolled
|
||||||
|
$(window).scroll(navbarCollapse);
|
||||||
|
|
||||||
// Floating label headings for the contact form
|
// Floating label headings for the contact form
|
||||||
$(function() {
|
$(function() {
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
[Unit]
|
|
||||||
Description=NCNU-Course Python Backend API
|
|
||||||
After=network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
ExecStart=python3 api.py
|
|
||||||
Restart=always
|
|
||||||
|
|
||||||
WorkingDirectory=/var/www/html/NCNU_Course
|
|
||||||
User=course
|
|
||||||
|
|
||||||
RestartSec=10s
|
|
||||||
|
|
||||||
StandardOutput=syslog
|
|
||||||
StandardOutput=syslog
|
|
||||||
SyslogIdentifier=ncnu-course
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user