merge: 新增分享及匯出圖片
This commit is contained in:
commit
427a56eb2e
17
api.py
17
api.py
@ -68,6 +68,23 @@ def save():
|
|||||||
else:
|
else:
|
||||||
return '{"status": "error access code"}', 403
|
return '{"status": "error access code"}', 403
|
||||||
|
|
||||||
|
@app.route('/shared/<uid>', methods=['GET'])
|
||||||
|
def shared(uid):
|
||||||
|
with sqlite3.connect('data.db') as conn:
|
||||||
|
sql = "SELECT `json` FROM `courseTables` WHERE `uid`=?"
|
||||||
|
|
||||||
|
data = conn.execute(sql, [uid]).fetchone()
|
||||||
|
|
||||||
|
if data:
|
||||||
|
ansJSON = data[0]
|
||||||
|
return json.dumps({
|
||||||
|
"status": "ok",
|
||||||
|
"data": ansJSON
|
||||||
|
}), 200
|
||||||
|
else:
|
||||||
|
return json.dumps({
|
||||||
|
"status": "not found",
|
||||||
|
}), 404
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app.debug = True
|
app.debug = True
|
||||||
app.run(host='0.0.0.0')
|
app.run(host='0.0.0.0')
|
||||||
|
|||||||
110
index.html
110
index.html
@ -18,113 +18,8 @@
|
|||||||
</head>
|
</head>
|
||||||
<body id="page-top">
|
<body id="page-top">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div id='main'>
|
<div id='main'>
|
||||||
<!-- Navigation-->
|
<router-view></router-view>
|
||||||
<nav class="navbar navbar-expand-lg bg-secondary text-uppercase fixed-top" id="mainNav">
|
|
||||||
<div class="container">
|
|
||||||
<a class="navbar-brand js-scroll-trigger" href="#page-top">暨大排課表</a>
|
|
||||||
<button class="navbar-toggler navbar-toggler-right text-uppercase font-weight-bold bg-primary text-white rounded" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
|
||||||
Menu
|
|
||||||
<i class="fas fa-bars"></i>
|
|
||||||
</button>
|
|
||||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
|
||||||
<ul class="navbar-nav ml-auto">
|
|
||||||
<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="logout()">登出Facebook—{{user.name}}</a></li>
|
|
||||||
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<br><br>
|
|
||||||
<!-- Portfolio Section-->
|
|
||||||
<section class="page-section portfolio" id="portfolio">
|
|
||||||
<div class="container" id='table'>
|
|
||||||
<!-- Portfolio Section Heading-->
|
|
||||||
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">課表</h2>
|
|
||||||
<!-- Icon Divider-->
|
|
||||||
<div class="divider-custom">
|
|
||||||
<div class="divider-custom-line"></div>
|
|
||||||
<div class="divider-custom-icon"><i class="fas fa-star"></i></div>
|
|
||||||
<div class="divider-custom-line"></div>
|
|
||||||
</div>
|
|
||||||
<div class="divider-custom">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-4">
|
|
||||||
<div v-if="token!=''"><button class="btn btn-info" @click="saveCourseTable()">儲存</button></div>
|
|
||||||
<div v-if="token==''"><button class="btn btn-info" @click="saveCourseTable()">儲存(登入Facebook)</button></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>
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-lg-3">
|
|
||||||
<div class="row">
|
|
||||||
<choose-department
|
|
||||||
v-bind:departments="departments"
|
|
||||||
v-bind:selected="selectDepartment"
|
|
||||||
v-on:selectok="select"
|
|
||||||
v-on:foundedok="founded"
|
|
||||||
>
|
|
||||||
</choose-department><br>
|
|
||||||
</div><br><br>
|
|
||||||
<div class="row">
|
|
||||||
<course-anslist
|
|
||||||
v-bind:courses="courses"
|
|
||||||
v-bind:selected_d="selectDepartment"
|
|
||||||
v-bind:selected_c="selectCourses"
|
|
||||||
v-bind:find_name="foundName"
|
|
||||||
v-on:add-course="addCourse"
|
|
||||||
v-on:show-temp="saveTemp"
|
|
||||||
v-on:delete-temp="deleteTemp"
|
|
||||||
>
|
|
||||||
</course-anslist>
|
|
||||||
</div><br><br>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-lg-9 table-responsive " >
|
|
||||||
<course-table
|
|
||||||
id='course-table-div'
|
|
||||||
v-bind:selectCourses="selectCourses"
|
|
||||||
v-bind:select_c="selectCourses"
|
|
||||||
v-on:remove-course="removeCourse"
|
|
||||||
></course-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- Portfolio Grid Items-->
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="myModal" 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">
|
|
||||||
已經更新為 1092 新課表<br>
|
|
||||||
但因學校未更新通識課資料,因此還沒有「通識課程分類」<br><br>
|
|
||||||
2021 01/14 更新
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">我知道了</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@ -144,12 +39,15 @@
|
|||||||
<script src="assets/mail/jqBootstrapValidation.js"></script>
|
<script src="assets/mail/jqBootstrapValidation.js"></script>
|
||||||
<script src="assets/mail/contact_me.js"></script>
|
<script src="assets/mail/contact_me.js"></script>
|
||||||
<!-- Core me JS-->
|
<!-- Core me JS-->
|
||||||
|
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
|
||||||
<script src="js/scripts.js"></script>
|
<script src="js/scripts.js"></script>
|
||||||
<script src='js/vue.js'></script>
|
<script src='js/vue.js'></script>
|
||||||
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
|
||||||
<script src="js/components/table.vue"></script>
|
<script src="js/components/table.vue"></script>
|
||||||
<script src="js/components/chooseDepartment.vue"></script>
|
<script src="js/components/chooseDepartment.vue"></script>
|
||||||
<script src="js/components/coursesList.vue"></script>
|
<script src="js/components/coursesList.vue"></script>
|
||||||
|
<script src="js/components/main.vue"></script>
|
||||||
|
<script src="js/components/share.vue"></script>
|
||||||
<script src="js/index.vue"></script>
|
<script src="js/index.vue"></script>
|
||||||
<script>
|
<script>
|
||||||
$(window).ready(() => {
|
$(window).ready(() => {
|
||||||
|
|||||||
311
js/components/main.vue
Normal file
311
js/components/main.vue
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
var mainWindow = {
|
||||||
|
data: function(){
|
||||||
|
return {
|
||||||
|
'courses': [],
|
||||||
|
'selectCourses': [],
|
||||||
|
'departments': [],
|
||||||
|
'selectDepartment': '',
|
||||||
|
'foundName': "",
|
||||||
|
"user": "",
|
||||||
|
'token': ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
var main = this
|
||||||
|
window.fbAsyncInit = function() {
|
||||||
|
FB.init({
|
||||||
|
appId : '',
|
||||||
|
cookie : true,
|
||||||
|
xfbml : true,
|
||||||
|
version : 'v9.0'
|
||||||
|
});
|
||||||
|
|
||||||
|
FB.AppEvents.logPageView();
|
||||||
|
main.getCourseTable()
|
||||||
|
};
|
||||||
|
|
||||||
|
(function(d, s, id){
|
||||||
|
var js, fjs = d.getElementsByTagName(s)[0];
|
||||||
|
if (d.getElementById(id)) {return;}
|
||||||
|
js = d.createElement(s); js.id = id;
|
||||||
|
js.src = "https://connect.facebook.net/en_US/sdk.js";
|
||||||
|
fjs.parentNode.insertBefore(js, fjs);
|
||||||
|
}(document, 'script', 'facebook-jssdk'));
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
var main = this
|
||||||
|
axios
|
||||||
|
.get("./output.json")
|
||||||
|
.then(response => (main.courses = response.data))
|
||||||
|
.then(function(){
|
||||||
|
for(var course of main.courses){
|
||||||
|
// console.log(course.name)
|
||||||
|
if(main.departments.indexOf(course.department)==-1){
|
||||||
|
main.departments.push(course.department)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(){
|
||||||
|
main.departments.sort()
|
||||||
|
main.selectDepartment = main.departments[15]
|
||||||
|
})
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
'login': function(){
|
||||||
|
var main = this
|
||||||
|
FB.login(function(){
|
||||||
|
main.getCourseTable()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
'logout': function(){
|
||||||
|
var main = this
|
||||||
|
FB.logout(function(response) {
|
||||||
|
main.user = ""
|
||||||
|
main.token = ""
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'getCourseTable': function(){
|
||||||
|
var main = this
|
||||||
|
FB.getLoginStatus(function(response) {
|
||||||
|
main.statusChangeCallback(response);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'statusChangeCallback': function(response){
|
||||||
|
if(response.status == "connected"){
|
||||||
|
this.token = response.authResponse.accessToken
|
||||||
|
|
||||||
|
var main = this
|
||||||
|
FB.api('/me', function(response){main.user = response.name})
|
||||||
|
|
||||||
|
fetch('https://api.snsd0805.com/courseTable?token='+this.token)
|
||||||
|
.then(function(response){
|
||||||
|
return response.json()
|
||||||
|
}).then(function(jsonData){
|
||||||
|
console.log(jsonData)
|
||||||
|
main.selectCourses = JSON.parse(jsonData['data'])
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
alert("錯誤: "+err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'saveCourseTable': function(){
|
||||||
|
var main = this
|
||||||
|
if(this.token!=""){
|
||||||
|
fetch('https://api.snsd0805.com/courseTable',{
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
'token': main.token,
|
||||||
|
'data': main.selectCourses
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(function(response){
|
||||||
|
return response.json()
|
||||||
|
})
|
||||||
|
.then(function(response){
|
||||||
|
if(response.status=="saved"){
|
||||||
|
alert("已儲存")
|
||||||
|
}else{
|
||||||
|
alert("錯誤")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
alert("錯誤: "+err)
|
||||||
|
})
|
||||||
|
|
||||||
|
}else{
|
||||||
|
this.login()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'getTime': function(timeString){
|
||||||
|
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
|
||||||
|
},
|
||||||
|
'select': function(department){
|
||||||
|
this.selectDepartment = department
|
||||||
|
},
|
||||||
|
'founded': function(courseName){
|
||||||
|
this.foundName = courseName
|
||||||
|
},
|
||||||
|
'addCourse': function(course){
|
||||||
|
var time = this.getTime(course.time)
|
||||||
|
for(var t of time){
|
||||||
|
this.selectCourses.push({
|
||||||
|
'time': t,
|
||||||
|
'name': course.name,
|
||||||
|
'temp': false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'removeCourse': function(course){
|
||||||
|
console.log("remove "+course)
|
||||||
|
for(var i=this.selectCourses.length-1;i>=0;i--){
|
||||||
|
if(this.selectCourses[i].name == course){
|
||||||
|
this.selectCourses.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'saveTemp': function(course){
|
||||||
|
if(course==null){
|
||||||
|
}else{
|
||||||
|
this.tempCourse = []
|
||||||
|
var time = this.getTime(course.time)
|
||||||
|
for(var t of time){
|
||||||
|
this.selectCourses.push({
|
||||||
|
'time': t,
|
||||||
|
'name': course.name,
|
||||||
|
'temp': true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'deleteTemp': function(course){
|
||||||
|
for(var i=this.selectCourses.length-1;i>=0;i--){
|
||||||
|
if(this.selectCourses[i].name == course.name && this.selectCourses[i].temp == true){
|
||||||
|
this.selectCourses.splice(i, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'generatePic': function(){
|
||||||
|
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();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'share': function(){
|
||||||
|
url = "https://snsd0805.com/NCNU_Course/#/share/"
|
||||||
|
if(this.user!="")
|
||||||
|
alert("請複製以下網址給你的朋友,跟他分享你的課表\n\n"+url+this.user.id)
|
||||||
|
else
|
||||||
|
this.login()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
'course-table': courseTable,
|
||||||
|
'choose-department': chooseDepartment,
|
||||||
|
'course-anslist': coursesList
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<!-- Navigation-->
|
||||||
|
<nav class="navbar navbar-expand-lg bg-secondary text-uppercase fixed-top" id="mainNav">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand js-scroll-trigger" href="#page-top">暨大排課表</a>
|
||||||
|
<button class="navbar-toggler navbar-toggler-right text-uppercase font-weight-bold bg-primary text-white rounded" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
Menu
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||||
|
<ul class="navbar-nav ml-auto">
|
||||||
|
<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="logout()">登出Facebook—{{user}}</a></li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="page-section portfolio" id="portfolio">
|
||||||
|
<div class="container" id='table'>
|
||||||
|
<!-- Portfolio Section Heading-->
|
||||||
|
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">課表</h2>
|
||||||
|
<!-- Icon Divider-->
|
||||||
|
<div class="divider-custom">
|
||||||
|
<div class="divider-custom-line"></div>
|
||||||
|
<div class="divider-custom-icon"><i class="fas fa-star"></i></div>
|
||||||
|
<div class="divider-custom-line"></div>
|
||||||
|
</div>
|
||||||
|
<div class="divider-custom">
|
||||||
|
<div v-if="token!=''"><button class="btn btn-info" @click="saveCourseTable()">儲存</button></div>
|
||||||
|
<div v-if="token==''"><button class="btn btn-info" @click="saveCourseTable()">儲存(必須登入Facebook帳號)</button></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 class="row">
|
||||||
|
<div class="col-lg-3">
|
||||||
|
<div class="row">
|
||||||
|
<choose-department
|
||||||
|
v-bind:departments="departments"
|
||||||
|
v-bind:selected="selectDepartment"
|
||||||
|
v-on:selectok="select"
|
||||||
|
v-on:foundedok="founded"
|
||||||
|
>
|
||||||
|
</choose-department><br>
|
||||||
|
</div><br><br>
|
||||||
|
<div class="row">
|
||||||
|
<course-anslist
|
||||||
|
v-bind:courses="courses"
|
||||||
|
v-bind:selected_d="selectDepartment"
|
||||||
|
v-bind:selected_c="selectCourses"
|
||||||
|
v-bind:find_name="foundName"
|
||||||
|
v-on:add-course="addCourse"
|
||||||
|
v-on:show-temp="saveTemp"
|
||||||
|
v-on:delete-temp="deleteTemp"
|
||||||
|
>
|
||||||
|
</course-anslist>
|
||||||
|
</div><br><br>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-9 table-responsive " >
|
||||||
|
<course-table
|
||||||
|
v-bind:selectCourses="selectCourses"
|
||||||
|
v-bind:select_c="selectCourses"
|
||||||
|
v-bind:is_shared="False"
|
||||||
|
v-on:remove-course="removeCourse"
|
||||||
|
></course-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Portfolio Grid Items-->
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="modal fade" id="myModal" 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">
|
||||||
|
已經更新為 1092 新課表<br>
|
||||||
|
但因學校未更新通識課資料,因此還沒有「通識課程分類」<br><br>
|
||||||
|
2021 01/14 更新
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">我知道了</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
104
js/components/share.vue
Normal file
104
js/components/share.vue
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
var share = {
|
||||||
|
data: function(){
|
||||||
|
return {
|
||||||
|
'selectCourses': [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getCourses()
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
'course-table': courseTable,
|
||||||
|
'choose-department': chooseDepartment,
|
||||||
|
'course-anslist': coursesList
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
'getCourses': function(){
|
||||||
|
uid = this.$route.params.id
|
||||||
|
|
||||||
|
var main = this
|
||||||
|
fetch('https://api.snsd0805.com/shared/'+uid)
|
||||||
|
.then(function(response){
|
||||||
|
return response.json()
|
||||||
|
}).then(function(jsonData){
|
||||||
|
main.selectCourses = JSON.parse(jsonData['data'])
|
||||||
|
})
|
||||||
|
.catch(function(err){
|
||||||
|
alert("錯誤: "+err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div>
|
||||||
|
<!-- Navigation-->
|
||||||
|
<nav class="navbar navbar-expand-lg bg-secondary text-uppercase fixed-top" id="mainNav">
|
||||||
|
<div class="container">
|
||||||
|
<a class="navbar-brand js-scroll-trigger" href="#page-top">暨大排課表</a>
|
||||||
|
<button class="navbar-toggler navbar-toggler-right text-uppercase font-weight-bold bg-primary text-white rounded" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
Menu
|
||||||
|
<i class="fas fa-bars"></i>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||||
|
<ul class="navbar-nav ml-auto">
|
||||||
|
<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>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
|
||||||
|
<section class="page-section portfolio" id="portfolio">
|
||||||
|
<div class="container" id='table'>
|
||||||
|
<!-- Portfolio Section Heading-->
|
||||||
|
<h2 class="page-section-heading text-center text-uppercase text-secondary mb-0">跟你分享我的課表</h2>
|
||||||
|
<!-- Icon Divider-->
|
||||||
|
<div class="divider-custom">
|
||||||
|
<div class="divider-custom-line"></div>
|
||||||
|
<div class="divider-custom-icon"><i class="fas fa-star"></i></div>
|
||||||
|
<div class="divider-custom-line"></div>
|
||||||
|
</div>
|
||||||
|
<div class="divider-custom">
|
||||||
|
<div>
|
||||||
|
<router-link to="/" class="btn btn-primary">安排我自己的課表</router-link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
|
||||||
|
<div class="col-lg-12 table-responsive " >
|
||||||
|
<course-table
|
||||||
|
v-bind:selectCourses="selectCourses"
|
||||||
|
v-bind:select_c="selectCourses"
|
||||||
|
v-bind:is_shared="true"
|
||||||
|
></course-table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Portfolio Grid Items-->
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="modal fade" id="myModal" 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">
|
||||||
|
已經更新為 1092 新課表<br>
|
||||||
|
但因學校未更新通識課資料,因此還沒有「通識課程分類」<br><br>
|
||||||
|
2021 01/14 更新
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="button" class="btn btn-secondary" data-dismiss="modal">我知道了</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
@ -1,9 +1,10 @@
|
|||||||
var courseDiv = {
|
var courseDiv = {
|
||||||
props: ['course'],
|
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 }}
|
||||||
<button type="button"
|
<button type="button"
|
||||||
|
v-if="!is_shared"
|
||||||
v-on:click="$emit('remove-course', course.name)"
|
v-on:click="$emit('remove-course', course.name)"
|
||||||
class="btn btn-danger btn-sm"
|
class="btn btn-danger btn-sm"
|
||||||
>
|
>
|
||||||
@ -21,7 +22,7 @@ var tempDiv = {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
var courseTable = {
|
var courseTable = {
|
||||||
props: ['select_c'],
|
props: ['select_c', 'is_shared'],
|
||||||
data: function(){
|
data: function(){
|
||||||
return {
|
return {
|
||||||
'courses': {},
|
'courses': {},
|
||||||
@ -95,6 +96,7 @@ var courseTable = {
|
|||||||
<course-div
|
<course-div
|
||||||
v-if="exist(week+'z')"
|
v-if="exist(week+'z')"
|
||||||
v-bind:course="courses[week+'z']"
|
v-bind:course="courses[week+'z']"
|
||||||
|
v-bind:is_shared="is_shared"
|
||||||
v-on:remove-course="removeCourseHandler"
|
v-on:remove-course="removeCourseHandler"
|
||||||
></course-div>
|
></course-div>
|
||||||
|
|
||||||
@ -109,6 +111,7 @@ var courseTable = {
|
|||||||
<course-div
|
<course-div
|
||||||
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-on:remove-course="removeCourseHandler"
|
v-on:remove-course="removeCourseHandler"
|
||||||
></course-div>
|
></course-div>
|
||||||
<temp-div
|
<temp-div
|
||||||
|
|||||||
241
js/index.vue
241
js/index.vue
@ -1,233 +1,12 @@
|
|||||||
var vm = new Vue({
|
Vue.use(VueRouter)
|
||||||
el: "#main",
|
const router = new VueRouter({
|
||||||
data: {
|
routes: [
|
||||||
'courses': [],
|
{ path: '/', component: mainWindow },
|
||||||
'selectCourses': [],
|
{ path: '/share/:id', component: share }
|
||||||
'departments': [],
|
]
|
||||||
'selectDepartment': '',
|
|
||||||
'foundName': "",
|
|
||||||
"user": "",
|
|
||||||
'token': ""
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
window.fbAsyncInit = function() {
|
|
||||||
FB.init({
|
|
||||||
appId : '',
|
|
||||||
cookie : true,
|
|
||||||
xfbml : true,
|
|
||||||
version : 'v9.0'
|
|
||||||
});
|
|
||||||
|
|
||||||
FB.AppEvents.logPageView();
|
|
||||||
vm.getCourseTable()
|
|
||||||
};
|
|
||||||
|
|
||||||
(function(d, s, id){
|
|
||||||
var js, fjs = d.getElementsByTagName(s)[0];
|
|
||||||
if (d.getElementById(id)) {return;}
|
|
||||||
js = d.createElement(s); js.id = id;
|
|
||||||
js.src = "https://connect.facebook.net/en_US/sdk.js";
|
|
||||||
fjs.parentNode.insertBefore(js, fjs);
|
|
||||||
}(document, 'script', 'facebook-jssdk'));
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
axios
|
|
||||||
.get("./output.json")
|
|
||||||
.then(response => (vm.courses = response.data))
|
|
||||||
.then(function(){
|
|
||||||
for(var course of vm.courses){
|
|
||||||
// console.log(course.name)
|
|
||||||
if(vm.departments.indexOf(course.department)==-1){
|
|
||||||
vm.departments.push(course.department)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(function(){
|
|
||||||
vm.departments.sort()
|
|
||||||
vm.selectDepartment = vm.departments[15]
|
|
||||||
})
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
'login': function(){
|
|
||||||
FB.login(function(){
|
|
||||||
vm.getCourseTable()
|
|
||||||
})
|
|
||||||
},
|
|
||||||
'logout': function(){
|
|
||||||
FB.logout(function(response) {
|
|
||||||
vm.user = ""
|
|
||||||
vm.token = ""
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'getCourseTable': function(){
|
|
||||||
FB.getLoginStatus(function(response) {
|
|
||||||
vm.statusChangeCallback(response);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'statusChangeCallback': function(response){
|
|
||||||
if(response.status == "connected"){
|
|
||||||
this.token = response.authResponse.accessToken
|
|
||||||
|
|
||||||
FB.api('/me', function(response){vm.user = response})
|
|
||||||
|
|
||||||
fetch('https://api.snsd0805.com/courseTable?token='+this.token)
|
|
||||||
.then(function(response){
|
|
||||||
return response.json()
|
|
||||||
}).then(function(jsonData){
|
|
||||||
console.log(jsonData)
|
|
||||||
vm.selectCourses = JSON.parse(jsonData['data'])
|
|
||||||
})
|
|
||||||
.catch(function(err){
|
|
||||||
alert("錯誤: "+err)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'saveCourseTable': function(){
|
|
||||||
if(this.token!=""){
|
|
||||||
fetch('https://api.snsd0805.com/courseTable',{
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({
|
|
||||||
'token': vm.token,
|
|
||||||
'data': vm.selectCourses
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(function(response){
|
|
||||||
return response.json()
|
|
||||||
})
|
|
||||||
.then(function(response){
|
|
||||||
if(response.status=="saved"){
|
|
||||||
alert("已儲存")
|
|
||||||
}else{
|
|
||||||
alert("錯誤")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(function(err){
|
|
||||||
alert("錯誤: "+err)
|
|
||||||
})
|
|
||||||
|
|
||||||
}else{
|
|
||||||
this.login()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'getTime': function(timeString){
|
|
||||||
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
|
|
||||||
},
|
|
||||||
'select': function(department){
|
|
||||||
this.selectDepartment = department
|
|
||||||
},
|
|
||||||
'founded': function(courseName){
|
|
||||||
this.foundName = courseName
|
|
||||||
},
|
|
||||||
'addCourse': function(course){
|
|
||||||
var time = this.getTime(course.time)
|
|
||||||
for(var t of time){
|
|
||||||
this.selectCourses.push({
|
|
||||||
'time': t,
|
|
||||||
'name': course.name,
|
|
||||||
'temp': false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'removeCourse': function(course){
|
|
||||||
console.log("remove "+course)
|
|
||||||
for(var i=this.selectCourses.length-1;i>=0;i--){
|
|
||||||
if(this.selectCourses[i].name == course){
|
|
||||||
this.selectCourses.splice(i, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'saveTemp': function(course){
|
|
||||||
if(course==null){
|
|
||||||
}else{
|
|
||||||
this.tempCourse = []
|
|
||||||
var time = this.getTime(course.time)
|
|
||||||
for(var t of time){
|
|
||||||
this.selectCourses.push({
|
|
||||||
'time': t,
|
|
||||||
'name': course.name,
|
|
||||||
'temp': true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'deleteTemp': function(course){
|
|
||||||
for(var i=this.selectCourses.length-1;i>=0;i--){
|
|
||||||
if(this.selectCourses[i].name == course.name && this.selectCourses[i].temp == true){
|
|
||||||
this.selectCourses.splice(i, 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'generatePic': function(){
|
|
||||||
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();
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'share': function(){
|
|
||||||
url = "https://snsd0805.com/NCNU_Course/share.html?id="
|
|
||||||
if(this.user!="")
|
|
||||||
alert("請複製以下網址給你的朋友,跟他分享你的課表\n\n"+url+this.user.id)
|
|
||||||
else
|
|
||||||
this.login()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
'course-table': courseTable,
|
|
||||||
'choose-department': chooseDepartment,
|
|
||||||
'course-anslist': coursesList,
|
|
||||||
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
var vm = new Vue({
|
||||||
|
el: "#main",
|
||||||
|
router
|
||||||
|
})
|
||||||
// 'update': function(){
|
|
||||||
// this.tableBody = ""
|
|
||||||
// for(var hour=8;hour<=21;hour++){
|
|
||||||
// // console.log(hour)
|
|
||||||
// symbolIndex = (hour<12)?(hour-8):(hour-9)
|
|
||||||
// this.tableBody += "<tr>"
|
|
||||||
// if(hour==12){ //處理中午時段
|
|
||||||
// this.tableBody += "<th style='text-align: center;' scope='row'>"+hour+"~"+(hour+1)+"<br>z</th>"
|
|
||||||
// this.tableBody += "<td style='text-align: center; background-color: #1abc9c;' colspan='5'>中午休息時間</td>"
|
|
||||||
|
|
||||||
// continue
|
|
||||||
// }else{
|
|
||||||
// this.tableBody += "<th style='text-align: center;' scope='row'>"+hour+"~"+(hour+1)+"<br>"+String.fromCharCode(97+symbolIndex)+"</th>"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for(var week=1;week<=5;week++){
|
|
||||||
// this.tableBody += "<td>"
|
|
||||||
// // console.log(symbolIndex)
|
|
||||||
// var course = this.exist(week+String.fromCharCode(97+symbolIndex))
|
|
||||||
// if(course){
|
|
||||||
// this.tableBody += "<div style='border: 5px #1abc9c solid; text-align: center;'>"
|
|
||||||
// // console.log(week+String.fromCharCode(97+(hour-8)))
|
|
||||||
// this.tableBody += course.name+' <button type="button" v-on:click=\"$emit(\'remove\', course)\" class="btn btn-danger btn-sm">刪</button>'
|
|
||||||
// }
|
|
||||||
// this.tableBody += "</td>"
|
|
||||||
// }
|
|
||||||
// this.tableBody += "</tr>"
|
|
||||||
// }
|
|
||||||
// this.tableBody += "</tbody>"
|
|
||||||
// }
|
|
||||||
Loading…
Reference in New Issue
Block a user