diff --git a/.gitignore b/.gitignore index 14ea590..154f96c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,8 @@ $RECYCLE.BIN/ .TemporaryItems .Trashes +lib_refer +project.config.json + # Node.js node_modules/ diff --git a/app.js b/app.js index 4edc902..ccedb93 100644 --- a/app.js +++ b/app.js @@ -1,12 +1,15 @@ //app.js //导入leancloud库,与后台交互 -const AV = require('./utils/av-live-query-weapp-min'); +const AV = require('./lib/av-live-query-weapp-min'); //初始化 AV.init({ - appId: 'fQCxN98zS5thYY3AceKdI8Pj-MdYXbMMI', - appKey: 'Tdi1DcLlVYrTabFiBaA00pjj', + appId: 'eVHYNBdT5D2lDxNj5jtJXsWT-MdYXbMMI', + appKey: 'waM3bwf1ftpsMLjRBqqVyJIQ', }); +// test Appid +// appId: 'fQCxN98zS5thYY3AceKdI8Pj-MdYXbMMI', +// appKey: 'Tdi1DcLlVYrTabFiBaA00pjj', App({ config: { diff --git a/app.json b/app.json index b6003ae..aad6154 100644 --- a/app.json +++ b/app.json @@ -7,7 +7,9 @@ "pages/websocket/websocket", "pages/game/game", "pages/shouquan/shouquan", - "pages/outside/outside" + "pages/outside/outside", + "pages/classes/classes", + "pages/classroom/classroom" ], "window": { "backgroundTextStyle": "light", diff --git a/app.wxss b/app.wxss index d5b078b..145c85b 100644 --- a/app.wxss +++ b/app.wxss @@ -1,6 +1,11 @@ page, .lab { height: 100%; } +.flex-wrap{ + display: flex; + flex-direction: row; +} + .lab { display: flex; flex-direction: column; diff --git a/readme.txt.txt b/constants/api.js similarity index 100% rename from readme.txt.txt rename to constants/api.js diff --git a/constants/appconstants.js b/constants/appconstants.js new file mode 100644 index 0000000..e69de29 diff --git a/lib/live-query-binding.js b/lib/live-query-binding.js new file mode 100644 index 0000000..8d08007 --- /dev/null +++ b/lib/live-query-binding.js @@ -0,0 +1,25 @@ +module.exports = (subscription, initialStats, onChange) => { + let stats = [...initialStats] + const remove = value => { + stats = stats.filter(target => target.id !== value.id) + return onChange(stats) + } + const upsert = value => { + let existed = false; + stats = stats.map(target => (target.id === value.id ? ((existed = true), value) : target)) + if (!existed) stats = [value, ...stats] + return onChange(stats) + } + subscription.on('create', upsert) + subscription.on('update', upsert) + subscription.on('enter', upsert) + subscription.on('leave', remove) + subscription.on('delete', remove) + return () => { + subscription.off('create', upsert) + subscription.off('update', upsert) + subscription.off('enter', upsert) + subscription.off('leave', remove) + subscription.off('delete', remove) + } +} diff --git a/model/class.js b/model/class.js new file mode 100644 index 0000000..b8d0e97 --- /dev/null +++ b/model/class.js @@ -0,0 +1,48 @@ +const AV = require('../lib/av-live-query-weapp-min'); +const Presence = require("./presence") + +class Class extends AV.Object{ + get name(){ + return this.get("name"); + } + set name(value){ + this.set("name", value); + } + get students(){ + + } + add_student(user){ + + } + del_student(user){ + let students = this.get("students"); + if(user.id in students){ + this.remove(user.id); + } + } + enter() { + this.leave(); + console.log("class.enter"); + console.log(AV.User.current()); + this._presence = new Presence({ + user: AV.User.current(), + class: this + }); + this._presence.save(); + } + leave() { + if (this._presence != null) { + this._presence.destroy(); + } + } + present_students() { + var query = new AV.Query("Presence"); + //query.equalTo("class", this._class.id); + let students = query.find(); + console.log(students); + return students; + } +} + +AV.Object.register(Class, "Class_"); +module.exports = Class; \ No newline at end of file diff --git a/model/grade.js b/model/grade.js new file mode 100644 index 0000000..53d936b --- /dev/null +++ b/model/grade.js @@ -0,0 +1,43 @@ +const AV = require('../lib/av-live-query-weapp-min'); + +//数据储存模板--分数 +class Grade extends AV.Object { + get mark() { + return this.get('done'); + } + set mark(value) { + this.set('mark', value); + } + get student(){ + return this.get("student"); + } + set student(value){ + this.set("student". value); + } + + get class() { + return this.get('class'); + } + + set class(value){ + this.set("class", value); + } + get content(){ + return this.get("content"); + } + set content(value) { + this.set('content', value); + } + get date(){ + return this.get("date"); + } + set date(value){ + this.set("date", value) + } + add_mark(value){ + this.increment(value); + } +} + +AV.Object.register(Grade, 'Grade'); +module.exports = Grade; \ No newline at end of file diff --git a/model/presence.js b/model/presence.js new file mode 100644 index 0000000..a7add19 --- /dev/null +++ b/model/presence.js @@ -0,0 +1,25 @@ +const AV = require('../lib/av-live-query-weapp-min'); + +class Presence extends AV.Object{ + set user(value){ + this.set("user", value); + } + get user(){ + return this.get("user"); + } + set class(value){ + this.set("class", value); + } + get class(){ + return this.get("class"); + } + set isasking(value){ + this.set("isasking", value); + } + get isasking(){ + return this.get("isasking"); + } +} + +AV.Object.register(Presence, "Presence"); +module.exports = Presence; \ No newline at end of file diff --git a/model/studentclassmap.js b/model/studentclassmap.js new file mode 100644 index 0000000..ccecdda --- /dev/null +++ b/model/studentclassmap.js @@ -0,0 +1,17 @@ +const AV = require("../..//lib/av-live-query-weapp-min") + + +class StudentClassMap extends AV.Object{ + get class(){ + return this.get("class"); + } + set class(value){ + this.set("class", value); + } + get user(){ + return this.get("user"); + } + set user(value){ + this.set("user", value); + } +} \ No newline at end of file diff --git a/model/user.js b/model/user.js new file mode 100644 index 0000000..47db961 --- /dev/null +++ b/model/user.js @@ -0,0 +1,11 @@ +const AV = require("../lib/av-live-query-weapp-min") + +function login() { + return AV.Promise.resolve(AV.User.current()).then(user => + user ? (user.isAuthenticated().then(authed => authed ? user : null)) : null + ).then(user => user ? user : AV.User.loginWithWeapp({ + preferUnionId: true, + })).catch(error => console.error(error.message)); +} + +module.exports = login; \ No newline at end of file diff --git a/pages/classes/classes.js b/pages/classes/classes.js new file mode 100644 index 0000000..cfca575 --- /dev/null +++ b/pages/classes/classes.js @@ -0,0 +1,102 @@ +const { Class } = require("../../model/class"); +const login = require("../../model/user"); +const AV = require("../../lib/av-live-query-weapp-min.js"); +const { jsonify } = require('../../utils/leancloudutils'); +// pages/class/class.js + +const getDataForRender = class_ => ({ + name: class_.get('name'), + objectId: class_.get('objectId') +}); + +Page({ + + /** + 页面的初始数据data,用于与.wxlm文件绑定 + classes: 课程列表 type: Array + 元素class: 课程信息 class.objectId 唯一 + class.objectId 课程唯一主键 + class.name 课程名称 + */ + data: { + classes: [ + ] + }, + + classes: [], + enter_class: function(event){ + console.log(event); + var class_id = event.currentTarget.dataset.class_id; + var class_name = event.currentTarget.dataset.class_name; + wx.navigateTo({ + url: "../classroom/classroom?class_id="+class_id+"&"+"class_name="+class_name, + }) + }, + + /** + * 生命周期函数--监听页面加载 + */ + onLoad: function (options) { + login().then((user)=>{ + console.log(user); + console.log(AV.User.current()); + }); + }, + + /** + * 生命周期函数--监听页面初次渲染完成 + */ + onReady: function () { + + }, + + /** + * 生命周期函数--监听页面显示 + */ + onShow: function () { + var query = new AV.Query("Class_"); + query.find().then((classes) => { + this.classes = classes + this.setData(jsonify({ classes })); + }) + }, + + /** + * 生命周期函数--监听页面隐藏 + */ + onHide: function () { + + }, + + /** + * 生命周期函数--监听页面卸载 + */ + onUnload: function () { + + }, + + /** + * 页面相关事件处理函数--监听用户下拉动作 + */ + onPullDownRefresh: function () { + var query = new AV.Query("Class_"); + query.find().then((classes) => { + this.classes = classes + this.setData(jsonify({classes})); + }) + }, + + /** + * 页面上拉触底事件的处理函数 + */ + onReachBottom: function () { + + }, + + /** + * 用户点击右上角分享 + */ + onShareAppMessage: function () { + + } +}) \ No newline at end of file diff --git a/pages/classes/classes.json b/pages/classes/classes.json new file mode 100644 index 0000000..7360326 --- /dev/null +++ b/pages/classes/classes.json @@ -0,0 +1,4 @@ +{ + "usingComponents": {}, + "enablePullDownRefresh": true +} \ No newline at end of file diff --git a/pages/classes/classes.wxml b/pages/classes/classes.wxml new file mode 100644 index 0000000..1afd37e --- /dev/null +++ b/pages/classes/classes.wxml @@ -0,0 +1,14 @@ + + + + + {{class.name}} + + + \ No newline at end of file diff --git a/pages/classes/classes.wxss b/pages/classes/classes.wxss new file mode 100644 index 0000000..015bcde --- /dev/null +++ b/pages/classes/classes.wxss @@ -0,0 +1,28 @@ +.header { + height: 54px; + align-items: center; + background-color: #FFF; +} + +.class-list { + padding: 4px 6px 48px; +} + +.classroom { + font-size: 18px; + height: 30px; + padding: 10px 12px; + overflow: hidden; + align-items: center; + background-color: #fff; + margin: 1px 0; + border-radius: 3px; +} + +.classroom text { + white-space: nowrap; + display: block; + width: 100%; + height: 50px; + line-height: 17px; +} diff --git a/pages/classroom/classroom.js b/pages/classroom/classroom.js new file mode 100644 index 0000000..05c9d09 --- /dev/null +++ b/pages/classroom/classroom.js @@ -0,0 +1,180 @@ +// pages/classroom/classroom.js +const AV = require("../../lib/av-live-query-weapp-min") +const { jsonify } = require('../../utils/leancloudutils'); +const bind = require("../../lib/live-query-binding") + +Page({ + /** + 页面的初始数据 + students: 该课程所有的学生 + 元素student + student.objectId 该学生的主键,唯一 + student.username 学生的用户名,是唯一,就像微信号一样 + student.name 学生的姓名 + student.present 是否出席 + student.isasking :0:没有提问,1:提问,2:请回答 + */ + presence: null, + students: [], + class: null, + class_id: null, + data: { + //以下数据的同步由该代码文件实现,数据的呈现由classroom.wxml实现 + students: [], // 该课程所有的学生, 元素类型见上文中的student + current_user: null, //目前登陆的用户,类型为对象,属性有objectId,username, name + teacher: null, + //该课程教员,类型为对象 + //请在进入界面时判断用户是否为教员以给与权限或更改界面 + //属性如下:objectId, username, name + class_name: "", //课程名称 + class_id: "", //该课程的主键(编号) + }, + sco1: function () { + //打1分的函数 + }, + sco2: function () { + //打2分的函数 + }, + sco3: function () { + //打3分的函数 + }, + ask: function () { + //学生提问的函数 + }, + rep: function () { + //点这个学生要回答他问题的函数 + }, + pull_present: function(){ + var query = new AV.Query("Presence"); + //console.log(this.class); + query.equalTo("class", this.class); + query.include("user"); + set_present = this.set_present.bind(this); + return AV.Promise.all([query.find().then(set_present), query.subscribe()]).then(([presents, subscription])=>{ + this.PresentSubscription = subscription; + if(this.presentUnbind) this.presentUnbind(); + this.presentUnbind = bind(subscription, presents, set_present); + }).catch(error=> console.error(error.message)); + }, + set_present: function(presents){ + //console.log("set_present"); + //console.log(presents); + var is_asking={}; + var present_stu_ids = presents.map((present)=>{ + user = present.get("user"); + is_asking[user.id]=present.get("isasking"); + return user.id; + }); + students = this.students.map((student)=>{ + if(present_stu_ids.indexOf(student.id)>-1){ + student.set("ispresent",true); + student.set("isasking", is_asking[student.id]); + }else{ + student.set("ispresent",false); + student.set("isasking", 0); + } + + return student; + }) + this.setData(jsonify({students})); + return presents; + }, + + fetch_class: function(class_id){ + this.class = AV.Object.createWithoutData("Class_", class_id); + return this.class.fetch().then((class_) => { + //console.log(this.class); + this.setData({ + class_name: this.class.get("name"), + class_id: this.class.get("objectId") + }); + }).catch(error=>console.error(error.message)) + }, + fetch_students: function(){ + //console.log("fetch_students"); + var query = new AV.Query("StudentClassMap"); + query.equalTo("class", this.class); + query.include("user"); + //console.log("fetch_students2") + return query.find(); + }, + set_students: function(studentClassMaps){ + //console.log("set_students"); + var students = [] + studentClassMaps.forEach((scm, idx, a)=>{ + console.log(a); + students.push(scm.get("user")); + }); + this.students = students; + console.log("this.students"); + console.log(students); + this.setData(jsonify((students))); + return students; + }, + + /** + * 生命周期函数--监听页面加载 + */ + onLoad: function (options) { + this.class_id = options.class_id; + //this.class = AV.Object.createWithoutData("Class_", this.class_id); + this.fetch_class.bind(this)(this.class_id).then(this.fetch_students).then(this.set_students.bind(this)).then(this.pull_present.bind(this)); + console.log("onLoad"); + }, + + /** + * 生命周期函数--监听页面初次渲染完成 + */ + onReady: function () { + console.log("onReady"); + }, + + /** + * 生命周期函数--监听页面显示 + */ + onShow: function () { + console.log("onShow"); + console.log("enter class when onShow"); + console.log(AV.User.current()); + this.class.enter(); + }, + + /** + * 生命周期函数--监听页面隐藏 + */ + onHide: function () { + this.class.leave(); + console.log("onHide"); + }, + + /** + * 生命周期函数--监听页面卸载 + */ + onUnload: function () { + this.class.leave(); + console.log("onUnload"); + this.PresentSubscription.unsubscribe(); + this.presentUnbind(); + }, + + /** + * 页面相关事件处理函数--监听用户下拉动作 + */ + onPullDownRefresh: function () { + this.pull_present.bind(this)(); + }, + + /** + * 页面上拉触底事件的处理函数 + */ + onReachBottom: function () { + + }, + + /** + * 用户点击右上角分享 + */ + onShareAppMessage: function () { + console.log("onShareAppMessage"); + } +}) \ No newline at end of file diff --git a/pages/classroom/classroom.json b/pages/classroom/classroom.json new file mode 100644 index 0000000..7360326 --- /dev/null +++ b/pages/classroom/classroom.json @@ -0,0 +1,4 @@ +{ + "usingComponents": {}, + "enablePullDownRefresh": true +} \ No newline at end of file diff --git a/pages/classroom/classroom.wxml b/pages/classroom/classroom.wxml new file mode 100644 index 0000000..705d2de --- /dev/null +++ b/pages/classroom/classroom.wxml @@ -0,0 +1,29 @@ + + + + + + + + + {{student.username}} + + + {{student.username}} + + {{student.username}} + + + + + + + + + + + + + + + diff --git a/pages/classroom/classroom.wxss b/pages/classroom/classroom.wxss new file mode 100644 index 0000000..d4e30be --- /dev/null +++ b/pages/classroom/classroom.wxss @@ -0,0 +1,62 @@ +/* pages/classroom/classroom.wxss */ + +.grid-view { + display: -webkit-flex; + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + width: 100%; +} + +/* 下面这个实现表格式的布局,有多行多列,width=25% 表示将会显示4列 */ + +.grid-celll +{ + margin-left:auto; + margin-right:auto; + text-align: center; + width:230rpx; + display: flex; + flex-direction: column; + flex-wrap: wrap; +} + + +.grid-cell { + padding: 30rpx 0; + border-bottom: 1rpx solid #eee; + position: relative; +} + +.bla { + color:black; + +} + +.reed { + color: red; + position: absolute; + right: 3rpx; + top: 50%; + height: 40rpx; + line-height: 40rpx; + margin-top: -20rpx; +} + +.gre { + color: greenyellow; + position: absolute; + right: 3rpx; + top: 50%; + height: 40rpx; + line-height: 40rpx; + margin-top: -20rpx; +} + +.index { + font-family: 'PingFang SC'; +} +.sco { + margin: 20rpx 50rpx; +} diff --git a/pages/index/index.js b/pages/index/index.js index f1def29..7d68f54 100644 --- a/pages/index/index.js +++ b/pages/index/index.js @@ -7,12 +7,14 @@ Page({ { id: 'https', title: '实验一:HTTPS' }, { id: 'session', title: '实验二:会话' }, { id: 'websocket', title: '实验三:WebSocket' }, - { id: 'game', title: '实验四:剪刀石头布小游戏' } + { id: 'game', title: '实验四:剪刀石头布小游戏' }, + { id: "classes", title: "进入教室"} ], done: lab.getFinishLabs() }, onShow() { + console.log({ done: lab.getFinishLabs() }); this.setData({ done: lab.getFinishLabs() }); }, diff --git a/pages/index/index.json b/pages/index/index.json index 69f4998..834c3dd 100644 --- a/pages/index/index.json +++ b/pages/index/index.json @@ -1,3 +1,3 @@ { - "navigationBarTitleText": "腾讯云实验室" + "navigationBarTitleText": "积分教室" } \ No newline at end of file diff --git a/project.config.json b/project.config.json index a7461b2..8dad655 100644 --- a/project.config.json +++ b/project.config.json @@ -4,8 +4,8 @@ "ignore": [] }, "setting": { - "urlCheck": false, - "es6": true, + "urlCheck": true, + "es6": false, "postcss": true, "minified": true, "newFeature": true, @@ -23,7 +23,7 @@ "compileType": "miniprogram", "libVersion": "2.8.3", "appid": "wx2a901996834ef5fb", - "projectname": "miniprogram-3", + "projectname": "smart-class", "debugOptions": { "hidedInDevtools": [] }, diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..e69de29 diff --git a/utils/leancloudutils.js b/utils/leancloudutils.js new file mode 100644 index 0000000..d0c7702 --- /dev/null +++ b/utils/leancloudutils.js @@ -0,0 +1,20 @@ +const isPlainObject = target => + target && + target.toString() == '[object Object]' && + Object.getPrototypeOf(target) == Object.prototype; +const _jsonify = target => { + if (target && typeof target.toJSON === 'function') return target.toJSON(); + if (Array.isArray(target)) return target.map(_jsonify); + return target; +}; + +exports.jsonify = target => + isPlainObject(target) + ? Object.keys(target).reduce( + (result, key) => ({ + ...result, + [key]: _jsonify(target[key]) + }), + {} + ) + : _jsonify(target); diff --git a/utils/userutils.js b/utils/userutils.js new file mode 100644 index 0000000..e69de29 diff --git a/读我.txt b/读我.txt index 9ebb734..47dd6d7 100644 --- a/读我.txt +++ b/读我.txt @@ -1,11 +1,15 @@ -登录微信公众平台,前往 设置 > 开发设置 > 服务器配置 > 「修改」 链接,增加下述域名为白名单中的域名 +# 后台数据交互部分日志 + +## 已完成-登录微信公众平台,前往 设置 > 开发设置 > 服务器配置 > 「修改」 链接,增加下述域名为白名单中的域名 +request合法域名 fqcxn98z.api.lncldglobal.com fqcxn98z.engine.lncldglobal.com fqcxn98z.rtm.lncldglobal.com fqcxn98z.push.lncldglobal.com app-router.leancloud.cn +socket合法域名 us-w1-backend2.leancloud.cn us-w1-backend3.leancloud.cn us-w1-backend4.leancloud.cn us-w1-backend5.leancloud.cn -us-w1-backend6.leancloud.cn \ No newline at end of file +us-w1-backend6.leancloud.cn